Index: test/tools/llvm-objdump/archive-headers.test =================================================================== --- /dev/null +++ test/tools/llvm-objdump/archive-headers.test @@ -0,0 +1,12 @@ +#RUN: llvm-objdump -a %p/Inputs/liblong_filenames.a | FileCheck %s + +#CHECK: In archive {{.*}}/Inputs/liblong_filenames.a: +#CHECK: -rw-r--r-- 204299/200 1416 Tue Oct 30 15:33:29 2012 1.o +#CHECK: -rw-r--r-- 204299/200 1224 Tue Oct 30 15:33:29 2012 2.o +#CHECK: -rw-r--r-- 204299/200 1312 Tue Oct 30 15:33:29 2012 3.o +#CHECK: -rw-r--r-- 204299/200 957 Tue Oct 30 15:33:29 2012 4.o +#CHECK: -rw-r--r-- 204299/200 951 Tue Oct 30 15:33:29 2012 5.o +#CHECK: -rw-r--r-- 204299/200 951 Tue Oct 30 15:33:29 2012 6.o +#CHECK: -rw-r--r-- 204299/200 977 Tue Oct 30 15:33:29 2012 abcdefghijklmnopqrstuvwxyz1.o +#CHECK: -rw-r--r-- 204299/200 1272 Tue Oct 30 15:33:29 2012 abcdefghijklmnopqrstuvwxyz2.o +#CHECK: -rw-r--r-- 204299/200 977 Tue Oct 30 15:29:33 2012 abcdefghijklmnopq.o Index: tools/llvm-objdump/MachODump.cpp =================================================================== --- tools/llvm-objdump/MachODump.cpp +++ tools/llvm-objdump/MachODump.cpp @@ -80,6 +80,10 @@ cl::desc("Print archive headers for Mach-O archives " "(requires -macho)")); +cl::alias +ArchiveHeadersShort("a", cl::desc("Alias for --archive-headers"), + cl::aliasopt(ArchiveHeaders)); + cl::opt ArchiveMemberOffsets("archive-member-offsets", cl::desc("Print the offset to each archive member for " Index: tools/llvm-objdump/llvm-objdump.cpp =================================================================== --- tools/llvm-objdump/llvm-objdump.cpp +++ tools/llvm-objdump/llvm-objdump.cpp @@ -2123,6 +2123,75 @@ report_error(o->getFileName(), "Invalid/Unsupported object file format"); } +static void printArchiveChild(StringRef Filename, const Archive::Child &C) { + Expected ModeOrErr = C.getAccessMode(); + if (!ModeOrErr) { + consumeError(ModeOrErr.takeError()); + outs() << "ill-formed archive entry.\n"; + return; + } + sys::fs::perms Mode = ModeOrErr.get(); + // 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() << "-"; + outs() << ((Mode & sys::fs::owner_read) ? "r" : "-"); + outs() << ((Mode & sys::fs::owner_write) ? "w" : "-"); + outs() << ((Mode & sys::fs::owner_exe) ? "x" : "-"); + outs() << ((Mode & sys::fs::group_read) ? "r" : "-"); + outs() << ((Mode & sys::fs::group_write) ? "w" : "-"); + outs() << ((Mode & sys::fs::group_exe) ? "x" : "-"); + outs() << ((Mode & sys::fs::others_read) ? "r" : "-"); + outs() << ((Mode & sys::fs::others_write) ? "w" : "-"); + outs() << ((Mode & sys::fs::others_exe) ? "x" : "-"); + + outs() << " "; + + Expected UIDOrErr = C.getUID(); + if (!UIDOrErr) + report_error(Filename, UIDOrErr.takeError()); + unsigned UID = UIDOrErr.get(); + outs() << format("%3d/", UID); + Expected GIDOrErr = C.getGID(); + if (!GIDOrErr) + report_error(Filename, GIDOrErr.takeError()); + unsigned GID = GIDOrErr.get(); + outs() << format("%-3d ", GID); + Expected Size = C.getRawSize(); + if (!Size) + report_error(Filename, Size.takeError()); + outs() << format("%5" PRId64, Size.get()) << " "; + + StringRef RawLastModified = C.getRawLastModified(); + unsigned Seconds; + if (RawLastModified.getAsInteger(10, Seconds)) + outs() << "(date: \"" << RawLastModified + << "\" contains non-decimal chars) "; + 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)); + } + + Expected NameOrErr = C.getName(); + if (!NameOrErr) { + consumeError(NameOrErr.takeError()); + Expected NameOrErr = C.getRawName(); + if (!NameOrErr) + report_error(Filename, NameOrErr.takeError()); + StringRef RawName = NameOrErr.get(); + outs() << RawName << "\n"; + } else { + StringRef Name = NameOrErr.get(); + outs() << Name << "\n"; + } +} + +static void printArchiveHeaders(StringRef Filename, const Archive *A) { + outs() << "In archive " << Filename << ":\n"; +} + static void DumpObject(ObjectFile *o, const Archive *a = nullptr) { StringRef ArchiveName = a != nullptr ? a->getFileName() : ""; // Avoid other output when using a raw option. @@ -2132,7 +2201,9 @@ outs() << a->getFileName() << "(" << o->getFileName() << ")"; else outs() << o->getFileName(); - outs() << ":\tfile format " << o->getFileFormatName() << "\n\n"; + outs() << ":\tfile format " << o->getFileFormatName() << "\n"; + if (!ArchiveHeaders || MachOOpt) + outs() << "\n"; } if (Disassemble) @@ -2190,6 +2261,8 @@ /// Dump each object file in \a a; static void DumpArchive(const Archive *a) { + if (ArchiveHeaders && !MachOOpt) + printArchiveHeaders(a->getFileName(), a); Error Err = Error::success(); for (auto &C : a->children(Err)) { Expected> ChildOrErr = C.getAsBinary(); @@ -2204,6 +2277,8 @@ DumpObject(I, a); else report_error(a->getFileName(), object_error::invalid_file_type); + if (ArchiveHeaders && !MachOOpt) + printArchiveChild(a->getFileName(), C); } if (Err) report_error(a->getFileName(), std::move(Err)); @@ -2275,7 +2350,7 @@ && !WeakBind && !RawClangAST && !(UniversalHeaders && MachOOpt) - && !(ArchiveHeaders && MachOOpt) + && !ArchiveHeaders && !(IndirectSymbols && MachOOpt) && !(DataInCode && MachOOpt) && !(LinkOptHints && MachOOpt)