diff options
author | Michael J. Spencer <bigcheesegs@gmail.com> | 2016-02-11 04:59:45 +0000 |
---|---|---|
committer | Michael J. Spencer <bigcheesegs@gmail.com> | 2016-02-11 04:59:45 +0000 |
commit | 582c4d2babbb93271485cc4fee837b6b880c7610 (patch) | |
tree | db0afba7c6ed6022d9d5e614011c5eba62188c85 /llvm/tools/llvm-readobj | |
parent | 60d82b269cc544ba88389feb4a53210ea65dc204 (diff) | |
download | bcm5719-llvm-582c4d2babbb93271485cc4fee837b6b880c7610.tar.gz bcm5719-llvm-582c4d2babbb93271485cc4fee837b6b880c7610.zip |
[readobj] Handle ELF files with no section table or with no program headers.
This adds support for finding the dynamic table and dynamic symbol table via
the section table or the program header table. If there's no section table an
attempt is made to figure out the length of the dynamic symbol table.
llvm-svn: 260488
Diffstat (limited to 'llvm/tools/llvm-readobj')
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 251 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/llvm-readobj.h | 6 |
2 files changed, 159 insertions, 98 deletions
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 92b92f1fad1..2d73c10c070 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -48,6 +48,28 @@ namespace { template <class ELFT> class DumpStyle; +/// \brief Represents a region described by entries in the .dynamic table. +struct DynRegionInfo { + DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} + DynRegionInfo(const void *A, uint64_t S, uint64_t ES) + : Addr(A), Size(S), EntSize(ES) {} + /// \brief Address in current address space. + const void *Addr; + /// \brief Size in bytes of the region. + uint64_t Size; + /// \brief Size of each entity in the region. + uint64_t EntSize; + + template <typename Type> iterator_range<const Type *> getAsRange() const { + const Type *Start = reinterpret_cast<const Type *>(Addr); + if (Size == 0) + return {Start, Start}; + if (EntSize != sizeof(Type) || Size % EntSize) + reportError("Invalid entity size"); + return {Start, Start + (Size / EntSize)}; + } +}; + template<typename ELFT> class ELFDumper : public ObjDumper { public: @@ -82,6 +104,7 @@ private: typedef ELFFile<ELFT> ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; + typedef typename ELFO::Elf_Sym_Range Elf_Sym_Range; typedef typename ELFO::Elf_Dyn Elf_Dyn; typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; typedef typename ELFO::Elf_Rel Elf_Rel; @@ -101,21 +124,25 @@ private: typedef typename ELFO::Elf_Verdef Elf_Verdef; typedef typename ELFO::Elf_Verdaux Elf_Verdaux; - /// \brief Represents a region described by entries in the .dynamic table. - struct DynRegionInfo { - DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} - /// \brief Address in current address space. - const void *Addr; - /// \brief Size in bytes of the region. - uintX_t Size; - /// \brief Size of each entity in the region. - uintX_t EntSize; - }; + DynRegionInfo checkDRI(DynRegionInfo DRI) { + if (DRI.Addr < Obj->base() || + (const uint8_t *)DRI.Addr + DRI.Size > Obj->base() + Obj->getBufSize()) + error(llvm::object::object_error::parse_failed); + return DRI; + } + + DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) { + return checkDRI({Obj->base() + P->p_offset, P->p_filesz, EntSize}); + } + + DynRegionInfo createDRIFrom(const Elf_Shdr *S) { + return checkDRI({Obj->base() + S->sh_offset, S->sh_size, S->sh_entsize}); + } void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments); void printSymbolsHelper(bool IsDynamic); - void printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, + void printSymbol(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, bool IsDynamic); void printDynamicRelocation(Elf_Rela Rel); @@ -123,23 +150,9 @@ private: void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab); void printValue(uint64_t Type, uint64_t Value); - template <typename REL> - static const REL *dyn_rel_begin(const DynRegionInfo ®ion); - template <typename REL> - static const REL *dyn_rel_end(const DynRegionInfo ®ion); Elf_Rel_Range dyn_rels() const; Elf_Rela_Range dyn_relas() const; StringRef getDynamicString(uint64_t Offset) const; - const Elf_Dyn *dynamic_table_begin() const { - ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_begin(DynamicProgHeader); - error(Ret.getError()); - return *Ret; - } - const Elf_Dyn *dynamic_table_end() const { - ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_end(DynamicProgHeader); - error(Ret.getError()); - return *Ret; - } StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, bool &IsDefault); void LoadVersionMap(); @@ -147,15 +160,17 @@ private: void LoadVersionDefs(const Elf_Shdr *sec) const; const ELFO *Obj; + DynRegionInfo DynamicTable; + + // Dynamic relocation info. DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; - const Elf_Phdr *DynamicProgHeader = nullptr; + + DynRegionInfo DynSymRegion; StringRef DynamicStringTable; - const Elf_Sym *DynSymStart = nullptr; StringRef SOName; const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; - const Elf_Shdr *DotDynSymSec = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; ArrayRef<Elf_Word> ShndxTable; @@ -188,16 +203,18 @@ private: public: Elf_Dyn_Range dynamic_table() const { - ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader); - error(Ret.getError()); - return *Ret; + return DynamicTable.getAsRange<Elf_Dyn>(); + } + + Elf_Sym_Range dynamic_symbols() const { + return DynSymRegion.getAsRange<Elf_Sym>(); } std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic); - const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } ArrayRef<Elf_Word> getShndxTable() { return ShndxTable; } + StringRef getDynamicStringTable() const { return DynamicStringTable; } }; template <typename ELFT> class DumpStyle { @@ -340,7 +357,7 @@ void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const { template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() { // If there is no dynamic symtab or version table, there is nothing to do. - if (!DynSymStart || !dot_gnu_version_sec) + if (!DynSymRegion.Addr || !dot_gnu_version_sec) return; // Has the VersionMap already been loaded? @@ -374,18 +391,15 @@ static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper, W.printHex("Offset", Sec->sh_offset); W.printNumber("Link", Sec->sh_link); - const typename ELFO::Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset; - ErrorOr<StringRef> StrTableOrErr = - Obj->getStringTableForSymtab(*DynSymSec); - error(StrTableOrErr.getError()); + StringRef StrTable = Dumper->getDynamicStringTable(); // Same number of entries in the dynamic symbol table (DT_SYMTAB). ListScope Syms(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Obj->symbols(DynSymSec)) { + for (const typename ELFO::Elf_Sym &Sym : Dumper->dynamic_symbols()) { DictScope S(W, "Symbol"); std::string FullSymbolName = - Dumper->getFullSymbolName(&Sym, *StrTableOrErr, true /* IsDynamic */); + Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */); W.printNumber("Version", *P); W.printString("Name", FullSymbolName); P += sizeof(typename ELFO::Elf_Half); @@ -461,7 +475,7 @@ StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, // Determine the position in the symbol table of this entry. size_t entry_index = (reinterpret_cast<uintptr_t>(symb) - - reinterpret_cast<uintptr_t>(DynSymStart)) / + reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) / sizeof(Elf_Sym); // Get the corresponding version index entry @@ -517,7 +531,7 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, template <typename ELFO> static void getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, - const typename ELFO::Elf_Shdr *SymTab, + const typename ELFO::Elf_Sym *FirstSym, ArrayRef<typename ELFO::Elf_Word> ShndxTable, StringRef &SectionName, unsigned &SectionIndex) { SectionIndex = Symbol->st_shndx; @@ -536,7 +550,7 @@ getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, else { if (SectionIndex == SHN_XINDEX) SectionIndex = - Obj.getExtendedSymbolTableIndex(Symbol, SymTab, ShndxTable); + Obj.getExtendedSymbolTableIndex(Symbol, FirstSym, ShndxTable); ErrorOr<const typename ELFO::Elf_Shdr *> Sec = Obj.getSection(SectionIndex); error(Sec.getError()); SectionName = errorOrDefault(Obj.getSectionName(*Sec)); @@ -990,7 +1004,7 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) SmallVector<const Elf_Phdr *, 4> LoadSegments; for (const Elf_Phdr &Phdr : Obj->program_headers()) { if (Phdr.p_type == ELF::PT_DYNAMIC) { - DynamicProgHeader = &Phdr; + DynamicTable = createDRIFrom(&Phdr, sizeof(Elf_Dyn)); continue; } if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) @@ -1005,10 +1019,17 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) reportError("Multilpe SHT_SYMTAB"); DotSymtabSec = &Sec; break; + case ELF::SHT_DYNAMIC: { + if (DynamicTable.Addr == nullptr) + DynamicTable = createDRIFrom(&Sec); + const Elf_Shdr *DynStrSec = unwrapOrError(Obj->getSection(Sec.sh_link)); + DynamicStringTable = unwrapOrError(Obj->getStringTable(DynStrSec)); + break; + } case ELF::SHT_DYNSYM: - if (DotDynSymSec != nullptr) - reportError("Multilpe SHT_DYNSYM"); - DotDynSymSec = &Sec; + // The dynamic table does not contain the size of the dynamic symbol + // table, so get that from the section table if present. + DynSymRegion = createDRIFrom(&Sec); break; case ELF::SHT_SYMTAB_SHNDX: { ErrorOr<ArrayRef<Elf_Word>> TableOrErr = Obj->getSHNDXTable(Sec); @@ -1049,12 +1070,12 @@ void ELFDumper<ELFT>::parseDynamicTable( const Elf_Phdr *const *I = std::upper_bound( LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr<ELFT>); if (I == LoadSegments.begin()) - report_fatal_error("Virtual address is not in any segment"); + return nullptr; --I; const Elf_Phdr &Phdr = **I; uint64_t Delta = VAddr - Phdr.p_vaddr; if (Delta >= Phdr.p_filesz) - report_fatal_error("Virtual address is not in any segment"); + return nullptr; return Obj->base() + Phdr.p_offset + Delta; }; @@ -1078,8 +1099,11 @@ void ELFDumper<ELFT>::parseDynamicTable( StringTableSize = Dyn.getVal(); break; case ELF::DT_SYMTAB: - DynSymStart = - reinterpret_cast<const Elf_Sym *>(toMappedAddr(Dyn.getPtr())); + if (DynSymRegion.Addr) + break; + DynSymRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynSymRegion.EntSize = sizeof(Elf_Sym); + // Figure out the size once we have scanned the entire dynamic table. break; case ELF::DT_RELA: DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); @@ -1108,35 +1132,59 @@ void ELFDumper<ELFT>::parseDynamicTable( DynamicStringTable = StringRef(StringTableBegin, StringTableSize); if (SONameOffset) SOName = getDynamicString(SONameOffset); -} - -template <typename ELFT> -template <typename REL> -const REL *ELFDumper<ELFT>::dyn_rel_begin(const DynRegionInfo &Region) { - if (Region.Size && Region.EntSize != sizeof(REL)) - report_fatal_error("Invalid relocation entry size"); - return reinterpret_cast<const REL *>(Region.Addr); -} - -template <typename ELFT> -template <typename REL> -const REL *ELFDumper<ELFT>::dyn_rel_end(const DynRegionInfo &Region) { - uint64_t Size = Region.Size; - if (Size % sizeof(REL)) - report_fatal_error("Invalid relocation table size"); - return dyn_rel_begin<REL>(Region) + Size / sizeof(REL); + if (DynSymRegion.Addr && !DynSymRegion.Size) { + // There was no section table entry for the dynamic section, and there is + // no DT entry describing its size, so attempt to guess at its size. + // Initally guess that it ends at the end of the file. + const void *Start = DynSymRegion.Addr; + const void *End = Obj->base() + Obj->getBufSize(); + + // Check all the sections we know about. + for (const Elf_Shdr &Sec : Obj->sections()) { + const void *Addr = Obj->base() + Sec.sh_offset; + if (Addr >= Start && Addr < End) + End = Addr; + } + + // Check all the dynamic regions we know about. + auto CheckDRI = [&](DynRegionInfo DRI) { + if (DRI.Addr >= Start && DRI.Addr < End) + End = DRI.Addr; + }; + + CheckDRI(DynamicTable); + CheckDRI(DynRelRegion); + CheckDRI(DynRelaRegion); + + if (DynamicStringTable.data() >= Start && DynamicStringTable.data() < End) + End = DynamicStringTable.data(); + + // Scan to the first invalid symbol. + auto SymI = reinterpret_cast<const Elf_Sym *>(Start); + for (; ((const char *)SymI + sizeof(Elf_Sym)) <= End; ++SymI) { + uint32_t NameOffset = SymI->st_name; + if (SymI > Start && !NameOffset) + break; + if (NameOffset >= DynamicStringTable.size()) + break; + uint16_t SectionIndex = SymI->st_shndx; + if ((Obj->getNumSections() && SectionIndex >= Obj->getNumSections()) && + SectionIndex < SHN_LORESERVE) + break; + } + End = SymI; + DynSymRegion.Size = (const char *)End - (const char *)Start; + } } template <typename ELFT> typename ELFDumper<ELFT>::Elf_Rel_Range ELFDumper<ELFT>::dyn_rels() const { - return make_range(dyn_rel_begin<Elf_Rel>(DynRelRegion), - dyn_rel_end<Elf_Rel>(DynRelRegion)); + return DynRelRegion.getAsRange<Elf_Rel>(); } template <typename ELFT> typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const { - return make_range(dyn_rel_begin<Elf_Rela>(DynRelaRegion), - dyn_rel_end<Elf_Rela>(DynRelaRegion)); + return DynRelaRegion.getAsRange<Elf_Rela>(); } template<class ELFT> @@ -1211,7 +1259,7 @@ void ELFDumper<ELFT>::printSections() { if (!SymSec) continue; if (*SymSec == &Sec) - printSymbol(&Sym, Symtab, StrTable, false); + printSymbol(&Sym, Obj->symbol_begin(Symtab), StrTable, false); } } @@ -1328,7 +1376,8 @@ void ELFDumper<ELFT>::printDynamicRelocation(Elf_Rela Rel) { Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef SymbolName; uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); - const Elf_Sym *Sym = DynSymStart + SymIndex; + const Elf_Sym *Sym = + DynSymRegion.getAsRange<Elf_Sym>().begin() + SymIndex; SymbolName = errorOrDefault(Sym->getName(DynamicStringTable)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); @@ -1346,14 +1395,21 @@ void ELFDumper<ELFT>::printDynamicRelocation(Elf_Rela Rel) { template<class ELFT> void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) { - const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec; - if (!Symtab) - return; - ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); - error(StrTableOrErr.getError()); - StringRef StrTable = *StrTableOrErr; - for (const Elf_Sym &Sym : Obj->symbols(Symtab)) - printSymbol(&Sym, Symtab, StrTable, IsDynamic); + StringRef StrTable = DynamicStringTable; + Elf_Sym_Range Syms(nullptr, nullptr); + if (IsDynamic) + Syms = DynSymRegion.getAsRange<Elf_Sym>(); + else { + if (!DotSymtabSec) + return; + ErrorOr<StringRef> StrTableOrErr = + Obj->getStringTableForSymtab(*DotSymtabSec); + error(StrTableOrErr.getError()); + StrTable = *StrTableOrErr; + Syms = Obj->symbols(DotSymtabSec); + } + for (const Elf_Sym &Sym : Syms) + printSymbol(&Sym, Syms.begin(), StrTable, IsDynamic); } template<class ELFT> @@ -1369,11 +1425,12 @@ void ELFDumper<ELFT>::printDynamicSymbols() { } template <class ELFT> -void ELFDumper<ELFT>::printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, - StringRef StrTable, bool IsDynamic) { +void ELFDumper<ELFT>::printSymbol(const Elf_Sym *Symbol, + const Elf_Sym *FirstSym, StringRef StrTable, + bool IsDynamic) { unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Symbol, SymTab, ShndxTable, SectionName, + getSectionNameIndex(*Obj, Symbol, FirstSym, ShndxTable, SectionName, SectionIndex); std::string FullSymbolName = getFullSymbolName(Symbol, StrTable, IsDynamic); unsigned char SymbolType = Symbol->getType(); @@ -1650,8 +1707,8 @@ template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() { template<class ELFT> void ELFDumper<ELFT>::printDynamicTable() { - auto I = dynamic_table_begin(); - auto E = dynamic_table_end(); + auto I = dynamic_table().begin(); + auto E = dynamic_table().end(); if (I == E) return; @@ -1747,10 +1804,10 @@ void ELFDumper<ELFT>::printGnuHashTable() { W.printNumber("Shift Count", GnuHashTable->shift2); W.printHexList("Bloom Filter", GnuHashTable->filter()); W.printList("Buckets", GnuHashTable->buckets()); - if (!DotDynSymSec) + if (!DynSymRegion.Size || !DynSymRegion.EntSize) reportError("No dynamic symbol section"); - W.printHexList("Values", - GnuHashTable->values(DotDynSymSec->getEntityCount())); + W.printHexList( + "Values", GnuHashTable->values(DynSymRegion.Size / DynSymRegion.EntSize)); } template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { @@ -1878,11 +1935,9 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - const Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); - ErrorOr<StringRef> StrTable = Obj->getStringTableForSymtab(*DynSymSec); - error(StrTable.getError()); - const Elf_Sym *DynSymBegin = Obj->symbol_begin(DynSymSec); - const Elf_Sym *DynSymEnd = Obj->symbol_end(DynSymSec); + StringRef StrTable = Dumper->getDynamicStringTable(); + const Elf_Sym *DynSymBegin = Dumper->dynamic_symbols().begin(); + const Elf_Sym *DynSymEnd = Dumper->dynamic_symbols().end(); std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); if (*DtGotSym > DynSymTotal) @@ -1942,8 +1997,8 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym; for (; It != GotGlobalEnd; ++It) { DictScope D(W, "Entry"); - printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, - *StrTable, true); + printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, StrTable, + true); } } @@ -2046,7 +2101,7 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry( unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(), Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); @@ -2080,7 +2135,7 @@ void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(), Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); diff --git a/llvm/tools/llvm-readobj/llvm-readobj.h b/llvm/tools/llvm-readobj/llvm-readobj.h index 39af4781027..3eb21e434b7 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/llvm/tools/llvm-readobj/llvm-readobj.h @@ -12,6 +12,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorOr.h" #include <string> namespace llvm { @@ -22,6 +23,11 @@ namespace llvm { // Various helper functions. LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg); void error(std::error_code ec); + template <class T> T unwrapOrError(ErrorOr<T> EO) { + if (EO) + return *EO; + reportError(EO.getError().message()); + } bool relocAddressLess(object::RelocationRef A, object::RelocationRef B); } // namespace llvm |