From: Michael J. Spencer Date: Thu, 9 Jul 2015 00:21:06 +0000 (+0000) Subject: [Object][ELF] Support dumping hash-tables from files with no section table. X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=7d0e4c73d428a78483d8a2748517d2a99b6f133e;p=oota-llvm.git [Object][ELF] Support dumping hash-tables from files with no section table. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241765 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 3b0c548ffe1..99d8deecc6c 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -16,6 +16,7 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntervalMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" @@ -139,6 +140,7 @@ public: typedef Elf_Verneed_Impl Elf_Verneed; typedef Elf_Vernaux_Impl Elf_Vernaux; typedef Elf_Versym_Impl Elf_Versym; + typedef Elf_Hash Elf_Hash; typedef ELFEntityIterator Elf_Dyn_Iter; typedef iterator_range Elf_Dyn_Range; typedef ELFEntityIterator Elf_Rela_Iter; @@ -176,6 +178,7 @@ private: const Elf_Shdr *dot_symtab_sec = nullptr; // Symbol table section. StringRef DynSymStrTab; // Dynnamic symbol string table. const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. + const Elf_Hash *HashTable = nullptr; const Elf_Shdr *SymbolTableSectionHeaderIndex = nullptr; DenseMap ExtendedSymbolTable; @@ -229,6 +232,8 @@ private: void LoadVersionNeeds(const Elf_Shdr *ec) const; void LoadVersionMap() const; + void scanDynamicTable(); + public: template const T *getEntry(uint32_t Section, uint32_t Entry) const; @@ -237,6 +242,7 @@ public: const Elf_Shdr *getDotSymtabSec() const { return dot_symtab_sec; } const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } + const Elf_Hash *getHashTable() const { return HashTable; } ErrorOr getStringTable(const Elf_Shdr *Section) const; const char *getDynamicString(uintX_t Offset) const; @@ -578,8 +584,10 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) Header = reinterpret_cast(base()); - if (Header->e_shoff == 0) + if (Header->e_shoff == 0) { + scanDynamicTable(); return; + } const uint64_t SectionTableOffset = Header->e_shoff; @@ -604,6 +612,13 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) for (const Elf_Shdr &Sec : sections()) { switch (Sec.sh_type) { + case ELF::SHT_HASH: + if (HashTable) { + EC = object_error::parse_failed; + return; + } + HashTable = reinterpret_cast(base() + Sec.sh_offset); + break; case ELF::SHT_SYMTAB_SHNDX: if (SymbolTableSectionHeaderIndex) { // More than one .symtab_shndx! @@ -701,7 +716,21 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) } } - // Scan program headers. + scanDynamicTable(); + + EC = std::error_code(); +} + +template +void ELFFile::scanDynamicTable() { + // Build load-address to file-offset map. + typedef typename IntervalMap< + uintX_t, uintptr_t, + IntervalMapImpl::NodeSizer::LeafSize, + IntervalMapHalfOpenInfo> LoadMapT; + LoadMapT::Allocator Alloc; + LoadMapT LoadMap(Alloc); + for (Elf_Phdr_Iter PhdrI = program_header_begin(), PhdrE = program_header_end(); PhdrI != PhdrE; ++PhdrI) { @@ -709,34 +738,36 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) DynamicRegion.Addr = base() + PhdrI->p_offset; DynamicRegion.Size = PhdrI->p_filesz; DynamicRegion.EntSize = sizeof(Elf_Dyn); - break; + continue; } + if (PhdrI->p_type != ELF::PT_LOAD) + continue; + if (PhdrI->p_filesz == 0) + continue; + LoadMap.insert(PhdrI->p_vaddr, PhdrI->p_vaddr + PhdrI->p_filesz, + PhdrI->p_offset); } - // Scan dynamic table. + auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { + auto I = LoadMap.find(VAddr); + if (I == LoadMap.end()) + return nullptr; + return base() + I.value() + (VAddr - I.start()); + }; + for (Elf_Dyn_Iter DynI = dynamic_table_begin(), DynE = dynamic_table_end(); DynI != DynE; ++DynI) { switch (DynI->d_tag) { - case ELF::DT_RELA: { - uint64_t VBase = 0; - const uint8_t *FBase = nullptr; - for (Elf_Phdr_Iter PhdrI = program_header_begin(), - PhdrE = program_header_end(); - PhdrI != PhdrE; ++PhdrI) { - if (PhdrI->p_type != ELF::PT_LOAD) - continue; - if (DynI->getPtr() >= PhdrI->p_vaddr && - DynI->getPtr() < PhdrI->p_vaddr + PhdrI->p_memsz) { - VBase = PhdrI->p_vaddr; - FBase = base() + PhdrI->p_offset; - break; - } - } - if (!VBase) - return; - DynRelaRegion.Addr = FBase + DynI->getPtr() - VBase; + case ELF::DT_HASH: + if (HashTable) + continue; + HashTable = + reinterpret_cast(toMappedAddr(DynI->getPtr())); + break; + case ELF::DT_RELA: + if (!DynRelaRegion.Addr) + DynRelaRegion.Addr = toMappedAddr(DynI->getPtr()); break; - } case ELF::DT_RELASZ: DynRelaRegion.Size = DynI->getVal(); break; @@ -744,8 +775,6 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) DynRelaRegion.EntSize = DynI->getVal(); } } - - EC = std::error_code(); } template diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index 63e13909ae5..127e7dc2351 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -10,6 +10,7 @@ #ifndef LLVM_OBJECT_ELFTYPES_H #define LLVM_OBJECT_ELFTYPES_H +#include "llvm/ADT/ArrayRef.h" #include "llvm/Object/Error.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/ELF.h" @@ -463,6 +464,23 @@ struct Elf_Phdr_Impl> { Elf_Xword p_align; // Segment alignment constraint }; +// ELFT needed for endianess. +template +struct Elf_Hash { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT); + Elf_Word nbucket; + Elf_Word nchain; + + ArrayRef buckets() const { + return ArrayRef(&nbucket + 2, &nbucket + 2 + nbucket); + } + + ArrayRef chains() const { + return ArrayRef(&nbucket + 2 + nbucket, + &nbucket + 2 + nbucket + nchain); + } +}; + // MIPS .reginfo section template struct Elf_Mips_RegInfo; diff --git a/test/Object/Inputs/no-section-table.so b/test/Object/Inputs/no-section-table.so new file mode 100644 index 00000000000..fd176ebf7ce Binary files /dev/null and b/test/Object/Inputs/no-section-table.so differ diff --git a/test/Object/no-section-table.test b/test/Object/no-section-table.test new file mode 100644 index 00000000000..1049390ce85 --- /dev/null +++ b/test/Object/no-section-table.test @@ -0,0 +1,8 @@ +RUN: llvm-readobj %p/Inputs/no-section-table.so -hash-table | FileCheck %s + +CHECK: HashTable { +CHECK: Num Buckets: 3 +CHECK: Num Chains: 13 +CHECK: Buckets: [12, 10, 11] +CHECK: Chains: [0, 0, 0, 0, 2, 3, 4, 0, 7, 5, 6, 8, 9] +CHECK: } diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index a4b25efeb9b..574964a4cc5 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -56,6 +56,7 @@ public: void printDynamicTable() override; void printNeededLibraries() override; void printProgramHeaders() override; + void printHashTable() override; void printAttributes() override; void printMipsPLTGOT() override; @@ -1119,6 +1120,18 @@ void ELFDumper::printProgramHeaders() { } } +template +void ELFDumper::printHashTable() { + DictScope D(W, "HashTable"); + auto HT = Obj->getHashTable(); + if (!HT) + return; + W.printNumber("Num Buckets", HT->nbucket); + W.printNumber("Num Chains", HT->nchain); + W.printList("Buckets", HT->buckets()); + W.printList("Chains", HT->chains()); +} + template void ELFDumper::printAttributes() { W.startLine() << "Attributes not implemented.\n"; diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h index 27e15b256cc..5ecf0ec3d6f 100644 --- a/tools/llvm-readobj/ObjDumper.h +++ b/tools/llvm-readobj/ObjDumper.h @@ -37,6 +37,7 @@ public: virtual void printDynamicTable() { } virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } + virtual void printHashTable() { } // Only implemented for ARM ELF at this time. virtual void printAttributes() { } diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h index 245588ba060..f3cc57ef940 100644 --- a/tools/llvm-readobj/StreamWriter.h +++ b/tools/llvm-readobj/StreamWriter.h @@ -181,8 +181,8 @@ public: startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n'; } - template - void printList(StringRef Label, const SmallVectorImpl &List) { + template + void printList(StringRef Label, const T &List) { startLine() << Label << ": ["; bool Comma = false; for (const auto &Item : List) { diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp index 990299bc2ce..12afacb0a85 100644 --- a/tools/llvm-readobj/llvm-readobj.cpp +++ b/tools/llvm-readobj/llvm-readobj.cpp @@ -127,6 +127,10 @@ namespace opts { cl::opt ProgramHeaders("program-headers", cl::desc("Display ELF program headers")); + // -hash-table + cl::opt HashTable("hash-table", + cl::desc("Display ELF hash table")); + // -expand-relocs cl::opt ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); @@ -300,6 +304,8 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printNeededLibraries(); if (opts::ProgramHeaders) Dumper->printProgramHeaders(); + if (opts::HashTable) + Dumper->printHashTable(); if (Obj->getArch() == llvm::Triple::arm && Obj->isELF()) if (opts::ARMAttributes) Dumper->printAttributes();