Add the option, -archive-headers, used with -macho to print the Mach-O archive header...
authorKevin Enderby <enderby@apple.com>
Thu, 15 Jan 2015 23:19:11 +0000 (23:19 +0000)
committerKevin Enderby <enderby@apple.com>
Thu, 15 Jan 2015 23:19:11 +0000 (23:19 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226228 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/Archive.h
lib/Object/Archive.cpp
test/tools/llvm-objdump/X86/macho-archive-headers.test [new file with mode: 0644]
tools/llvm-objdump/MachODump.cpp
tools/llvm-objdump/llvm-objdump.cpp
tools/llvm-objdump/llvm-objdump.h

index 4e96205a93ba850ff555b30f02a16bfaa97cd3ab..71906d16770164dbe74c5a438092d78fc0ccc4b5 100644 (file)
@@ -41,6 +41,9 @@ struct ArchiveMemberHeader {
 
   sys::fs::perms getAccessMode() const;
   sys::TimeValue getLastModified() const;
+  llvm::StringRef getRawLastModified() const {
+    return StringRef(LastModified, sizeof(LastModified)).rtrim(" ");
+  }
   unsigned getUID() const;
   unsigned getGID() const;
 };
@@ -78,6 +81,9 @@ public:
     sys::TimeValue getLastModified() const {
       return getHeader()->getLastModified();
     }
+    StringRef getRawLastModified() const {
+      return getHeader()->getRawLastModified();
+    }
     unsigned getUID() const { return getHeader()->getUID(); }
     unsigned getGID() const { return getHeader()->getGID(); }
     sys::fs::perms getAccessMode() const {
@@ -85,10 +91,13 @@ public:
     }
     /// \return the size of the archive member without the header or padding.
     uint64_t getSize() const;
+    /// \return the size of the archive member with the header and padding.
+    uint64_t getRawSize() const;
 
     StringRef getBuffer() const {
       return StringRef(Data.data() + StartOfFile, getSize());
     }
+    uint64_t getChildOffset() const;
 
     ErrorOr<MemoryBufferRef> getMemoryBufferRef() const;
 
@@ -194,6 +203,7 @@ public:
   child_iterator findSym(StringRef name) const;
 
   bool hasSymbolTable() const;
+  child_iterator getSymbolTableChild() const { return SymbolTable; }
 
 private:
   child_iterator SymbolTable;
index 5aada91ecc0fcd8b1eb98b1fb844c69afa7cae27..ba35e49faa67b26269d7de4c6742bdf6e13ca5e3 100644 (file)
@@ -110,6 +110,12 @@ uint64_t Archive::Child::getSize() const {
   return Data.size() - StartOfFile;
 }
 
+uint64_t Archive::Child::getRawSize() const {
+  if (Parent->IsThin)
+    return getHeader()->getSize();
+  return Data.size();
+}
+
 Archive::Child Archive::Child::getNext() const {
   size_t SpaceToSkip = Data.size();
   // If it's odd, add 1 to make it even.
@@ -125,6 +131,13 @@ Archive::Child Archive::Child::getNext() const {
   return Child(Parent, NextLoc);
 }
 
+uint64_t Archive::Child::getChildOffset() const {
+  const char *a = Parent->Data.getBuffer().data();
+  const char *c = Data.data();
+  uint64_t offset = c - a;
+  return offset;
+}
+
 ErrorOr<StringRef> Archive::Child::getName() const {
   StringRef name = getRawName();
   // Check if it's a special name.
diff --git a/test/tools/llvm-objdump/X86/macho-archive-headers.test b/test/tools/llvm-objdump/X86/macho-archive-headers.test
new file mode 100644 (file)
index 0000000..3d9043e
--- /dev/null
@@ -0,0 +1,10 @@
+RUN: llvm-objdump %p/Inputs/macho-universal-archive.x86_64.i386 -macho -archive-headers -arch all \
+RUN: | FileCheck %s
+
+# Note the date as printed by ctime(3) is time zone dependent and not checked.
+CHECK: Archive : {{.*}}/macho-universal-archive.x86_64.i386 (architecture x86_64)
+CHECK: -rw-r--r--124/11     44 {{.*}} __.SYMDEF SORTED
+CHECK: -rw-r--r--124/0     860 {{.*}} hello.o
+CHECK: Archive : {{.*}}/macho-universal-archive.x86_64.i386 (architecture i386)
+CHECK: -rw-r--r--124/11     60 {{.*}} __.SYMDEF SORTED
+CHECK: -rw-r--r--124/0     388 {{.*}} foo.o
index 03fad5f922fc13d660228869069396330e3a0ded..51140c29cede279b8986abfe047cfbca3a687bc3 100644 (file)
@@ -66,9 +66,14 @@ static cl::opt<bool>
     PrintImmHex("print-imm-hex",
                 cl::desc("Use hex format for immediate values"));
 
+cl::opt<bool> llvm::UniversalHeaders("universal-headers",
+                                     cl::desc("Print Mach-O universal headers "
+                                              "(requires -macho)"));
+
 cl::opt<bool>
-    llvm::UniversalHeaders("universal-headers",
-                           cl::desc("Print Mach-O universal headers"));
+    llvm::ArchiveHeaders("archive-headers",
+                         cl::desc("Print archive headers for Mach-O archives "
+                                  "(requires -macho)"));
 
 static cl::list<std::string>
     ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"),
@@ -514,6 +519,106 @@ static void printMachOUniversalHeaders(const object::MachOUniversalBinary *UB,
   }
 }
 
+static void printArchiveChild(Archive::Child &C, bool verbose,
+                              bool print_offset) {
+  if (print_offset)
+    outs() << C.getChildOffset() << "\t";
+  sys::fs::perms Mode = C.getAccessMode();
+  if (verbose) {
+    // FIXME: this first dash, "-", is for (Mode & S_IFMT) == S_IFREG.
+    // But there is nothing in sys::fs::perms for S_IFMT or S_IFREG.
+    outs() << "-";
+    if (Mode & sys::fs::owner_read)
+      outs() << "r";
+    else
+      outs() << "-";
+    if (Mode & sys::fs::owner_write)
+      outs() << "w";
+    else
+      outs() << "-";
+    if (Mode & sys::fs::owner_exe)
+      outs() << "x";
+    else
+      outs() << "-";
+    if (Mode & sys::fs::group_read)
+      outs() << "r";
+    else
+      outs() << "-";
+    if (Mode & sys::fs::group_write)
+      outs() << "w";
+    else
+      outs() << "-";
+    if (Mode & sys::fs::group_exe)
+      outs() << "x";
+    else
+      outs() << "-";
+    if (Mode & sys::fs::others_read)
+      outs() << "r";
+    else
+      outs() << "-";
+    if (Mode & sys::fs::others_write)
+      outs() << "w";
+    else
+      outs() << "-";
+    if (Mode & sys::fs::others_exe)
+      outs() << "x";
+    else
+      outs() << "-";
+  } else {
+    outs() << format("0%o ", Mode);
+  }
+
+  unsigned UID = C.getUID();
+  outs() << format("%3d/", UID);
+  unsigned GID = C.getGID();
+  outs() << format("%-3d ", GID);
+  uint64_t Size = C.getRawSize() - sizeof(object::ArchiveMemberHeader);
+  outs() << format("%5d ", Size);
+
+  StringRef RawLastModified = C.getRawLastModified();
+  if (verbose) {
+    unsigned Seconds;
+    if (RawLastModified.getAsInteger(10, Seconds))
+      outs() << "(date: \"%s\" contains non-decimal chars) " << RawLastModified;
+    else {
+      // Since cime(3) returns a 26 character string of the form:
+      // "Sun Sep 16 01:03:52 1973\n\0"
+      // just print 24 characters.
+      time_t t = Seconds;
+      outs() << format("%.24s ", ctime(&t));
+    }
+  } else {
+    outs() << RawLastModified << " ";
+  }
+
+  if (verbose) {
+    ErrorOr<StringRef> NameOrErr = C.getName();
+    if (NameOrErr.getError()) {
+      StringRef RawName = C.getRawName();
+      outs() << RawName << "\n";
+    } else {
+      StringRef Name = NameOrErr.get();
+      outs() << Name << "\n";
+    }
+  } else {
+    StringRef RawName = C.getRawName();
+    outs() << RawName << "\n";
+  }
+}
+
+static void printArchiveHeaders(Archive *A, bool verbose, bool print_offset) {
+  if (A->hasSymbolTable()) {
+    Archive::child_iterator S = A->getSymbolTableChild();
+    Archive::Child C = *S;
+    printArchiveChild(C, verbose, print_offset);
+  }
+  for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); I != E;
+       ++I) {
+    Archive::Child C = *I;
+    printArchiveChild(C, verbose, print_offset);
+  }
+}
+
 // ParseInputMachO() parses the named Mach-O file in Filename and handles the
 // -arch flags selecting just those slices as specified by them and also parses
 // archive files.  Then for each individual Mach-O file ProcessMachO() is
