[llvm-readobj] Support 'GNU' style for MIPS GOT/PLT dumping

This change adds `printMipsGOT` and `printMipsPLT` methods to the
`DumpStyle` class and overrides them in the `GNUStyle` and `LLVMStyle`
descendants. To pass information about GOT/PLT layout into these
methods, the `MipsGOTParser` class has been extended to hold all
necessary data.

llvm-svn: 321253
This commit is contained in:
Simon Atanasyan 2017-12-21 10:26:02 +00:00
parent 7093860aac
commit 62d3259d2d
3 changed files with 617 additions and 269 deletions

View File

@ -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

View File

@ -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

View File

@ -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);
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;
StringRef getPltStrTable() const { return PltStrTable; }
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;
const Elf_Shdr *GotSec;
size_t LocalNum;
size_t GlobalNum;
std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const;
const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum);
const Elf_Shdr *PltSec;
const Elf_Shdr *PltRelSec;
const Elf_Shdr *PltSymTable;
Elf_Sym_Range GotDynSyms;
StringRef PltStrTable;
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);
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;
}
}
// 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);
}
// 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));
}
}
template <class ELFT> uint64_t MipsGOTParser<ELFT>::getGp() const {
return GotSec->sh_addr + 0x7ff0;
}
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)"));
}
}
{
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;
}
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> 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;
}
}
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);
W.printHex("Value", Sym->st_value);
W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes));
unsigned SectionIndex = 0;
StringRef SectionName;
getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(),
Dumper->getShndxTable(), SectionName, SectionIndex);
W.printHex("Section", SectionName, SectionIndex);
std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true);
W.printNumber("Name", FullSymbolName, Sym->st_name);
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);
}
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);
uint64_t MipsGOTParser<ELFT>::getGotAddress(const Entry *E) const {
int64_t Offset = std::distance(GotEntries.data(), E) * sizeof(Entry);
return GotSec->sh_addr + Offset;
}
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));
int64_t MipsGOTParser<ELFT>::getGotOffset(const Entry *E) const {
int64_t Offset = std::distance(GotEntries.data(), E) * sizeof(Entry);
return Offset - 0x7ff0;
}
unsigned SectionIndex = 0;
StringRef SectionName;
getSectionNameIndex(*Obj, Sym, Dumper->dynamic_symbols().begin(),
Dumper->getShndxTable(), SectionName, SectionIndex);
W.printHex("Section", SectionName, SectionIndex);
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];
}
std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true);
W.printNumber("Name", FullSymbolName, Sym->st_name);
template <class ELFT>
const typename MipsGOTParser<ELFT>::Entry *
MipsGOTParser<ELFT>::getPltLazyResolver() const {
return PltEntries.empty() ? nullptr : &PltEntries[0];
}
template <class ELFT>
const typename MipsGOTParser<ELFT>::Entry *
MipsGOTParser<ELFT>::getPltModulePointer() const {
return PltEntries.size() < 2 ? nullptr : &PltEntries[1];
}
template <class ELFT>
typename MipsGOTParser<ELFT>::Entries
MipsGOTParser<ELFT>::getPltEntries() const {
if (PltEntries.size() <= 2)
return Entries();
return PltEntries.slice(2, PltEntries.size() - 2);
}
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>
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));
}
}
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;
}
if (Obj->getHeader()->e_machine != EM_MIPS)
reportError("MIPS PLT GOT is available for MIPS targets only");
MipsGOTParser<ELFT> GOTParser(this, Obj, dynamic_table(), W);
if (dynamic_table().empty())
GOTParser.parseStaticGOT();
else {
GOTParser.parseGOT();
GOTParser.parsePLT();
}
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);
}
}
}