From 2fc34c5f847adc68529d4786becd48459b79a0a6 Mon Sep 17 00:00:00 2001 From: David Meyer Date: Thu, 1 Mar 2012 01:36:50 +0000 Subject: [PATCH] [Object] * Add begin_dynamic_table() / end_dynamic_table() private interface to ELFObjectFile. * Add begin_libraries_needed() / end_libraries_needed() interface to ObjectFile, for grabbing the list of needed libraries for a shared object or dynamic executable. * Implement this new interface completely for ELF, leave stubs for COFF and MachO. * Add 'llvm-readobj' tool for dumping ObjectFile information. llvm-svn: 151785 --- llvm/include/llvm/Object/COFF.h | 7 + llvm/include/llvm/Object/ELF.h | 265 +++++++++++++++++- llvm/include/llvm/Object/MachO.h | 5 + llvm/include/llvm/Object/ObjectFile.h | 54 ++++ llvm/lib/Object/COFFObjectFile.cpp | 20 ++ llvm/lib/Object/MachOObjectFile.cpp | 21 ++ .../Object/Inputs/shared-object-test.elf-i386 | Bin 1792 -> 1848 bytes .../Inputs/shared-object-test.elf-x86-64 | Bin 2680 -> 2760 bytes llvm/test/Object/Inputs/shared.ll | 6 +- llvm/test/Object/readobj-shared-object.test | 44 +++ llvm/tools/CMakeLists.txt | 1 + llvm/tools/Makefile | 2 +- llvm/tools/llvm-readobj/CMakeLists.txt | 5 + llvm/tools/llvm-readobj/LLVMBuild.txt | 22 ++ llvm/tools/llvm-readobj/Makefile | 18 ++ llvm/tools/llvm-readobj/llvm-readobj.cpp | 188 +++++++++++++ 16 files changed, 654 insertions(+), 4 deletions(-) create mode 100644 llvm/test/Object/readobj-shared-object.test create mode 100644 llvm/tools/llvm-readobj/CMakeLists.txt create mode 100644 llvm/tools/llvm-readobj/LLVMBuild.txt create mode 100644 llvm/tools/llvm-readobj/Makefile create mode 100644 llvm/tools/llvm-readobj/llvm-readobj.cpp diff --git a/llvm/include/llvm/Object/COFF.h b/llvm/include/llvm/Object/COFF.h index 732141219e61..6212785e3f2f 100644 --- a/llvm/include/llvm/Object/COFF.h +++ b/llvm/include/llvm/Object/COFF.h @@ -145,12 +145,19 @@ protected: virtual error_code getRelocationValueString(DataRefImpl Rel, SmallVectorImpl &Result) const; + virtual error_code getLibraryNext(DataRefImpl LibData, + LibraryRef &Result) const; + virtual error_code getLibraryPath(DataRefImpl LibData, + StringRef &Result) const; + public: COFFObjectFile(MemoryBuffer *Object, error_code &ec); virtual symbol_iterator begin_symbols() const; virtual symbol_iterator end_symbols() const; virtual symbol_iterator begin_dynamic_symbols() const; virtual symbol_iterator end_dynamic_symbols() const; + virtual library_iterator begin_libraries_needed() const; + virtual library_iterator end_libraries_needed() const; virtual section_iterator begin_sections() const; virtual section_iterator end_sections() const; diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index 6e3fa013af33..ce002f2e4e32 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -176,6 +176,71 @@ struct Elf_Sym_Impl : Elf_Sym_Base { } }; +// Elf_Dyn: Entry in the dynamic table +template +struct Elf_Dyn_Base; + +template +struct Elf_Dyn_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, false) + Elf_Sword d_tag; + union { + Elf_Word d_val; + Elf_Addr d_ptr; + } d_un; +}; + +template +struct Elf_Dyn_Base { + LLVM_ELF_IMPORT_TYPES(target_endianness, true) + Elf_Sxword d_tag; + union { + Elf_Xword d_val; + Elf_Addr d_ptr; + } d_un; +}; + +template +struct Elf_Dyn_Impl : Elf_Dyn_Base { + using Elf_Dyn_Base::d_tag; + using Elf_Dyn_Base::d_un; + int64_t getTag() const { return d_tag; } + uint64_t getVal() const { return d_un.d_val; } + uint64_t getPtr() const { return d_un.ptr; } +}; + +template +class ELFObjectFile; + +// DynRefImpl: Reference to an entry in the dynamic table +// This is an ELF-specific interface. +template +class DynRefImpl { + typedef Elf_Dyn_Impl Elf_Dyn; + typedef ELFObjectFile OwningType; + + DataRefImpl DynPimpl; + const OwningType *OwningObject; + +public: + DynRefImpl() : OwningObject(NULL) { + std::memset(&DynPimpl, 0, sizeof(DynPimpl)); + } + + DynRefImpl(DataRefImpl DynP, const OwningType *Owner); + + bool operator==(const DynRefImpl &Other) const; + bool operator <(const DynRefImpl &Other) const; + + error_code getNext(DynRefImpl &Result) const; + int64_t getTag() const; + uint64_t getVal() const; + uint64_t getPtr() const; + + DataRefImpl getRawDataRefImpl() const; +}; + +// Elf_Rel: Elf Relocation template struct Elf_Rel_Base; @@ -255,8 +320,11 @@ class ELFObjectFile : public ObjectFile { typedef Elf_Shdr_Impl Elf_Shdr; typedef Elf_Sym_Impl Elf_Sym; + typedef Elf_Dyn_Impl Elf_Dyn; typedef Elf_Rel_Impl Elf_Rel; typedef Elf_Rel_Impl Elf_Rela; + typedef DynRefImpl DynRef; + typedef content_iterator dyn_iterator; protected: struct Elf_Ehdr { @@ -300,6 +368,8 @@ private: IndexMap_t SymbolTableSectionsIndexMap; DenseMap ExtendedSymbolTable; + const Elf_Shdr *dot_dynamic_sec; // .dynamic + /// @brief Map sections to an array of relocation sections that reference /// them sorted by section index. RelocMap_t SectionRelocMap; @@ -329,6 +399,9 @@ protected: const Elf_Sym *getSymbol(DataRefImpl Symb) const; // FIXME: Should be private? void validateSymbol(DataRefImpl Symb) const; +public: + const Elf_Dyn *getDyn(DataRefImpl DynData) const; + protected: virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const; virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const; @@ -341,6 +414,12 @@ protected: virtual error_code getSymbolSection(DataRefImpl Symb, section_iterator &Res) const; + friend class DynRefImpl; + virtual error_code getDynNext(DataRefImpl DynData, DynRef &Result) const; + + virtual error_code getLibraryNext(DataRefImpl Data, LibraryRef &Result) const; + virtual error_code getLibraryPath(DataRefImpl Data, StringRef &Res) const; + virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res) const; virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const; virtual error_code getSectionAddress(DataRefImpl Sec, uint64_t &Res) const; @@ -376,11 +455,19 @@ public: ELFObjectFile(MemoryBuffer *Object, error_code &ec); virtual symbol_iterator begin_symbols() const; virtual symbol_iterator end_symbols() const; + virtual symbol_iterator begin_dynamic_symbols() const; virtual symbol_iterator end_dynamic_symbols() const; + virtual section_iterator begin_sections() const; virtual section_iterator end_sections() const; + virtual library_iterator begin_libraries_needed() const; + virtual library_iterator end_libraries_needed() const; + + virtual dyn_iterator begin_dynamic_table() const; + virtual dyn_iterator end_dynamic_table() const; + virtual uint8_t getBytesInAddress() const; virtual StringRef getFileFormatName() const; virtual unsigned getArch() const; @@ -1171,7 +1258,8 @@ ELFObjectFile::ELFObjectFile(MemoryBuffer *Object , SectionHeaderTable(0) , dot_shstrtab_sec(0) , dot_strtab_sec(0) - , dot_dynstr_sec(0) { + , dot_dynstr_sec(0) + , dot_dynamic_sec(0) { const uint64_t FileSize = Data->getBufferSize(); @@ -1227,6 +1315,12 @@ ELFObjectFile::ELFObjectFile(MemoryBuffer *Object if (sh->sh_type == ELF::SHT_REL || sh->sh_type == ELF::SHT_RELA) { SectionRelocMap[getSection(sh->sh_info)].push_back(i); } + if (sh->sh_type == ELF::SHT_DYNAMIC) { + if (dot_dynamic_sec != NULL) + // FIXME: Proper error handling. + report_fatal_error("More than one .dynamic!"); + dot_dynamic_sec = sh; + } ++sh; } @@ -1352,6 +1446,121 @@ section_iterator ELFObjectFile return section_iterator(SectionRef(ret, this)); } +template +typename ELFObjectFile::dyn_iterator +ELFObjectFile::begin_dynamic_table() const { + DataRefImpl DynData; + memset(&DynData, 0, sizeof(DynData)); + if (dot_dynamic_sec == NULL || dot_dynamic_sec->sh_size == 0) { + DynData.d.a = std::numeric_limits::max(); + } else { + DynData.d.a = 0; + } + return dyn_iterator(DynRef(DynData, this)); +} + +template +typename ELFObjectFile::dyn_iterator +ELFObjectFile + ::end_dynamic_table() const { + DataRefImpl DynData; + memset(&DynData, 0, sizeof(DynData)); + DynData.d.a = std::numeric_limits::max(); + return dyn_iterator(DynRef(DynData, this)); +} + +template +error_code ELFObjectFile + ::getDynNext(DataRefImpl DynData, + DynRef &Result) const { + ++DynData.d.a; + + // Check to see if we are at the end of .dynamic + if (DynData.d.a >= dot_dynamic_sec->getEntityCount()) { + // We are at the end. Return the terminator. + DynData.d.a = std::numeric_limits::max(); + } + + Result = DynRef(DynData, this); + return object_error::success; +} + +template +library_iterator ELFObjectFile + ::begin_libraries_needed() const { + // Find the first DT_NEEDED entry + dyn_iterator i = begin_dynamic_table(); + dyn_iterator e = end_dynamic_table(); + error_code ec; + while (i != e) { + if (i->getTag() == ELF::DT_NEEDED) + break; + i.increment(ec); + if (ec) + report_fatal_error("dynamic table iteration failed"); + } + // Use the same DataRefImpl format as DynRef. + return library_iterator(LibraryRef(i->getRawDataRefImpl(), this)); +} + +template +error_code ELFObjectFile + ::getLibraryNext(DataRefImpl Data, + LibraryRef &Result) const { + // Use the same DataRefImpl format as DynRef. + dyn_iterator i = dyn_iterator(DynRef(Data, this)); + dyn_iterator e = end_dynamic_table(); + + // Skip the current dynamic table entry. + error_code ec; + if (i != e) { + i.increment(ec); + // TODO: proper error handling + if (ec) + report_fatal_error("dynamic table iteration failed"); + } + + // Find the next DT_NEEDED entry. + while (i != e) { + if (i->getTag() == ELF::DT_NEEDED) + break; + i.increment(ec); + if (ec) + report_fatal_error("dynamic table iteration failed"); + } + Result = LibraryRef(i->getRawDataRefImpl(), this); + return object_error::success; +} + +template +error_code ELFObjectFile + ::getLibraryPath(DataRefImpl Data, StringRef &Res) const { + dyn_iterator i = dyn_iterator(DynRef(Data, this)); + if (i == end_dynamic_table()) + report_fatal_error("getLibraryPath() called on iterator end"); + + if (i->getTag() != ELF::DT_NEEDED) + report_fatal_error("Invalid library_iterator"); + + // This uses .dynstr to lookup the name of the DT_NEEDED entry. + // THis works as long as DT_STRTAB == .dynstr. This is true most of + // the time, but the specification allows exceptions. + // TODO: This should really use DT_STRTAB instead. Doing this requires + // reading the program headers. + if (dot_dynstr_sec == NULL) + report_fatal_error("Dynamic string table is missing"); + Res = getString(dot_dynstr_sec, i->getVal()); + return object_error::success; +} + +template +library_iterator ELFObjectFile + ::end_libraries_needed() const { + dyn_iterator e = end_dynamic_table(); + // Use the same DataRefImpl format as DynRef. + return library_iterator(LibraryRef(e->getRawDataRefImpl(), this)); +} + template uint8_t ELFObjectFile::getBytesInAddress() const { return is64Bits ? 8 : 4; @@ -1449,6 +1658,12 @@ ELFObjectFile::getSymbol(DataRefImpl Symb) const { return getEntry(SymbolTableSections[Symb.d.b], Symb.d.a); } +template +const typename ELFObjectFile::Elf_Dyn * +ELFObjectFile::getDyn(DataRefImpl DynData) const { + return getEntry(dot_dynamic_sec, DynData.d.a); +} + template const typename ELFObjectFile::Elf_Rel * ELFObjectFile::getRel(DataRefImpl Rel) const { @@ -1527,6 +1742,54 @@ error_code ELFObjectFile return object_error::success; } +template +inline DynRefImpl + ::DynRefImpl(DataRefImpl DynP, const OwningType *Owner) + : DynPimpl(DynP) + , OwningObject(Owner) {} + +template +inline bool DynRefImpl + ::operator==(const DynRefImpl &Other) const { + return DynPimpl == Other.DynPimpl; +} + +template +inline bool DynRefImpl + ::operator <(const DynRefImpl &Other) const { + return DynPimpl < Other.DynPimpl; +} + +template +inline error_code DynRefImpl + ::getNext(DynRefImpl &Result) const { + return OwningObject->getDynNext(DynPimpl, Result); +} + +template +inline int64_t DynRefImpl + ::getTag() const { + return OwningObject->getDyn(DynPimpl)->d_tag; +} + +template +inline uint64_t DynRefImpl + ::getVal() const { + return OwningObject->getDyn(DynPimpl)->d_un.d_val; +} + +template +inline uint64_t DynRefImpl + ::getPtr() const { + return OwningObject->getDyn(DynPimpl)->d_un.d_ptr; +} + +template +inline DataRefImpl DynRefImpl + ::getRawDataRefImpl() const { + return DynPimpl; +} + } } diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index 3edbe08f6373..185df06a996c 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -34,6 +34,8 @@ public: virtual symbol_iterator end_symbols() const; virtual symbol_iterator begin_dynamic_symbols() const; virtual symbol_iterator end_dynamic_symbols() const; + virtual library_iterator begin_libraries_needed() const; + virtual library_iterator end_libraries_needed() const; virtual section_iterator begin_sections() const; virtual section_iterator end_sections() const; @@ -92,6 +94,9 @@ protected: SmallVectorImpl &Result) const; virtual error_code getRelocationHidden(DataRefImpl Rel, bool &Result) const; + virtual error_code getLibraryNext(DataRefImpl LibData, LibraryRef &Res) const; + virtual error_code getLibraryPath(DataRefImpl LibData, StringRef &Res) const; + private: MachOObject *MachOObj; mutable uint32_t RegisteredStringTable; diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h index 56d8c249c7f8..dd47ceb74795 100644 --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -228,6 +228,32 @@ public: }; typedef content_iterator symbol_iterator; +/// LibraryRef - This is a value type class that represents a single library in +/// the list of libraries needed by a shared or dynamic object. +class LibraryRef { + friend class SectionRef; + DataRefImpl LibraryPimpl; + const ObjectFile *OwningObject; + +public: + LibraryRef() : OwningObject(NULL) { + std::memset(&LibraryPimpl, 0, sizeof(LibraryPimpl)); + } + + LibraryRef(DataRefImpl LibraryP, const ObjectFile *Owner); + + bool operator==(const LibraryRef &Other) const; + bool operator <(const LibraryRef &Other) const; + + error_code getNext(LibraryRef &Result) const; + + // Get the path to this library, as stored in the object file. + error_code getPath(StringRef &Result) const; + + DataRefImpl getRawDataRefImpl() const; +}; +typedef content_iterator library_iterator; + const uint64_t UnknownAddressOrSize = ~0ULL; /// ObjectFile - This class is the base class for all object file types. @@ -307,6 +333,11 @@ protected: return object_error::success; } + // Same for LibraryRef + friend class LibraryRef; + virtual error_code getLibraryNext(DataRefImpl Lib, LibraryRef &Res) const = 0; + virtual error_code getLibraryPath(DataRefImpl Lib, StringRef &Res) const = 0; + public: virtual symbol_iterator begin_symbols() const = 0; @@ -318,6 +349,9 @@ public: virtual section_iterator begin_sections() const = 0; virtual section_iterator end_sections() const = 0; + virtual library_iterator begin_libraries_needed() const = 0; + virtual library_iterator end_libraries_needed() const = 0; + /// @brief The number of bytes used to represent an address in this object /// file format. virtual uint8_t getBytesInAddress() const = 0; @@ -509,6 +543,26 @@ inline error_code RelocationRef::getValueString(SmallVectorImpl &Result) inline error_code RelocationRef::getHidden(bool &Result) const { return OwningObject->getRelocationHidden(RelocationPimpl, Result); } +// Inline function definitions. +inline LibraryRef::LibraryRef(DataRefImpl LibraryP, const ObjectFile *Owner) + : LibraryPimpl(LibraryP) + , OwningObject(Owner) {} + +inline bool LibraryRef::operator==(const LibraryRef &Other) const { + return LibraryPimpl == Other.LibraryPimpl; +} + +inline bool LibraryRef::operator <(const LibraryRef &Other) const { + return LibraryPimpl < Other.LibraryPimpl; +} + +inline error_code LibraryRef::getNext(LibraryRef &Result) const { + return OwningObject->getLibraryNext(LibraryPimpl, Result); +} + +inline error_code LibraryRef::getPath(StringRef &Result) const { + return OwningObject->getLibraryPath(LibraryPimpl, Result); +} } // end namespace object } // end namespace llvm diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp index d55aba5ce986..393c574d5324 100644 --- a/llvm/lib/Object/COFFObjectFile.cpp +++ b/llvm/lib/Object/COFFObjectFile.cpp @@ -515,6 +515,16 @@ symbol_iterator COFFObjectFile::end_dynamic_symbols() const { report_fatal_error("Dynamic symbols unimplemented in COFFObjectFile"); } +library_iterator COFFObjectFile::begin_libraries_needed() const { + // TODO: implement + report_fatal_error("Libraries needed unimplemented in COFFObjectFile"); +} + +library_iterator COFFObjectFile::end_libraries_needed() const { + // TODO: implement + report_fatal_error("Libraries needed unimplemented in COFFObjectFile"); +} + section_iterator COFFObjectFile::begin_sections() const { DataRefImpl ret; std::memset(&ret, 0, sizeof(DataRefImpl)); @@ -726,6 +736,16 @@ error_code COFFObjectFile::getRelocationValueString(DataRefImpl Rel, return object_error::success; } +error_code COFFObjectFile::getLibraryNext(DataRefImpl LibData, + LibraryRef &Result) const { + report_fatal_error("getLibraryNext not implemented in COFFObjectFile"); +} + +error_code COFFObjectFile::getLibraryPath(DataRefImpl LibData, + StringRef &Result) const { + report_fatal_error("getLibraryPath not implemented in COFFObjectFile"); +} + namespace llvm { ObjectFile *ObjectFile::createCOFFObjectFile(MemoryBuffer *Object) { diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 76a01f94e95c..360ab1676c46 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -377,6 +377,16 @@ symbol_iterator MachOObjectFile::end_dynamic_symbols() const { report_fatal_error("Dynamic symbols unimplemented in MachOObjectFile"); } +library_iterator MachOObjectFile::begin_libraries_needed() const { + // TODO: implement + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} + +library_iterator MachOObjectFile::end_libraries_needed() const { + // TODO: implement + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} + /*===-- Sections ----------------------------------------------------------===*/ void MachOObjectFile::moveToNextSection(DataRefImpl &DRI) const { @@ -1175,6 +1185,17 @@ error_code MachOObjectFile::getRelocationHidden(DataRefImpl Rel, return object_error::success; } +error_code MachOObjectFile::getLibraryNext(DataRefImpl LibData, + LibraryRef &Res) const { + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} + +error_code MachOObjectFile::getLibraryPath(DataRefImpl LibData, + StringRef &Res) const { + report_fatal_error("Needed libraries unimplemented in MachOObjectFile"); +} + + /*===-- Miscellaneous -----------------------------------------------------===*/ uint8_t MachOObjectFile::getBytesInAddress() const { diff --git a/llvm/test/Object/Inputs/shared-object-test.elf-i386 b/llvm/test/Object/Inputs/shared-object-test.elf-i386 index 5129cc40bff421aaa9c410a4f5fa18e83e67fd5e..fb639155d7601acb720fbcbd3300908c30ec953c 100644 GIT binary patch literal 1848 zcmb7^O-~b16ozkUQNH9$LrgGH6BnA82_%SHihP+=3Bp3%4AXW>Nv0ia#{`UtE?DrB zSdz$s1xx>ed-(t{iFu4p3* z=8+jRPtCX)P2(;fy)s}ih%sr>cFQ z`jyn>x+d=b9C=7!AI_B4m3BgXgnP1Yc12u$A$Fm&5uY+6=1CU8p3#nD(&zp7uvwQ) zJ~C;pdfU>MIs3kBIHlIKc3qOr=bKvGYQ=58d(<-Zu(96`>*;zgimO57H$Jy(CW*SK zFWRrxyl(6*8m(G(<%jhk35@SoyGlxePGbD9T_>Xv$I4MXWd7_&L*h+5Ja)FZm#)Oe zmv^S{b*L~qRw|w7tZJosAYAr(J;xEgIpHGbgHQN+p6NyDapAoHUq1!{l8@Q{r6UX&SImlzbl77IF)=sF4lm+sNa`2XUmo7%!tv9r$CTFBK zyzhg|mP+$@lUqW%pY*BnPL;=7a>9P#qu}y*XXiK6-Blj@QkVC1aYNozmLru4d7(3; zsfC~w>dUU0xGU!!c_swT28Y7}HJzO4@`uilcKhXA{UzT5VkfQbxwUO&dTVW4fgW1h zvQ4k7%@=0-Vr@EL`L{L`(DH0;n6h)r+T7yr94hKn=FeTy9OK)B5Kc0n+s{bTH>5Cd z)#J^(w}|~hHhtiv%*`cf1e>|Zcaoo*JF>|~n47!O`MF7t@^kZ(?0mlIHiJ%B_oB!| zam`Iif4#D~T(0<=Yirx9JN{02xw7gTf91p5@|)MM^0U^>)cnl7HbnD7I2*Ko0B+pI AoB#j- literal 1792 zcmb7^O-~b16oyY}Q4o|54Kcw4O<2^#G!ii`wFsz5k)W8Un_+0Dlw{hHc1*yS$if8+ z7A*WhCT?7~aN!Sdp+A6~yZSzJdvVm5=tQht>Je3c~7lhM7c092x z*1jb*h5isfKCjG>z_h z=LhqBUn=DVZmtM$Kpnh*ecABJxu}7ks{%3V;1R%|7iy6?0UMtA55alaUOd;g6rhgz zzRCc1WP4#&R-o7uJHQ8hOK2^ut^#2ESysb4MolkmS^X;pSH{yjl z@Lce9yr09rth=E)=4Bn;#nE5tCi*o}sZbYrN1C+|v{ENh)Fo~xcvg`yfxW@uu;9-o z(++g_U5vi?`MjUi{0oTdnC{M1@9XfAbsiv;D8x&oh34F4Ap;ov2odV~g8W-|>RQXAjFO5AIrUud=#Ot^}*g h%a51VgZ1)4Wht<1bIdl)lScVVhjdMoMw#igKLGKbw?+T} diff --git a/llvm/test/Object/Inputs/shared-object-test.elf-x86-64 b/llvm/test/Object/Inputs/shared-object-test.elf-x86-64 index 71081ebfd165844fd90b3ab603f1a79f787a734b..92667f58d656794b37e394a1be5dff819e8ad942 100644 GIT binary patch literal 2760 zcmcguPfrt35TCLjRS}9BVuFd7crh`XkSKC6rbYQ$nnCNJ8#K*&KaA>r=(Rp|8x)6qgM|n6hTD(a z72;JVS$RRzkA3pIdY_eIzZa7ibep2liXzrwzcQAOf3|qIbN9Z2H}tmoCCYt%OS!{B zZgFNh|DA&;_+6gA27>|aAgY2t=6P)4QlBzVwvQ5a$ge0rtF)#Rd8w%(>foDhh#LH% za;YsD^@Q-3m<);g{}}k*Y+vShE@v_J>*V(1UP9Ygwf%mZ+~!eN5^ZSQBR38XV{(JG z*XsG5fO(Tl5&NBk2D$rD?0yJYCBZqzw%>o{7uir^jl3cLpwDz;$nhN`U-wxqv4-Lmv? ze!wNQcQhb)fAG#CPSCe`*dKh_h}pj6e2y zZ`tGBtEjzwUYp-zd)W*A@jg~BX+NK`<>hd|J{Tg&LhhO#>D;C9qF%6|iM_$XIi9#T z;v)SCXHVN#^np1{gS@u=TjC7sur|J^b5i5b3S2wTpuqo zKCX{%8U4}uQMXmb$Mx|&#qB;W^*64Mf4pEH>bLz~&~(F)!l;4H?QNE~*Ggq?dt+mF kz3Npdf2uwQnD7Vmvs>+nM*9nfGRA-h1* zd#U>*X9nwFeX6t?jaD=095g73tGmrOGV)HnwH?-j>f2_8l6uErK^%oiNI|gOVIT?H z2?cR8;+2W!55HEK{E3+lm>Yh@e2H@Jo>OkWn42CSD}3T$1i!}PTesUqZp2jZJ3I~@ zT+W{m;(jGR#Dw~NR0Guev+Ct62rZ|KZ%#^5pZ`I)AMRczJfE|kgxlnIl6J~#kZNJ4 zMt*eAl)@OEw8>B6{e=9u7F63|Bj&j&h^WKHZiW1vR^so~*(AlePVT<{I-h1o$u;VL z{Da@ug`vlNLcOlDUUCmT>H~hP{&E&%z#nzGsW|*mZ*bICmoe`nWa0BXB=BzA5e(}@%J<#crWlSB2Tb)=d!-Uj=O?$h4&cmF7((R z|FOZoW`Et_$eT6NkvbsHs_x|<>uj;Y_Q(5$3+cw|&fl=VtcCb`?~oe0_U?Sr@@26{ zc{PlCNGeFIHpv{dv+-kT6ih``USN5G2mTv*kzRt>S?rTOF#CPPNbdfQIy3b+v$#jL z!sCc>KeD(-IQLn6SbrKNoYSoR>Aod;kGm(%SJu8jI5%0m-_Npmzuy3tyyUr`VGf?Y z4SD*dbwIAC*dRA@(skpRQQVE^F5`pxZi(?heRqxVL4Efnl_wtZW9GrKR#pKz38Mn{}^2XF7A* KtffI)J^l}43AZc& diff --git a/llvm/test/Object/Inputs/shared.ll b/llvm/test/Object/Inputs/shared.ll index 3db0f82d9cd5..1a62d560b93a 100644 --- a/llvm/test/Object/Inputs/shared.ll +++ b/llvm/test/Object/Inputs/shared.ll @@ -1,12 +1,14 @@ ; How to make the shared objects from this file: ; +; LDARGS="--unresolved-symbols=ignore-all -soname=libfoo.so --no-as-needed -lc -lm" +; ; X86-32 ELF: ; llc -mtriple=i386-linux-gnu shared.ll -filetype=obj -o tmp32.o -relocation-model=pic -; ld -melf_i386 -shared tmp32.o -o shared-object-test.elf-i386 --unresolved-symbols=ignore-all +; ld -melf_i386 -shared tmp32.o -o shared-object-test.elf-i386 $LDARGS ; ; X86-64 ELF: ; llc -mtriple=x86_64-linux-gnu shared.ll -filetype=obj -o tmp64.o -relocation-model=pic -; ld -melf_x86_64 -shared tmp64.o -o shared-object-test.elf-x86-64 --unresolved-symbols=ignore-all +; ld -melf_x86_64 -shared tmp64.o -o shared-object-test.elf-x86-64 $LDARGS @defined_sym = global i32 1, align 4 diff --git a/llvm/test/Object/readobj-shared-object.test b/llvm/test/Object/readobj-shared-object.test new file mode 100644 index 000000000000..be71907c23b3 --- /dev/null +++ b/llvm/test/Object/readobj-shared-object.test @@ -0,0 +1,44 @@ +RUN: llvm-readobj %p/Inputs/shared-object-test.elf-i386 \ +RUN: | FileCheck %s -check-prefix ELF +RUN: llvm-readobj %p/Inputs/shared-object-test.elf-x86-64 \ +RUN: | FileCheck %s -check-prefix ELF + +ELF:Symbols: +ELF: .dynsym DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: .dynstr DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: .text DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: .eh_frame DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: .tdata DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: .dynamic DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: .got.plt DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: .data DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: .bss DBG {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} formatspecific +ELF: shared.ll FILE {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} absolute,formatspecific +ELF: local_func FUNC {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} +ELF: _GLOBAL_OFFSET_TABLE_ DATA {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} absolute +ELF: _DYNAMIC DATA {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} absolute +ELF: common_sym DATA {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global +ELF: tls_sym DATA {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global,threadlocal +ELF: defined_sym DATA {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global +ELF: __bss_start ? {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global,absolute +ELF: _end ? {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global,absolute +ELF: global_func FUNC {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global +ELF: _edata ? {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global,absolute +ELF: Total: 21 + +ELF:Dynamic Symbols: +ELF: common_sym DATA {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global +ELF: tls_sym DATA {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global,threadlocal +ELF: defined_sym DATA {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global +ELF: __bss_start ? {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global,absolute +ELF: _end ? {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global,absolute +ELF: global_func FUNC {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global +ELF: _edata ? {{[0-9a-f]+}} {{[0-9a-f]+}} {{[0-9a-f]+}} global,absolute +ELF: Total: {{[0-9a-f]+}} + +ELF:Libraries needed: +ELF: libc.so.6 +ELF: libm.so.6 +ELF: Total: 2 + + diff --git a/llvm/tools/CMakeLists.txt b/llvm/tools/CMakeLists.txt index 86cdbcd53338..9668c764c689 100644 --- a/llvm/tools/CMakeLists.txt +++ b/llvm/tools/CMakeLists.txt @@ -37,6 +37,7 @@ add_subdirectory(llvm-extract) add_subdirectory(llvm-diff) add_subdirectory(macho-dump) add_subdirectory(llvm-objdump) +add_subdirectory(llvm-readobj) add_subdirectory(llvm-rtdyld) add_subdirectory(llvm-dwarfdump) diff --git a/llvm/tools/Makefile b/llvm/tools/Makefile index 79bbb9e89638..8bf091a72a08 100644 --- a/llvm/tools/Makefile +++ b/llvm/tools/Makefile @@ -32,7 +32,7 @@ PARALLEL_DIRS := opt llvm-as llvm-dis \ llvm-ld llvm-prof llvm-link \ lli llvm-extract llvm-mc \ bugpoint llvm-bcanalyzer llvm-stub \ - llvm-diff macho-dump llvm-objdump \ + llvm-diff macho-dump llvm-objdump llvm-readobj \ llvm-rtdyld llvm-dwarfdump llvm-cov \ llvm-size llvm-stress diff --git a/llvm/tools/llvm-readobj/CMakeLists.txt b/llvm/tools/llvm-readobj/CMakeLists.txt new file mode 100644 index 000000000000..be80469f28d5 --- /dev/null +++ b/llvm/tools/llvm-readobj/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_LINK_COMPONENTS archive bitreader object) + +add_llvm_tool(llvm-readobj + llvm-readobj.cpp + ) diff --git a/llvm/tools/llvm-readobj/LLVMBuild.txt b/llvm/tools/llvm-readobj/LLVMBuild.txt new file mode 100644 index 000000000000..c9f934f4b6fa --- /dev/null +++ b/llvm/tools/llvm-readobj/LLVMBuild.txt @@ -0,0 +1,22 @@ +;===- ./tools/llvm-readobj/LLVMBuild.txt ---------------------------*- Conf -*--===; +; +; The LLVM Compiler Infrastructure +; +; This file is distributed under the University of Illinois Open Source +; License. See LICENSE.TXT for details. +; +;===------------------------------------------------------------------------===; +; +; This is an LLVMBuild description file for the components in this subdirectory. +; +; For more information on the LLVMBuild system, please see: +; +; http://llvm.org/docs/LLVMBuild.html +; +;===------------------------------------------------------------------------===; + +[component_0] +type = Tool +name = llvm-readobj +parent = Tools +required_libraries = Archive BitReader Object diff --git a/llvm/tools/llvm-readobj/Makefile b/llvm/tools/llvm-readobj/Makefile new file mode 100644 index 000000000000..a7a7de356303 --- /dev/null +++ b/llvm/tools/llvm-readobj/Makefile @@ -0,0 +1,18 @@ +##===- tools/llvm-readobj/Makefile -----------------------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LEVEL := ../.. +TOOLNAME := llvm-readobj +LINK_COMPONENTS := archive bitreader object + +# This tool has no plugins, optimize startup time. +TOOL_NO_EXPORTS := 1 + +include $(LEVEL)/Makefile.common + diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp new file mode 100644 index 000000000000..7b8683f134b8 --- /dev/null +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -0,0 +1,188 @@ +/*===- pso-stub.c - Stub executable to run llvm bitcode files -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +//===----------------------------------------------------------------------===*/ + +#include +#include +#include +#include "llvm/Object/ObjectFile.h" +#include "llvm/Analysis/Verifier.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Signals.h" +#include "llvm/Support/FormattedStream.h" + +using namespace llvm; +using namespace llvm::object; + +static cl::opt +InputFilename(cl::Positional, cl::desc(""), cl::init("")); + +void DumpSymbolHeader() { + outs() << format(" %-32s", (const char*)"Name") + << format(" %-4s", (const char*)"Type") + << format(" %-16s", (const char*)"Address") + << format(" %-16s", (const char*)"Size") + << format(" %-16s", (const char*)"FileOffset") + << format(" %-26s", (const char*)"Flags") + << "\n"; +} + +const char *GetTypeStr(SymbolRef::Type Type) { + switch (Type) { + case SymbolRef::ST_Unknown: return "?"; + case SymbolRef::ST_Data: return "DATA"; + case SymbolRef::ST_Debug: return "DBG"; + case SymbolRef::ST_File: return "FILE"; + case SymbolRef::ST_Function: return "FUNC"; + case SymbolRef::ST_Other: return "-"; + } + return "INV"; +} + +std::string GetFlagStr(uint32_t Flags) { + std::string result; + if (Flags & SymbolRef::SF_Undefined) + result += "undef,"; + if (Flags & SymbolRef::SF_Global) + result += "global,"; + if (Flags & SymbolRef::SF_Weak) + result += "weak,"; + if (Flags & SymbolRef::SF_Absolute) + result += "absolute,"; + if (Flags & SymbolRef::SF_ThreadLocal) + result += "threadlocal,"; + if (Flags & SymbolRef::SF_Common) + result += "common,"; + if (Flags & SymbolRef::SF_FormatSpecific) + result += "formatspecific,"; + + // Remove trailing comma + if (result.size() > 0) { + result.erase(result.size() - 1); + } + return result; +} + +void DumpSymbol(const SymbolRef &sym) { + StringRef Name; + SymbolRef::Type Type; + uint32_t Flags; + uint64_t Address; + uint64_t Size; + uint64_t FileOffset; + sym.getName(Name); + sym.getAddress(Address); + sym.getSize(Size); + sym.getFileOffset(FileOffset); + sym.getType(Type); + sym.getFlags(Flags); + + // format() can't handle StringRefs + outs() << format(" %-32s", Name.str().c_str()) + << format(" %-4s", GetTypeStr(Type)) + << format(" %16"PRIx64, Address) + << format(" %16"PRIx64, Size) + << format(" %16"PRIx64, FileOffset) + << " " << GetFlagStr(Flags) + << "\n"; +} + + +// Iterate through the normal symbols in the ObjectFile +void DumpSymbols(const ObjectFile *obj) { + error_code ec; + uint32_t count = 0; + outs() << "Symbols:\n"; + symbol_iterator it = obj->begin_symbols(); + symbol_iterator ie = obj->end_symbols(); + while (it != ie) { + DumpSymbol(*it); + it.increment(ec); + if (ec) + report_fatal_error("Symbol iteration failed"); + ++count; + } + outs() << " Total: " << count << "\n\n"; +} + +// Iterate through the dynamic symbols in the ObjectFile. +void DumpDynamicSymbols(const ObjectFile *obj) { + error_code ec; + uint32_t count = 0; + outs() << "Dynamic Symbols:\n"; + symbol_iterator it = obj->begin_dynamic_symbols(); + symbol_iterator ie = obj->end_dynamic_symbols(); + while (it != ie) { + DumpSymbol(*it); + it.increment(ec); + if (ec) + report_fatal_error("Symbol iteration failed"); + ++count; + } + outs() << " Total: " << count << "\n\n"; +} + +void DumpLibrary(const LibraryRef &lib) { + StringRef path; + lib.getPath(path); + outs() << " " << path << "\n"; +} + +// Iterate through needed libraries +void DumpLibrariesNeeded(const ObjectFile *obj) { + error_code ec; + uint32_t count = 0; + library_iterator it = obj->begin_libraries_needed(); + library_iterator ie = obj->end_libraries_needed(); + outs() << "Libraries needed:\n"; + while (it != ie) { + DumpLibrary(*it); + it.increment(ec); + if (ec) + report_fatal_error("Needed libraries iteration failed"); + ++count; + } + outs() << " Total: " << count << "\n\n"; +} + +int main(int argc, char** argv) { + error_code ec; + sys::PrintStackTraceOnErrorSignal(); + PrettyStackTraceProgram X(argc, argv); + + cl::ParseCommandLineOptions(argc, argv, + "LLVM Object Reader\n"); + + if (InputFilename.empty()) { + errs() << "Please specify an input filename\n"; + return 1; + } + + // Open the object file + OwningPtr File; + if (MemoryBuffer::getFile(InputFilename, File)) { + errs() << InputFilename << ": Open failed\n"; + return 1; + } + + ObjectFile *obj = ObjectFile::createObjectFile(File.take()); + if (!obj) { + errs() << InputFilename << ": Object type not recognized\n"; + } + + DumpSymbols(obj); + DumpDynamicSymbols(obj); + DumpLibrariesNeeded(obj); + return 0; +} +