[llvm-readobj] Print MIPS PLT table

Now the -mips-plt-got prints both MIPS GOT and PLT tables.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241836 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Simon Atanasyan 2015-07-09 18:23:10 +00:00
parent ba8d948e93
commit 13c5e09c6e
3 changed files with 198 additions and 73 deletions

Binary file not shown.

View File

@ -0,0 +1,34 @@
RUN: llvm-readobj -mips-plt-got %p/Inputs/got-plt.exe.elf-mipsel | FileCheck %s
CHECK: PLT GOT {
CHECK-NEXT: Reserved entries [
CHECK-NEXT: Entry {
CHECK-NEXT: Address: 0x410814
CHECK-NEXT: Initial: 0x0
CHECK-NEXT: Purpose: PLT lazy resolver
CHECK-NEXT: }
CHECK-NEXT: Entry {
CHECK-NEXT: Address: 0x410818
CHECK-NEXT: Initial: 0x0
CHECK-NEXT: Purpose: Module pointer
CHECK-NEXT: }
CHECK-NEXT: ]
CHECK-NEXT: Entries [
CHECK-NEXT: Entry {
CHECK-NEXT: Address: 0x41081C
CHECK-NEXT: Initial: 0x4007C0
CHECK-NEXT: Value: 0x0
CHECK-NEXT: Type: Function (0x2)
CHECK-NEXT: Section: Undefined (0x0)
CHECK-NEXT: Name: puts@GLIBC_2.0 (71)
CHECK-NEXT: }
CHECK-NEXT: Entry {
CHECK-NEXT: Address: 0x410820
CHECK-NEXT: Initial: 0x4007C0
CHECK-NEXT: Value: 0x0
CHECK-NEXT: Type: Function (0x2)
CHECK-NEXT: Section: Undefined (0x0)
CHECK-NEXT: Name: __libc_start_main@GLIBC_2.0 (53)
CHECK-NEXT: }
CHECK-NEXT: ]
CHECK-NEXT: }

View File

