From 7ecc477012cfec660a6f2d52807b25ccfa6eedac Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Wed, 17 Feb 2016 15:38:21 +0000 Subject: [PATCH] Change how readobj stores info about dynamic symbols. We used to keep both a section and a pointer to the first symbol. The oddity of keeping a section for dynamic symbols is because there is a DT_SYMTAB but no DT_SYMTABZ, so to print the table we have to find the size via a section table. The reason for still keeping a pointer to the first symbol is because we want to be able to print relocation tables even if the section table is missing (it is mandatory only for files used in linking). With this patch we keep just a DynRegionInfo. This then requires changing a few places that were asking for a Elf_Shdr but actually just needed the first symbol. The test change is to delete the program header pointer. Now that we use the information of both DT_SYMTAB and .dynsym, we don't depend on the sh_entsize of .dynsym if we see DT_SYMTAB. Note: It is questionable if it is worth it putting the effort to report broken sh_entsize given that in files with no section table we have to assume it is sizeof(Elf_Sym), but that is for another change. Extracted from r260488. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@261099 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/ELF.h | 12 ++- test/Object/Inputs/invalid-sh_entsize.elf | Bin 1736 -> 1736 bytes test/Object/invalid.test | 4 +- tools/llvm-readobj/ELFDumper.cpp | 107 +++++++++++++--------- 4 files changed, 77 insertions(+), 46 deletions(-) diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index b0eaa3f5ed4..d01c3cfab16 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -200,6 +200,9 @@ public: uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef ShndxTable) const; + uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym, + const Elf_Sym *FirstSym, + ArrayRef ShndxTable) const; const Elf_Ehdr *getHeader() const { return Header; } ErrorOr getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, @@ -225,8 +228,15 @@ template uint32_t ELFFile::getExtendedSymbolTableIndex( const Elf_Sym *Sym, const Elf_Shdr *SymTab, ArrayRef ShndxTable) const { + return getExtendedSymbolTableIndex(Sym, symbol_begin(SymTab), ShndxTable); +} + +template +uint32_t ELFFile::getExtendedSymbolTableIndex( + const Elf_Sym *Sym, const Elf_Sym *FirstSym, + ArrayRef ShndxTable) const { assert(Sym->st_shndx == ELF::SHN_XINDEX); - unsigned Index = Sym - symbol_begin(SymTab); + unsigned Index = Sym - FirstSym; // The size of the table was checked in getSHNDXTable. return ShndxTable[Index]; diff --git a/test/Object/Inputs/invalid-sh_entsize.elf b/test/Object/Inputs/invalid-sh_entsize.elf index 9ea80731491c18aa7769b97262538a6483c75a39..ed501311b29bfd8b09fd92f6330eee8fbd7da939 100755 GIT binary patch delta 14 WcmX@XdxCd@!sNFs92+$jumJ!pD+Oi% delta 12 TcmX@XdxCd@0;9u5#pP@O9bp6; diff --git a/test/Object/invalid.test b/test/Object/invalid.test index cc5cd68304c..a32c621cca6 100644 --- a/test/Object/invalid.test +++ b/test/Object/invalid.test @@ -35,9 +35,11 @@ SECTION-NEXT: AddressAlignment: SECTION-NEXT: EntrySize: 32 RUN: not llvm-readobj -t %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-SYM-SIZE %s -RUN: not llvm-readobj --dyn-symbols %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-SYM-SIZE %s INVALID-SYM-SIZE: Invalid symbol size +RUN: not llvm-readobj --dyn-symbols %p/Inputs/invalid-sh_entsize.elf 2>&1 | FileCheck --check-prefix=INVALID-DYNSYM-SIZE %s +INVALID-DYNSYM-SIZE: Invalid entity size + RUN: not llvm-readobj -t %p/Inputs/invalid-section-index.elf 2>&1 | FileCheck --check-prefix=INVALID-SECTION-INDEX %s INVALID-SECTION-INDEX: Invalid section index diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index f305d6d0d6c..407f9710da5 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -48,9 +48,14 @@ namespace { template class DumpStyle; -/// \brief Represents a region described by entries in the .dynamic table. +/// Represents a contiguous uniform range in the file. We cannot just create a +/// range directly because when creating one of these from the .dynamic table +/// the size, entity size and virtual address are different entries in arbitrary +/// order (DT_REL, DT_RELSZ, DT_RELENT for example). 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. @@ -102,6 +107,7 @@ private: typedef ELFFile 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; @@ -121,10 +127,14 @@ private: typedef typename ELFO::Elf_Verdef Elf_Verdef; typedef typename ELFO::Elf_Verdaux Elf_Verdaux; + DynRegionInfo createDRIFrom(const Elf_Shdr *S) { + return {Obj->base() + S->sh_offset, S->sh_size, S->sh_entsize}; + } + void parseDynamicTable(ArrayRef 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); @@ -155,13 +165,12 @@ private: DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; DynRegionInfo DynPLTRelRegion; + DynRegionInfo DynSymRegion; const Elf_Phdr *DynamicProgHeader = nullptr; 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 ShndxTable; @@ -199,11 +208,15 @@ public: return *Ret; } + Elf_Sym_Range dynamic_symbols() const { + return DynSymRegion.getAsRange(); + } + 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 getShndxTable() { return ShndxTable; } + StringRef getDynamicStringTable() const { return DynamicStringTable; } }; template class DumpStyle { @@ -346,7 +359,7 @@ void ELFDumper::LoadVersionDefs(const Elf_Shdr *sec) const { template void ELFDumper::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? @@ -380,18 +393,15 @@ static void printVersionSymbolSection(ELFDumper *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 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); @@ -467,7 +477,7 @@ StringRef ELFDumper::getSymbolVersion(StringRef StrTab, // Determine the position in the symbol table of this entry. size_t entry_index = (reinterpret_cast(symb) - - reinterpret_cast(DynSymStart)) / + reinterpret_cast(DynSymRegion.Addr)) / sizeof(Elf_Sym); // Get the corresponding version index entry @@ -523,7 +533,7 @@ std::string ELFDumper::getFullSymbolName(const Elf_Sym *Symbol, template 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 ShndxTable, StringRef &SectionName, unsigned &SectionIndex) { SectionIndex = Symbol->st_shndx; @@ -542,7 +552,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 Sec = Obj.getSection(SectionIndex); error(Sec.getError()); SectionName = errorOrDefault(Obj.getSectionName(*Sec)); @@ -1012,9 +1022,9 @@ ELFDumper::ELFDumper(const ELFFile *Obj, StreamWriter &Writer) DotSymtabSec = &Sec; break; case ELF::SHT_DYNSYM: - if (DotDynSymSec != nullptr) + if (DynSymRegion.Size) reportError("Multilpe SHT_DYNSYM"); - DotDynSymSec = &Sec; + DynSymRegion = createDRIFrom(&Sec); break; case ELF::SHT_SYMTAB_SHNDX: { ErrorOr> TableOrErr = Obj->getSHNDXTable(Sec); @@ -1084,8 +1094,8 @@ void ELFDumper::parseDynamicTable( StringTableSize = Dyn.getVal(); break; case ELF::DT_SYMTAB: - DynSymStart = - reinterpret_cast(toMappedAddr(Dyn.getPtr())); + DynSymRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynSymRegion.EntSize = sizeof(Elf_Sym); break; case ELF::DT_RELA: DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); @@ -1213,7 +1223,7 @@ void ELFDumper::printSections() { if (!SymSec) continue; if (*SymSec == &Sec) - printSymbol(&Sym, Symtab, StrTable, false); + printSymbol(&Sym, Obj->symbol_begin(Symtab), StrTable, false); } } @@ -1341,7 +1351,7 @@ void ELFDumper::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 = dynamic_symbols().begin() + SymIndex; SymbolName = errorOrDefault(Sym->getName(DynamicStringTable)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); @@ -1359,14 +1369,23 @@ void ELFDumper::printDynamicRelocation(Elf_Rela Rel) { template void ELFDumper::printSymbolsHelper(bool IsDynamic) { - const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec; - if (!Symtab) - return; - ErrorOr 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; + Elf_Sym_Range Syms(nullptr, nullptr); + + if (IsDynamic) { + StrTable = DynamicStringTable; + Syms = dynamic_symbols(); + } else { + if (!DotSymtabSec) + return; + ErrorOr 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 @@ -1382,11 +1401,12 @@ void ELFDumper::printDynamicSymbols() { } template -void ELFDumper::printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, - StringRef StrTable, bool IsDynamic) { +void ELFDumper::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(); @@ -1760,10 +1780,11 @@ void ELFDumper::printGnuHashTable() { W.printNumber("Shift Count", GnuHashTable->shift2); W.printHexList("Bloom Filter", GnuHashTable->filter()); W.printList("Buckets", GnuHashTable->buckets()); - if (!DotDynSymSec) + Elf_Sym_Range Syms = dynamic_symbols(); + unsigned NumSyms = std::distance(Syms.begin(), Syms.end()); + if (!NumSyms) reportError("No dynamic symbol section"); - W.printHexList("Values", - GnuHashTable->values(DotDynSymSec->getEntityCount())); + W.printHexList("Values", GnuHashTable->values(NumSyms)); } template void ELFDumper::printLoadName() { @@ -1891,11 +1912,9 @@ template void MipsGOTParser::parseGOT() { return; } - const Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); - ErrorOr 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) @@ -1955,8 +1974,8 @@ template void MipsGOTParser::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); } } @@ -2059,7 +2078,7 @@ void MipsGOTParser::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); @@ -2093,7 +2112,7 @@ void MipsGOTParser::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);