@@ -542,6 +647,8 @@ void llvm::ParseInputMachO(StringRef Filename) {
 
   if (Archive *A = dyn_cast<Archive>(&Bin)) {
     outs() << "Archive : " << Filename << "\n";
+    if (ArchiveHeaders)
+      printArchiveHeaders(A, true, false);
     for (Archive::child_iterator I = A->child_begin(), E = A->child_end();
          I != E; ++I) {
       ErrorOr<std::unique_ptr<Binary>> ChildOrErr = I->getAsBinary();
@@ -587,6 +694,8 @@ void llvm::ParseInputMachO(StringRef Filename) {
               if (!ArchitectureName.empty())
                 outs() << " (architecture " << ArchitectureName << ")";
               outs() << "\n";
+              if (ArchiveHeaders)
+                printArchiveHeaders(A.get(), true, false);
               for (Archive::child_iterator AI = A->child_begin(),
                                            AE = A->child_end();
                    AI != AE; ++AI) {
@@ -627,6 +736,8 @@ void llvm::ParseInputMachO(StringRef Filename) {
                          I->getAsArchive()) {
             std::unique_ptr<Archive> &A = *AOrErr;
             outs() << "Archive : " << Filename << "\n";
+            if (ArchiveHeaders)
+              printArchiveHeaders(A.get(), true, false);
             for (Archive::child_iterator AI = A->child_begin(),
                                          AE = A->child_end();
                  AI != AE; ++AI) {
@@ -662,6 +773,8 @@ void llvm::ParseInputMachO(StringRef Filename) {
         if (!ArchitectureName.empty())
           outs() << " (architecture " << ArchitectureName << ")";
         outs() << "\n";
+        if (ArchiveHeaders)
+          printArchiveHeaders(A.get(), true, false);
         for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end();
              AI != AE; ++AI) {
           ErrorOr<std::unique_ptr<Binary>> ChildOrErr = AI->getAsBinary();
index aff6272d2fa3300da16bb6e8c8f658dc3af822bd..6334859b25778be41952f7a7e3014192c7a7030a 100644 (file)
@@ -892,7 +892,8 @@ int main(int argc, char **argv) {
       && !Bind
       && !LazyBind
       && !WeakBind
-      && !(UniversalHeaders && MachOOpt)) {
+      && !(UniversalHeaders && MachOOpt)
+      && !(ArchiveHeaders && MachOOpt)) {
     cl::PrintHelpMessage();
     return 2;
   }
index f829dd1a71c350332c34e11d47d0a4e1411305bd..491a819132e65a8b2a24202f64286dcda661297e 100644 (file)
@@ -35,6 +35,7 @@ extern cl::opt<bool> Bind;
 extern cl::opt<bool> LazyBind;
 extern cl::opt<bool> WeakBind;
 extern cl::opt<bool> UniversalHeaders;
+extern cl::opt<bool> ArchiveHeaders;
 
 // Various helper functions.
 bool error(std::error_code ec);