@ -1162,9 +1162,10 @@ public:
typedef typename ObjectFile::Elf_Shdr Elf_Shdr;
typedef typename ObjectFile::Elf_Sym Elf_Sym;
MipsGOTParser(const ObjectFile *Obj, StreamWriter &W) : Obj(Obj), W(W) {}
MipsGOTParser(const ObjectFile *Obj, StreamWriter &W);
void parseGOT(const Elf_Shdr &GOTShdr);
void parseGOT();
void parsePLT();
private:
typedef typename ObjectFile::Elf_Addr GOTEntry;
@ -1173,35 +1174,79 @@ private:
const ObjectFile *Obj;
StreamWriter &W;
llvm::Optional<uint64_t> DtPltGot;
llvm::Optional<uint64_t> DtLocalGotNum;
llvm::Optional<uint64_t> DtGotSym;
llvm::Optional<uint64_t> DtMipsPltGot;
llvm::Optional<uint64_t> DtJmpRel;
std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const;
GOTIter makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum);
bool getGOTTags(uint64_t &LocalGotNum, uint64_t &GotSym);
void printGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It);
void printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It,
const Elf_Sym *Sym, bool IsDynamic);
void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It,
StringRef Purpose);
void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It,
const Elf_Sym *Sym);
};
}
template <class ELFT>
void MipsGOTParser<ELFT>::parseGOT(const Elf_Shdr &GOTShdr) {
MipsGOTParser<ELFT>::MipsGOTParser(const ObjectFile *Obj, StreamWriter &W)
: Obj(Obj), W(W) {
for (const auto &Entry : Obj->dynamic_table()) {
switch (Entry.getTag()) {
case ELF::DT_PLTGOT:
DtPltGot = Entry.getVal();
break;
case ELF::DT_MIPS_LOCAL_GOTNO:
DtLocalGotNum = Entry.getVal();
break;
case ELF::DT_MIPS_GOTSYM:
DtGotSym = Entry.getVal();
break;
case ELF::DT_MIPS_PLTGOT:
DtMipsPltGot = Entry.getVal();
break;
case ELF::DT_JMPREL:
DtJmpRel = Entry.getVal();
break;
}
}
}
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;
}
ErrorOr<ArrayRef<uint8_t>> GOT = Obj->getSectionContents(&GOTShdr);
const Elf_Shdr *GOTShdr = findSectionByAddress(Obj, *DtPltGot);
if (!GOTShdr) {
W.startLine() << "There is no .got section in the file.\n";
return;
}
ErrorOr<ArrayRef<uint8_t>> GOT = Obj->getSectionContents(GOTShdr);
if (!GOT) {
W.startLine() << "The .got section is empty.\n";
return;
}
uint64_t DtLocalGotNum;
uint64_t DtGotSym;
if (!getGOTTags(DtLocalGotNum, DtGotSym))
return;
if (DtLocalGotNum > getGOTTotal(*GOT)) {
if (*DtLocalGotNum > getGOTTotal(*GOT)) {
W.startLine() << "MIPS_LOCAL_GOTNO exceeds a number of GOT entries.\n";
return;
}
@ -1210,37 +1255,37 @@ void MipsGOTParser<ELFT>::parseGOT(const Elf_Shdr &GOTShdr) {
const Elf_Sym *DynSymEnd = Obj->dynamic_symbol_end();
std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd));
if (DtGotSym > DynSymTotal) {
if (*DtGotSym > DynSymTotal) {
W.startLine() << "MIPS_GOTSYM exceeds a number of dynamic symbols.\n";
return;
}
std::size_t GlobalGotNum = DynSymTotal - DtGotSym;
std::size_t GlobalGotNum = DynSymTotal - *DtGotSym;
if (DtLocalGotNum + GlobalGotNum > getGOTTotal(*GOT)) {
if (*DtLocalGotNum + GlobalGotNum > getGOTTotal(*GOT)) {
W.startLine() << "Number of global GOT entries exceeds the size of GOT.\n";
return;
}
GOTIter GotBegin = makeGOTIter(*GOT, 0);
GOTIter GotLocalEnd = makeGOTIter(*GOT, DtLocalGotNum);
GOTIter GotLocalEnd = makeGOTIter(*GOT, *DtLocalGotNum);
GOTIter It = GotBegin;
DictScope GS(W, "Primary GOT");
W.printHex("Canonical gp value", GOTShdr.sh_addr + 0x7ff0);
W.printHex("Canonical gp value", GOTShdr->sh_addr + 0x7ff0);
{
ListScope RS(W, "Reserved entries");
{
DictScope D(W, "Entry");
printGotEntry(GOTShdr.sh_addr, GotBegin, It++);
printGotEntry(GOTShdr->sh_addr, GotBegin, It++);
W.printString("Purpose", StringRef("Lazy resolver"));
}
if (It != GotLocalEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) {
DictScope D(W, "Entry");
printGotEntry(GOTShdr.sh_addr, GotBegin, It++);
printGotEntry(GOTShdr->sh_addr, GotBegin, It++);
W.printString("Purpose", StringRef("Module pointer (GNU extension)"));
}
}
@ -1248,24 +1293,88 @@ void MipsGOTParser<ELFT>::parseGOT(const Elf_Shdr &GOTShdr) {
ListScope LS(W, "Local entries");
for (; It != GotLocalEnd; ++It) {
DictScope D(W, "Entry");
printGotEntry(GOTShdr.sh_addr, GotBegin, It);
printGotEntry(GOTShdr->sh_addr, GotBegin, It);
}
}
{
ListScope GS(W, "Global entries");
GOTIter GotGlobalEnd = makeGOTIter(*GOT, DtLocalGotNum + GlobalGotNum);
const Elf_Sym *GotDynSym = DynSymBegin + DtGotSym;
GOTIter GotGlobalEnd = makeGOTIter(*GOT, *DtLocalGotNum + GlobalGotNum);
const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym;
for (; It != GotGlobalEnd; ++It) {
DictScope D(W, "Entry");
printGlobalGotEntry(GOTShdr.sh_addr, GotBegin, It, GotDynSym++, true);
printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, true);
}
}
std::size_t SpecGotNum = getGOTTotal(*GOT) - DtLocalGotNum - GlobalGotNum;
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 = findSectionByAddress(Obj, *DtMipsPltGot);
if (!PLTShdr) {
W.startLine() << "There is no .got.plt section in the file.\n";
return;
}
ErrorOr<ArrayRef<uint8_t>> PLT = Obj->getSectionContents(PLTShdr);
if (!PLT) {
W.startLine() << "The .got.plt section is empty.\n";
return;
}
const Elf_Shdr *PLTRelShdr = findSectionByAddress(Obj, *DtJmpRel);
if (!PLTShdr) {
W.startLine() << "There is no .rel.plt section in the file.\n";
return;
}
GOTIter PLTBegin = makeGOTIter(*PLT, 0);
GOTIter PLTEnd = makeGOTIter(*PLT, getGOTTotal(*PLT));
GOTIter 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 (typename ObjectFile::Elf_Rel_Iter RI = Obj->rel_begin(PLTRelShdr),
RE = Obj->rel_end(PLTRelShdr);
RI != RE && It != PLTEnd; ++RI, ++It) {
const Elf_Sym *Sym =
Obj->getRelocationSymbol(&*PLTRelShdr, &*RI).second;
printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, Sym);
}
break;
case ELF::SHT_RELA:
for (typename ObjectFile::Elf_Rela_Iter RI = Obj->rela_begin(PLTRelShdr),
RE = Obj->rela_end(PLTRelShdr);
RI != RE && It != PLTEnd; ++RI, ++It) {
const Elf_Sym *Sym =
Obj->getRelocationSymbol(&*PLTRelShdr, &*RI).second;
printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, Sym);
}
break;
}
}
}
template <class ELFT>
std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const {
return GOT.size() / sizeof(GOTEntry);
@ -1278,36 +1387,6 @@ MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) {
return GOTIter(sizeof(GOTEntry), Data + EntryNum * sizeof(GOTEntry));
}
template <class ELFT>
bool MipsGOTParser<ELFT>::getGOTTags(uint64_t &LocalGotNum, uint64_t &GotSym) {
bool FoundLocalGotNum = false;
bool FoundGotSym = false;
for (const auto &Entry : Obj->dynamic_table()) {
switch (Entry.getTag()) {
case ELF::DT_MIPS_LOCAL_GOTNO:
LocalGotNum = Entry.getVal();
FoundLocalGotNum = true;
break;
case ELF::DT_MIPS_GOTSYM:
GotSym = Entry.getVal();
FoundGotSym = true;
break;
}
}
if (!FoundLocalGotNum) {
W.startLine() << "Cannot find MIPS_LOCAL_GOTNO dynamic table tag.\n";
return false;
}
if (!FoundGotSym) {
W.startLine() << "Cannot find MIPS_GOTSYM dynamic table tag.\n";
return false;
}
return true;
}
template <class ELFT>
void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt,
GOTIter It) {
@ -1335,32 +1414,44 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt,
W.printNumber("Name", FullSymbolName, Sym->st_name);
}
template <class ELFT>
void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt,
GOTIter 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);
}
template <class ELFT>
void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt,
GOTIter It, 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));
unsigned SectionIndex = 0;
StringRef SectionName;
getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex);
W.printHex("Section", SectionName, SectionIndex);
std::string FullSymbolName = getFullSymbolName(*Obj, Sym, true);
W.printNumber("Name", FullSymbolName, Sym->st_name);
}
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;
}
llvm::Optional<uint64_t> DtPltGot;
for (const auto &Entry : Obj->dynamic_table()) {
if (Entry.getTag() == ELF::DT_PLTGOT) {
DtPltGot = Entry.getVal();
break;
}
}
if (!DtPltGot) {
W.startLine() << "Cannot find PLTGOT dynamic table tag.\n";
return;
}
const Elf_Shdr *GotShdr = findSectionByAddress(Obj, *DtPltGot);
if (!GotShdr) {
W.startLine() << "There is no .got section in the file.\n";
return;
}
MipsGOTParser<ELFT>(Obj, W).parseGOT(*GotShdr);
MipsGOTParser<ELFT> GOTParser(Obj, W);
GOTParser.parseGOT();
GOTParser.parsePLT();
}
static const EnumEntry<unsigned> ElfMipsISAExtType[] = {