From cdfe54f8a9e12b4d3a86bbc96e4a968f37ec4290 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Thu, 15 Jan 2015 23:19:11 +0000 Subject: [PATCH] Add the option, -archive-headers, used with -macho to print the Mach-O archive headers to llvm-objdump. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@226228 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/Archive.h | 10 ++ lib/Object/Archive.cpp | 13 ++ .../X86/macho-archive-headers.test | 10 ++ tools/llvm-objdump/MachODump.cpp | 117 +++++++++++++++++- tools/llvm-objdump/llvm-objdump.cpp | 3 +- tools/llvm-objdump/llvm-objdump.h | 1 + 6 files changed, 151 insertions(+), 3 deletions(-) create mode 100644 test/tools/llvm-objdump/X86/macho-archive-headers.test diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index 4e96205a93b..71906d16770 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -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 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; diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 5aada91ecc0..ba35e49faa6 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -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 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 index 00000000000..3d9043e671a --- /dev/null +++ b/test/tools/llvm-objdump/X86/macho-archive-headers.test @@ -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 diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 03fad5f922f..51140c29ced 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -66,9 +66,14 @@ static cl::opt PrintImmHex("print-imm-hex", cl::desc("Use hex format for immediate values")); +cl::opt llvm::UniversalHeaders("universal-headers", + cl::desc("Print Mach-O universal headers " + "(requires -macho)")); + cl::opt - 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 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 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(&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> 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 &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> ChildOrErr = AI->getAsBinary(); diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index aff6272d2fa..6334859b257 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -892,7 +892,8 @@ int main(int argc, char **argv) { && !Bind && !LazyBind && !WeakBind - && !(UniversalHeaders && MachOOpt)) { + && !(UniversalHeaders && MachOOpt) + && !(ArchiveHeaders && MachOOpt)) { cl::PrintHelpMessage(); return 2; } diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index f829dd1a71c..491a819132e 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -35,6 +35,7 @@ extern cl::opt Bind; extern cl::opt LazyBind; extern cl::opt WeakBind; extern cl::opt UniversalHeaders; +extern cl::opt ArchiveHeaders; // Various helper functions. bool error(std::error_code ec); -- 2.34.1