summaryrefslogtreecommitdiff
path: root/tools/llvm-readobj
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-readobj')
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.cpp20
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp29
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp250
-rw-r--r--tools/llvm-readobj/ObjDumper.h1
-rw-r--r--tools/llvm-readobj/StreamWriter.h4
-rw-r--r--tools/llvm-readobj/Win64EHDumper.cpp4
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp10
7 files changed, 228 insertions, 90 deletions
diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp
index a1ea79f3688ea..bf5ff8e1d0310 100644
--- a/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -201,10 +201,10 @@ ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF,
if (FunctionOnly && Symbol.getType() != SymbolRef::ST_Function)
continue;
- uint64_t Address;
- if (std::error_code EC = Symbol.getAddress(Address))
+ ErrorOr<uint64_t> Address = Symbol.getAddress();
+ if (std::error_code EC = Address.getError())
return EC;
- if (Address == VA)
+ if (*Address == VA)
return Symbol;
}
return readobj_error::unknown_symbol;
@@ -605,7 +605,10 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,
if (std::error_code EC = FunctionNameOrErr.getError())
report_fatal_error(EC.message());
FunctionName = *FunctionNameOrErr;
- Function->getAddress(FunctionAddress);
+ ErrorOr<uint64_t> FunctionAddressOrErr = Function->getAddress();
+ if (std::error_code EC = FunctionAddressOrErr.getError())
+ report_fatal_error(EC.message());
+ FunctionAddress = *FunctionAddressOrErr;
} else {
const pe32_header *PEHeader;
if (COFF.getPE32Header(PEHeader))
@@ -620,8 +623,10 @@ bool Decoder::dumpUnpackedEntry(const COFFObjectFile &COFF,
if (std::error_code EC = Name.getError())
report_fatal_error(EC.message());
- uint64_t Address;
- XDataRecord->getAddress(Address);
+ ErrorOr<uint64_t> AddressOrErr = XDataRecord->getAddress();
+ if (std::error_code EC = AddressOrErr.getError())
+ report_fatal_error(EC.message());
+ uint64_t Address = *AddressOrErr;
SW.printString("ExceptionRecord", formatSymbol(*Name, Address));
@@ -666,7 +671,8 @@ bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF,
if (std::error_code EC = FunctionNameOrErr.getError())
report_fatal_error(EC.message());
FunctionName = *FunctionNameOrErr;
- Function->getAddress(FunctionAddress);
+ ErrorOr<uint64_t> FunctionAddressOrErr = Function->getAddress();
+ FunctionAddress = *FunctionAddressOrErr;
} else {
const pe32_header *PEHeader;
if (COFF.getPE32Header(PEHeader))
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index f5effe2924419..cf897d7cb4840 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -48,7 +48,6 @@ public:
COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer)
: ObjDumper(Writer)
, Obj(Obj) {
- cacheRelocations();
}
void printFileHeaders() override;
@@ -92,6 +91,7 @@ private:
typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy;
const llvm::object::COFFObjectFile *Obj;
+ bool RelocCached = false;
RelocMapTy RelocMap;
StringRef CVFileIndexToStringOffsetTable;
StringRef CVStringTable;
@@ -119,6 +119,7 @@ std::error_code createCOFFDumper(const object::ObjectFile *Obj,
// symbol used for the relocation at the offset.
std::error_code COFFDumper::resolveSymbol(const coff_section *Section,
uint64_t Offset, SymbolRef &Sym) {
+ cacheRelocations();
const auto &Relocations = RelocMap[Section];
for (const auto &Relocation : Relocations) {
uint64_t RelocationOffset = Relocation.getOffset();
@@ -339,6 +340,10 @@ static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
}
void COFFDumper::cacheRelocations() {
+ if (RelocCached)
+ return;
+ RelocCached = true;
+
for (const SectionRef &S : Obj->sections()) {
const coff_section *Section = Obj->getCOFFSection(S);
@@ -580,7 +585,11 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) {
W.printString("FunctionName", Name);
DataExtractor DE(FunctionLineTables[Name], true, 4);
- uint32_t Offset = 8; // Skip relocations.
+ uint32_t Offset = 6; // Skip relocations.
+ uint16_t Flags = DE.getU16(&Offset);
+ W.printHex("Flags", Flags);
+ bool HasColumnInformation =
+ Flags & COFF::DEBUG_LINE_TABLES_HAVE_COLUMN_RECORDS;
uint32_t FunctionSize = DE.getU32(&Offset);
W.printHex("CodeSize", FunctionSize);
while (DE.isValidOffset(Offset)) {
@@ -588,9 +597,12 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) {
// in the line table. The filename string is accessed using double
// indirection to the string table subsection using the index subsection.
uint32_t OffsetInIndex = DE.getU32(&Offset),
- SegmentLength = DE.getU32(&Offset),
+ SegmentLength = DE.getU32(&Offset),
FullSegmentSize = DE.getU32(&Offset);
- if (FullSegmentSize != 12 + 8 * SegmentLength) {
+
+ if (FullSegmentSize !=
+ 12 + 8 * SegmentLength +
+ (HasColumnInformation ? 4 * SegmentLength : 0)) {
error(object_error::parse_failed);
return;
}
@@ -631,6 +643,15 @@ void COFFDumper::printCodeViewDebugInfo(const SectionRef &Section) {
format("+0x%X", PC).snprint(Buffer, 32);
W.printNumber(Buffer, LineNumber);
}
+ if (HasColumnInformation) {
+ for (unsigned J = 0; J != SegmentLength && DE.isValidOffset(Offset);
+ ++J) {
+ uint16_t ColStart = DE.getU16(&Offset);
+ W.printNumber("ColStart", ColStart);
+ uint16_t ColEnd = DE.getU16(&Offset);
+ W.printNumber("ColEnd", ColEnd);
+ }
+ }
}
}
}
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
index a4b25efeb9ba1..1cdf5529c0809 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -56,6 +56,7 @@ public:
void printDynamicTable() override;
void printNeededLibraries() override;
void printProgramHeaders() override;
+ void printHashTable() override;
void printAttributes() override;
void printMipsPLTGOT() override;
@@ -1119,6 +1120,18 @@ void ELFDumper<ELFT>::printProgramHeaders() {
}
}
+template <typename ELFT>
+void ELFDumper<ELFT>::printHashTable() {
+ DictScope D(W, "HashTable");
+ auto HT = Obj->getHashTable();
+ if (!HT)
+ return;
+ W.printNumber("Num Buckets", HT->nbucket);
+ W.printNumber("Num Chains", HT->nchain);
+ W.printList("Buckets", HT->buckets());
+ W.printList("Chains", HT->chains());
+}
+
template <class ELFT>
void ELFDumper<ELFT>::printAttributes() {
W.startLine() << "Attributes not implemented.\n";
@@ -1162,9 +1175,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 +1187,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);
- if (!GOT) {
- W.startLine() << "The .got section is empty.\n";
+ const Elf_Shdr *GOTShdr = findSectionByAddress(Obj, *DtPltGot);
+ if (!GOTShdr) {
+ W.startLine() << "There is no .got section in the file.\n";
return;
}
- uint64_t DtLocalGotNum;
- uint64_t DtGotSym;
- if (!getGOTTags(DtLocalGotNum, DtGotSym))
+ ErrorOr<ArrayRef<uint8_t>> GOT = Obj->getSectionContents(GOTShdr);
+ if (!GOT) {
+ W.startLine() << "The .got section is empty.\n";
return;
+ }
- if (DtLocalGotNum > getGOTTotal(*GOT)) {
+ if (*DtLocalGotNum > getGOTTotal(*GOT)) {
W.startLine() << "MIPS_LOCAL_GOTNO exceeds a number of GOT entries.\n";
return;
}
@@ -1210,37 +1268,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 +1306,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);
@@ -1279,36 +1401,6 @@ MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) {
}
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) {
int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry);
@@ -1335,32 +1427,44 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt,
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;
- }
+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);
+}
- llvm::Optional<uint64_t> DtPltGot;
- for (const auto &Entry : Obj->dynamic_table()) {
- if (Entry.getTag() == ELF::DT_PLTGOT) {
- DtPltGot = Entry.getVal();
- break;
- }
- }
+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));
- if (!DtPltGot) {
- W.startLine() << "Cannot find PLTGOT dynamic table tag.\n";
- return;
- }
+ unsigned SectionIndex = 0;
+ StringRef SectionName;
+ getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex);
+ W.printHex("Section", SectionName, SectionIndex);
- const Elf_Shdr *GotShdr = findSectionByAddress(Obj, *DtPltGot);
- if (!GotShdr) {
- W.startLine() << "There is no .got section in the file.\n";
+ 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;
}
- MipsGOTParser<ELFT>(Obj, W).parseGOT(*GotShdr);
+ MipsGOTParser<ELFT> GOTParser(Obj, W);
+ GOTParser.parseGOT();
+ GOTParser.parsePLT();
}
static const EnumEntry<unsigned> ElfMipsISAExtType[] = {
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
index 27e15b256cc57..5ecf0ec3d6fa0 100644
--- a/tools/llvm-readobj/ObjDumper.h
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -37,6 +37,7 @@ public:
virtual void printDynamicTable() { }
virtual void printNeededLibraries() { }
virtual void printProgramHeaders() { }
+ virtual void printHashTable() { }
// Only implemented for ARM ELF at this time.
virtual void printAttributes() { }
diff --git a/tools/llvm-readobj/StreamWriter.h b/tools/llvm-readobj/StreamWriter.h
index 245588ba06006..f3cc57ef940e7 100644
--- a/tools/llvm-readobj/StreamWriter.h
+++ b/tools/llvm-readobj/StreamWriter.h
@@ -181,8 +181,8 @@ public:
startLine() << Label << ": " << (Value ? "Yes" : "No") << '\n';
}
- template <typename T_>
- void printList(StringRef Label, const SmallVectorImpl<T_> &List) {
+ template <typename T>
+ void printList(StringRef Label, const T &List) {
startLine() << Label << ": [";
bool Comma = false;
for (const auto &Item : List) {
diff --git a/tools/llvm-readobj/Win64EHDumper.cpp b/tools/llvm-readobj/Win64EHDumper.cpp
index 5a8af4135bd75..f57eea20e2d9c 100644
--- a/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/tools/llvm-readobj/Win64EHDumper.cpp
@@ -144,8 +144,10 @@ static std::error_code resolveRelocation(const Dumper::Context &Ctx,
Ctx.ResolveSymbol(Section, Offset, Symbol, Ctx.UserData))
return EC;
- if (std::error_code EC = Symbol.getAddress(ResolvedAddress))
+ ErrorOr<uint64_t> ResolvedAddressOrErr = Symbol.getAddress();
+ if (std::error_code EC = ResolvedAddressOrErr.getError())
return EC;
+ ResolvedAddress = *ResolvedAddressOrErr;
section_iterator SI = Ctx.COFF.section_begin();
if (std::error_code EC = Symbol.getSection(SI))
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index c5bccf9796094..12afacb0a858e 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -127,6 +127,10 @@ namespace opts {
cl::opt<bool> ProgramHeaders("program-headers",
cl::desc("Display ELF program headers"));
+ // -hash-table
+ cl::opt<bool> HashTable("hash-table",
+ cl::desc("Display ELF hash table"));
+
// -expand-relocs
cl::opt<bool> ExpandRelocs("expand-relocs",
cl::desc("Expand each shown relocation to multiple lines"));
@@ -199,9 +203,7 @@ bool error(std::error_code EC) {
}
bool relocAddressLess(RelocationRef a, RelocationRef b) {
- uint64_t a_addr = a.getOffset();
- uint64_t b_addr = b.getOffset();
- return a_addr < b_addr;
+ return a.getOffset() < b.getOffset();
}
} // namespace llvm
@@ -302,6 +304,8 @@ static void dumpObject(const ObjectFile *Obj) {
Dumper->printNeededLibraries();
if (opts::ProgramHeaders)
Dumper->printProgramHeaders();
+ if (opts::HashTable)
+ Dumper->printHashTable();
if (Obj->getArch() == llvm::Triple::arm && Obj->isELF())
if (opts::ARMAttributes)
Dumper->printAttributes();