diff options
-rw-r--r-- | llvm/test/tools/llvm-readobj/mips-got.test | 136 | ||||
-rw-r--r-- | llvm/test/tools/llvm-readobj/mips-plt.test | 32 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 706 |
3 files changed, 611 insertions, 263 deletions
diff --git a/llvm/test/tools/llvm-readobj/mips-got.test b/llvm/test/tools/llvm-readobj/mips-got.test index 65ccf13f2b4..a5c15fdfe23 100644 --- a/llvm/test/tools/llvm-readobj/mips-got.test +++ b/llvm/test/tools/llvm-readobj/mips-got.test @@ -1,4 +1,4 @@ -RUN: llvm-readobj -mips-plt-got %p/Inputs/relocs.obj.elf-mips | \ +RUN: not llvm-readobj -mips-plt-got %p/Inputs/relocs.obj.elf-mips 2>&1 | \ RUN: FileCheck %s -check-prefix GOT-OBJ RUN: llvm-readobj -mips-plt-got %p/Inputs/dynamic-table-exe.mips | \ RUN: FileCheck %s -check-prefix GOT-EXE @@ -11,7 +11,26 @@ RUN: FileCheck %s -check-prefix GOT-EMPTY RUN: llvm-readobj -mips-plt-got %p/Inputs/got-static.exe.mips | \ RUN: FileCheck %s -check-prefix GOT-STATIC -GOT-OBJ: Cannot find .got section +RUN: not llvm-readobj -mips-plt-got %p/Inputs/relocs.obj.elf-mips \ +RUN: --elf-output-style=GNU 2>&1 | \ +RUN: FileCheck %s -check-prefix GNU-GOT-OBJ +RUN: llvm-readobj -mips-plt-got %p/Inputs/dynamic-table-exe.mips \ +RUN: --elf-output-style=GNU | \ +RUN: FileCheck %s -check-prefix GNU-GOT-EXE +RUN: llvm-readobj -mips-plt-got %p/Inputs/dynamic-table-so.mips \ +RUN: --elf-output-style=GNU | \ +RUN: FileCheck %s -check-prefix GNU-GOT-SO +RUN: llvm-readobj -mips-plt-got %p/Inputs/got-tls.so.elf-mips64el \ +RUN: --elf-output-style=GNU | \ +RUN: FileCheck %s -check-prefix GNU-GOT-TLS +RUN: llvm-readobj -mips-plt-got %p/Inputs/got-empty.exe.mipsel \ +RUN: --elf-output-style=GNU | \ +RUN: FileCheck %s -check-prefix GNU-GOT-EMPTY +RUN: llvm-readobj -mips-plt-got %p/Inputs/got-static.exe.mips \ +RUN: --elf-output-style=GNU | \ +RUN: FileCheck %s -check-prefix GNU-GOT-STATIC + +GOT-OBJ: Error reading file: Cannot find .got section. GOT-EXE: Primary GOT { GOT-EXE-NEXT: Canonical gp value: 0x418880 @@ -366,3 +385,116 @@ GOT-STATIC-NEXT: Initial: 0x400104 GOT-STATIC-NEXT: } GOT-STATIC-NEXT: ] GOT-STATIC-NEXT: } + +GNU-GOT-OBJ: Error reading file: Cannot find .got section. + +GNU-GOT-EXE: Primary GOT: +GNU-GOT-EXE-NEXT: Canonical gp value: 00418880 + +GNU-GOT-EXE: Reserved entries: +GNU-GOT-EXE-NEXT: Address Access Initial Purpose +GNU-GOT-EXE-NEXT: 00410890 -32752(gp) 00000000 Lazy resolver +GNU-GOT-EXE-NEXT: 00410894 -32748(gp) 80000000 Module pointer (GNU extension) + +GNU-GOT-EXE: Local entries: +GNU-GOT-EXE-NEXT: Address Access Initial +GNU-GOT-EXE-NEXT: 00410898 -32744(gp) 00400418 +GNU-GOT-EXE-NEXT: 0041089c -32740(gp) 00410840 +GNU-GOT-EXE-NEXT: 004108a0 -32736(gp) 00000000 + +GNU-GOT-EXE: Global entries: +GNU-GOT-EXE-NEXT: Address Access Initial Sym.Val. Type Ndx Name +GNU-GOT-EXE-NEXT: 004108a4 -32732(gp) 00000000 00000000 FUNC UND __gmon_start__ + +GNU-GOT-EXE: PLT GOT: + +GNU-GOT-EXE: Reserved entries: +GNU-GOT-EXE-NEXT: Address Initial Purpose +GNU-GOT-EXE-NEXT: 00410854 00000000 PLT lazy resolver +GNU-GOT-EXE-NEXT: 00410894 80000000 Module pointer + +GNU-GOT-EXE: Entries: +GNU-GOT-EXE-NEXT: Address Initial Sym.Val. Type Ndx Name +GNU-GOT-EXE-NEXT: 0041085c 00400800 00000000 FUNC UND puts +GNU-GOT-EXE-NEXT: 00410860 00400800 00000000 FUNC UND __libc_start_main + +GNU-GOT-SO: Primary GOT: +GNU-GOT-SO-NEXT: Canonical gp value: 000188d0 + +GNU-GOT-SO: Reserved entries: +GNU-GOT-SO-NEXT: Address Access Initial Purpose +GNU-GOT-SO-NEXT: 000108e0 -32752(gp) 00000000 Lazy resolver +GNU-GOT-SO-NEXT: 000108e4 -32748(gp) 80000000 Module pointer (GNU extension) + +GNU-GOT-SO: Local entries: +GNU-GOT-SO-NEXT: Address Access Initial +GNU-GOT-SO-NEXT: 000108e8 -32744(gp) 000108e0 +GNU-GOT-SO-NEXT: 000108ec -32740(gp) 00010000 +GNU-GOT-SO-NEXT: 000108f0 -32736(gp) 00010920 +GNU-GOT-SO-NEXT: 000108f4 -32732(gp) 000108cc +GNU-GOT-SO-NEXT: 000108f8 -32728(gp) 00000000 +GNU-GOT-SO-NEXT: 000108fc -32724(gp) 00000000 +GNU-GOT-SO-NEXT: 00010900 -32720(gp) 00000000 +GNU-GOT-SO-NEXT: 00010904 -32716(gp) 00000000 + +GNU-GOT-SO: Global entries: +GNU-GOT-SO-NEXT: Address Access Initial Sym.Val. Type Ndx Name +GNU-GOT-SO-NEXT: 00010908 -32712(gp) 00000000 00000000 NOTYPE UND _ITM_registerTMCloneTable +GNU-GOT-SO-NEXT: 0001090c -32708(gp) 00000000 00000000 NOTYPE UND _Jv_RegisterClasses +GNU-GOT-SO-NEXT: 00010910 -32704(gp) 00000000 00000000 FUNC UND __gmon_start__ +GNU-GOT-SO-NEXT: 00010914 -32700(gp) 00000840 00000840 FUNC UND puts +GNU-GOT-SO-NEXT: 00010918 -32696(gp) 00000000 00000000 NOTYPE UND _ITM_deregisterTMCloneTable +GNU-GOT-SO-NEXT: 0001091c -32692(gp) 00000000 00000000 FUNC UND __cxa_finalize + +GNU-GOT-TLS: Primary GOT: +GNU-GOT-TLS-NEXT: Canonical gp value: 0000000000018bf0 + +GNU-GOT-TLS: Reserved entries: +GNU-GOT-TLS-NEXT: Address Access Initial Purpose +GNU-GOT-TLS-NEXT: 0000000000010c00 -32752(gp) 0000000000000000 Lazy resolver +GNU-GOT-TLS-NEXT: 0000000000010c08 -32744(gp) 8000000000000000 Module pointer (GNU extension) + +GNU-GOT-TLS: Local entries: +GNU-GOT-TLS-NEXT: Address Access Initial +GNU-GOT-TLS-NEXT: 0000000000010c10 -32736(gp) 0000000000010000 +GNU-GOT-TLS-NEXT: 0000000000010c18 -32728(gp) 0000000000010c00 +GNU-GOT-TLS-NEXT: 0000000000010c20 -32720(gp) 0000000000010cb8 +GNU-GOT-TLS-NEXT: 0000000000010c28 -32712(gp) 0000000000010bf0 +GNU-GOT-TLS-NEXT: 0000000000010c30 -32704(gp) 0000000000000000 +GNU-GOT-TLS-NEXT: 0000000000010c38 -32696(gp) 0000000000000948 +GNU-GOT-TLS-NEXT: 0000000000010c40 -32688(gp) 0000000000000a20 +GNU-GOT-TLS-NEXT: 0000000000010c48 -32680(gp) 0000000000000af0 +GNU-GOT-TLS-NEXT: 0000000000010c50 -32672(gp) 0000000000000000 +GNU-GOT-TLS-NEXT: 0000000000010c58 -32664(gp) 0000000000000000 +GNU-GOT-TLS-NEXT: 0000000000010c60 -32656(gp) 0000000000000000 + +GNU-GOT-TLS: Global entries: +GNU-GOT-TLS-NEXT: Address Access Initial Sym.Val. Type Ndx Name +GNU-GOT-TLS-NEXT: 0000000000010c68 -32648(gp) 0000000000000000 0000000000000000 NOTYPE UND _ITM_registerTMCloneTable +GNU-GOT-TLS-NEXT: 0000000000010c70 -32640(gp) 0000000000000000 0000000000000000 NOTYPE UND _Jv_RegisterClasses +GNU-GOT-TLS-NEXT: 0000000000010c78 -32632(gp) 0000000000000000 0000000000000000 FUNC UND __gmon_start__ +GNU-GOT-TLS-NEXT: 0000000000010c80 -32624(gp) 0000000000000b60 0000000000000b60 FUNC UND __tls_get_addr +GNU-GOT-TLS-NEXT: 0000000000010c88 -32616(gp) 0000000000000000 0000000000000000 NOTYPE UND _ITM_deregisterTMCloneTable +GNU-GOT-TLS-NEXT: 0000000000010c90 -32608(gp) 0000000000000000 0000000000000000 FUNC UND __cxa_finalize + +GNU-GOTY : Primary GOT: +GNU-GOT-EMPTY: Canonical gp value: 00409ff0 + +GNU-GOTY : Reserved entries: +GNU-GOT-EMPTY: Address Access Initial Purpose +GNU-GOT-EMPTY: 00402000 -32752(gp) 00000000 Lazy resolver +GNU-GOT-EMPTY: 00402004 -32748(gp) 80000000 Module pointer (GNU extension) + +GNU-GOT-STATIC: Static GOT: +GNU-GOT-STATIC-NEXT: Canonical gp value: 00418100 + +GNU-GOT-STATIC: Reserved entries: +GNU-GOT-STATIC-NEXT: Address Access Initial Purpose +GNU-GOT-STATIC-NEXT: 00410110 -32752(gp) 00000000 Lazy resolver +GNU-GOT-STATIC-NEXT: 00410114 -32748(gp) 80000000 Module pointer (GNU extension) + +GNU-GOT-STATIC: Local entries: +GNU-GOT-STATIC-NEXT: Address Access Initial +GNU-GOT-STATIC-NEXT: 00410118 -32744(gp) 00400000 +GNU-GOT-STATIC-NEXT: 0041011c -32740(gp) 00400100 +GNU-GOT-STATIC-NEXT: 00410120 -32736(gp) 00400104 diff --git a/llvm/test/tools/llvm-readobj/mips-plt.test b/llvm/test/tools/llvm-readobj/mips-plt.test index ab0824b0be6..f41940c9cf3 100644 --- a/llvm/test/tools/llvm-readobj/mips-plt.test +++ b/llvm/test/tools/llvm-readobj/mips-plt.test @@ -1,4 +1,7 @@ RUN: llvm-readobj -mips-plt-got %p/Inputs/got-plt.exe.elf-mipsel | FileCheck %s +RUN: llvm-readobj -mips-plt-got --elf-output-style=GNU \ +RUN: %p/Inputs/got-plt.exe.elf-mipsel \ +RUN: | FileCheck --check-prefix=GNU %s CHECK: PLT GOT { CHECK-NEXT: Reserved entries [ @@ -32,3 +35,32 @@ CHECK-NEXT: Name: __libc_start_main@GLIBC_2.0 (53) CHECK-NEXT: } CHECK-NEXT: ] CHECK-NEXT: } + +GNU: Primary GOT: +GNU-NEXT: Canonical gp value: 00418840 + +GNU: Reserved entries: +GNU-NEXT: Address Access Initial Purpose +GNU-NEXT: 00410850 -32752(gp) 00000000 Lazy resolver +GNU-NEXT: 00410854 -32748(gp) 80000000 Module pointer (GNU extension) + +GNU: Local entries: +GNU-NEXT: Address Access Initial +GNU-NEXT: 00410858 -32744(gp) 004003d4 +GNU-NEXT: 0041085c -32740(gp) 00410800 +GNU-NEXT: 00410860 -32736(gp) 00000000 + +GNU: Global entries: +GNU-NEXT: Address Access Initial Sym.Val. Type Ndx Name +GNU-NEXT: 00410864 -32732(gp) 00000000 00000000 FUNC UND __gmon_start__ +GNU-NEXT: PLT GOT: + +GNU: Reserved entries: +GNU-NEXT: Address Initial Purpose +GNU-NEXT: 00410814 00000000 PLT lazy resolver +GNU-NEXT: 00410854 80000000 Module pointer + +GNU: Entries: +GNU-NEXT: Address Initial Sym.Val. Type Ndx Name +GNU-NEXT: 0041081c 004007c0 00000000 FUNC UND puts +GNU-NEXT: 00410820 004007c0 00000000 FUNC UND __libc_start_main diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 9678667abff..053d93df233 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -77,6 +77,7 @@ using namespace ELF; #define TYPEDEF_ELF_TYPES(ELFT) \ using ELFO = ELFFile<ELFT>; \ + using Elf_Addr = typename ELFO::Elf_Addr; \ using Elf_Shdr = typename ELFO::Elf_Shdr; \ using Elf_Sym = typename ELFO::Elf_Sym; \ using Elf_Dyn = typename ELFO::Elf_Dyn; \ @@ -249,6 +250,9 @@ public: Elf_Rela_Range dyn_relas() const; std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic) const; + void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, + StringRef &SectionName, + unsigned &SectionIndex) const; void printSymbolsHelper(bool IsDynamic) const; const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } @@ -287,6 +291,8 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const { ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic); } +template <class ELFT> class MipsGOTParser; + template <typename ELFT> class DumpStyle { public: using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr; @@ -310,6 +316,8 @@ public: virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0; virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0; virtual void printNotes(const ELFFile<ELFT> *Obj) = 0; + virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; + virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; const ELFDumper<ELFT> *dumper() const { return Dumper; } private: @@ -337,6 +345,8 @@ public: void printProgramHeaders(const ELFO *Obj) override; void printHashHistogram(const ELFFile<ELFT> *Obj) override; void printNotes(const ELFFile<ELFT> *Obj) override; + void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; + void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; private: struct Field { @@ -395,6 +405,8 @@ public: void printProgramHeaders(const ELFO *Obj) override; void printHashHistogram(const ELFFile<ELFT> *Obj) override; void printNotes(const ELFFile<ELFT> *Obj) override; + void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; + void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; private: void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab); @@ -735,11 +747,10 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, } template <typename ELFT> -static void -getSectionNameIndex(const ELFFile<ELFT> &Obj, const typename ELFT::Sym *Symbol, - const typename ELFT::Sym *FirstSym, - ArrayRef<typename ELFT::Word> ShndxTable, - StringRef &SectionName, unsigned &SectionIndex) { +void ELFDumper<ELFT>::getSectionNameIndex(const Elf_Sym *Symbol, + const Elf_Sym *FirstSym, + StringRef &SectionName, + unsigned &SectionIndex) const { SectionIndex = Symbol->st_shndx; if (Symbol->isUndefined()) SectionName = "Undefined"; @@ -758,8 +769,8 @@ getSectionNameIndex(const ELFFile<ELFT> &Obj, const typename ELFT::Sym *Symbol, SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>( Symbol, FirstSym, ShndxTable)); const typename ELFT::Shdr *Sec = - unwrapOrError(Obj.getSection(SectionIndex)); - SectionName = unwrapOrError(Obj.getSectionName(Sec)); + unwrapOrError(Obj->getSection(SectionIndex)); + SectionName = unwrapOrError(Obj->getSectionName(Sec)); } } @@ -1905,47 +1916,83 @@ template <> void ELFDumper<ELFType<support::little, false>>::printAttributes() { template <class ELFT> class MipsGOTParser { public: TYPEDEF_ELF_TYPES(ELFT) - using GOTEntry = typename ELFO::Elf_Addr; + using Entry = typename ELFO::Elf_Addr; + using Entries = ArrayRef<Entry>; - MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, - Elf_Dyn_Range DynTable, ScopedPrinter &W); + const bool IsStatic; + const ELFO * const Obj; - void parseStaticGOT(); - void parseGOT(); - void parsePLT(); + MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, Elf_Sym_Range DynSyms); -private: - ELFDumper<ELFT> *Dumper; - const ELFO *Obj; - ScopedPrinter &W; - Optional<uint64_t> DtPltGot; - Optional<uint64_t> DtLocalGotNum; - Optional<uint64_t> DtGotSym; - Optional<uint64_t> DtMipsPltGot; - Optional<uint64_t> DtJmpRel; + bool hasGot() const { return !GotEntries.empty(); } + bool hasPlt() const { return !PltEntries.empty(); } + + uint64_t getGp() const; + + const Entry *getGotLazyResolver() const; + const Entry *getGotModulePointer() const; + const Entry *getPltLazyResolver() const; + const Entry *getPltModulePointer() const; + + Entries getLocalEntries() const; + Entries getGlobalEntries() const; + Entries getOtherEntries() const; + Entries getPltEntries() const; + + uint64_t getGotAddress(const Entry * E) const; + int64_t getGotOffset(const Entry * E) const; + const Elf_Sym *getGotSym(const Entry *E) const; + + uint64_t getPltAddress(const Entry * E) const; + const Elf_Sym *getPltSym(const Entry *E) const; - std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const; - const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); - - void printLocalGOT(const Elf_Shdr *GOTShdr, size_t Num); - void printGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, - const GOTEntry *It); - void printGlobalGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, - const GOTEntry *It, const Elf_Sym *Sym, - StringRef StrTable); - void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, - const GOTEntry *It, StringRef Purpose); - void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, - const GOTEntry *It, StringRef StrTable, - const Elf_Sym *Sym); + StringRef getPltStrTable() const { return PltStrTable; } + +private: + const Elf_Shdr *GotSec; + size_t LocalNum; + size_t GlobalNum; + + const Elf_Shdr *PltSec; + const Elf_Shdr *PltRelSec; + const Elf_Shdr *PltSymTable; + Elf_Sym_Range GotDynSyms; + StringRef PltStrTable; + + Entries GotEntries; + Entries PltEntries; }; } // end anonymous namespace template <class ELFT> -MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, - Elf_Dyn_Range DynTable, ScopedPrinter &W) - : Dumper(Dumper), Obj(Obj), W(W) { +MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, Elf_Dyn_Range DynTable, + Elf_Sym_Range DynSyms) + : IsStatic(DynTable.empty()), Obj(Obj), GotSec(nullptr), LocalNum(0), + GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr) { + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed GOT description. + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + + // Find static GOT secton. + if (IsStatic) { + GotSec = findSectionByName(*Obj, ".got"); + if (!GotSec) + reportError("Cannot find .got section"); + + ArrayRef<uint8_t> Content = unwrapOrError(Obj->getSectionContents(GotSec)); + GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()), + Content.size() / sizeof(Entry)); + LocalNum = GotEntries.size(); + return; + } + + // Lookup dynamic table tags which define GOT/PLT layouts. + Optional<uint64_t> DtPltGot; + Optional<uint64_t> DtLocalGotNum; + Optional<uint64_t> DtGotSym; + Optional<uint64_t> DtMipsPltGot; + Optional<uint64_t> DtJmpRel; for (const auto &Entry : DynTable) { switch (Entry.getTag()) { case ELF::DT_PLTGOT: @@ -1965,261 +2012,175 @@ MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, break; } } -} - -template <class ELFT> -void MipsGOTParser<ELFT>::printLocalGOT(const Elf_Shdr *GOTShdr, size_t Num) { - ArrayRef<uint8_t> GOT = unwrapOrError(Obj->getSectionContents(GOTShdr)); - - const GOTEntry *GotBegin = makeGOTIter(GOT, 0); - const GOTEntry *GotEnd = makeGOTIter(GOT, Num); - const GOTEntry *It = GotBegin; - - W.printHex("Canonical gp value", GOTShdr->sh_addr + 0x7ff0); - { - ListScope RS(W, "Reserved entries"); - - { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It++); - W.printString("Purpose", StringRef("Lazy resolver")); - } - if (It != GotEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It++); - W.printString("Purpose", StringRef("Module pointer (GNU extension)")); - } + // Find dynamic GOT section. + if (DtPltGot || DtLocalGotNum || DtGotSym) { + if (!DtPltGot) + report_fatal_error("Cannot find PLTGOT dynamic table tag."); + if (!DtLocalGotNum) + report_fatal_error("Cannot find MIPS_LOCAL_GOTNO dynamic table tag."); + if (!DtGotSym) + report_fatal_error("Cannot find MIPS_GOTSYM dynamic table tag."); + + size_t DynSymTotal = DynSyms.size(); + if (*DtGotSym > DynSymTotal) + reportError("MIPS_GOTSYM exceeds a number of dynamic symbols"); + + GotSec = findNotEmptySectionByAddress(Obj, *DtPltGot); + if (!GotSec) + reportError("There is no not empty GOT section at 0x" + + Twine::utohexstr(*DtPltGot)); + + LocalNum = *DtLocalGotNum; + GlobalNum = DynSymTotal - *DtGotSym; + + ArrayRef<uint8_t> Content = unwrapOrError(Obj->getSectionContents(GotSec)); + GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()), + Content.size() / sizeof(Entry)); + GotDynSyms = DynSyms.drop_front(*DtGotSym); } - { - ListScope LS(W, "Local entries"); - for (; It != GotEnd; ++It) { - DictScope D(W, "Entry"); - printGotEntry(GOTShdr->sh_addr, GotBegin, It); - } - } -} -template <class ELFT> void MipsGOTParser<ELFT>::parseStaticGOT() { - const Elf_Shdr *GOTShdr = findSectionByName(*Obj, ".got"); - if (!GOTShdr) { - W.startLine() << "Cannot find .got section.\n"; - return; + // Find PLT section. + if (DtMipsPltGot || DtJmpRel) { + if (!DtMipsPltGot) + report_fatal_error("Cannot find MIPS_PLTGOT dynamic table tag."); + if (!DtJmpRel) + report_fatal_error("Cannot find JMPREL dynamic table tag."); + + PltSec = findNotEmptySectionByAddress(Obj, *DtMipsPltGot); + if (!PltSec) + report_fatal_error("There is no not empty PLTGOT section at 0x " + + Twine::utohexstr(*DtMipsPltGot)); + + PltRelSec = findNotEmptySectionByAddress(Obj, *DtJmpRel); + if (!PltRelSec) + report_fatal_error("There is no not empty RELPLT section at 0x" + + Twine::utohexstr(*DtJmpRel)); + + ArrayRef<uint8_t> PltContent = + unwrapOrError(Obj->getSectionContents(PltSec)); + PltEntries = Entries(reinterpret_cast<const Entry *>(PltContent.data()), + PltContent.size() / sizeof(Entry)); + + PltSymTable = unwrapOrError(Obj->getSection(PltRelSec->sh_link)); + PltStrTable = unwrapOrError(Obj->getStringTableForSymtab(*PltSymTable)); } - - DictScope GS(W, "Static GOT"); - printLocalGOT(GOTShdr, GOTShdr->sh_size / sizeof(GOTEntry)); } -template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { - // See "Global Offset Table" in Chapter 5 in the following document - // for detailed GOT description. - // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf - if (!DtPltGot) { - W.startLine() << "Cannot find PLTGOT dynamic table tag.\n"; - return; - } - if (!DtLocalGotNum) { - W.startLine() << "Cannot find MIPS_LOCAL_GOTNO dynamic table tag.\n"; - return; - } - if (!DtGotSym) { - W.startLine() << "Cannot find MIPS_GOTSYM dynamic table tag.\n"; - return; - } - - std::size_t DynSymTotal = Dumper->dynamic_symbols().size(); - - if (*DtGotSym > DynSymTotal) - report_fatal_error("MIPS_GOTSYM exceeds a number of dynamic symbols"); - - std::size_t GlobalGotNum = DynSymTotal - *DtGotSym; - - if (*DtLocalGotNum + GlobalGotNum == 0) { - W.startLine() << "GOT is empty.\n"; - return; - } - - const Elf_Shdr *GOTShdr = findNotEmptySectionByAddress(Obj, *DtPltGot); - if (!GOTShdr) - report_fatal_error("There is no not empty GOT section at 0x" + - Twine::utohexstr(*DtPltGot)); - - ArrayRef<uint8_t> GOT = unwrapOrError(Obj->getSectionContents(GOTShdr)); - - if (*DtLocalGotNum + GlobalGotNum > getGOTTotal(GOT)) - report_fatal_error("Number of GOT entries exceeds the size of GOT section"); - - DictScope GS(W, "Primary GOT"); - printLocalGOT(GOTShdr, *DtLocalGotNum); - - { - ListScope GS(W, "Global entries"); - - const GOTEntry *GotBegin = makeGOTIter(GOT, 0); - const GOTEntry *GotEnd = makeGOTIter(GOT, *DtLocalGotNum + GlobalGotNum); - const Elf_Sym *GotDynSym = Dumper->dynamic_symbols().begin() + *DtGotSym; - for (auto It = makeGOTIter(GOT, *DtLocalGotNum); It != GotEnd; ++It) { - DictScope D(W, "Entry"); - printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, - Dumper->getDynamicStringTable()); - } - } - - std::size_t SpecGotNum = getGOTTotal(GOT) - *DtLocalGotNum - GlobalGotNum; - W.printNumber("Number of TLS and multi-GOT entries", uint64_t(SpecGotNum)); +template <class ELFT> uint64_t MipsGOTParser<ELFT>::getGp() const { + return GotSec->sh_addr + 0x7ff0; } -template <class ELFT> void MipsGOTParser<ELFT>::parsePLT() { - if (!DtMipsPltGot) { - W.startLine() << "Cannot find MIPS_PLTGOT dynamic table tag.\n"; - return; - } - if (!DtJmpRel) { - W.startLine() << "Cannot find JMPREL dynamic table tag.\n"; - return; - } - - const Elf_Shdr *PLTShdr = findNotEmptySectionByAddress(Obj, *DtMipsPltGot); - if (!PLTShdr) - report_fatal_error("There is no not empty PLTGOT section at 0x " + - Twine::utohexstr(*DtMipsPltGot)); - ArrayRef<uint8_t> PLT = unwrapOrError(Obj->getSectionContents(PLTShdr)); - - const Elf_Shdr *PLTRelShdr = findNotEmptySectionByAddress(Obj, *DtJmpRel); - if (!PLTRelShdr) - report_fatal_error("There is no not empty RELPLT section at 0x" + - Twine::utohexstr(*DtJmpRel)); - const Elf_Shdr *SymTable = - unwrapOrError(Obj->getSection(PLTRelShdr->sh_link)); - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTable)); - - const GOTEntry *PLTBegin = makeGOTIter(PLT, 0); - const GOTEntry *PLTEnd = makeGOTIter(PLT, getGOTTotal(PLT)); - const GOTEntry *It = PLTBegin; - - DictScope GS(W, "PLT GOT"); - { - ListScope RS(W, "Reserved entries"); - printPLTEntry(PLTShdr->sh_addr, PLTBegin, It++, "PLT lazy resolver"); - if (It != PLTEnd) - printPLTEntry(PLTShdr->sh_addr, PLTBegin, It++, "Module pointer"); - } - { - ListScope GS(W, "Entries"); - - switch (PLTRelShdr->sh_type) { - case ELF::SHT_REL: - for (const Elf_Rel &Rel : unwrapOrError(Obj->rels(PLTRelShdr))) { - const Elf_Sym *Sym = - unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTable)); - printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, StrTable, Sym); - if (++It == PLTEnd) - break; - } - break; - case ELF::SHT_RELA: - for (const Elf_Rela &Rel : unwrapOrError(Obj->relas(PLTRelShdr))) { - const Elf_Sym *Sym = - unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTable)); - printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, StrTable, Sym); - if (++It == PLTEnd) - break; - } - break; - } - } +template <class ELFT> +const typename MipsGOTParser<ELFT>::Entry * +MipsGOTParser<ELFT>::getGotLazyResolver() const { + return LocalNum > 0 ? &GotEntries[0] : nullptr; } template <class ELFT> -std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const { - return GOT.size() / sizeof(GOTEntry); +const typename MipsGOTParser<ELFT>::Entry * +MipsGOTParser<ELFT>::getGotModulePointer() const { + if (LocalNum < 2) + return nullptr; + const Entry &E = GotEntries[1]; + if ((E >> (sizeof(Entry) * 8 - 1)) == 0) + return nullptr; + return &E; } template <class ELFT> -const typename MipsGOTParser<ELFT>::GOTEntry * -MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) { - const char *Data = reinterpret_cast<const char *>(GOT.data()); - return reinterpret_cast<const GOTEntry *>(Data + EntryNum * sizeof(GOTEntry)); +typename MipsGOTParser<ELFT>::Entries +MipsGOTParser<ELFT>::getLocalEntries() const { + size_t Skip = getGotModulePointer() ? 2 : 1; + if (LocalNum - Skip <= 0) + return Entries(); + return GotEntries.slice(Skip, LocalNum - Skip); } template <class ELFT> -void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, - const GOTEntry *BeginIt, - const GOTEntry *It) { - int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); - W.printHex("Address", GotAddr + Offset); - W.printNumber("Access", Offset - 0x7ff0); - W.printHex("Initial", *It); +typename MipsGOTParser<ELFT>::Entries +MipsGOTParser<ELFT>::getGlobalEntries() const { + if (GlobalNum == 0) + return Entries(); + return GotEntries.slice(LocalNum, GlobalNum); } template <class ELFT> -void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, - const GOTEntry *BeginIt, - const GOTEntry *It, - const Elf_Sym *Sym, - StringRef StrTable) { - printGotEntry(GotAddr, BeginIt, It); +typename MipsGOTParser<ELFT>::Entries +MipsGOTParser<ELFT>::getOtherEntries() const { + size_t OtherNum = GotEntries.size() - LocalNum - GlobalNum; + if (OtherNum == 0) + return Entries(); + return GotEntries.slice(LocalNum + GlobalNum, OtherNum); +} - W.printHex("Value", Sym->st_value); - W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); +template <class ELFT> +uint64_t MipsGOTParser<ELFT>::getGotAddress(const Entry *E) const { + int64_t Offset = std::distance(GotEntries.data(), E) * sizeof(Entry); + return GotSec->sh_addr + Offset; +} - unsigned SectionIndex = 0; - StringRef SectionName; - getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(), - Dumper->getShndxTable(), SectionName, SectionIndex); - W.printHex("Section", SectionName, SectionIndex); +template <class ELFT> +int64_t MipsGOTParser<ELFT>::getGotOffset(const Entry *E) const { + int64_t Offset = std::distance(GotEntries.data(), E) * sizeof(Entry); + return Offset - 0x7ff0; +} - std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true); - W.printNumber("Name", FullSymbolName, Sym->st_name); +template <class ELFT> +const typename MipsGOTParser<ELFT>::Elf_Sym * +MipsGOTParser<ELFT>::getGotSym(const Entry *E) const { + int64_t Offset = std::distance(GotEntries.data(), E); + return &GotDynSyms[Offset - LocalNum]; } template <class ELFT> -void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, - const GOTEntry *BeginIt, - const GOTEntry *It, StringRef Purpose) { - DictScope D(W, "Entry"); - int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); - W.printHex("Address", PLTAddr + Offset); - W.printHex("Initial", *It); - W.printString("Purpose", Purpose); +const typename MipsGOTParser<ELFT>::Entry * +MipsGOTParser<ELFT>::getPltLazyResolver() const { + return PltEntries.empty() ? nullptr : &PltEntries[0]; } template <class ELFT> -void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, - const GOTEntry *BeginIt, - const GOTEntry *It, StringRef StrTable, - const Elf_Sym *Sym) { - DictScope D(W, "Entry"); - int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); - W.printHex("Address", PLTAddr + Offset); - W.printHex("Initial", *It); - W.printHex("Value", Sym->st_value); - W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); +const typename MipsGOTParser<ELFT>::Entry * +MipsGOTParser<ELFT>::getPltModulePointer() const { + return PltEntries.size() < 2 ? nullptr : &PltEntries[1]; +} - unsigned SectionIndex = 0; - StringRef SectionName; - getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(), - Dumper->getShndxTable(), SectionName, SectionIndex); - W.printHex("Section", SectionName, SectionIndex); +template <class ELFT> +typename MipsGOTParser<ELFT>::Entries +MipsGOTParser<ELFT>::getPltEntries() const { + if (PltEntries.size() <= 2) + return Entries(); + return PltEntries.slice(2, PltEntries.size() - 2); +} - std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true); - W.printNumber("Name", FullSymbolName, Sym->st_name); +template <class ELFT> +uint64_t MipsGOTParser<ELFT>::getPltAddress(const Entry *E) const { + int64_t Offset = std::distance(PltEntries.data(), E) * sizeof(Entry); + return PltSec->sh_addr + Offset; } -template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { - if (Obj->getHeader()->e_machine != EM_MIPS) { - W.startLine() << "MIPS PLT GOT is available for MIPS targets only.\n"; - return; +template <class ELFT> +const typename MipsGOTParser<ELFT>::Elf_Sym * +MipsGOTParser<ELFT>::getPltSym(const Entry *E) const { + int64_t Offset = std::distance(getPltEntries().data(), E); + if (PltRelSec->sh_type == ELF::SHT_REL) { + Elf_Rel_Range Rels = unwrapOrError(Obj->rels(PltRelSec)); + return unwrapOrError(Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); + } else { + Elf_Rela_Range Rels = unwrapOrError(Obj->relas(PltRelSec)); + return unwrapOrError(Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); } +} - MipsGOTParser<ELFT> GOTParser(this, Obj, dynamic_table(), W); - if (dynamic_table().empty()) - GOTParser.parseStaticGOT(); - else { - GOTParser.parseGOT(); - GOTParser.parsePLT(); - } +template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { + if (Obj->getHeader()->e_machine != EM_MIPS) + reportError("MIPS PLT GOT is available for MIPS targets only"); + + MipsGOTParser<ELFT> Parser(Obj, dynamic_table(), dynamic_symbols()); + if (Parser.hasGot()) + ELFDumperStyle->printMipsGOT(Parser); + if (Parser.hasPlt()) + ELFDumperStyle->printMipsPLT(Parser); } static const EnumEntry<unsigned> ElfMipsISAExtType[] = { @@ -3597,6 +3558,119 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { } } +template <class ELFT> +void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { + size_t Bias = ELFT::Is64Bits ? 8 : 0; + auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) { + OS.PadToColumn(2); + OS << format_hex_no_prefix(Parser.getGotAddress(E), 8 + Bias); + OS.PadToColumn(11 + Bias); + OS << format_decimal(Parser.getGotOffset(E), 6) << "(gp)"; + OS.PadToColumn(22 + Bias); + OS << format_hex_no_prefix(*E, 8 + Bias); + OS.PadToColumn(31 + 2 * Bias); + OS << Purpose << "\n"; + }; + + OS << (Parser.IsStatic ? "Static GOT:\n" : "Primary GOT:\n"); + OS << " Canonical gp value: " + << format_hex_no_prefix(Parser.getGp(), 8 + Bias) << "\n\n"; + + OS << " Reserved entries:\n"; + OS << " Address Access Initial Purpose\n"; + PrintEntry(Parser.getGotLazyResolver(), "Lazy resolver"); + if (Parser.getGotModulePointer()) + PrintEntry(Parser.getGotModulePointer(), "Module pointer (GNU extension)"); + + if (!Parser.getLocalEntries().empty()) { + OS << "\n"; + OS << " Local entries:\n"; + OS << " Address Access Initial\n"; + for (auto &E : Parser.getLocalEntries()) + PrintEntry(&E, ""); + } + + if (Parser.IsStatic) + return; + + if (!Parser.getGlobalEntries().empty()) { + OS << "\n"; + OS << " Global entries:\n"; + OS << " Address Access Initial Sym.Val. Type Ndx Name\n"; + for (auto &E : Parser.getGlobalEntries()) { + const Elf_Sym *Sym = Parser.getGotSym(&E); + std::string SymName = this->dumper()->getFullSymbolName( + Sym, this->dumper()->getDynamicStringTable(), false); + + OS.PadToColumn(2); + OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias)); + OS.PadToColumn(11 + Bias); + OS << to_string(format_decimal(Parser.getGotOffset(&E), 6)) + "(gp)"; + OS.PadToColumn(22 + Bias); + OS << to_string(format_hex_no_prefix(E, 8 + Bias)); + OS.PadToColumn(31 + 2 * Bias); + OS << to_string(format_hex_no_prefix(Sym->st_value, 8 + Bias)); + OS.PadToColumn(40 + 3 * Bias); + OS << printEnum(Sym->getType(), makeArrayRef(ElfSymbolTypes)); + OS.PadToColumn(48 + 3 * Bias); + OS << getSymbolSectionNdx(Parser.Obj, Sym, + this->dumper()->dynamic_symbols().begin()); + OS.PadToColumn(52 + 3 * Bias); + OS << SymName << "\n"; + } + } + + if (!Parser.getOtherEntries().empty()) + OS << "\n Number of TLS and multi-GOT entries " + << Parser.getOtherEntries().size() << "\n"; +} + +template <class ELFT> +void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { + size_t Bias = ELFT::Is64Bits ? 8 : 0; + auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) { + OS.PadToColumn(2); + OS << format_hex_no_prefix(Parser.getGotAddress(E), 8 + Bias); + OS.PadToColumn(11 + Bias); + OS << format_hex_no_prefix(*E, 8 + Bias); + OS.PadToColumn(20 + 2 * Bias); + OS << Purpose << "\n"; + }; + + OS << "PLT GOT:\n\n"; + + OS << " Reserved entries:\n"; + OS << " Address Initial Purpose\n"; + PrintEntry(Parser.getPltLazyResolver(), "PLT lazy resolver"); + if (Parser.getPltModulePointer()) + PrintEntry(Parser.getGotModulePointer(), "Module pointer"); + + if (!Parser.getPltEntries().empty()) { + OS << "\n"; + OS << " Entries:\n"; + OS << " Address Initial Sym.Val. Type Ndx Name\n"; + for (auto &E : Parser.getPltEntries()) { + const Elf_Sym *Sym = Parser.getPltSym(&E); + std::string SymName = this->dumper()->getFullSymbolName( + Sym, this->dumper()->getDynamicStringTable(), false); + + OS.PadToColumn(2); + OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias)); + OS.PadToColumn(11 + Bias); + OS << to_string(format_hex_no_prefix(E, 8 + Bias)); + OS.PadToColumn(20 + 2 * Bias); + OS << to_string(format_hex_no_prefix(Sym->st_value, 8 + Bias)); + OS.PadToColumn(29 + 3 * Bias); + OS << printEnum(Sym->getType(), makeArrayRef(ElfSymbolTypes)); + OS.PadToColumn(37 + 3 * Bias); + OS << getSymbolSectionNdx(Parser.Obj, Sym, + this->dumper()->dynamic_symbols().begin()); + OS.PadToColumn(41 + 3 * Bias); + OS << SymName << "\n"; + } + } +} + template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { const Elf_Ehdr *e = Obj->getHeader(); { @@ -3854,8 +3928,7 @@ void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, bool IsDynamic) { unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Symbol, First, this->dumper()->getShndxTable(), - SectionName, SectionIndex); + this->dumper()->getSectionNameIndex(Symbol, First, SectionName, SectionIndex); std::string FullSymbolName = this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); unsigned char SymbolType = Symbol->getType(); @@ -3992,3 +4065,114 @@ template <class ELFT> void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { W.startLine() << "printNotes not implemented!\n"; } + +template <class ELFT> +void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { + auto PrintEntry = [&](const Elf_Addr *E) { + W.printHex("Address", Parser.getGotAddress(E)); + W.printNumber("Access", Parser.getGotOffset(E)); + W.printHex("Initial", *E); + }; + + DictScope GS(W, Parser.IsStatic ? "Static GOT" : "Primary GOT"); + + W.printHex("Canonical gp value", Parser.getGp()); + { + ListScope RS(W, "Reserved entries"); + { + DictScope D(W, "Entry"); + PrintEntry(Parser.getGotLazyResolver()); + W.printString("Purpose", StringRef("Lazy resolver")); + } + + if (Parser.getGotModulePointer()) { + DictScope D(W, "Entry"); + PrintEntry(Parser.getGotModulePointer()); + W.printString("Purpose", StringRef("Module pointer (GNU extension)")); + } + } + { + ListScope LS(W, "Local entries"); + for (auto &E : Parser.getLocalEntries()) { + DictScope D(W, "Entry"); + PrintEntry(&E); + } + } + + if (Parser.IsStatic) + return; + + { + ListScope GS(W, "Global entries"); + for (auto &E : Parser.getGlobalEntries()) { + DictScope D(W, "Entry"); + + PrintEntry(&E); + + const Elf_Sym *Sym = Parser.getGotSym(&E); + W.printHex("Value", Sym->st_value); + W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); + + unsigned SectionIndex = 0; + StringRef SectionName; + this->dumper()->getSectionNameIndex( + Sym, this->dumper()->dynamic_symbols().begin(), SectionName, + SectionIndex); + W.printHex("Section", SectionName, SectionIndex); + + std::string SymName = this->dumper()->getFullSymbolName( + Sym, this->dumper()->getDynamicStringTable(), true); + W.printNumber("Name", SymName, Sym->st_name); + } + } + + W.printNumber("Number of TLS and multi-GOT entries", + Parser.getOtherEntries().size()); +} + +template <class ELFT> +void LLVMStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { + auto PrintEntry = [&](const Elf_Addr *E) { + W.printHex("Address", Parser.getPltAddress(E)); + W.printHex("Initial", *E); + }; + + DictScope GS(W, "PLT GOT"); + + { + ListScope RS(W, "Reserved entries"); + { + DictScope D(W, "Entry"); + PrintEntry(Parser.getPltLazyResolver()); + W.printString("Purpose", StringRef("PLT lazy resolver")); + } + + if (auto E = Parser.getPltModulePointer()) { + DictScope D(W, "Entry"); + PrintEntry(E); + W.printString("Purpose", StringRef("Module pointer")); + } + } + { + ListScope LS(W, "Entries"); + for (auto &E : Parser.getPltEntries()) { + DictScope D(W, "Entry"); + PrintEntry(&E); + + const Elf_Sym *Sym = Parser.getPltSym(&E); + W.printHex("Value", Sym->st_value); + W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); + + unsigned SectionIndex = 0; + StringRef SectionName; + this->dumper()->getSectionNameIndex( + Sym, this->dumper()->dynamic_symbols().begin(), SectionName, + SectionIndex); + W.printHex("Section", SectionName, SectionIndex); + + std::string SymName = + this->dumper()->getFullSymbolName(Sym, Parser.getPltStrTable(), true); + W.printNumber("Name", SymName, Sym->st_name); + } + } +} |