diff options
author | David Meyer <pdox@google.com> | 2012-03-01 01:36:50 +0000 |
---|---|---|
committer | David Meyer <pdox@google.com> | 2012-03-01 01:36:50 +0000 |
commit | 5c2b4ea73c8f48bb5f96c86fe437385b8fb3dcda (patch) | |
tree | e62d2d345c810a0aaf0a561192a31079c5acb5b6 | |
parent | 741981adf3a2bc0c6652c9c4ec846250950f3e68 (diff) | |
download | external_llvm-5c2b4ea73c8f48bb5f96c86fe437385b8fb3dcda.zip external_llvm-5c2b4ea73c8f48bb5f96c86fe437385b8fb3dcda.tar.gz external_llvm-5c2b4ea73c8f48bb5f96c86fe437385b8fb3dcda.tar.bz2 |
[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.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@151785 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/llvm/Object/COFF.h | 7 | ||||
-rw-r--r-- | include/llvm/Object/ELF.h | 265 | ||||
-rw-r--r-- | include/llvm/Object/MachO.h | 5 | ||||
-rw-r--r-- | include/llvm/Object/ObjectFile.h | 54 | ||||
-rw-r--r-- | lib/Object/COFFObjectFile.cpp | 20 | ||||
-rw-r--r-- | lib/Object/MachOObjectFile.cpp | 21 | ||||
-rw-r--r-- | test/Object/Inputs/shared-object-test.elf-i386 | bin | 1792 -> 1848 bytes | |||
-rw-r--r-- | test/Object/Inputs/shared-object-test.elf-x86-64 | bin | 2680 -> 2760 bytes | |||
-rw-r--r-- | test/Object/Inputs/shared.ll | 6 | ||||
-rw-r--r-- | test/Object/readobj-shared-object.test | 44 | ||||
-rw-r--r-- | tools/CMakeLists.txt | 1 | ||||
-rw-r--r-- | tools/Makefile | 2 | ||||
-rw-r--r-- | tools/llvm-readobj/CMakeLists.txt | 5 | ||||
-rw-r--r-- | tools/llvm-readobj/LLVMBuild.txt | 22 | ||||
-rw-r--r-- | tools/llvm-readobj/Makefile | 18 | ||||
-rw-r--r-- | tools/llvm-readobj/llvm-readobj.cpp | 188 |
16 files changed, 654 insertions, 4 deletions
diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 7321412..6212785 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -145,12 +145,19 @@ protected: virtual error_code getRelocationValueString(DataRefImpl Rel, SmallVectorImpl<char> &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/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 6e3fa01..ce002f2 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -176,6 +176,71 @@ struct Elf_Sym_Impl : Elf_Sym_Base<target_endianness, is64Bits> { } }; +// Elf_Dyn: Entry in the dynamic table +template<support::endianness target_endianness, bool is64Bits> +struct Elf_Dyn_Base; + +template<support::endianness target_endianness> +struct Elf_Dyn_Base<target_endianness, false> { + LLVM_ELF_IMPORT_TYPES(target_endianness, false) + Elf_Sword d_tag; + union { + Elf_Word d_val; + Elf_Addr d_ptr; + } d_un; +}; + +template<support::endianness target_endianness> +struct Elf_Dyn_Base<target_endianness, true> { + LLVM_ELF_IMPORT_TYPES(target_endianness, true) + Elf_Sxword d_tag; + union { + Elf_Xword d_val; + Elf_Addr d_ptr; + } d_un; +}; + +template<support::endianness target_endianness, bool is64Bits> +struct Elf_Dyn_Impl : Elf_Dyn_Base<target_endianness, is64Bits> { + using Elf_Dyn_Base<target_endianness, is64Bits>::d_tag; + using Elf_Dyn_Base<target_endianness, is64Bits>::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<support::endianness target_endianness, bool is64Bits> +class ELFObjectFile; + +// DynRefImpl: Reference to an entry in the dynamic table +// This is an ELF-specific interface. +template<support::endianness target_endianness, bool is64Bits> +class DynRefImpl { + typedef Elf_Dyn_Impl<target_endianness, is64Bits> Elf_Dyn; + typedef ELFObjectFile<target_endianness, is64Bits> 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<support::endianness target_endianness, bool is64Bits, bool isRela> struct Elf_Rel_Base; @@ -255,8 +320,11 @@ class ELFObjectFile : public ObjectFile { typedef Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr; typedef Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym; + typedef Elf_Dyn_Impl<target_endianness, is64Bits> Elf_Dyn; typedef Elf_Rel_Impl<target_endianness, is64Bits, false> Elf_Rel; typedef Elf_Rel_Impl<target_endianness, is64Bits, true> Elf_Rela; + typedef DynRefImpl<target_endianness, is64Bits> DynRef; + typedef content_iterator<DynRef> dyn_iterator; protected: struct Elf_Ehdr { @@ -300,6 +368,8 @@ private: IndexMap_t SymbolTableSectionsIndexMap; DenseMap<const Elf_Sym*, ELF::Elf64_Word> 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<target_endianness, is64Bits>; + 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<target_endianness, is64Bits>::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<target_endianness, is64Bits>::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; } @@ -1353,6 +1447,121 @@ section_iterator ELFObjectFile<target_endianness, is64Bits> } template<support::endianness target_endianness, bool is64Bits> +typename ELFObjectFile<target_endianness, is64Bits>::dyn_iterator +ELFObjectFile<target_endianness, is64Bits>::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<uint32_t>::max(); + } else { + DynData.d.a = 0; + } + return dyn_iterator(DynRef(DynData, this)); +} + +template<support::endianness target_endianness, bool is64Bits> +typename ELFObjectFile<target_endianness, is64Bits>::dyn_iterator +ELFObjectFile<target_endianness, is64Bits> + ::end_dynamic_table() const { + DataRefImpl DynData; + memset(&DynData, 0, sizeof(DynData)); + DynData.d.a = std::numeric_limits<uint32_t>::max(); + return dyn_iterator(DynRef(DynData, this)); +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<uint32_t>::max(); + } + + Result = DynRef(DynData, this); + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +library_iterator ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +library_iterator ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> uint8_t ELFObjectFile<target_endianness, is64Bits>::getBytesInAddress() const { return is64Bits ? 8 : 4; } @@ -1450,6 +1659,12 @@ ELFObjectFile<target_endianness, is64Bits>::getSymbol(DataRefImpl Symb) const { } template<support::endianness target_endianness, bool is64Bits> +const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Dyn * +ELFObjectFile<target_endianness, is64Bits>::getDyn(DataRefImpl DynData) const { + return getEntry<Elf_Dyn>(dot_dynamic_sec, DynData.d.a); +} + +template<support::endianness target_endianness, bool is64Bits> const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Rel * ELFObjectFile<target_endianness, is64Bits>::getRel(DataRefImpl Rel) const { return getEntry<Elf_Rel>(Rel.w.b, Rel.w.c); @@ -1527,6 +1742,54 @@ error_code ELFObjectFile<target_endianness, is64Bits> return object_error::success; } +template<support::endianness target_endianness, bool is64Bits> +inline DynRefImpl<target_endianness, is64Bits> + ::DynRefImpl(DataRefImpl DynP, const OwningType *Owner) + : DynPimpl(DynP) + , OwningObject(Owner) {} + +template<support::endianness target_endianness, bool is64Bits> +inline bool DynRefImpl<target_endianness, is64Bits> + ::operator==(const DynRefImpl &Other) const { + return DynPimpl == Other.DynPimpl; +} + +template<support::endianness target_endianness, bool is64Bits> +inline bool DynRefImpl<target_endianness, is64Bits> + ::operator <(const DynRefImpl &Other) const { + return DynPimpl < Other.DynPimpl; +} + +template<support::endianness target_endianness, bool is64Bits> +inline error_code DynRefImpl<target_endianness, is64Bits> + ::getNext(DynRefImpl &Result) const { + return OwningObject->getDynNext(DynPimpl, Result); +} + +template<support::endianness target_endianness, bool is64Bits> +inline int64_t DynRefImpl<target_endianness, is64Bits> + ::getTag() const { + return OwningObject->getDyn(DynPimpl)->d_tag; +} + +template<support::endianness target_endianness, bool is64Bits> +inline uint64_t DynRefImpl<target_endianness, is64Bits> + ::getVal() const { + return OwningObject->getDyn(DynPimpl)->d_un.d_val; +} + +template<support::endianness target_endianness, bool is64Bits> +inline uint64_t DynRefImpl<target_endianness, is64Bits> + ::getPtr() const { + return OwningObject->getDyn(DynPimpl)->d_un.d_ptr; +} + +template<support::endianness target_endianness, bool is64Bits> +inline DataRefImpl DynRefImpl<target_endianness, is64Bits> + ::getRawDataRefImpl() const { + return DynPimpl; +} + } } diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 3edbe08..185df06 100644 --- a/include/llvm/Object/MachO.h +++ b/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<char> &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/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 56d8c24..dd47ceb 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -228,6 +228,32 @@ public: }; typedef content_iterator<SymbolRef> 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<LibraryRef> 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<char> &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/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index d55aba5..393c574 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/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/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 76a01f9..360ab16 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/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/test/Object/Inputs/shared-object-test.elf-i386 b/test/Object/Inputs/shared-object-test.elf-i386 Binary files differindex 5129cc4..fb63915 100644 --- a/test/Object/Inputs/shared-object-test.elf-i386 +++ b/test/Object/Inputs/shared-object-test.elf-i386 diff --git a/test/Object/Inputs/shared-object-test.elf-x86-64 b/test/Object/Inputs/shared-object-test.elf-x86-64 Binary files differindex 71081eb..92667f5 100644 --- a/test/Object/Inputs/shared-object-test.elf-x86-64 +++ b/test/Object/Inputs/shared-object-test.elf-x86-64 diff --git a/test/Object/Inputs/shared.ll b/test/Object/Inputs/shared.ll index 3db0f82..1a62d56 100644 --- a/test/Object/Inputs/shared.ll +++ b/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/test/Object/readobj-shared-object.test b/test/Object/readobj-shared-object.test new file mode 100644 index 0000000..be71907 --- /dev/null +++ b/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/tools/CMakeLists.txt b/tools/CMakeLists.txt index 86cdbcd..9668c76 100644 --- a/tools/CMakeLists.txt +++ b/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/tools/Makefile b/tools/Makefile index 79bbb9e..8bf091a 100644 --- a/tools/Makefile +++ b/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/tools/llvm-readobj/CMakeLists.txt b/tools/llvm-readobj/CMakeLists.txt new file mode 100644 index 0000000..be80469 --- /dev/null +++ b/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/tools/llvm-readobj/LLVMBuild.txt b/tools/llvm-readobj/LLVMBuild.txt new file mode 100644 index 0000000..c9f934f --- /dev/null +++ b/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/tools/llvm-readobj/Makefile b/tools/llvm-readobj/Makefile new file mode 100644 index 0000000..a7a7de3 --- /dev/null +++ b/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/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp new file mode 100644 index 0000000..7b8683f --- /dev/null +++ b/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 <stdio.h> +#include <stdlib.h> +#include <string.h> +#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<std::string> +InputFilename(cl::Positional, cl::desc("<input object>"), 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<MemoryBuffer> 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; +} + |