aboutsummaryrefslogtreecommitdiff
path: root/llvm/tools/llvm-readobj
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-readobj')
-rw-r--r--llvm/tools/llvm-readobj/COFFDumper.cpp265
-rw-r--r--llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h171
-rw-r--r--llvm/tools/llvm-readobj/ELFDumper.cpp2020
-rw-r--r--llvm/tools/llvm-readobj/ObjDumper.cpp4
-rw-r--r--llvm/tools/llvm-readobj/ObjDumper.h4
-rw-r--r--llvm/tools/llvm-readobj/WasmDumper.cpp26
-rw-r--r--llvm/tools/llvm-readobj/XCOFFDumper.cpp13
-rw-r--r--llvm/tools/llvm-readobj/llvm-readobj.cpp38
8 files changed, 1615 insertions, 926 deletions
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index 9b2c6adb9d93..89a904f53ae7 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -104,7 +104,10 @@ public:
bool GHash) override;
void printStackMap() const override;
void printAddrsig() override;
+ void printCGProfile() override;
+
private:
+ StringRef getSymbolName(uint32_t Index);
void printSymbols() override;
void printDynamicSymbols() override;
void printSymbol(const SymbolRef &Sym);
@@ -409,6 +412,11 @@ static const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_TERMINAL_SERVER_AWARE),
};
+static const EnumEntry<COFF::ExtendedDLLCharacteristics>
+ PEExtendedDLLCharacteristics[] = {
+ LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT),
+};
+
static const EnumEntry<COFF::SectionCharacteristics>
ImageSectionCharacteristics[] = {
LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD ),
@@ -516,23 +524,25 @@ static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = {
};
static const EnumEntry<COFF::DebugType> ImageDebugType[] = {
- { "Unknown" , COFF::IMAGE_DEBUG_TYPE_UNKNOWN },
- { "COFF" , COFF::IMAGE_DEBUG_TYPE_COFF },
- { "CodeView" , COFF::IMAGE_DEBUG_TYPE_CODEVIEW },
- { "FPO" , COFF::IMAGE_DEBUG_TYPE_FPO },
- { "Misc" , COFF::IMAGE_DEBUG_TYPE_MISC },
- { "Exception" , COFF::IMAGE_DEBUG_TYPE_EXCEPTION },
- { "Fixup" , COFF::IMAGE_DEBUG_TYPE_FIXUP },
- { "OmapToSrc" , COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC },
- { "OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC },
- { "Borland" , COFF::IMAGE_DEBUG_TYPE_BORLAND },
- { "Reserved10" , COFF::IMAGE_DEBUG_TYPE_RESERVED10 },
- { "CLSID" , COFF::IMAGE_DEBUG_TYPE_CLSID },
- { "VCFeature" , COFF::IMAGE_DEBUG_TYPE_VC_FEATURE },
- { "POGO" , COFF::IMAGE_DEBUG_TYPE_POGO },
- { "ILTCG" , COFF::IMAGE_DEBUG_TYPE_ILTCG },
- { "MPX" , COFF::IMAGE_DEBUG_TYPE_MPX },
- { "Repro" , COFF::IMAGE_DEBUG_TYPE_REPRO },
+ {"Unknown", COFF::IMAGE_DEBUG_TYPE_UNKNOWN},
+ {"COFF", COFF::IMAGE_DEBUG_TYPE_COFF},
+ {"CodeView", COFF::IMAGE_DEBUG_TYPE_CODEVIEW},
+ {"FPO", COFF::IMAGE_DEBUG_TYPE_FPO},
+ {"Misc", COFF::IMAGE_DEBUG_TYPE_MISC},
+ {"Exception", COFF::IMAGE_DEBUG_TYPE_EXCEPTION},
+ {"Fixup", COFF::IMAGE_DEBUG_TYPE_FIXUP},
+ {"OmapToSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_TO_SRC},
+ {"OmapFromSrc", COFF::IMAGE_DEBUG_TYPE_OMAP_FROM_SRC},
+ {"Borland", COFF::IMAGE_DEBUG_TYPE_BORLAND},
+ {"Reserved10", COFF::IMAGE_DEBUG_TYPE_RESERVED10},
+ {"CLSID", COFF::IMAGE_DEBUG_TYPE_CLSID},
+ {"VCFeature", COFF::IMAGE_DEBUG_TYPE_VC_FEATURE},
+ {"POGO", COFF::IMAGE_DEBUG_TYPE_POGO},
+ {"ILTCG", COFF::IMAGE_DEBUG_TYPE_ILTCG},
+ {"MPX", COFF::IMAGE_DEBUG_TYPE_MPX},
+ {"Repro", COFF::IMAGE_DEBUG_TYPE_REPRO},
+ {"ExtendedDLLCharacteristics",
+ COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS},
};
static const EnumEntry<COFF::WeakExternalCharacteristics>
@@ -601,8 +611,8 @@ void COFFDumper::cacheRelocations() {
void COFFDumper::printDataDirectory(uint32_t Index,
const std::string &FieldName) {
- const data_directory *Data;
- if (Obj->getDataDirectory(Index, Data))
+ const data_directory *Data = Obj->getDataDirectory(Index);
+ if (!Data)
return;
W.printHex(FieldName + "RVA", Data->RelativeVirtualAddress);
W.printHex(FieldName + "Size", Data->Size);
@@ -621,6 +631,7 @@ void COFFDumper::printFileHeaders() {
W.printHex ("TimeDateStamp", FormattedTime, Obj->getTimeDateStamp());
W.printHex ("PointerToSymbolTable", Obj->getPointerToSymbolTable());
W.printNumber("SymbolCount", Obj->getNumberOfSymbols());
+ W.printNumber("StringTableSize", Obj->getStringTableSize());
W.printNumber("OptionalHeaderSize", Obj->getSizeOfOptionalHeader());
W.printFlags ("Characteristics", Obj->getCharacteristics(),
makeArrayRef(ImageFileCharacteristics));
@@ -722,11 +733,15 @@ void COFFDumper::printCOFFDebugDirectory() {
W.printHex("SizeOfData", D.SizeOfData);
W.printHex("AddressOfRawData", D.AddressOfRawData);
W.printHex("PointerToRawData", D.PointerToRawData);
+ // Ideally, if D.AddressOfRawData == 0, we should try to load the payload
+ // using D.PointerToRawData instead.
+ if (D.AddressOfRawData == 0)
+ continue;
if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW) {
const codeview::DebugInfo *DebugInfo;
StringRef PDBFileName;
- if (std::error_code EC = Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = Obj->getDebugPDBInfo(&D, DebugInfo, PDBFileName))
+ reportError(std::move(E), Obj->getFileName());
DictScope PDBScope(W, "PDBInfo");
W.printHex("PDBSignature", DebugInfo->Signature.CVSignature);
@@ -736,12 +751,19 @@ void COFFDumper::printCOFFDebugDirectory() {
W.printString("PDBFileName", PDBFileName);
}
} else if (D.SizeOfData != 0) {
- // FIXME: Type values of 12 and 13 are commonly observed but are not in
- // the documented type enum. Figure out what they mean.
+ // FIXME: Data visualization for IMAGE_DEBUG_TYPE_VC_FEATURE and
+ // IMAGE_DEBUG_TYPE_POGO?
ArrayRef<uint8_t> RawData;
- if (std::error_code EC = Obj->getRvaAndSizeAsBytes(D.AddressOfRawData,
+ if (Error E = Obj->getRvaAndSizeAsBytes(D.AddressOfRawData,
D.SizeOfData, RawData))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ reportError(std::move(E), Obj->getFileName());
+ if (D.Type == COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS) {
+ // FIXME right now the only possible value would fit in 8 bits,
+ // but that might change in the future
+ uint16_t Characteristics = RawData[0];
+ W.printFlags("ExtendedCharacteristics", Characteristics,
+ makeArrayRef(PEExtendedDLLCharacteristics));
+ }
W.printBinaryBlock("RawData", RawData);
}
}
@@ -750,11 +772,11 @@ void COFFDumper::printCOFFDebugDirectory() {
void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count,
uint64_t EntrySize, PrintExtraCB PrintExtra) {
uintptr_t TableStart, TableEnd;
- if (std::error_code EC = Obj->getVaPtr(TableVA, TableStart))
- reportError(errorCodeToError(EC), Obj->getFileName());
- if (std::error_code EC =
+ if (Error E = Obj->getVaPtr(TableVA, TableStart))
+ reportError(std::move(E), Obj->getFileName());
+ if (Error E =
Obj->getVaPtr(TableVA + Count * EntrySize - 1, TableEnd))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ reportError(std::move(E), Obj->getFileName());
TableEnd++;
for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) {
uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I);
@@ -1135,7 +1157,7 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
return;
}
- std::string PC = formatv("+{0:X}", uint32_t(Line.Offset));
+ std::string PC = std::string(formatv("+{0:X}", uint32_t(Line.Offset)));
ListScope PCScope(W, PC);
codeview::LineInfo LI(Line.Flags);
@@ -1449,21 +1471,25 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
DictScope D(W, "Symbol");
COFFSymbolRef Symbol = Obj->getCOFFSymbol(Sym);
- const coff_section *Section;
- if (std::error_code EC = Obj->getSection(Symbol.getSectionNumber(), Section)) {
- W.startLine() << "Invalid section number: " << EC.message() << "\n";
+ Expected<const coff_section *> SecOrErr =
+ Obj->getSection(Symbol.getSectionNumber());
+ if (!SecOrErr) {
+ W.startLine() << "Invalid section number: " << Symbol.getSectionNumber()
+ << "\n";
W.flush();
+ consumeError(SecOrErr.takeError());
return;
}
+ const coff_section *Section = *SecOrErr;
StringRef SymbolName;
- if (Obj->getSymbolName(Symbol, SymbolName))
- SymbolName = "";
+ if (Expected<StringRef> SymNameOrErr = Obj->getSymbolName(Symbol))
+ SymbolName = *SymNameOrErr;
StringRef SectionName;
- if (Expected<StringRef> NameOrErr =
+ if (Expected<StringRef> SecNameOrErr =
getSectionName(Obj, Symbol.getSectionNumber(), Section))
- SectionName = *NameOrErr;
+ SectionName = *SecNameOrErr;
W.printString("Name", SymbolName);
W.printNumber("Value", Symbol.getValue());
@@ -1492,16 +1518,8 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux))
reportError(errorCodeToError(EC), Obj->getFileName());
- Expected<COFFSymbolRef> Linked = Obj->getSymbol(Aux->TagIndex);
- if (!Linked)
- reportError(Linked.takeError(), Obj->getFileName());
-
- StringRef LinkedName;
- if (std::error_code EC = Obj->getSymbolName(*Linked, LinkedName))
- reportError(errorCodeToError(EC), Obj->getFileName());
-
DictScope AS(W, "AuxWeakExternal");
- W.printNumber("Linked", LinkedName, Aux->TagIndex);
+ W.printNumber("Linked", getSymbolName(Aux->TagIndex), Aux->TagIndex);
W.printEnum ("Search", Aux->Characteristics,
makeArrayRef(WeakExternalCharacteristics));
@@ -1532,35 +1550,25 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT
&& Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
- const coff_section *Assoc;
- StringRef AssocName = "";
- if (std::error_code EC = Obj->getSection(AuxNumber, Assoc))
- reportError(errorCodeToError(EC), Obj->getFileName());
- Expected<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);
- if (!Res)
- reportError(Res.takeError(), Obj->getFileName());
- AssocName = *Res;
-
- W.printNumber("AssocSection", AssocName, AuxNumber);
+ Expected<const coff_section *> Assoc = Obj->getSection(AuxNumber);
+ if (!Assoc)
+ reportError(Assoc.takeError(), Obj->getFileName());
+ Expected<StringRef> AssocName = getSectionName(Obj, AuxNumber, *Assoc);
+ if (!AssocName)
+ reportError(AssocName.takeError(), Obj->getFileName());
+
+ W.printNumber("AssocSection", *AssocName, AuxNumber);
}
} else if (Symbol.isCLRToken()) {
const coff_aux_clr_token *Aux;
if (std::error_code EC = getSymbolAuxData(Obj, Symbol, I, Aux))
reportError(errorCodeToError(EC), Obj->getFileName());
- Expected<COFFSymbolRef> ReferredSym =
- Obj->getSymbol(Aux->SymbolTableIndex);
- if (!ReferredSym)
- reportError(ReferredSym.takeError(), Obj->getFileName());
-
- StringRef ReferredName;
- if (std::error_code EC = Obj->getSymbolName(*ReferredSym, ReferredName))
- reportError(errorCodeToError(EC), Obj->getFileName());
-
DictScope AS(W, "AuxCLRToken");
W.printNumber("AuxType", Aux->AuxType);
W.printNumber("Reserved", Aux->Reserved);
- W.printNumber("SymbolTableIndex", ReferredName, Aux->SymbolTableIndex);
+ W.printNumber("SymbolTableIndex", getSymbolName(Aux->SymbolTableIndex),
+ Aux->SymbolTableIndex);
} else {
W.startLine() << "<unhandled auxiliary record>\n";
@@ -1621,11 +1629,11 @@ void COFFDumper::printImportedSymbols(
iterator_range<imported_symbol_iterator> Range) {
for (const ImportedSymbolRef &I : Range) {
StringRef Sym;
- if (std::error_code EC = I.getSymbolName(Sym))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getSymbolName(Sym))
+ reportError(std::move(E), Obj->getFileName());
uint16_t Ordinal;
- if (std::error_code EC = I.getOrdinal(Ordinal))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getOrdinal(Ordinal))
+ reportError(std::move(E), Obj->getFileName());
W.printNumber("Symbol", Sym, Ordinal);
}
}
@@ -1637,17 +1645,17 @@ void COFFDumper::printDelayImportedSymbols(
for (const ImportedSymbolRef &S : Range) {
DictScope Import(W, "Import");
StringRef Sym;
- if (std::error_code EC = S.getSymbolName(Sym))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = S.getSymbolName(Sym))
+ reportError(std::move(E), Obj->getFileName());
uint16_t Ordinal;
- if (std::error_code EC = S.getOrdinal(Ordinal))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = S.getOrdinal(Ordinal))
+ reportError(std::move(E), Obj->getFileName());
W.printNumber("Symbol", Sym, Ordinal);
uint64_t Addr;
- if (std::error_code EC = I.getImportAddress(Index++, Addr))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getImportAddress(Index++, Addr))
+ reportError(std::move(E), Obj->getFileName());
W.printHex("Address", Addr);
}
}
@@ -1657,16 +1665,16 @@ void COFFDumper::printCOFFImports() {
for (const ImportDirectoryEntryRef &I : Obj->import_directories()) {
DictScope Import(W, "Import");
StringRef Name;
- if (std::error_code EC = I.getName(Name))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getName(Name))
+ reportError(std::move(E), Obj->getFileName());
W.printString("Name", Name);
uint32_t ILTAddr;
- if (std::error_code EC = I.getImportLookupTableRVA(ILTAddr))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getImportLookupTableRVA(ILTAddr))
+ reportError(std::move(E), Obj->getFileName());
W.printHex("ImportLookupTableRVA", ILTAddr);
uint32_t IATAddr;
- if (std::error_code EC = I.getImportAddressTableRVA(IATAddr))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getImportAddressTableRVA(IATAddr))
+ reportError(std::move(E), Obj->getFileName());
W.printHex("ImportAddressTableRVA", IATAddr);
// The import lookup table can be missing with certain older linkers, so
// fall back to the import address table in that case.
@@ -1680,12 +1688,12 @@ void COFFDumper::printCOFFImports() {
for (const DelayImportDirectoryEntryRef &I : Obj->delay_import_directories()) {
DictScope Import(W, "DelayImport");
StringRef Name;
- if (std::error_code EC = I.getName(Name))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getName(Name))
+ reportError(std::move(E), Obj->getFileName());
W.printString("Name", Name);
const delay_import_directory_table_entry *Table;
- if (std::error_code EC = I.getDelayImportTable(Table))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getDelayImportTable(Table))
+ reportError(std::move(E), Obj->getFileName());
W.printHex("Attributes", Table->Attributes);
W.printHex("ModuleHandle", Table->ModuleHandle);
W.printHex("ImportAddressTable", Table->DelayImportAddressTable);
@@ -1697,18 +1705,18 @@ void COFFDumper::printCOFFImports() {
}
void COFFDumper::printCOFFExports() {
- for (const ExportDirectoryEntryRef &E : Obj->export_directories()) {
+ for (const ExportDirectoryEntryRef &Exp : Obj->export_directories()) {
DictScope Export(W, "Export");
StringRef Name;
uint32_t Ordinal, RVA;
- if (std::error_code EC = E.getSymbolName(Name))
- reportError(errorCodeToError(EC), Obj->getFileName());
- if (std::error_code EC = E.getOrdinal(Ordinal))
- reportError(errorCodeToError(EC), Obj->getFileName());
- if (std::error_code EC = E.getExportRVA(RVA))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = Exp.getSymbolName(Name))
+ reportError(std::move(E), Obj->getFileName());
+ if (Error E = Exp.getOrdinal(Ordinal))
+ reportError(std::move(E), Obj->getFileName());
+ if (Error E = Exp.getExportRVA(RVA))
+ reportError(std::move(E), Obj->getFileName());
W.printNumber("Ordinal", Ordinal);
W.printString("Name", Name);
@@ -1746,10 +1754,10 @@ void COFFDumper::printCOFFBaseReloc() {
for (const BaseRelocRef &I : Obj->base_relocs()) {
uint8_t Type;
uint32_t RVA;
- if (std::error_code EC = I.getRVA(RVA))
- reportError(errorCodeToError(EC), Obj->getFileName());
- if (std::error_code EC = I.getType(Type))
- reportError(errorCodeToError(EC), Obj->getFileName());
+ if (Error E = I.getRVA(RVA))
+ reportError(std::move(E), Obj->getFileName());
+ if (Error E = I.getType(Type))
+ reportError(std::move(E), Obj->getFileName());
DictScope Import(W, "Entry");
W.printString("Type", getBaseRelocTypeName(Type));
W.printHex("Address", RVA);
@@ -1882,7 +1890,7 @@ void COFFDumper::printResourceDirectoryTable(
}
void COFFDumper::printStackMap() const {
- object::SectionRef StackMapSection;
+ SectionRef StackMapSection;
for (auto Sec : Obj->sections()) {
StringRef Name;
if (Expected<StringRef> NameOrErr = Sec.getName())
@@ -1896,7 +1904,7 @@ void COFFDumper::printStackMap() const {
}
}
- if (StackMapSection == object::SectionRef())
+ if (StackMapSection == SectionRef())
return;
StringRef StackMapContents =
@@ -1913,7 +1921,7 @@ void COFFDumper::printStackMap() const {
}
void COFFDumper::printAddrsig() {
- object::SectionRef AddrsigSection;
+ SectionRef AddrsigSection;
for (auto Sec : Obj->sections()) {
StringRef Name;
if (Expected<StringRef> NameOrErr = Sec.getName())
@@ -1927,7 +1935,7 @@ void COFFDumper::printAddrsig() {
}
}
- if (AddrsigSection == object::SectionRef())
+ if (AddrsigSection == SectionRef())
return;
StringRef AddrsigContents =
@@ -1945,19 +1953,58 @@ void COFFDumper::printAddrsig() {
if (Err)
reportError(createError(Err), Obj->getFileName());
- Expected<COFFSymbolRef> Sym = Obj->getSymbol(SymIndex);
- if (!Sym)
- reportError(Sym.takeError(), Obj->getFileName());
+ W.printNumber("Sym", getSymbolName(SymIndex), SymIndex);
+ Cur += Size;
+ }
+}
- StringRef SymName;
- if (std::error_code EC = Obj->getSymbolName(*Sym, SymName))
- reportError(errorCodeToError(EC), Obj->getFileName());
+void COFFDumper::printCGProfile() {
+ SectionRef CGProfileSection;
+ for (SectionRef Sec : Obj->sections()) {
+ StringRef Name = unwrapOrError(Obj->getFileName(), Sec.getName());
+ if (Name == ".llvm.call-graph-profile") {
+ CGProfileSection = Sec;
+ break;
+ }
+ }
- W.printNumber("Sym", SymName, SymIndex);
- Cur += Size;
+ if (CGProfileSection == SectionRef())
+ return;
+
+ StringRef CGProfileContents =
+ unwrapOrError(Obj->getFileName(), CGProfileSection.getContents());
+ BinaryStreamReader Reader(CGProfileContents, llvm::support::little);
+
+ ListScope L(W, "CGProfile");
+ while (!Reader.empty()) {
+ uint32_t FromIndex, ToIndex;
+ uint64_t Count;
+ if (Error Err = Reader.readInteger(FromIndex))
+ reportError(std::move(Err), Obj->getFileName());
+ if (Error Err = Reader.readInteger(ToIndex))
+ reportError(std::move(Err), Obj->getFileName());
+ if (Error Err = Reader.readInteger(Count))
+ reportError(std::move(Err), Obj->getFileName());
+
+ DictScope D(W, "CGProfileEntry");
+ W.printNumber("From", getSymbolName(FromIndex), FromIndex);
+ W.printNumber("To", getSymbolName(ToIndex), ToIndex);
+ W.printNumber("Weight", Count);
}
}
+StringRef COFFDumper::getSymbolName(uint32_t Index) {
+ Expected<COFFSymbolRef> Sym = Obj->getSymbol(Index);
+ if (!Sym)
+ reportError(Sym.takeError(), Obj->getFileName());
+
+ Expected<StringRef> SymName = Obj->getSymbolName(*Sym);
+ if (!SymName)
+ reportError(SymName.takeError(), Obj->getFileName());
+
+ return *SymName;
+}
+
void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
ArrayRef<ArrayRef<uint8_t>> IpiRecords,
ArrayRef<ArrayRef<uint8_t>> TpiRecords) {
diff --git a/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h b/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
index 0a365d4fe72a..27942224053f 100644
--- a/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
+++ b/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h
@@ -30,12 +30,14 @@ namespace DwarfCFIEH {
template <typename ELFT>
class PrinterContext {
+ using Elf_Shdr = typename ELFT::Shdr;
+ using Elf_Phdr = typename ELFT::Phdr;
+
ScopedPrinter &W;
const object::ELFObjectFile<ELFT> *ObjF;
- void printEHFrameHdr(uint64_t Offset, uint64_t Address, uint64_t Size) const;
-
- void printEHFrame(const typename ELFT::Shdr *EHFrameShdr) const;
+ void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const;
+ void printEHFrame(const Elf_Shdr *EHFrameShdr) const;
public:
PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> *ObjF)
@@ -45,13 +47,14 @@ public:
};
template <class ELFT>
-static const typename object::ELFObjectFile<ELFT>::Elf_Shdr *
+static const typename ELFT::Shdr *
findSectionByAddress(const object::ELFObjectFile<ELFT> *ObjF, uint64_t Addr) {
- auto Sections = ObjF->getELFFile()->sections();
- if (Error E = Sections.takeError())
- reportError(std::move(E), ObjF->getFileName());
+ Expected<typename ELFT::ShdrRange> SectionsOrErr =
+ ObjF->getELFFile()->sections();
+ if (!SectionsOrErr)
+ reportError(SectionsOrErr.takeError(), ObjF->getFileName());
- for (const auto &Shdr : *Sections)
+ for (const typename ELFT::Shdr &Shdr : *SectionsOrErr)
if (Shdr.sh_addr == Addr)
return &Shdr;
return nullptr;
@@ -60,61 +63,59 @@ findSectionByAddress(const object::ELFObjectFile<ELFT> *ObjF, uint64_t Addr) {
template <typename ELFT>
void PrinterContext<ELFT>::printUnwindInformation() const {
const object::ELFFile<ELFT> *Obj = ObjF->getELFFile();
- const typename ELFT::Phdr *EHFramePhdr = nullptr;
- auto PHs = Obj->program_headers();
- if (Error E = PHs.takeError())
- reportError(std::move(E), ObjF->getFileName());
-
- for (const auto &Phdr : *PHs) {
- if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) {
- EHFramePhdr = &Phdr;
- if (Phdr.p_memsz != Phdr.p_filesz)
- reportError(object::createError(
- "p_memsz does not match p_filesz for GNU_EH_FRAME"),
- ObjF->getFileName());
- break;
- }
- }
+ Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr)
+ reportError(PhdrsOrErr.takeError(), ObjF->getFileName());
- if (EHFramePhdr)
- printEHFrameHdr(EHFramePhdr->p_offset, EHFramePhdr->p_vaddr,
- EHFramePhdr->p_memsz);
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
+ if (Phdr.p_type != ELF::PT_GNU_EH_FRAME)
+ continue;
- auto Sections = Obj->sections();
- if (Error E = Sections.takeError())
- reportError(std::move(E), ObjF->getFileName());
+ if (Phdr.p_memsz != Phdr.p_filesz)
+ reportError(object::createError(
+ "p_memsz does not match p_filesz for GNU_EH_FRAME"),
+ ObjF->getFileName());
+ printEHFrameHdr(&Phdr);
+ break;
+ }
- for (const auto &Shdr : *Sections) {
- auto SectionName = Obj->getSectionName(&Shdr);
- if (Error E = SectionName.takeError())
- reportError(std::move(E), ObjF->getFileName());
+ Expected<typename ELFT::ShdrRange> SectionsOrErr =
+ ObjF->getELFFile()->sections();
+ if (!SectionsOrErr)
+ reportError(SectionsOrErr.takeError(), ObjF->getFileName());
- if (*SectionName == ".eh_frame")
+ for (const Elf_Shdr &Shdr : *SectionsOrErr) {
+ Expected<StringRef> NameOrErr = Obj->getSectionName(&Shdr);
+ if (!NameOrErr)
+ reportError(NameOrErr.takeError(), ObjF->getFileName());
+ if (*NameOrErr == ".eh_frame")
printEHFrame(&Shdr);
}
}
template <typename ELFT>
-void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset,
- uint64_t EHFrameHdrAddress,
- uint64_t EHFrameHdrSize) const {
+void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const {
DictScope L(W, "EHFrameHeader");
+ uint64_t EHFrameHdrAddress = EHFramePHdr->p_vaddr;
W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress);
- W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset);
- W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize);
+ W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset);
+ W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz);
const object::ELFFile<ELFT> *Obj = ObjF->getELFFile();
- const auto *EHFrameHdrShdr = findSectionByAddress(ObjF, EHFrameHdrAddress);
- if (EHFrameHdrShdr) {
- auto SectionName = Obj->getSectionName(EHFrameHdrShdr);
- if (Error E = SectionName.takeError())
- reportError(std::move(E), ObjF->getFileName());
-
- W.printString("Corresponding Section", *SectionName);
+ if (const Elf_Shdr *EHFrameHdr =
+ findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) {
+ Expected<StringRef> NameOrErr = Obj->getSectionName(EHFrameHdr);
+ if (!NameOrErr)
+ reportError(NameOrErr.takeError(), ObjF->getFileName());
+ W.printString("Corresponding Section", *NameOrErr);
}
- DataExtractor DE(makeArrayRef(Obj->base() + EHFrameHdrOffset, EHFrameHdrSize),
+ Expected<ArrayRef<uint8_t>> Content = Obj->getSegmentContents(EHFramePHdr);
+ if (!Content)
+ reportError(Content.takeError(), ObjF->getFileName());
+
+ DataExtractor DE(*Content,
ELFT::TargetEndianness == support::endianness::little,
ELFT::Is64Bits ? 8 : 4);
@@ -154,7 +155,7 @@ void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset,
unsigned NumEntries = 0;
uint64_t PrevPC = 0;
- while (Offset + 8 <= EHFrameHdrSize && NumEntries < FDECount) {
+ while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) {
DictScope D(W, std::string("entry ") + std::to_string(NumEntries));
auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress;
@@ -172,8 +173,7 @@ void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset,
}
template <typename ELFT>
-void PrinterContext<ELFT>::printEHFrame(
- const typename ELFT::Shdr *EHFrameShdr) const {
+void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const {
uint64_t Address = EHFrameShdr->sh_addr;
uint64_t ShOffset = EHFrameShdr->sh_offset;
W.startLine() << format(".eh_frame section at offset 0x%" PRIx64
@@ -181,26 +181,23 @@ void PrinterContext<ELFT>::printEHFrame(
ShOffset, Address);
W.indent();
- const object::ELFFile<ELFT> *Obj = ObjF->getELFFile();
- auto Result = Obj->getSectionContents(EHFrameShdr);
- if (Error E = Result.takeError())
- reportError(std::move(E), ObjF->getFileName());
+ Expected<ArrayRef<uint8_t>> DataOrErr =
+ ObjF->getELFFile()->getSectionContents(EHFrameShdr);
+ if (!DataOrErr)
+ reportError(DataOrErr.takeError(), ObjF->getFileName());
- auto Contents = Result.get();
- DWARFDataExtractor DE(
- StringRef(reinterpret_cast<const char *>(Contents.data()),
- Contents.size()),
- ELFT::TargetEndianness == support::endianness::little,
- ELFT::Is64Bits ? 8 : 4);
+ DWARFDataExtractor DE(*DataOrErr,
+ ELFT::TargetEndianness == support::endianness::little,
+ ELFT::Is64Bits ? 8 : 4);
DWARFDebugFrame EHFrame(Triple::ArchType(ObjF->getArch()), /*IsEH=*/true,
/*EHFrameAddress=*/Address);
- EHFrame.parse(DE);
+ if (Error E = EHFrame.parse(DE))
+ reportError(std::move(E), ObjF->getFileName());
- for (const auto &Entry : EHFrame) {
- if (const auto *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
+ for (const dwarf::FrameEntry &Entry : EHFrame) {
+ if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) {
W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n",
- Address + CIE->getOffset(),
- CIE->getLength());
+ Address + CIE->getOffset(), CIE->getLength());
W.indent();
W.printNumber("version", CIE->getVersion());
@@ -208,47 +205,33 @@ void PrinterContext<ELFT>::printEHFrame(
W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor());
W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor());
W.printNumber("return_address_register", CIE->getReturnAddressRegister());
-
- W.getOStream() << "\n";
- W.startLine() << "Program:\n";
- W.indent();
- CIE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel());
- W.unindent();
-
- W.unindent();
- W.getOStream() << "\n";
-
- } else if (const auto *FDE = dyn_cast<dwarf::FDE>(&Entry)) {
+ } else {
+ const dwarf::FDE *FDE = cast<dwarf::FDE>(&Entry);
W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64
" cie=[0x%" PRIx64 "]\n",
- Address + FDE->getOffset(),
- FDE->getLength(),
+ Address + FDE->getOffset(), FDE->getLength(),
Address + FDE->getLinkedCIE()->getOffset());
W.indent();
W.startLine() << format("initial_location: 0x%" PRIx64 "\n",
FDE->getInitialLocation());
- W.startLine()
- << format("address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
- FDE->getAddressRange(),
- FDE->getInitialLocation() + FDE->getAddressRange());
-
- W.getOStream() << "\n";
- W.startLine() << "Program:\n";
- W.indent();
- FDE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel());
- W.unindent();
-
- W.unindent();
- W.getOStream() << "\n";
- } else {
- llvm_unreachable("unexpected DWARF frame kind");
+ W.startLine() << format(
+ "address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n",
+ FDE->getAddressRange(),
+ FDE->getInitialLocation() + FDE->getAddressRange());
}
+
+ W.getOStream() << "\n";
+ W.startLine() << "Program:\n";
+ W.indent();
+ Entry.cfis().dump(W.getOStream(), nullptr, W.getIndentLevel());
+ W.unindent();
+ W.unindent();
+ W.getOStream() << "\n";
}
W.unindent();
}
-
}
}
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 8ffb68283405..15076f1f8933 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -52,6 +52,8 @@
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MipsABIFlags.h"
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
@@ -135,19 +137,34 @@ struct DynRegionInfo {
/// Name of the file. Used for error reporting.
StringRef FileName;
+ /// Error prefix. Used for error reporting to provide more information.
+ std::string Context;
+ /// Region size name. Used for error reporting.
+ StringRef SizePrintName = "size";
+ /// Entry size name. Used for error reporting. If this field is empty, errors
+ /// will not mention the entry size.
+ StringRef EntSizePrintName = "entry size";
template <typename Type> ArrayRef<Type> getAsArrayRef() const {
const Type *Start = reinterpret_cast<const Type *>(Addr);
if (!Start)
return {Start, Start};
- if (EntSize != sizeof(Type) || Size % EntSize) {
- // TODO: Add a section index to this warning.
- reportWarning(createError("invalid section size (" + Twine(Size) +
- ") or entity size (" + Twine(EntSize) + ")"),
- FileName);
- return {Start, Start};
- }
- return {Start, Start + (Size / EntSize)};
+ if (EntSize == sizeof(Type) && (Size % EntSize == 0))
+ return {Start, Start + (Size / EntSize)};
+
+ std::string Msg;
+ if (!Context.empty())
+ Msg += Context + " has ";
+
+ Msg += ("invalid " + SizePrintName + " (0x" + Twine::utohexstr(Size) + ")")
+ .str();
+ if (!EntSizePrintName.empty())
+ Msg +=
+ (" or " + EntSizePrintName + " (0x" + Twine::utohexstr(EntSize) + ")")
+ .str();
+
+ reportWarning(createError(Msg.c_str()), FileName);
+ return {Start, Start};
}
};
@@ -204,7 +221,7 @@ public:
void printProgramHeaders(bool PrintProgramHeaders,
cl::boolOrDefault PrintSectionMapping) override;
void printHashTable() override;
- void printGnuHashTable() override;
+ void printGnuHashTable(const object::ObjectFile *Obj) override;
void printLoadName() override;
void printVersionInfo() override;
void printGroupSections() override;
@@ -213,7 +230,7 @@ public:
void printStackMap() const override;
- void printHashHistogram() override;
+ void printHashHistograms() override;
void printCGProfile() override;
void printAddrsig() override;
@@ -268,10 +285,10 @@ private:
DynRegionInfo DynRelaRegion;
DynRegionInfo DynRelrRegion;
DynRegionInfo DynPLTRelRegion;
- DynRegionInfo DynSymRegion;
+ Optional<DynRegionInfo> DynSymRegion;
DynRegionInfo DynamicTable;
StringRef DynamicStringTable;
- std::string SOName = "<Not found>";
+ StringRef SOName = "<Not found>";
const Elf_Hash *HashTable = nullptr;
const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
@@ -290,6 +307,8 @@ private:
};
mutable SmallVector<Optional<VersionEntry>, 16> VersionMap;
+ std::unordered_set<std::string> Warnings;
+
public:
Elf_Dyn_Range dynamic_table() const {
// A valid .dynamic section contains an array of entries terminated
@@ -306,26 +325,31 @@ public:
return Table.slice(0, Size);
}
+ Optional<DynRegionInfo> getDynSymRegion() const { return DynSymRegion; }
+
Elf_Sym_Range dynamic_symbols() const {
- return DynSymRegion.getAsArrayRef<Elf_Sym>();
+ if (!DynSymRegion)
+ return Elf_Sym_Range();
+ return DynSymRegion->getAsArrayRef<Elf_Sym>();
}
Elf_Rel_Range dyn_rels() const;
Elf_Rela_Range dyn_relas() const;
Elf_Relr_Range dyn_relrs() const;
- std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable,
+ std::string getFullSymbolName(const Elf_Sym *Symbol,
+ Optional<StringRef> StrTable,
bool IsDynamic) const;
Expected<unsigned> getSymbolSectionIndex(const Elf_Sym *Symbol,
const Elf_Sym *FirstSym) const;
Expected<StringRef> getSymbolSectionName(const Elf_Sym *Symbol,
unsigned SectionIndex) const;
- Expected<std::string> getStaticSymbolName(uint32_t Index) const;
- std::string getDynamicString(uint64_t Value) const;
+ std::string getStaticSymbolName(uint32_t Index) const;
+ StringRef getDynamicString(uint64_t Value) const;
Expected<StringRef> getSymbolVersionByIndex(uint32_t VersionSymbolIndex,
bool &IsDefault) const;
void printSymbolsHelper(bool IsDynamic) const;
- void printDynamicEntry(raw_ostream &OS, uint64_t Type, uint64_t Value) const;
+ std::string getDynamicEntry(uint64_t Type, uint64_t Value) const;
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; }
@@ -347,6 +371,12 @@ public:
getVersionDefinitions(const Elf_Shdr *Sec) const;
Expected<std::vector<VerNeed>>
getVersionDependencies(const Elf_Shdr *Sec) const;
+
+ Expected<std::pair<const Elf_Sym *, std::string>>
+ getRelocationTarget(const Elf_Shdr *SymTab, const Elf_Rela &R) const;
+
+ std::function<Error(const Twine &Msg)> WarningHandler;
+ void reportUniqueWarning(Error Err) const;
};
template <class ELFT>
@@ -439,12 +469,12 @@ ELFDumper<ELFT>::getVersionTable(const Elf_Shdr *Sec, ArrayRef<Elf_Sym> *SymTab,
Expected<std::pair<ArrayRef<Elf_Sym>, StringRef>> SymTabOrErr =
getLinkAsSymtab(Obj, Sec, SecNdx, SHT_DYNSYM);
if (!SymTabOrErr) {
- ELFDumperStyle->reportUniqueWarning(SymTabOrErr.takeError());
+ reportUniqueWarning(SymTabOrErr.takeError());
return *VersionsOrErr;
}
if (SymTabOrErr->first.size() != VersionsOrErr->size())
- ELFDumperStyle->reportUniqueWarning(
+ reportUniqueWarning(
createError("SHT_GNU_versym section with index " + Twine(SecNdx) +
": the number of entries (" + Twine(VersionsOrErr->size()) +
") does not match the number of symbols (" +
@@ -490,7 +520,7 @@ ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr *Sec) const {
VerdAux Aux;
Aux.Offset = VerdauxBuf - Start;
if (Verdaux->vda_name <= StrTabOrErr->size())
- Aux.Name = StrTabOrErr->drop_front(Verdaux->vda_name);
+ Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name));
else
Aux.Name = "<invalid vda_name: " + to_string(Verdaux->vda_name) + ">";
return Aux;
@@ -558,7 +588,7 @@ ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
StringRef StrTab;
Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx);
if (!StrTabOrErr)
- ELFDumperStyle->reportUniqueWarning(StrTabOrErr.takeError());
+ reportUniqueWarning(StrTabOrErr.takeError());
else
StrTab = *StrTabOrErr;
@@ -600,7 +630,7 @@ ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
VN.Offset = VerneedBuf - Start;
if (Verneed->vn_file < StrTab.size())
- VN.File = StrTab.drop_front(Verneed->vn_file);
+ VN.File = std::string(StrTab.drop_front(Verneed->vn_file));
else
VN.File = "<corrupt vn_file: " + to_string(Verneed->vn_file) + ">";
@@ -630,7 +660,7 @@ ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
if (StrTab.size() <= Vernaux->vna_name)
Aux.Name = "<corrupt>";
else
- Aux.Name = StrTab.drop_front(Vernaux->vna_name);
+ Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name));
VernauxBuf += Vernaux->vna_next;
}
@@ -641,7 +671,8 @@ ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const {
template <class ELFT>
void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
- StringRef StrTable, SymtabName;
+ Optional<StringRef> StrTable;
+ StringRef SymtabName;
size_t Entries = 0;
Elf_Sym_Range Syms(nullptr, nullptr);
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
@@ -649,16 +680,36 @@ void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const {
StrTable = DynamicStringTable;
Syms = dynamic_symbols();
SymtabName = DynSymtabName;
- if (DynSymRegion.Addr)
- Entries = DynSymRegion.Size / DynSymRegion.EntSize;
+ Entries = Syms.size();
} else {
if (!DotSymtabSec)
return;
- StrTable = unwrapOrError(ObjF->getFileName(),
- Obj->getStringTableForSymtab(*DotSymtabSec));
- Syms = unwrapOrError(ObjF->getFileName(), Obj->symbols(DotSymtabSec));
- SymtabName =
- unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DotSymtabSec));
+
+ if (Expected<StringRef> StrTableOrErr =
+ Obj->getStringTableForSymtab(*DotSymtabSec))
+ StrTable = *StrTableOrErr;
+ else
+ reportUniqueWarning(createError(
+ "unable to get the string table for the SHT_SYMTAB section: " +
+ toString(StrTableOrErr.takeError())));
+
+ if (Expected<Elf_Sym_Range> SymsOrErr = Obj->symbols(DotSymtabSec))
+ Syms = *SymsOrErr;
+ else
+ reportUniqueWarning(
+ createError("unable to read symbols from the SHT_SYMTAB section: " +
+ toString(SymsOrErr.takeError())));
+
+ if (Expected<StringRef> SymtabNameOrErr =
+ Obj->getSectionName(DotSymtabSec)) {
+ SymtabName = *SymtabNameOrErr;
+ } else {
+ reportUniqueWarning(
+ createError("unable to get the name of the SHT_SYMTAB section: " +
+ toString(SymtabNameOrErr.takeError())));
+ SymtabName = "<?>";
+ }
+
Entries = DotSymtabSec->getEntityCount();
}
if (Syms.begin() == Syms.end())
@@ -687,14 +738,6 @@ public:
DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {
FileName = this->Dumper->getElfObject()->getFileName();
-
- // Dumper reports all non-critical errors as warnings.
- // It does not print the same warning more than once.
- WarningHandler = [this](const Twine &Msg) {
- if (Warnings.insert(Msg.str()).second)
- reportWarning(createError(Msg), FileName);
- return Error::success();
- };
}
virtual ~DumpStyle() = default;
@@ -712,8 +755,9 @@ public:
virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name,
size_t Offset, bool NonVisibilityBitsUsed) {}
virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
- const Elf_Sym *FirstSym, StringRef StrTable,
- bool IsDynamic, bool NonVisibilityBitsUsed) = 0;
+ const Elf_Sym *FirstSym,
+ Optional<StringRef> StrTable, bool IsDynamic,
+ bool NonVisibilityBitsUsed) = 0;
virtual void printProgramHeaders(const ELFFile<ELFT> *Obj,
bool PrintProgramHeaders,
cl::boolOrDefault PrintSectionMapping) = 0;
@@ -723,7 +767,7 @@ public:
const Elf_Shdr *Sec) = 0;
virtual void printVersionDependencySection(const ELFFile<ELFT> *Obj,
const Elf_Shdr *Sec) = 0;
- virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printHashHistograms(const ELFFile<ELFT> *Obj) = 0;
virtual void printCGProfile(const ELFFile<ELFT> *Obj) = 0;
virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0;
virtual void printNotes(const ELFFile<ELFT> *Obj) = 0;
@@ -734,7 +778,7 @@ public:
void printRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj,
std::function<void()> PrintHeader);
void printFunctionStackSize(const ELFObjectFile<ELFT> *Obj, uint64_t SymValue,
- SectionRef FunctionSec,
+ Optional<SectionRef> FunctionSec,
const StringRef SectionName, DataExtractor Data,
uint64_t *Offset);
void printStackSize(const ELFObjectFile<ELFT> *Obj, RelocationRef Rel,
@@ -747,14 +791,16 @@ public:
virtual void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) = 0;
const ELFDumper<ELFT> *dumper() const { return Dumper; }
- void reportUniqueWarning(Error Err) const;
-
protected:
- std::function<Error(const Twine &Msg)> WarningHandler;
+ void printDependentLibsHelper(
+ const ELFFile<ELFT> *Obj,
+ function_ref<void(const Elf_Shdr &)> OnSectionStart,
+ function_ref<void(StringRef, uint64_t)> OnSectionEntry);
+
+ void reportUniqueWarning(Error Err) const;
StringRef FileName;
private:
- std::unordered_set<std::string> Warnings;
const ELFDumper<ELFT> *Dumper;
};
@@ -790,7 +836,7 @@ public:
const Elf_Shdr *Sec) override;
void printVersionDependencySection(const ELFFile<ELFT> *Obj,
const Elf_Shdr *Sec) override;
- void printHashHistogram(const ELFFile<ELFT> *Obj) override;
+ void printHashHistograms(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
@@ -802,11 +848,18 @@ public:
void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override;
private:
+ void printHashHistogram(const Elf_Hash &HashTable);
+ void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable);
+
+ void printHashTableSymbols(const ELFO *Obj, const Elf_Hash &HashTable);
+ void printGnuHashTableSymbols(const ELFO *Obj,
+ const Elf_GnuHash &GnuHashTable);
+
struct Field {
std::string Str;
unsigned Column;
- Field(StringRef S, unsigned Col) : Str(S), Column(Col) {}
+ Field(StringRef S, unsigned Col) : Str(std::string(S)), Column(Col) {}
Field(unsigned Col) : Column(Col) {}
};
@@ -814,7 +867,7 @@ private:
std::string printEnum(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues) {
for (const auto &EnumItem : EnumValues)
if (EnumItem.Value == Value)
- return EnumItem.AltName;
+ return std::string(EnumItem.AltName);
return to_hexString(Value, false);
}
@@ -855,20 +908,17 @@ private:
void printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym,
StringRef StrTable, uint32_t Bucket);
void printRelocHeader(unsigned SType);
- void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
- const Elf_Rela &R, bool IsRela);
+ void printRelocation(const ELFO *Obj, unsigned SecIndex,
+ const Elf_Shdr *SymTab, const Elf_Rela &R,
+ unsigned RelIndex, bool IsRela);
void printRelocation(const ELFO *Obj, const Elf_Sym *Sym,
StringRef SymbolName, const Elf_Rela &R, bool IsRela);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
- StringRef StrTable, bool IsDynamic,
+ Optional<StringRef> StrTable, bool IsDynamic,
bool NonVisibilityBitsUsed) override;
std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym);
void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela);
- bool checkTLSSections(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
- bool checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
- bool checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
- bool checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec);
void printProgramHeaders(const ELFO *Obj);
void printSectionMapping(const ELFO *Obj);
void printGNUVersionSectionProlog(const ELFFile<ELFT> *Obj,
@@ -877,13 +927,18 @@ private:
};
template <class ELFT>
-void DumpStyle<ELFT>::reportUniqueWarning(Error Err) const {
+void ELFDumper<ELFT>::reportUniqueWarning(Error Err) const {
handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
cantFail(WarningHandler(EI.message()),
"WarningHandler should always return ErrorSuccess");
});
}
+template <class ELFT>
+void DumpStyle<ELFT>::reportUniqueWarning(Error Err) const {
+ this->dumper()->reportUniqueWarning(std::move(Err));
+}
+
template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
public:
TYPEDEF_ELF_TYPES(ELFT)
@@ -909,7 +964,7 @@ public:
const Elf_Shdr *Sec) override;
void printVersionDependencySection(const ELFFile<ELFT> *Obj,
const Elf_Shdr *Sec) override;
- void printHashHistogram(const ELFFile<ELFT> *Obj) override;
+ void printHashHistograms(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
void printNotes(const ELFFile<ELFT> *Obj) override;
@@ -921,13 +976,14 @@ public:
void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override;
private:
- void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
+ void printRelocation(const ELFO *Obj, unsigned SecIndex, Elf_Rela Rel,
+ unsigned RelIndex, const Elf_Shdr *SymTab);
void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel);
void printSymbols(const ELFO *Obj);
void printDynamicSymbols(const ELFO *Obj);
void printSymbolSection(const Elf_Sym *Symbol, const Elf_Sym *First);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
- StringRef StrTable, bool IsDynamic,
+ Optional<StringRef> StrTable, bool IsDynamic,
bool /*NonVisibilityBitsUsed*/) override;
void printProgramHeaders(const ELFO *Obj);
void printSectionMapping(const ELFO *Obj) {}
@@ -973,7 +1029,7 @@ std::error_code createELFDumper(const object::ObjectFile *Obj,
template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const {
// If there is no dynamic symtab or version table, there is nothing to do.
- if (!DynSymRegion.Addr || !SymbolVersionSection)
+ if (!DynSymRegion || !SymbolVersionSection)
return Error::success();
// Has the VersionMap already been loaded?
@@ -988,7 +1044,7 @@ template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const {
auto InsertEntry = [this](unsigned N, StringRef Version, bool IsVerdef) {
if (N >= VersionMap.size())
VersionMap.resize(N + 1);
- VersionMap[N] = {Version, IsVerdef};
+ VersionMap[N] = {std::string(Version), IsVerdef};
};
if (SymbolVersionDefSection) {
@@ -1023,38 +1079,85 @@ Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym *Sym,
return "";
}
+ assert(DynSymRegion && "DynSymRegion has not been initialised");
// Determine the position in the symbol table of this entry.
size_t EntryIndex = (reinterpret_cast<uintptr_t>(Sym) -
- reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) /
- sizeof(Elf_Sym);
+ reinterpret_cast<uintptr_t>(DynSymRegion->Addr)) /
+ sizeof(Elf_Sym);
// Get the corresponding version index entry.
- const Elf_Versym *Versym = unwrapOrError(
- ObjF->getFileName(), ObjF->getELFFile()->template getEntry<Elf_Versym>(
- SymbolVersionSection, EntryIndex));
- return this->getSymbolVersionByIndex(Versym->vs_index, IsDefault);
+ if (Expected<const Elf_Versym *> EntryOrErr =
+ ObjF->getELFFile()->template getEntry<Elf_Versym>(
+ SymbolVersionSection, EntryIndex))
+ return this->getSymbolVersionByIndex((*EntryOrErr)->vs_index, IsDefault);
+ else
+ return EntryOrErr.takeError();
+}
+
+template <typename ELFT>
+Expected<std::pair<const typename ELFT::Sym *, std::string>>
+ELFDumper<ELFT>::getRelocationTarget(const Elf_Shdr *SymTab,
+ const Elf_Rela &R) const {
+ const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+ Expected<const Elf_Sym *> SymOrErr = Obj->getRelocationSymbol(&R, SymTab);
+ if (!SymOrErr)
+ return SymOrErr.takeError();
+ const Elf_Sym *Sym = *SymOrErr;
+ if (!Sym)
+ return std::make_pair(nullptr, "");
+
+ // The st_name field of a STT_SECTION is usually 0 (empty string).
+ // This code block returns the section name.
+ if (Sym->getType() == ELF::STT_SECTION) {
+ Expected<const Elf_Shdr *> SecOrErr =
+ Obj->getSection(Sym, SymTab, ShndxTable);
+ if (!SecOrErr)
+ return SecOrErr.takeError();
+ // A section symbol describes the section at index 0.
+ if (*SecOrErr == nullptr)
+ return std::make_pair(Sym, "");
+
+ Expected<StringRef> NameOrErr = Obj->getSectionName(*SecOrErr);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ return std::make_pair(Sym, NameOrErr->str());
+ }
+
+ Expected<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*SymTab);
+ if (!StrTableOrErr)
+ return StrTableOrErr.takeError();
+
+ std::string SymbolName =
+ getFullSymbolName(Sym, *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM);
+ return std::make_pair(Sym, SymbolName);
}
static std::string maybeDemangle(StringRef Name) {
- return opts::Demangle ? demangle(Name) : Name.str();
+ return opts::Demangle ? demangle(std::string(Name)) : Name.str();
}
template <typename ELFT>
-Expected<std::string>
-ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
+std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
+ auto Warn = [&](Error E) -> std::string {
+ this->reportUniqueWarning(
+ createError("unable to read the name of symbol with index " +
+ Twine(Index) + ": " + toString(std::move(E))));
+ return "<?>";
+ };
+
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
Expected<const typename ELFT::Sym *> SymOrErr =
Obj->getSymbol(DotSymtabSec, Index);
if (!SymOrErr)
- return SymOrErr.takeError();
+ return Warn(SymOrErr.takeError());
Expected<StringRef> StrTabOrErr = Obj->getStringTableForSymtab(*DotSymtabSec);
if (!StrTabOrErr)
- return StrTabOrErr.takeError();
+ return Warn(StrTabOrErr.takeError());
Expected<StringRef> NameOrErr = (*SymOrErr)->getName(*StrTabOrErr);
if (!NameOrErr)
- return NameOrErr.takeError();
+ return Warn(NameOrErr.takeError());
return maybeDemangle(*NameOrErr);
}
@@ -1087,10 +1190,18 @@ ELFDumper<ELFT>::getSymbolVersionByIndex(uint32_t SymbolVersionIndex,
template <typename ELFT>
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
- StringRef StrTable,
+ Optional<StringRef> StrTable,
bool IsDynamic) const {
- std::string SymbolName = maybeDemangle(
- unwrapOrError(ObjF->getFileName(), Symbol->getName(StrTable)));
+ if (!StrTable)
+ return "<?>";
+
+ std::string SymbolName;
+ if (Expected<StringRef> NameOrErr = Symbol->getName(*StrTable)) {
+ SymbolName = maybeDemangle(*NameOrErr);
+ } else {
+ reportUniqueWarning(NameOrErr.takeError());
+ return "<?>";
+ }
if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) {
Elf_Sym_Range Syms = unwrapOrError(
@@ -1098,15 +1209,15 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
Expected<unsigned> SectionIndex =
getSymbolSectionIndex(Symbol, Syms.begin());
if (!SectionIndex) {
- ELFDumperStyle->reportUniqueWarning(SectionIndex.takeError());
+ reportUniqueWarning(SectionIndex.takeError());
return "<?>";
}
Expected<StringRef> NameOrErr = getSymbolSectionName(Symbol, *SectionIndex);
if (!NameOrErr) {
- ELFDumperStyle->reportUniqueWarning(NameOrErr.takeError());
+ reportUniqueWarning(NameOrErr.takeError());
return ("<section " + Twine(*SectionIndex) + ">").str();
}
- return *NameOrErr;
+ return std::string(*NameOrErr);
}
if (!IsDynamic)
@@ -1115,7 +1226,7 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
bool IsDefault;
Expected<StringRef> VersionOrErr = getSymbolVersion(&*Symbol, IsDefault);
if (!VersionOrErr) {
- ELFDumperStyle->reportUniqueWarning(VersionOrErr.takeError());
+ reportUniqueWarning(VersionOrErr.takeError());
return SymbolName + "@<corrupt>";
}
@@ -1170,7 +1281,7 @@ template <class ELFO>
static const typename ELFO::Elf_Shdr *
findNotEmptySectionByAddress(const ELFO *Obj, StringRef FileName,
uint64_t Addr) {
- for (const auto &Shdr : unwrapOrError(FileName, Obj->sections()))
+ for (const typename ELFO::Elf_Shdr &Shdr : cantFail(Obj->sections()))
if (Shdr.sh_addr == Addr && Shdr.sh_size > 0)
return &Shdr;
return nullptr;
@@ -1179,7 +1290,7 @@ findNotEmptySectionByAddress(const ELFO *Obj, StringRef FileName,
template <class ELFO>
static const typename ELFO::Elf_Shdr *
findSectionByName(const ELFO &Obj, StringRef FileName, StringRef Name) {
- for (const auto &Shdr : unwrapOrError(FileName, Obj.sections()))
+ for (const typename ELFO::Elf_Shdr &Shdr : cantFail(Obj.sections()))
if (Name == unwrapOrError(FileName, Obj.getSectionName(&Shdr)))
return &Shdr;
return nullptr;
@@ -1372,6 +1483,8 @@ static const EnumEntry<unsigned> ElfMachineType[] = {
ENUM_ENT(EM_STXP7X, "STMicroelectronics STxP7x family"),
ENUM_ENT(EM_NDS32, "Andes Technology compact code size embedded RISC processor family"),
ENUM_ENT(EM_ECOG1, "Cyan Technology eCOG1 microprocessor"),
+ // FIXME: Following EM_ECOG1X definitions is dead code since EM_ECOG1X has
+ // an identical number to EM_ECOG1.
ENUM_ENT(EM_ECOG1X, "Cyan Technology eCOG1X family"),
ENUM_ENT(EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core microcontrollers"),
ENUM_ENT(EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor"),
@@ -1406,6 +1519,7 @@ static const EnumEntry<unsigned> ElfMachineType[] = {
ENUM_ENT(EM_RISCV, "RISC-V"),
ENUM_ENT(EM_LANAI, "EM_LANAI"),
ENUM_ENT(EM_BPF, "EM_BPF"),
+ ENUM_ENT(EM_VE, "NEC SX-Aurora Vector Engine"),
};
static const EnumEntry<unsigned> ElfSymbolBindings[] = {
@@ -1731,6 +1845,7 @@ static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1030),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_XNACK),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_SRAM_ECC)
};
@@ -1786,18 +1901,22 @@ std::pair<const typename ELFT::Phdr *, const typename ELFT::Shdr *>
ELFDumper<ELFT>::findDynamic(const ELFFile<ELFT> *Obj) {
// Try to locate the PT_DYNAMIC header.
const Elf_Phdr *DynamicPhdr = nullptr;
- for (const Elf_Phdr &Phdr :
- unwrapOrError(ObjF->getFileName(), Obj->program_headers())) {
- if (Phdr.p_type != ELF::PT_DYNAMIC)
- continue;
- DynamicPhdr = &Phdr;
- break;
+ if (Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers()) {
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
+ if (Phdr.p_type != ELF::PT_DYNAMIC)
+ continue;
+ DynamicPhdr = &Phdr;
+ break;
+ }
+ } else {
+ this->reportUniqueWarning(createError(
+ "unable to read program headers to locate the PT_DYNAMIC segment: " +
+ toString(PhdrsOrErr.takeError())));
}
// Try to locate the .dynamic section in the sections header table.
const Elf_Shdr *DynamicSec = nullptr;
- for (const Elf_Shdr &Sec :
- unwrapOrError(ObjF->getFileName(), Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
if (Sec.sh_type != ELF::SHT_DYNAMIC)
continue;
DynamicSec = &Sec;
@@ -1847,6 +1966,9 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
bool IsPhdrTableValid = false;
if (DynamicPhdr) {
FromPhdr = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn));
+ FromPhdr.SizePrintName = "PT_DYNAMIC size";
+ FromPhdr.EntSizePrintName = "";
+
IsPhdrTableValid = !FromPhdr.getAsArrayRef<Elf_Dyn>().empty();
}
@@ -1860,6 +1982,11 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
FromSec =
checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset,
DynamicSec->sh_size, sizeof(Elf_Dyn), ObjF->getFileName()});
+ FromSec.Context = ("section with index " +
+ Twine(DynamicSec - &cantFail(Obj->sections()).front()))
+ .str();
+ FromSec.EntSizePrintName = "";
+
IsSecTableValid = !FromSec.getAsArrayRef<Elf_Dyn>().empty();
}
@@ -1917,19 +2044,33 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
ScopedPrinter &Writer)
: ObjDumper(Writer), ObjF(ObjF), DynRelRegion(ObjF->getFileName()),
DynRelaRegion(ObjF->getFileName()), DynRelrRegion(ObjF->getFileName()),
- DynPLTRelRegion(ObjF->getFileName()), DynSymRegion(ObjF->getFileName()),
- DynamicTable(ObjF->getFileName()) {
+ DynPLTRelRegion(ObjF->getFileName()), DynamicTable(ObjF->getFileName()) {
+ // Dumper reports all non-critical errors as warnings.
+ // It does not print the same warning more than once.
+ WarningHandler = [this](const Twine &Msg) {
+ if (Warnings.insert(Msg.str()).second)
+ reportWarning(createError(Msg), this->ObjF->getFileName());
+ return Error::success();
+ };
+
+ if (opts::Output == opts::GNU)
+ ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
+ else
+ ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
+
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
- for (const Elf_Shdr &Sec :
- unwrapOrError(ObjF->getFileName(), Obj->sections())) {
+ typename ELFT::ShdrRange Sections = cantFail(Obj->sections());
+ for (const Elf_Shdr &Sec : Sections) {
switch (Sec.sh_type) {
case ELF::SHT_SYMTAB:
if (!DotSymtabSec)
DotSymtabSec = &Sec;
break;
case ELF::SHT_DYNSYM:
- if (!DynSymRegion.Size) {
+ if (!DynSymRegion) {
DynSymRegion = createDRIFrom(&Sec);
+ DynSymRegion->Context =
+ ("section with index " + Twine(&Sec - &Sections.front())).str();
// This is only used (if Elf_Shdr present)for naming section in GNU
// style
DynSymtabName =
@@ -1968,11 +2109,6 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
}
loadDynamicTable(Obj);
-
- if (opts::Output == opts::GNU)
- ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
- else
- ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
}
template <typename ELFT>
@@ -1993,6 +2129,7 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
uint64_t SONameOffset = 0;
const char *StringTableBegin = nullptr;
uint64_t StringTableSize = 0;
+ Optional<DynRegionInfo> DynSymFromTable;
for (const Elf_Dyn &Dyn : dynamic_table()) {
switch (Dyn.d_tag) {
case ELF::DT_HASH:
@@ -2011,36 +2148,36 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
StringTableSize = Dyn.getVal();
break;
case ELF::DT_SYMTAB: {
- // Often we find the information about the dynamic symbol table
- // location in the SHT_DYNSYM section header. However, the value in
- // DT_SYMTAB has priority, because it is used by dynamic loaders to
- // locate .dynsym at runtime. The location we find in the section header
- // and the location we find here should match. If we can't map the
- // DT_SYMTAB value to an address (e.g. when there are no program headers), we
- // ignore its value.
+ // If we can't map the DT_SYMTAB value to an address (e.g. when there are
+ // no program headers), we ignore its value.
if (const uint8_t *VA = toMappedAddr(Dyn.getTag(), Dyn.getPtr())) {
- // EntSize is non-zero if the dynamic symbol table has been found via a
- // section header.
- if (DynSymRegion.EntSize && VA != DynSymRegion.Addr)
- reportWarning(
- createError(
- "SHT_DYNSYM section header and DT_SYMTAB disagree about "
- "the location of the dynamic symbol table"),
- ObjF->getFileName());
-
- DynSymRegion.Addr = VA;
- DynSymRegion.EntSize = sizeof(Elf_Sym);
+ DynSymFromTable.emplace(ObjF->getFileName());
+ DynSymFromTable->Addr = VA;
+ DynSymFromTable->EntSize = sizeof(Elf_Sym);
+ DynSymFromTable->EntSizePrintName = "";
}
break;
}
+ case ELF::DT_SYMENT: {
+ uint64_t Val = Dyn.getVal();
+ if (Val != sizeof(Elf_Sym))
+ reportWarning(createError("DT_SYMENT value of 0x" +
+ Twine::utohexstr(Val) +
+ " is not the size of a symbol (0x" +
+ Twine::utohexstr(sizeof(Elf_Sym)) + ")"),
+ ObjF->getFileName());
+ break;
+ }
case ELF::DT_RELA:
DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELASZ:
DynRelaRegion.Size = Dyn.getVal();
+ DynRelaRegion.SizePrintName = "DT_RELASZ value";
break;
case ELF::DT_RELAENT:
DynRelaRegion.EntSize = Dyn.getVal();
+ DynRelaRegion.EntSizePrintName = "DT_RELAENT value";
break;
case ELF::DT_SONAME:
SONameOffset = Dyn.getVal();
@@ -2050,9 +2187,11 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
break;
case ELF::DT_RELSZ:
DynRelRegion.Size = Dyn.getVal();
+ DynRelRegion.SizePrintName = "DT_RELSZ value";
break;
case ELF::DT_RELENT:
DynRelRegion.EntSize = Dyn.getVal();
+ DynRelRegion.EntSizePrintName = "DT_RELENT value";
break;
case ELF::DT_RELR:
case ELF::DT_ANDROID_RELR:
@@ -2061,10 +2200,16 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
case ELF::DT_RELRSZ:
case ELF::DT_ANDROID_RELRSZ:
DynRelrRegion.Size = Dyn.getVal();
+ DynRelrRegion.SizePrintName = Dyn.d_tag == ELF::DT_RELRSZ
+ ? "DT_RELRSZ value"
+ : "DT_ANDROID_RELRSZ value";
break;
case ELF::DT_RELRENT:
case ELF::DT_ANDROID_RELRENT:
DynRelrRegion.EntSize = Dyn.getVal();
+ DynRelrRegion.EntSizePrintName = Dyn.d_tag == ELF::DT_RELRENT
+ ? "DT_RELRENT value"
+ : "DT_ANDROID_RELRENT value";
break;
case ELF::DT_PLTREL:
if (Dyn.getVal() == DT_REL)
@@ -2075,18 +2220,78 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) {
reportError(createError(Twine("unknown DT_PLTREL value of ") +
Twine((uint64_t)Dyn.getVal())),
ObjF->getFileName());
+ DynPLTRelRegion.EntSizePrintName = "";
break;
case ELF::DT_JMPREL:
DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_PLTRELSZ:
DynPLTRelRegion.Size = Dyn.getVal();
+ DynPLTRelRegion.SizePrintName = "DT_PLTRELSZ value";
break;
}
}
- if (StringTableBegin)
- DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
+
+ if (StringTableBegin) {
+ const uint64_t FileSize = ObjF->getELFFile()->getBufSize();
+ const uint64_t Offset =
+ (const uint8_t *)StringTableBegin - ObjF->getELFFile()->base();
+ if (StringTableSize > FileSize - Offset)
+ reportUniqueWarning(createError(
+ "the dynamic string table at 0x" + Twine::utohexstr(Offset) +
+ " goes past the end of the file (0x" + Twine::utohexstr(FileSize) +
+ ") with DT_STRSZ = 0x" + Twine::utohexstr(StringTableSize)));
+ else
+ DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
+ }
+
SOName = getDynamicString(SONameOffset);
+
+ if (DynSymRegion) {
+ // Often we find the information about the dynamic symbol table
+ // location in the SHT_DYNSYM section header. However, the value in
+ // DT_SYMTAB has priority, because it is used by dynamic loaders to
+ // locate .dynsym at runtime. The location we find in the section header
+ // and the location we find here should match.
+ if (DynSymFromTable && DynSymFromTable->Addr != DynSymRegion->Addr)
+ reportUniqueWarning(
+ createError("SHT_DYNSYM section header and DT_SYMTAB disagree about "
+ "the location of the dynamic symbol table"));
+
+ // According to the ELF gABI: "The number of symbol table entries should
+ // equal nchain". Check to see if the DT_HASH hash table nchain value
+ // conflicts with the number of symbols in the dynamic symbol table
+ // according to the section header.
+ if (HashTable) {
+ if (DynSymRegion->EntSize == 0)
+ reportUniqueWarning(
+ createError("SHT_DYNSYM section has sh_entsize == 0"));
+ else if (HashTable->nchain != DynSymRegion->Size / DynSymRegion->EntSize)
+ reportUniqueWarning(createError(
+ "hash table nchain (" + Twine(HashTable->nchain) +
+ ") differs from symbol count derived from SHT_DYNSYM section "
+ "header (" +
+ Twine(DynSymRegion->Size / DynSymRegion->EntSize) + ")"));
+ }
+ }
+
+ // Delay the creation of the actual dynamic symbol table until now, so that
+ // checks can always be made against the section header-based properties,
+ // without worrying about tag order.
+ if (DynSymFromTable) {
+ if (!DynSymRegion) {
+ DynSymRegion = DynSymFromTable;
+ } else {
+ DynSymRegion->Addr = DynSymFromTable->Addr;
+ DynSymRegion->EntSize = DynSymFromTable->EntSize;
+ DynSymRegion->EntSizePrintName = DynSymFromTable->EntSizePrintName;
+ }
+ }
+
+ // Derive the dynamic symbol table size from the DT_HASH hash table, if
+ // present.
+ if (HashTable && DynSymRegion)
+ DynSymRegion->Size = HashTable->nchain * DynSymRegion->EntSize;
}
template <typename ELFT>
@@ -2156,8 +2361,8 @@ template <class ELFT> void ELFDumper<ELFT>::printHashSymbols() {
ELFDumperStyle->printHashSymbols(ObjF->getELFFile());
}
-template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() {
- ELFDumperStyle->printHashHistogram(ObjF->getELFFile());
+template <class ELFT> void ELFDumper<ELFT>::printHashHistograms() {
+ ELFDumperStyle->printHashHistograms(ObjF->getELFFile());
}
template <class ELFT> void ELFDumper<ELFT>::printCGProfile() {
@@ -2213,7 +2418,8 @@ static const EnumEntry<unsigned> ElfDynamicDTFlags1[] = {
LLVM_READOBJ_DT_FLAG_ENT(DF_1, NORELOC),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, SYMINTPOSE),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAUDIT),
- LLVM_READOBJ_DT_FLAG_ENT(DF_1, SINGLETON)
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, SINGLETON),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, PIE),
};
static const EnumEntry<unsigned> ElfDynamicDTMipsFlags[] = {
@@ -2257,10 +2463,24 @@ void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) {
}
template <class ELFT>
-void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
- uint64_t Value) const {
- const char *ConvChar =
- (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64;
+std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type,
+ uint64_t Value) const {
+ auto FormatHexValue = [](uint64_t V) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ const char *ConvChar =
+ (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64;
+ OS << format(ConvChar, V);
+ return OS.str();
+ };
+
+ auto FormatFlags = [](uint64_t V,
+ llvm::ArrayRef<llvm::EnumEntry<unsigned int>> Array) {
+ std::string Str;
+ raw_string_ostream OS(Str);
+ printFlags(V, Array, OS);
+ return OS.str();
+ };
// Handle custom printing of architecture specific tags
switch (ObjF->getELFFile()->getHeader()->e_machine) {
@@ -2268,8 +2488,7 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
switch (Type) {
case DT_AARCH64_BTI_PLT:
case DT_AARCH64_PAC_PLT:
- OS << Value;
- return;
+ return std::to_string(Value);
default:
break;
}
@@ -2277,12 +2496,10 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case EM_HEXAGON:
switch (Type) {
case DT_HEXAGON_VER:
- OS << Value;
- return;
+ return std::to_string(Value);
case DT_HEXAGON_SYMSZ:
case DT_HEXAGON_PLT:
- OS << format(ConvChar, Value);
- return;
+ return FormatHexValue(Value);
default:
break;
}
@@ -2293,8 +2510,7 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_MIPS_LOCAL_GOTNO:
case DT_MIPS_SYMTABNO:
case DT_MIPS_UNREFEXTNO:
- OS << Value;
- return;
+ return std::to_string(Value);
case DT_MIPS_TIME_STAMP:
case DT_MIPS_ICHECKSUM:
case DT_MIPS_IVERSION:
@@ -2335,11 +2551,9 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_MIPS_PLTGOT:
case DT_MIPS_RWPLT:
case DT_MIPS_RLD_MAP_REL:
- OS << format(ConvChar, Value);
- return;
+ return FormatHexValue(Value);
case DT_MIPS_FLAGS:
- printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS);
- return;
+ return FormatFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags));
default:
break;
}
@@ -2350,13 +2564,10 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
switch (Type) {
case DT_PLTREL:
- if (Value == DT_REL) {
- OS << "REL";
- break;
- } else if (Value == DT_RELA) {
- OS << "RELA";
- break;
- }
+ if (Value == DT_REL)
+ return "REL";
+ if (Value == DT_RELA)
+ return "RELA";
LLVM_FALLTHROUGH;
case DT_PLTGOT:
case DT_HASH:
@@ -2376,14 +2587,12 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_VERSYM:
case DT_GNU_HASH:
case DT_NULL:
- OS << format(ConvChar, Value);
- break;
+ return FormatHexValue(Value);
case DT_RELACOUNT:
case DT_RELCOUNT:
case DT_VERDEFNUM:
case DT_VERNEEDNUM:
- OS << Value;
- break;
+ return std::to_string(Value);
case DT_PLTRELSZ:
case DT_RELASZ:
case DT_RELAENT:
@@ -2396,8 +2605,7 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_PREINIT_ARRAYSZ:
case DT_ANDROID_RELSZ:
case DT_ANDROID_RELASZ:
- OS << Value << " (bytes)";
- break;
+ return std::to_string(Value) + " (bytes)";
case DT_NEEDED:
case DT_SONAME:
case DT_AUXILIARY:
@@ -2405,37 +2613,62 @@ void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type,
case DT_FILTER:
case DT_RPATH:
case DT_RUNPATH: {
- const std::map<uint64_t, const char*> TagNames = {
- {DT_NEEDED, "Shared library"},
- {DT_SONAME, "Library soname"},
- {DT_AUXILIARY, "Auxiliary library"},
- {DT_USED, "Not needed object"},
- {DT_FILTER, "Filter library"},
- {DT_RPATH, "Library rpath"},
- {DT_RUNPATH, "Library runpath"},
+ const std::map<uint64_t, const char *> TagNames = {
+ {DT_NEEDED, "Shared library"}, {DT_SONAME, "Library soname"},
+ {DT_AUXILIARY, "Auxiliary library"}, {DT_USED, "Not needed object"},
+ {DT_FILTER, "Filter library"}, {DT_RPATH, "Library rpath"},
+ {DT_RUNPATH, "Library runpath"},
};
- OS << TagNames.at(Type) << ": [" << getDynamicString(Value) << "]";
- break;
+
+ return (Twine(TagNames.at(Type)) + ": [" + getDynamicString(Value) + "]")
+ .str();
}
case DT_FLAGS:
- printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS);
- break;
+ return FormatFlags(Value, makeArrayRef(ElfDynamicDTFlags));
case DT_FLAGS_1:
- printFlags(Value, makeArrayRef(ElfDynamicDTFlags1), OS);
- break;
+ return FormatFlags(Value, makeArrayRef(ElfDynamicDTFlags1));
default:
- OS << format(ConvChar, Value);
- break;
+ return FormatHexValue(Value);
}
}
template <class ELFT>
-std::string ELFDumper<ELFT>::getDynamicString(uint64_t Value) const {
- if (DynamicStringTable.empty())
- return "<String table is empty or was not found>";
- if (Value < DynamicStringTable.size())
- return DynamicStringTable.data() + Value;
- return Twine("<Invalid offset 0x" + utohexstr(Value) + ">").str();
+StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const {
+ if (DynamicStringTable.empty() && !DynamicStringTable.data()) {
+ reportUniqueWarning(createError("string table was not found"));
+ return "<?>";
+ }
+
+ auto WarnAndReturn = [this](const Twine &Msg, uint64_t Offset) {
+ reportUniqueWarning(createError("string table at offset 0x" +
+ Twine::utohexstr(Offset) + Msg));
+ return "<?>";
+ };
+
+ const uint64_t FileSize = ObjF->getELFFile()->getBufSize();
+ const uint64_t Offset =
+ (const uint8_t *)DynamicStringTable.data() - ObjF->getELFFile()->base();
+ if (DynamicStringTable.size() > FileSize - Offset)
+ return WarnAndReturn(" with size 0x" +
+ Twine::utohexstr(DynamicStringTable.size()) +
+ " goes past the end of the file (0x" +
+ Twine::utohexstr(FileSize) + ")",
+ Offset);
+
+ if (Value >= DynamicStringTable.size())
+ return WarnAndReturn(
+ ": unable to read the string at 0x" + Twine::utohexstr(Offset + Value) +
+ ": it goes past the end of the table (0x" +
+ Twine::utohexstr(Offset + DynamicStringTable.size()) + ")",
+ Offset);
+
+ if (DynamicStringTable.back() != '\0')
+ return WarnAndReturn(": unable to read the string at 0x" +
+ Twine::utohexstr(Offset + Value) +
+ ": the string table is not null-terminated",
+ Offset);
+
+ return DynamicStringTable.data() + Value;
}
template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() {
@@ -2466,42 +2699,159 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicTable() {
template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() {
ListScope D(W, "NeededLibraries");
- std::vector<std::string> Libs;
+ std::vector<StringRef> Libs;
for (const auto &Entry : dynamic_table())
if (Entry.d_tag == ELF::DT_NEEDED)
Libs.push_back(getDynamicString(Entry.d_un.d_val));
- llvm::stable_sort(Libs);
+ llvm::sort(Libs);
- for (const auto &L : Libs)
+ for (StringRef L : Libs)
W.startLine() << L << "\n";
}
+template <class ELFT>
+static Error checkHashTable(const ELFFile<ELFT> *Obj,
+ const typename ELFT::Hash *H,
+ bool *IsHeaderValid = nullptr) {
+ auto MakeError = [&](uint64_t Off, const Twine &Msg = "") {
+ return createError("the hash table at offset 0x" + Twine::utohexstr(Off) +
+ " goes past the end of the file (0x" +
+ Twine::utohexstr(Obj->getBufSize()) + ")" + Msg);
+ };
+
+ // Each SHT_HASH section starts from two 32-bit fields: nbucket and nchain.
+ const unsigned HeaderSize = 2 * sizeof(typename ELFT::Word);
+ const uint64_t SecOffset = (const uint8_t *)H - Obj->base();
+
+ if (IsHeaderValid)
+ *IsHeaderValid = Obj->getBufSize() - SecOffset >= HeaderSize;
+
+ if (Obj->getBufSize() - SecOffset < HeaderSize)
+ return MakeError(SecOffset);
+
+ if (Obj->getBufSize() - SecOffset - HeaderSize <
+ ((uint64_t)H->nbucket + H->nchain) * sizeof(typename ELFT::Word))
+ return MakeError(SecOffset, ", nbucket = " + Twine(H->nbucket) +
+ ", nchain = " + Twine(H->nchain));
+ return Error::success();
+}
+
+template <class ELFT>
+static Error checkGNUHashTable(const ELFFile<ELFT> *Obj,
+ const typename ELFT::GnuHash *GnuHashTable,
+ bool *IsHeaderValid = nullptr) {
+ const uint8_t *TableData = reinterpret_cast<const uint8_t *>(GnuHashTable);
+ assert(TableData >= Obj->base() &&
+ TableData < Obj->base() + Obj->getBufSize() &&
+ "GnuHashTable must always point to a location inside the file");
+
+ uint64_t TableOffset = TableData - Obj->base();
+ if (IsHeaderValid)
+ *IsHeaderValid = TableOffset + /*Header size:*/ 16 < Obj->getBufSize();
+ if (TableOffset + 16 + (uint64_t)GnuHashTable->nbuckets * 4 +
+ (uint64_t)GnuHashTable->maskwords * sizeof(typename ELFT::Off) >=
+ Obj->getBufSize())
+ return createError("unable to dump the SHT_GNU_HASH "
+ "section at 0x" +
+ Twine::utohexstr(TableOffset) +
+ ": it goes past the end of the file");
+ return Error::success();
+}
+
template <typename ELFT> void ELFDumper<ELFT>::printHashTable() {
DictScope D(W, "HashTable");
if (!HashTable)
return;
- W.printNumber("Num Buckets", HashTable->nbucket);
- W.printNumber("Num Chains", HashTable->nchain);
+
+ bool IsHeaderValid;
+ Error Err = checkHashTable(ObjF->getELFFile(), HashTable, &IsHeaderValid);
+ if (IsHeaderValid) {
+ W.printNumber("Num Buckets", HashTable->nbucket);
+ W.printNumber("Num Chains", HashTable->nchain);
+ }
+
+ if (Err) {
+ reportUniqueWarning(std::move(Err));
+ return;
+ }
+
W.printList("Buckets", HashTable->buckets());
W.printList("Chains", HashTable->chains());
}
-template <typename ELFT> void ELFDumper<ELFT>::printGnuHashTable() {
+template <class ELFT>
+static Expected<ArrayRef<typename ELFT::Word>>
+getGnuHashTableChains(Optional<DynRegionInfo> DynSymRegion,
+ const typename ELFT::GnuHash *GnuHashTable) {
+ if (!DynSymRegion)
+ return createError("no dynamic symbol table found");
+
+ ArrayRef<typename ELFT::Sym> DynSymTable =
+ DynSymRegion->getAsArrayRef<typename ELFT::Sym>();
+ size_t NumSyms = DynSymTable.size();
+ if (!NumSyms)
+ return createError("the dynamic symbol table is empty");
+
+ if (GnuHashTable->symndx < NumSyms)
+ return GnuHashTable->values(NumSyms);
+
+ // A normal empty GNU hash table section produced by linker might have
+ // symndx set to the number of dynamic symbols + 1 (for the zero symbol)
+ // and have dummy null values in the Bloom filter and in the buckets
+ // vector (or no values at all). It happens because the value of symndx is not
+ // important for dynamic loaders when the GNU hash table is empty. They just
+ // skip the whole object during symbol lookup. In such cases, the symndx value
+ // is irrelevant and we should not report a warning.
+ ArrayRef<typename ELFT::Word> Buckets = GnuHashTable->buckets();
+ if (!llvm::all_of(Buckets, [](typename ELFT::Word V) { return V == 0; }))
+ return createError("the first hashed symbol index (" +
+ Twine(GnuHashTable->symndx) +
+ ") is larger than the number of dynamic symbols (" +
+ Twine(NumSyms) + ")");
+ // There is no way to represent an array of (dynamic symbols count - symndx)
+ // length.
+ return ArrayRef<typename ELFT::Word>();
+}
+
+template <typename ELFT>
+void ELFDumper<ELFT>::printGnuHashTable(const object::ObjectFile *Obj) {
DictScope D(W, "GnuHashTable");
if (!GnuHashTable)
return;
- W.printNumber("Num Buckets", GnuHashTable->nbuckets);
- W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx);
- W.printNumber("Num Mask Words", GnuHashTable->maskwords);
- W.printNumber("Shift Count", GnuHashTable->shift2);
- W.printHexList("Bloom Filter", GnuHashTable->filter());
- W.printList("Buckets", GnuHashTable->buckets());
- Elf_Sym_Range Syms = dynamic_symbols();
- unsigned NumSyms = std::distance(Syms.begin(), Syms.end());
- if (!NumSyms)
- reportError(createError("No dynamic symbol section"), ObjF->getFileName());
- W.printHexList("Values", GnuHashTable->values(NumSyms));
+
+ bool IsHeaderValid;
+ Error Err =
+ checkGNUHashTable<ELFT>(ObjF->getELFFile(), GnuHashTable, &IsHeaderValid);
+ if (IsHeaderValid) {
+ W.printNumber("Num Buckets", GnuHashTable->nbuckets);
+ W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx);
+ W.printNumber("Num Mask Words", GnuHashTable->maskwords);
+ W.printNumber("Shift Count", GnuHashTable->shift2);
+ }
+
+ if (Err) {
+ reportUniqueWarning(std::move(Err));
+ return;
+ }
+
+ ArrayRef<typename ELFT::Off> BloomFilter = GnuHashTable->filter();
+ W.printHexList("Bloom Filter", BloomFilter);
+
+ ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets();
+ W.printList("Buckets", Buckets);
+
+ Expected<ArrayRef<Elf_Word>> Chains =
+ getGnuHashTableChains<ELFT>(DynSymRegion, GnuHashTable);
+ if (!Chains) {
+ reportUniqueWarning(
+ createError("unable to dump 'Values' for the SHT_GNU_HASH "
+ "section: " +
+ toString(Chains.takeError())));
+ return;
+ }
+
+ W.printHexList("Values", *Chains);
}
template <typename ELFT> void ELFDumper<ELFT>::printLoadName() {
@@ -2512,6 +2862,7 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
switch (Obj->getHeader()->e_machine) {
case EM_ARM:
+ case EM_RISCV:
printAttributes();
break;
case EM_MIPS: {
@@ -2521,9 +2872,14 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
MipsGOTParser<ELFT> Parser(Obj, ObjF->getFileName(), dynamic_table(),
dynamic_symbols());
- if (Parser.hasGot())
+ if (Error E = Parser.findGOT(dynamic_table(), dynamic_symbols()))
+ reportError(std::move(E), ObjF->getFileName());
+ else if (!Parser.isGotEmpty())
ELFDumperStyle->printMipsGOT(Parser);
- if (Parser.hasPlt())
+
+ if (Error E = Parser.findPLT(dynamic_table()))
+ reportError(std::move(E), ObjF->getFileName());
+ else if (!Parser.isPltEmpty())
ELFDumperStyle->printMipsPLT(Parser);
break;
}
@@ -2532,38 +2888,45 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() {
}
}
-template <class ELFT> void ELFDumper<ELFT>::printAttributes() {
- W.startLine() << "Attributes not implemented.\n";
-}
-
namespace {
-template <> void ELFDumper<ELF32LE>::printAttributes() {
- const ELFFile<ELF32LE> *Obj = ObjF->getELFFile();
- if (Obj->getHeader()->e_machine != EM_ARM) {
+template <class ELFT> void ELFDumper<ELFT>::printAttributes() {
+ const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+ if (!Obj->isLE()) {
W.startLine() << "Attributes not implemented.\n";
return;
}
+ const unsigned Machine = Obj->getHeader()->e_machine;
+ assert((Machine == EM_ARM || Machine == EM_RISCV) &&
+ "Attributes not implemented.");
+
DictScope BA(W, "BuildAttributes");
- for (const ELFO::Elf_Shdr &Sec :
- unwrapOrError(ObjF->getFileName(), Obj->sections())) {
- if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES)
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
+ if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES &&
+ Sec.sh_type != ELF::SHT_RISCV_ATTRIBUTES)
continue;
ArrayRef<uint8_t> Contents =
unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec));
- if (Contents[0] != ARMBuildAttrs::Format_Version) {
- errs() << "unrecognised FormatVersion: 0x"
- << Twine::utohexstr(Contents[0]) << '\n';
+ if (Contents[0] != ELFAttrs::Format_Version) {
+ reportWarning(createError(Twine("unrecognised FormatVersion: 0x") +
+ Twine::utohexstr(Contents[0])),
+ ObjF->getFileName());
continue;
}
-
W.printHex("FormatVersion", Contents[0]);
if (Contents.size() == 1)
continue;
- ARMAttributeParser(&W).Parse(Contents, true);
+ // TODO: Delete the redundant FormatVersion check above.
+ if (Machine == EM_ARM) {
+ if (Error E = ARMAttributeParser(&W).parse(Contents, support::little))
+ reportWarning(std::move(E), ObjF->getFileName());
+ } else if (Machine == EM_RISCV) {
+ if (Error E = RISCVAttributeParser(&W).parse(Contents, support::little))
+ reportWarning(std::move(E), ObjF->getFileName());
+ }
}
}
@@ -2578,9 +2941,11 @@ public:
MipsGOTParser(const ELFO *Obj, StringRef FileName, Elf_Dyn_Range DynTable,
Elf_Sym_Range DynSyms);
+ Error findGOT(Elf_Dyn_Range DynTable, Elf_Sym_Range DynSyms);
+ Error findPLT(Elf_Dyn_Range DynTable);
- bool hasGot() const { return !GotEntries.empty(); }
- bool hasPlt() const { return !PltEntries.empty(); }
+ bool isGotEmpty() const { return GotEntries.empty(); }
+ bool isPltEmpty() const { return PltEntries.empty(); }
uint64_t getGp() const;
@@ -2628,7 +2993,11 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName,
Elf_Sym_Range DynSyms)
: IsStatic(DynTable.empty()), Obj(Obj), GotSec(nullptr), LocalNum(0),
GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr),
- FileName(FileName) {
+ FileName(FileName) {}
+
+template <class ELFT>
+Error MipsGOTParser<ELFT>::findGOT(Elf_Dyn_Range DynTable,
+ Elf_Sym_Range DynSyms) {
// 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
@@ -2637,22 +3006,20 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName,
if (IsStatic) {
GotSec = findSectionByName(*Obj, FileName, ".got");
if (!GotSec)
- return;
+ return Error::success();
ArrayRef<uint8_t> Content =
unwrapOrError(FileName, Obj->getSectionContents(GotSec));
GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),
Content.size() / sizeof(Entry));
LocalNum = GotEntries.size();
- return;
+ return Error::success();
}
- // Lookup dynamic table tags which define GOT/PLT layouts.
+ // Lookup dynamic table tags which define the GOT layout.
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:
@@ -2664,6 +3031,49 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName,
case ELF::DT_MIPS_GOTSYM:
DtGotSym = Entry.getVal();
break;
+ }
+ }
+
+ if (!DtPltGot && !DtLocalGotNum && !DtGotSym)
+ return Error::success();
+
+ if (!DtPltGot)
+ return createError("cannot find PLTGOT dynamic tag");
+ if (!DtLocalGotNum)
+ return createError("cannot find MIPS_LOCAL_GOTNO dynamic tag");
+ if (!DtGotSym)
+ return createError("cannot find MIPS_GOTSYM dynamic tag");
+
+ size_t DynSymTotal = DynSyms.size();
+ if (*DtGotSym > DynSymTotal)
+ return createError("DT_MIPS_GOTSYM value (" + Twine(*DtGotSym) +
+ ") exceeds the number of dynamic symbols (" +
+ Twine(DynSymTotal) + ")");
+
+ GotSec = findNotEmptySectionByAddress(Obj, FileName, *DtPltGot);
+ if (!GotSec)
+ return createError("there is no non-empty GOT section at 0x" +
+ Twine::utohexstr(*DtPltGot));
+
+ LocalNum = *DtLocalGotNum;
+ GlobalNum = DynSymTotal - *DtGotSym;
+
+ ArrayRef<uint8_t> Content =
+ unwrapOrError(FileName, Obj->getSectionContents(GotSec));
+ GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),
+ Content.size() / sizeof(Entry));
+ GotDynSyms = DynSyms.drop_front(*DtGotSym);
+
+ return Error::success();
+}
+
+template <class ELFT>
+Error MipsGOTParser<ELFT>::findPLT(Elf_Dyn_Range DynTable) {
+ // Lookup dynamic table tags which define the PLT layout.
+ Optional<uint64_t> DtMipsPltGot;
+ Optional<uint64_t> DtJmpRel;
+ for (const auto &Entry : DynTable) {
+ switch (Entry.getTag()) {
case ELF::DT_MIPS_PLTGOT:
DtMipsPltGot = Entry.getVal();
break;
@@ -2673,63 +3083,56 @@ MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName,
}
}
- // 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(
- createError("MIPS_GOTSYM exceeds a number of dynamic symbols"),
- FileName);
-
- GotSec = findNotEmptySectionByAddress(Obj, FileName, *DtPltGot);
- if (!GotSec)
- reportError(createError("There is no not empty GOT section at 0x" +
- Twine::utohexstr(*DtPltGot)),
- FileName);
-
- LocalNum = *DtLocalGotNum;
- GlobalNum = DynSymTotal - *DtGotSym;
-
- ArrayRef<uint8_t> Content =
- unwrapOrError(FileName, Obj->getSectionContents(GotSec));
- GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()),
- Content.size() / sizeof(Entry));
- GotDynSyms = DynSyms.drop_front(*DtGotSym);
- }
+ if (!DtMipsPltGot && !DtJmpRel)
+ return Error::success();
// 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, FileName, * DtMipsPltGot);
- if (!PltSec)
- report_fatal_error("There is no not empty PLTGOT section at 0x " +
- Twine::utohexstr(*DtMipsPltGot));
-
- PltRelSec = findNotEmptySectionByAddress(Obj, FileName, * DtJmpRel);
- if (!PltRelSec)
- report_fatal_error("There is no not empty RELPLT section at 0x" +
- Twine::utohexstr(*DtJmpRel));
+ if (!DtMipsPltGot)
+ return createError("cannot find MIPS_PLTGOT dynamic tag");
+ if (!DtJmpRel)
+ return createError("cannot find JMPREL dynamic tag");
+
+ PltSec = findNotEmptySectionByAddress(Obj, FileName, *DtMipsPltGot);
+ if (!PltSec)
+ return createError("there is no non-empty PLTGOT section at 0x" +
+ Twine::utohexstr(*DtMipsPltGot));
+
+ PltRelSec = findNotEmptySectionByAddress(Obj, FileName, *DtJmpRel);
+ if (!PltRelSec)
+ return createError("there is no non-empty RELPLT section at 0x" +
+ Twine::utohexstr(*DtJmpRel));
+
+ if (Expected<ArrayRef<uint8_t>> PltContentOrErr =
+ Obj->getSectionContents(PltSec))
+ PltEntries =
+ Entries(reinterpret_cast<const Entry *>(PltContentOrErr->data()),
+ PltContentOrErr->size() / sizeof(Entry));
+ else
+ return createError("unable to read PLTGOT section content: " +
+ toString(PltContentOrErr.takeError()));
- ArrayRef<uint8_t> PltContent =
- unwrapOrError(FileName, Obj->getSectionContents(PltSec));
- PltEntries = Entries(reinterpret_cast<const Entry *>(PltContent.data()),
- PltContent.size() / sizeof(Entry));
+ if (Expected<const Elf_Shdr *> PltSymTableOrErr =
+ Obj->getSection(PltRelSec->sh_link)) {
+ PltSymTable = *PltSymTableOrErr;
+ } else {
+ unsigned SecNdx = PltRelSec - &cantFail(Obj->sections()).front();
+ return createError("unable to get a symbol table linked to the RELPLT "
+ "section with index " +
+ Twine(SecNdx) + ": " +
+ toString(PltSymTableOrErr.takeError()));
+ }
- PltSymTable = unwrapOrError(FileName, Obj->getSection(PltRelSec->sh_link));
- PltStrTable =
- unwrapOrError(FileName, Obj->getStringTableForSymtab(*PltSymTable));
+ if (Expected<StringRef> StrTabOrErr =
+ Obj->getStringTableForSymtab(*PltSymTable)) {
+ PltStrTable = *StrTabOrErr;
+ } else {
+ unsigned SecNdx = PltSymTable - &cantFail(Obj->sections()).front();
+ return createError(
+ "unable to get a string table for the symbol table with index " +
+ Twine(SecNdx) + ": " + toString(StrTabOrErr.takeError()));
}
+
+ return Error::success();
}
template <class ELFT> uint64_t MipsGOTParser<ELFT>::getGp() const {
@@ -2977,7 +3380,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() {
template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
const Elf_Shdr *StackMapSection = nullptr;
- for (const auto &Sec : unwrapOrError(ObjF->getFileName(), Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
StringRef Name =
unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec));
if (Name == ".llvm_stackmaps") {
@@ -3020,7 +3423,7 @@ static std::string getSectionHeadersNumString(const ELFFile<ELFT> *Obj,
if (ElfHeader->e_shnum != 0)
return to_string(ElfHeader->e_shnum);
- ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(FileName, Obj->sections());
+ ArrayRef<typename ELFT::Shdr> Arr = cantFail(Obj->sections());
if (Arr.empty())
return "0";
return "0 (" + to_string(Arr[0].sh_size) + ")";
@@ -3033,7 +3436,7 @@ static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj,
if (ElfHeader->e_shstrndx != SHN_XINDEX)
return to_string(ElfHeader->e_shstrndx);
- ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(FileName, Obj->sections());
+ ArrayRef<typename ELFT::Shdr> Arr = cantFail(Obj->sections());
if (Arr.empty())
return "65535 (corrupt: out of range)";
return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) +
@@ -3127,7 +3530,7 @@ std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj,
std::vector<GroupSection> Ret;
uint64_t I = 0;
- for (const Elf_Shdr &Sec : unwrapOrError(FileName, Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
++I;
if (Sec.sh_type != ELF::SHT_GROUP)
continue;
@@ -3202,23 +3605,18 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) {
}
template <class ELFT>
-void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
- const Elf_Rela &R, bool IsRela) {
- const Elf_Sym *Sym =
- unwrapOrError(this->FileName, Obj->getRelocationSymbol(&R, SymTab));
- std::string TargetName;
- if (Sym && Sym->getType() == ELF::STT_SECTION) {
- const Elf_Shdr *Sec = unwrapOrError(
- this->FileName,
- Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable()));
- TargetName = unwrapOrError(this->FileName, Obj->getSectionName(Sec));
- } else if (Sym) {
- StringRef StrTable =
- unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*SymTab));
- TargetName = this->dumper()->getFullSymbolName(
- Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);
- }
- printRelocation(Obj, Sym, TargetName, R, IsRela);
+void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, unsigned SecIndex,
+ const Elf_Shdr *SymTab, const Elf_Rela &R,
+ unsigned RelIndex, bool IsRela) {
+ Expected<std::pair<const typename ELFT::Sym *, std::string>> Target =
+ this->dumper()->getRelocationTarget(SymTab, R);
+ if (!Target)
+ this->reportUniqueWarning(createError(
+ "unable to print relocation " + Twine(RelIndex) + " in section " +
+ Twine(SecIndex) + ": " + toString(Target.takeError())));
+ else
+ printRelocation(Obj, /*Sym=*/Target->first, /*Name=*/Target->second, R,
+ IsRela);
}
template <class ELFT>
@@ -3237,10 +3635,10 @@ void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Sym *Sym,
Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
Fields[2].Str = RelocName.c_str();
- if (Sym && (!SymbolName.empty() || Sym->getValue() != 0))
+ if (Sym)
Fields[3].Str = to_string(format_hex_no_prefix(Sym->getValue(), Width));
- Fields[4].Str = SymbolName;
+ Fields[4].Str = std::string(SymbolName);
for (const Field &F : Fields)
printField(F);
@@ -3283,7 +3681,7 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) {
template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
bool HasRelocSections = false;
- for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&
Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL &&
Sec.sh_type != ELF::SHT_ANDROID_RELA &&
@@ -3316,6 +3714,9 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
printRelocHeader(Sec.sh_type);
const Elf_Shdr *SymTab =
unwrapOrError(this->FileName, Obj->getSection(Sec.sh_link));
+ unsigned SecNdx = &Sec - &cantFail(Obj->sections()).front();
+ unsigned RelNdx = 0;
+
switch (Sec.sh_type) {
case ELF::SHT_REL:
for (const auto &R : unwrapOrError(this->FileName, Obj->rels(&Sec))) {
@@ -3323,12 +3724,12 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
Rela.r_offset = R.r_offset;
Rela.r_info = R.r_info;
Rela.r_addend = 0;
- printRelocation(Obj, SymTab, Rela, false);
+ printRelocation(Obj, SecNdx, SymTab, Rela, ++RelNdx, false);
}
break;
case ELF::SHT_RELA:
for (const auto &R : unwrapOrError(this->FileName, Obj->relas(&Sec)))
- printRelocation(Obj, SymTab, R, true);
+ printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx, true);
break;
case ELF::SHT_RELR:
case ELF::SHT_ANDROID_RELR:
@@ -3338,12 +3739,13 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
<< "\n";
else
for (const auto &R : RelrRelas)
- printRelocation(Obj, SymTab, R, false);
+ printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx, false);
break;
case ELF::SHT_ANDROID_REL:
case ELF::SHT_ANDROID_RELA:
for (const auto &R : AndroidRelas)
- printRelocation(Obj, SymTab, R, Sec.sh_type == ELF::SHT_ANDROID_RELA);
+ printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx,
+ Sec.sh_type == ELF::SHT_ANDROID_RELA);
break;
}
}
@@ -3402,6 +3804,11 @@ static std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "MIPS_ABIFLAGS";
}
break;
+ case EM_RISCV:
+ switch (Type) {
+ case SHT_RISCV_ATTRIBUTES:
+ return "RISCV_ATTRIBUTES";
+ }
}
switch (Type) {
case SHT_NULL:
@@ -3500,7 +3907,7 @@ static void printSectionDescription(formatted_raw_ostream &OS,
template <class ELFT>
void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
unsigned Bias = ELFT::Is64Bits ? 0 : 8;
- ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());
+ ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections());
OS << "There are " << to_string(Sections.size())
<< " section headers, starting at offset "
<< "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n";
@@ -3514,12 +3921,21 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
printField(F);
OS << "\n";
- const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
+ StringRef SecStrTable;
+ if (Expected<StringRef> SecStrTableOrErr =
+ Obj->getSectionStringTable(Sections, this->dumper()->WarningHandler))
+ SecStrTable = *SecStrTableOrErr;
+ else
+ this->reportUniqueWarning(SecStrTableOrErr.takeError());
+
size_t SectionIndex = 0;
for (const Elf_Shdr &Sec : Sections) {
Fields[0].Str = to_string(SectionIndex);
- Fields[1].Str = unwrapOrError<StringRef>(
- ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler));
+ if (SecStrTable.empty())
+ Fields[1].Str = "<no-strings>";
+ else
+ Fields[1].Str = std::string(unwrapOrError<StringRef>(
+ this->FileName, Obj->getSectionName(&Sec, SecStrTable)));
Fields[2].Str =
getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type);
Fields[3].Str =
@@ -3555,10 +3971,10 @@ void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Entries,
bool NonVisibilityBitsUsed) {
if (!Name.empty())
- OS << "\nSymbol table '" << Name << "' contains " << Entries
- << " entries:\n";
+ OS << "\nSymbol table '" << Name << "'";
else
- OS << "\n Symbol table for image:\n";
+ OS << "\nSymbol table for image";
+ OS << " contains " << Entries << " entries:\n";
if (ELFT::Is64Bits)
OS << " Num: Value Size Type Bind Vis";
@@ -3616,8 +4032,9 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,
template <class ELFT>
void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
- const Elf_Sym *FirstSym, StringRef StrTable,
- bool IsDynamic, bool NonVisibilityBitsUsed) {
+ const Elf_Sym *FirstSym,
+ Optional<StringRef> StrTable, bool IsDynamic,
+ bool NonVisibilityBitsUsed) {
static int Idx = 0;
static bool Dynamic = true;
@@ -3707,67 +4124,110 @@ void GNUStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols,
this->dumper()->printSymbolsHelper(false);
}
-template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
- if (this->dumper()->getDynamicStringTable().empty())
+template <class ELFT>
+void GNUStyle<ELFT>::printHashTableSymbols(const ELFO *Obj,
+ const Elf_Hash &SysVHash) {
+ StringRef StringTable = this->dumper()->getDynamicStringTable();
+ if (StringTable.empty())
return;
- auto StringTable = this->dumper()->getDynamicStringTable();
- auto DynSyms = this->dumper()->dynamic_symbols();
- // Try printing .hash
- if (auto SysVHash = this->dumper()->getHashTable()) {
- OS << "\n Symbol table of .hash for image:\n";
- if (ELFT::Is64Bits)
- OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
- else
- OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
- OS << "\n";
+ if (ELFT::Is64Bits)
+ OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
+ else
+ OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
+ OS << "\n";
- auto Buckets = SysVHash->buckets();
- auto Chains = SysVHash->chains();
- for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) {
- if (Buckets[Buc] == ELF::STN_UNDEF)
- continue;
- std::vector<bool> Visited(SysVHash->nchain);
- for (uint32_t Ch = Buckets[Buc]; Ch < SysVHash->nchain; Ch = Chains[Ch]) {
- if (Ch == ELF::STN_UNDEF)
- break;
+ Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols();
+ const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0];
+ if (!FirstSym) {
+ Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion();
+ this->reportUniqueWarning(
+ createError(Twine("unable to print symbols for the .hash table: the "
+ "dynamic symbol table ") +
+ (DynSymRegion ? "is empty" : "was not found")));
+ return;
+ }
- if (Visited[Ch]) {
- reportWarning(
- createError(".hash section is invalid: bucket " + Twine(Ch) +
- ": a cycle was detected in the linked chain"),
- this->FileName);
- break;
- }
+ auto Buckets = SysVHash.buckets();
+ auto Chains = SysVHash.chains();
+ for (uint32_t Buc = 0; Buc < SysVHash.nbucket; Buc++) {
+ if (Buckets[Buc] == ELF::STN_UNDEF)
+ continue;
+ std::vector<bool> Visited(SysVHash.nchain);
+ for (uint32_t Ch = Buckets[Buc]; Ch < SysVHash.nchain; Ch = Chains[Ch]) {
+ if (Ch == ELF::STN_UNDEF)
+ break;
- printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc);
- Visited[Ch] = true;
+ if (Visited[Ch]) {
+ reportWarning(createError(".hash section is invalid: bucket " +
+ Twine(Ch) +
+ ": a cycle was detected in the linked chain"),
+ this->FileName);
+ break;
}
+
+ printHashedSymbol(Obj, FirstSym, Ch, StringTable, Buc);
+ Visited[Ch] = true;
+ }
+ }
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printGnuHashTableSymbols(const ELFO *Obj,
+ const Elf_GnuHash &GnuHash) {
+ StringRef StringTable = this->dumper()->getDynamicStringTable();
+ if (StringTable.empty())
+ return;
+
+ Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols();
+ const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0];
+ if (!FirstSym) {
+ Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion();
+ this->reportUniqueWarning(createError(
+ Twine("unable to print symbols for the .gnu.hash table: the "
+ "dynamic symbol table ") +
+ (DynSymRegion ? "is empty" : "was not found")));
+ return;
+ }
+
+ ArrayRef<Elf_Word> Buckets = GnuHash.buckets();
+ for (uint32_t Buc = 0; Buc < GnuHash.nbuckets; Buc++) {
+ if (Buckets[Buc] == ELF::STN_UNDEF)
+ continue;
+ uint32_t Index = Buckets[Buc];
+ uint32_t GnuHashable = Index - GnuHash.symndx;
+ // Print whole chain
+ while (true) {
+ printHashedSymbol(Obj, FirstSym, Index++, StringTable, Buc);
+ // Chain ends at symbol with stopper bit
+ if ((GnuHash.values(DynSyms.size())[GnuHashable++] & 1) == 1)
+ break;
}
}
+}
+
+template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
+ if (const Elf_Hash *SysVHash = this->dumper()->getHashTable()) {
+ OS << "\n Symbol table of .hash for image:\n";
+ if (Error E = checkHashTable<ELFT>(Obj, SysVHash))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printHashTableSymbols(Obj, *SysVHash);
+ }
- // Try printing .gnu.hash
- if (auto GnuHash = this->dumper()->getGnuHashTable()) {
+ // Try printing the .gnu.hash table.
+ if (const Elf_GnuHash *GnuHash = this->dumper()->getGnuHashTable()) {
OS << "\n Symbol table of .gnu.hash for image:\n";
if (ELFT::Is64Bits)
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
else
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
OS << "\n";
- auto Buckets = GnuHash->buckets();
- for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) {
- if (Buckets[Buc] == ELF::STN_UNDEF)
- continue;
- uint32_t Index = Buckets[Buc];
- uint32_t GnuHashable = Index - GnuHash->symndx;
- // Print whole chain
- while (true) {
- printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc);
- // Chain ends at symbol with stopper bit
- if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1)
- break;
- }
- }
+
+ if (Error E = checkGNUHashTable<ELFT>(Obj, GnuHash))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printGnuHashTableSymbols(Obj, *GnuHash);
}
}
@@ -3779,63 +4239,76 @@ static inline std::string printPhdrFlags(unsigned Flag) {
return Str;
}
-// SHF_TLS sections are only in PT_TLS, PT_LOAD or PT_GNU_RELRO
-// PT_TLS must only have SHF_TLS sections
template <class ELFT>
-bool GNUStyle<ELFT>::checkTLSSections(const Elf_Phdr &Phdr,
- const Elf_Shdr &Sec) {
- return (((Sec.sh_flags & ELF::SHF_TLS) &&
- ((Phdr.p_type == ELF::PT_TLS) || (Phdr.p_type == ELF::PT_LOAD) ||
- (Phdr.p_type == ELF::PT_GNU_RELRO))) ||
- (!(Sec.sh_flags & ELF::SHF_TLS) && Phdr.p_type != ELF::PT_TLS));
+static bool checkTLSSections(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
+ if (Sec.sh_flags & ELF::SHF_TLS) {
+ // .tbss must only be shown in the PT_TLS segment.
+ if (Sec.sh_type == ELF::SHT_NOBITS)
+ return Phdr.p_type == ELF::PT_TLS;
+
+ // SHF_TLS sections are only shown in PT_TLS, PT_LOAD or PT_GNU_RELRO
+ // segments.
+ return (Phdr.p_type == ELF::PT_TLS) || (Phdr.p_type == ELF::PT_LOAD) ||
+ (Phdr.p_type == ELF::PT_GNU_RELRO);
+ }
+
+ // PT_TLS must only have SHF_TLS sections.
+ return Phdr.p_type != ELF::PT_TLS;
}
-// Non-SHT_NOBITS must have its offset inside the segment
-// Only non-zero section can be at end of segment
template <class ELFT>
-bool GNUStyle<ELFT>::checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
+static bool checkOffsets(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
+ // SHT_NOBITS sections don't need to have an offset inside the segment.
if (Sec.sh_type == ELF::SHT_NOBITS)
return true;
- bool IsSpecial =
- (Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
- // .tbss is special, it only has memory in PT_TLS and has NOBITS properties
- auto SectionSize =
- (IsSpecial && Phdr.p_type != ELF::PT_TLS) ? 0 : Sec.sh_size;
- if (Sec.sh_offset >= Phdr.p_offset)
- return ((Sec.sh_offset + SectionSize <= Phdr.p_filesz + Phdr.p_offset)
- /*only non-zero sized sections at end*/
- && (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz));
- return false;
-}
-
-// SHF_ALLOC must have VMA inside segment
-// Only non-zero section can be at end of segment
+
+ if (Sec.sh_offset < Phdr.p_offset)
+ return false;
+
+ // Only non-empty sections can be at the end of a segment.
+ if (Sec.sh_size == 0)
+ return (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz);
+ return Sec.sh_offset + Sec.sh_size <= Phdr.p_offset + Phdr.p_filesz;
+}
+
+// Check that an allocatable section belongs to a virtual address
+// space of a segment.
template <class ELFT>
-bool GNUStyle<ELFT>::checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
+static bool checkVMA(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
if (!(Sec.sh_flags & ELF::SHF_ALLOC))
return true;
- bool IsSpecial =
+
+ if (Sec.sh_addr < Phdr.p_vaddr)
+ return false;
+
+ bool IsTbss =
(Sec.sh_type == ELF::SHT_NOBITS) && ((Sec.sh_flags & ELF::SHF_TLS) != 0);
- // .tbss is special, it only has memory in PT_TLS and has NOBITS properties
- auto SectionSize =
- (IsSpecial && Phdr.p_type != ELF::PT_TLS) ? 0 : Sec.sh_size;
- if (Sec.sh_addr >= Phdr.p_vaddr)
- return ((Sec.sh_addr + SectionSize <= Phdr.p_vaddr + Phdr.p_memsz) &&
- (Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz));
- return false;
+ // .tbss is special, it only has memory in PT_TLS and has NOBITS properties.
+ bool IsTbssInNonTLS = IsTbss && Phdr.p_type != ELF::PT_TLS;
+ // Only non-empty sections can be at the end of a segment.
+ if (Sec.sh_size == 0 || IsTbssInNonTLS)
+ return Sec.sh_addr + 1 <= Phdr.p_vaddr + Phdr.p_memsz;
+ return Sec.sh_addr + Sec.sh_size <= Phdr.p_vaddr + Phdr.p_memsz;
}
-// No section with zero size must be at start or end of PT_DYNAMIC
template <class ELFT>
-bool GNUStyle<ELFT>::checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
- if (Phdr.p_type != ELF::PT_DYNAMIC || Sec.sh_size != 0 || Phdr.p_memsz == 0)
+static bool checkPTDynamic(const typename ELFT::Phdr &Phdr,
+ const typename ELFT::Shdr &Sec) {
+ if (Phdr.p_type != ELF::PT_DYNAMIC || Phdr.p_memsz == 0 || Sec.sh_size != 0)
return true;
- // Is section within the phdr both based on offset and VMA ?
- return ((Sec.sh_type == ELF::SHT_NOBITS) ||
- (Sec.sh_offset > Phdr.p_offset &&
- Sec.sh_offset < Phdr.p_offset + Phdr.p_filesz)) &&
- (!(Sec.sh_flags & ELF::SHF_ALLOC) ||
- (Sec.sh_addr > Phdr.p_vaddr && Sec.sh_addr < Phdr.p_memsz));
+
+ // We get here when we have an empty section. Only non-empty sections can be
+ // at the start or at the end of PT_DYNAMIC.
+ // Is section within the phdr both based on offset and VMA?
+ bool CheckOffset = (Sec.sh_type == ELF::SHT_NOBITS) ||
+ (Sec.sh_offset > Phdr.p_offset &&
+ Sec.sh_offset < Phdr.p_offset + Phdr.p_filesz);
+ bool CheckVA = !(Sec.sh_flags & ELF::SHF_ALLOC) ||
+ (Sec.sh_addr > Phdr.p_vaddr && Sec.sh_addr < Phdr.p_memsz);
+ return CheckOffset && CheckVA;
}
template <class ELFT>
@@ -3872,8 +4345,15 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
unsigned Width = ELFT::Is64Bits ? 18 : 10;
unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7;
- for (const auto &Phdr :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError("unable to dump program headers: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
Fields[0].Str = getElfPtType(Header->e_machine, Phdr.p_type);
Fields[1].Str = to_string(format_hex(Phdr.p_offset, 8));
Fields[2].Str = to_string(format_hex(Phdr.p_vaddr, Width));
@@ -3885,8 +4365,31 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
for (auto Field : Fields)
printField(Field);
if (Phdr.p_type == ELF::PT_INTERP) {
- OS << "\n [Requesting program interpreter: ";
- OS << reinterpret_cast<const char *>(Obj->base()) + Phdr.p_offset << "]";
+ OS << "\n";
+ auto ReportBadInterp = [&](const Twine &Msg) {
+ reportWarning(
+ createError("unable to read program interpreter name at offset 0x" +
+ Twine::utohexstr(Phdr.p_offset) + ": " + Msg),
+ this->FileName);
+ };
+
+ if (Phdr.p_offset >= Obj->getBufSize()) {
+ ReportBadInterp("it goes past the end of the file (0x" +
+ Twine::utohexstr(Obj->getBufSize()) + ")");
+ continue;
+ }
+
+ const char *Data =
+ reinterpret_cast<const char *>(Obj->base()) + Phdr.p_offset;
+ size_t MaxSize = Obj->getBufSize() - Phdr.p_offset;
+ size_t Len = strnlen(Data, MaxSize);
+ if (Len == MaxSize) {
+ ReportBadInterp("it is not null-terminated");
+ continue;
+ }
+
+ OS << " [Requesting program interpreter: ";
+ OS << StringRef(Data, Len) << "]";
}
OS << "\n";
}
@@ -3897,21 +4400,28 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {
OS << "\n Section to Segment mapping:\n Segment Sections...\n";
DenseSet<const Elf_Shdr *> BelongsToSegment;
int Phnum = 0;
- for (const Elf_Phdr &Phdr :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError(
+ "can't read program headers to build section to segment mapping: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
std::string Sections;
OS << format(" %2.2d ", Phnum++);
- for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {
- // Check if each section is in a segment and then print mapping.
+ // Check if each section is in a segment and then print mapping.
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
+ if (Sec.sh_type == ELF::SHT_NULL)
+ continue;
+
// readelf additionally makes sure it does not print zero sized sections
// at end of segments and for PT_DYNAMIC both start and end of section
// .tbss must only be shown in PT_TLS section.
- bool TbssInNonTLS = (Sec.sh_type == ELF::SHT_NOBITS) &&
- ((Sec.sh_flags & ELF::SHF_TLS) != 0) &&
- Phdr.p_type != ELF::PT_TLS;
- if (!TbssInNonTLS && checkTLSSections(Phdr, Sec) &&
- checkoffsets(Phdr, Sec) && checkVMA(Phdr, Sec) &&
- checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL)) {
+ if (checkTLSSections<ELFT>(Phdr, Sec) && checkOffsets<ELFT>(Phdr, Sec) &&
+ checkVMA<ELFT>(Phdr, Sec) && checkPTDynamic<ELFT>(Phdr, Sec)) {
Sections +=
unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() +
" ";
@@ -3924,7 +4434,7 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) {
// Display sections that do not belong to a segment.
std::string Sections;
- for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
if (BelongsToSegment.find(&Sec) == BelongsToSegment.end())
Sections +=
unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() + ' ';
@@ -3946,21 +4456,35 @@ RelSymbol<ELFT> getSymbolForReloc(const ELFFile<ELFT> *Obj, StringRef FileName,
const ELFDumper<ELFT> *Dumper,
const typename ELFT::Rela &Reloc) {
uint32_t SymIndex = Reloc.getSymbol(Obj->isMips64EL());
- const typename ELFT::Sym *Sym = Dumper->dynamic_symbols().begin() + SymIndex;
- Expected<StringRef> ErrOrName = Sym->getName(Dumper->getDynamicStringTable());
-
- std::string Name;
- if (ErrOrName) {
- Name = maybeDemangle(*ErrOrName);
- } else {
+ auto WarnAndReturn = [&](const typename ELFT::Sym *Sym,
+ const Twine &Reason) -> RelSymbol<ELFT> {
reportWarning(
createError("unable to get name of the dynamic symbol with index " +
- Twine(SymIndex) + ": " + toString(ErrOrName.takeError())),
+ Twine(SymIndex) + ": " + Reason),
FileName);
- Name = "<corrupt>";
- }
+ return {Sym, "<corrupt>"};
+ };
- return {Sym, std::move(Name)};
+ ArrayRef<typename ELFT::Sym> Symbols = Dumper->dynamic_symbols();
+ const typename ELFT::Sym *FirstSym = Symbols.begin();
+ if (!FirstSym)
+ return WarnAndReturn(nullptr, "no dynamic symbol table found");
+
+ // We might have an object without a section header. In this case the size of
+ // Symbols is zero, because there is no way to know the size of the dynamic
+ // table. We should allow this case and not print a warning.
+ if (!Symbols.empty() && SymIndex >= Symbols.size())
+ return WarnAndReturn(
+ nullptr,
+ "index is greater than or equal to the number of dynamic symbols (" +
+ Twine(Symbols.size()) + ")");
+
+ const typename ELFT::Sym *Sym = FirstSym + SymIndex;
+ Expected<StringRef> ErrOrName = Sym->getName(Dumper->getDynamicStringTable());
+ if (!ErrOrName)
+ return WarnAndReturn(Sym, toString(ErrOrName.takeError()));
+
+ return {Sym == FirstSym ? nullptr : Sym, maybeDemangle(*ErrOrName)};
}
} // namespace
@@ -3971,6 +4495,15 @@ void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R,
printRelocation(Obj, S.Sym, S.Name, R, IsRela);
}
+template <class ELFT>
+static size_t getMaxDynamicTagSize(const ELFFile<ELFT> *Obj,
+ typename ELFT::DynRange Tags) {
+ size_t Max = 0;
+ for (const typename ELFT::Dyn &Dyn : Tags)
+ Max = std::max(Max, Obj->getDynamicTagAsString(Dyn.d_tag).size());
+ return Max;
+}
+
template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) {
Elf_Dyn_Range Table = this->dumper()->dynamic_table();
if (Table.empty())
@@ -3985,19 +4518,22 @@ template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) {
1)
<< " contains " << Table.size() << " entries:\n";
- bool Is64 = ELFT::Is64Bits;
- if (Is64)
- OS << " Tag Type Name/Value\n";
- else
- OS << " Tag Type Name/Value\n";
+ // The type name is surrounded with round brackets, hence add 2.
+ size_t MaxTagSize = getMaxDynamicTagSize(Obj, Table) + 2;
+ // The "Name/Value" column should be indented from the "Type" column by N
+ // spaces, where N = MaxTagSize - length of "Type" (4) + trailing
+ // space (1) = 3.
+ OS << " Tag" + std::string(ELFT::Is64Bits ? 16 : 8, ' ') + "Type"
+ << std::string(MaxTagSize - 3, ' ') << "Name/Value\n";
+
+ std::string ValueFmt = " %-" + std::to_string(MaxTagSize) + "s ";
for (auto Entry : Table) {
uintX_t Tag = Entry.getTag();
- std::string TypeString =
+ std::string Type =
std::string("(") + Obj->getDynamicTagAsString(Tag).c_str() + ")";
- OS << " " << format_hex(Tag, Is64 ? 18 : 10)
- << format(" %-20s ", TypeString.c_str());
- this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());
- OS << "\n";
+ std::string Value = this->dumper()->getDynamicEntry(Tag, Entry.getVal());
+ OS << " " << format_hex(Tag, ELFT::Is64Bits ? 18 : 10)
+ << format(ValueFmt.c_str(), Type.c_str()) << Value << "\n";
}
}
@@ -4052,19 +4588,20 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
Obj->base(),
1)
<< " contains " << DynPLTRelRegion.Size << " bytes:\n";
- }
- if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) {
- printRelocHeader(ELF::SHT_RELA);
- for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>())
- printDynamicRelocation(Obj, Rela, true);
- } else {
- printRelocHeader(ELF::SHT_REL);
- for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef<Elf_Rel>()) {
- Elf_Rela Rela;
- Rela.r_offset = Rel.r_offset;
- Rela.r_info = Rel.r_info;
- Rela.r_addend = 0;
- printDynamicRelocation(Obj, Rela, false);
+
+ if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) {
+ printRelocHeader(ELF::SHT_RELA);
+ for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>())
+ printDynamicRelocation(Obj, Rela, true);
+ } else {
+ printRelocHeader(ELF::SHT_REL);
+ for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef<Elf_Rel>()) {
+ Elf_Rela Rela;
+ Rela.r_offset = Rel.r_offset;
+ Rela.r_info = Rel.r_info;
+ Rela.r_addend = 0;
+ printDynamicRelocation(Obj, Rela, false);
+ }
}
}
}
@@ -4231,116 +4768,137 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
OS << '\n';
}
-// Hash histogram shows statistics of how efficient the hash was for the
-// dynamic symbol table. The table shows number of hash buckets for different
-// lengths of chains as absolute number and percentage of the total buckets.
-// Additionally cumulative coverage of symbols for each set of buckets.
template <class ELFT>
-void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
- // Print histogram for .hash section
- if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) {
- size_t NBucket = HashTable->nbucket;
- size_t NChain = HashTable->nchain;
- ArrayRef<Elf_Word> Buckets = HashTable->buckets();
- ArrayRef<Elf_Word> Chains = HashTable->chains();
- size_t TotalSyms = 0;
- // If hash table is correct, we have at least chains with 0 length
- size_t MaxChain = 1;
- size_t CumulativeNonZero = 0;
-
- if (NChain == 0 || NBucket == 0)
- return;
+void GNUStyle<ELFT>::printHashHistogram(const Elf_Hash &HashTable) {
+ size_t NBucket = HashTable.nbucket;
+ size_t NChain = HashTable.nchain;
+ ArrayRef<Elf_Word> Buckets = HashTable.buckets();
+ ArrayRef<Elf_Word> Chains = HashTable.chains();
+ size_t TotalSyms = 0;
+ // If hash table is correct, we have at least chains with 0 length
+ size_t MaxChain = 1;
+ size_t CumulativeNonZero = 0;
+
+ if (NChain == 0 || NBucket == 0)
+ return;
- std::vector<size_t> ChainLen(NBucket, 0);
- // Go over all buckets and and note chain lengths of each bucket (total
- // unique chain lengths).
- for (size_t B = 0; B < NBucket; B++) {
- std::vector<bool> Visited(NChain);
- for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) {
- if (C == ELF::STN_UNDEF)
- break;
- if (Visited[C]) {
- reportWarning(
- createError(".hash section is invalid: bucket " + Twine(C) +
- ": a cycle was detected in the linked chain"),
- this->FileName);
- break;
- }
- Visited[C] = true;
- if (MaxChain <= ++ChainLen[B])
- MaxChain++;
+ std::vector<size_t> ChainLen(NBucket, 0);
+ // Go over all buckets and and note chain lengths of each bucket (total
+ // unique chain lengths).
+ for (size_t B = 0; B < NBucket; B++) {
+ std::vector<bool> Visited(NChain);
+ for (size_t C = Buckets[B]; C < NChain; C = Chains[C]) {
+ if (C == ELF::STN_UNDEF)
+ break;
+ if (Visited[C]) {
+ reportWarning(createError(".hash section is invalid: bucket " +
+ Twine(C) +
+ ": a cycle was detected in the linked chain"),
+ this->FileName);
+ break;
}
- TotalSyms += ChainLen[B];
+ Visited[C] = true;
+ if (MaxChain <= ++ChainLen[B])
+ MaxChain++;
}
+ TotalSyms += ChainLen[B];
+ }
- if (!TotalSyms)
- return;
+ if (!TotalSyms)
+ return;
- std::vector<size_t> Count(MaxChain, 0) ;
- // Count how long is the chain for each bucket
- for (size_t B = 0; B < NBucket; B++)
- ++Count[ChainLen[B]];
- // Print Number of buckets with each chain lengths and their cumulative
- // coverage of the symbols
- OS << "Histogram for bucket list length (total of " << NBucket
- << " buckets)\n"
- << " Length Number % of total Coverage\n";
- for (size_t I = 0; I < MaxChain; I++) {
- CumulativeNonZero += Count[I] * I;
- OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
- (Count[I] * 100.0) / NBucket,
- (CumulativeNonZero * 100.0) / TotalSyms);
- }
+ std::vector<size_t> Count(MaxChain, 0);
+ // Count how long is the chain for each bucket
+ for (size_t B = 0; B < NBucket; B++)
+ ++Count[ChainLen[B]];
+ // Print Number of buckets with each chain lengths and their cumulative
+ // coverage of the symbols
+ OS << "Histogram for bucket list length (total of " << NBucket
+ << " buckets)\n"
+ << " Length Number % of total Coverage\n";
+ for (size_t I = 0; I < MaxChain; I++) {
+ CumulativeNonZero += Count[I] * I;
+ OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
+ (Count[I] * 100.0) / NBucket,
+ (CumulativeNonZero * 100.0) / TotalSyms);
}
+}
- // Print histogram for .gnu.hash section
- if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) {
- size_t NBucket = GnuHashTable->nbuckets;
- ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets();
- unsigned NumSyms = this->dumper()->dynamic_symbols().size();
- if (!NumSyms)
- return;
- ArrayRef<Elf_Word> Chains = GnuHashTable->values(NumSyms);
- size_t Symndx = GnuHashTable->symndx;
- size_t TotalSyms = 0;
- size_t MaxChain = 1;
- size_t CumulativeNonZero = 0;
+template <class ELFT>
+void GNUStyle<ELFT>::printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) {
+ Expected<ArrayRef<Elf_Word>> ChainsOrErr = getGnuHashTableChains<ELFT>(
+ this->dumper()->getDynSymRegion(), &GnuHashTable);
+ if (!ChainsOrErr) {
+ this->reportUniqueWarning(
+ createError("unable to print the GNU hash table histogram: " +
+ toString(ChainsOrErr.takeError())));
+ return;
+ }
- if (Chains.empty() || NBucket == 0)
- return;
+ ArrayRef<Elf_Word> Chains = *ChainsOrErr;
+ size_t Symndx = GnuHashTable.symndx;
+ size_t TotalSyms = 0;
+ size_t MaxChain = 1;
+ size_t CumulativeNonZero = 0;
- std::vector<size_t> ChainLen(NBucket, 0);
+ size_t NBucket = GnuHashTable.nbuckets;
+ if (Chains.empty() || NBucket == 0)
+ return;
- for (size_t B = 0; B < NBucket; B++) {
- if (!Buckets[B])
- continue;
- size_t Len = 1;
- for (size_t C = Buckets[B] - Symndx;
- C < Chains.size() && (Chains[C] & 1) == 0; C++)
- if (MaxChain < ++Len)
- MaxChain++;
- ChainLen[B] = Len;
- TotalSyms += Len;
- }
- MaxChain++;
+ ArrayRef<Elf_Word> Buckets = GnuHashTable.buckets();
+ std::vector<size_t> ChainLen(NBucket, 0);
+ for (size_t B = 0; B < NBucket; B++) {
+ if (!Buckets[B])
+ continue;
+ size_t Len = 1;
+ for (size_t C = Buckets[B] - Symndx;
+ C < Chains.size() && (Chains[C] & 1) == 0; C++)
+ if (MaxChain < ++Len)
+ MaxChain++;
+ ChainLen[B] = Len;
+ TotalSyms += Len;
+ }
+ MaxChain++;
- if (!TotalSyms)
- return;
+ if (!TotalSyms)
+ return;
- std::vector<size_t> Count(MaxChain, 0) ;
- for (size_t B = 0; B < NBucket; B++)
- ++Count[ChainLen[B]];
- // Print Number of buckets with each chain lengths and their cumulative
- // coverage of the symbols
- OS << "Histogram for `.gnu.hash' bucket list length (total of " << NBucket
- << " buckets)\n"
- << " Length Number % of total Coverage\n";
- for (size_t I = 0; I <MaxChain; I++) {
- CumulativeNonZero += Count[I] * I;
- OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
- (Count[I] * 100.0) / NBucket,
- (CumulativeNonZero * 100.0) / TotalSyms);
- }
+ std::vector<size_t> Count(MaxChain, 0);
+ for (size_t B = 0; B < NBucket; B++)
+ ++Count[ChainLen[B]];
+ // Print Number of buckets with each chain lengths and their cumulative
+ // coverage of the symbols
+ OS << "Histogram for `.gnu.hash' bucket list length (total of " << NBucket
+ << " buckets)\n"
+ << " Length Number % of total Coverage\n";
+ for (size_t I = 0; I < MaxChain; I++) {
+ CumulativeNonZero += Count[I] * I;
+ OS << format("%7lu %-10lu (%5.1f%%) %5.1f%%\n", I, Count[I],
+ (Count[I] * 100.0) / NBucket,
+ (CumulativeNonZero * 100.0) / TotalSyms);
+ }
+}
+
+// Hash histogram shows statistics of how efficient the hash was for the
+// dynamic symbol table. The table shows the number of hash buckets for
+// different lengths of chains as an absolute number and percentage of the total
+// buckets, and the cumulative coverage of symbols for each set of buckets.
+template <class ELFT>
+void GNUStyle<ELFT>::printHashHistograms(const ELFFile<ELFT> *Obj) {
+ // Print histogram for the .hash section.
+ if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) {
+ if (Error E = checkHashTable<ELFT>(Obj, HashTable))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printHashHistogram(*HashTable);
+ }
+
+ // Print histogram for the .gnu.hash section.
+ if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) {
+ if (Error E = checkGNUHashTable<ELFT>(Obj, GnuHashTable))
+ this->reportUniqueWarning(std::move(E));
+ else
+ printGnuHashHistogram(*GnuHashTable);
}
}
@@ -4713,7 +5271,7 @@ template <typename ELFT> static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) {
std::string str;
raw_string_ostream ABI(str);
ABI << Major << "." << Minor << "." << Patch;
- return {OSName, ABI.str(), /*IsValid=*/true};
+ return {std::string(OSName), ABI.str(), /*IsValid=*/true};
}
static std::string getGNUBuildId(ArrayRef<uint8_t> Desc) {
@@ -4883,11 +5441,18 @@ static void printCoreNote(raw_ostream &OS, const CoreNote &Note) {
template <class ELFT>
void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
- auto PrintHeader = [&](const typename ELFT::Off Offset,
+ auto PrintHeader = [&](Optional<StringRef> SecName,
+ const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
- OS << "Displaying notes found at file offset " << format_hex(Offset, 10)
- << " with length " << format_hex(Size, 10) << ":\n"
- << " Owner Data size \tDescription\n";
+ OS << "Displaying notes found ";
+
+ if (SecName)
+ OS << "in: " << *SecName << "\n";
+ else
+ OS << "at file offset " << format_hex(Offset, 10) << " with length "
+ << format_hex(Size, 10) << ":\n";
+
+ OS << " Owner Data size \tDescription\n";
};
auto ProcessNote = [&](const Elf_Note &Note) {
@@ -4947,12 +5512,13 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
}
};
- ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());
+ ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections());
if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) {
for (const auto &S : Sections) {
if (S.sh_type != SHT_NOTE)
continue;
- PrintHeader(S.sh_offset, S.sh_size);
+ PrintHeader(expectedToOptional(Obj->getSectionName(&S)), S.sh_offset,
+ S.sh_size);
Error Err = Error::success();
for (auto Note : Obj->notes(S, Err))
ProcessNote(Note);
@@ -4960,11 +5526,18 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
reportError(std::move(Err), this->FileName);
}
} else {
- for (const auto &P :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError(
+ "unable to read program headers to locate the PT_NOTE segment: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &P : *PhdrsOrErr) {
if (P.p_type != PT_NOTE)
continue;
- PrintHeader(P.p_offset, P.p_filesz);
+ PrintHeader(/*SecName=*/None, P.p_offset, P.p_filesz);
Error Err = Error::success();
for (auto Note : Obj->notes(P, Err))
ProcessNote(Note);
@@ -4980,8 +5553,87 @@ void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
}
template <class ELFT>
+void DumpStyle<ELFT>::printDependentLibsHelper(
+ const ELFFile<ELFT> *Obj,
+ function_ref<void(const Elf_Shdr &)> OnSectionStart,
+ function_ref<void(StringRef, uint64_t)> OnLibEntry) {
+ auto Warn = [this](unsigned SecNdx, StringRef Msg) {
+ this->reportUniqueWarning(
+ createError("SHT_LLVM_DEPENDENT_LIBRARIES section at index " +
+ Twine(SecNdx) + " is broken: " + Msg));
+ };
+
+ unsigned I = -1;
+ for (const Elf_Shdr &Shdr : cantFail(Obj->sections())) {
+ ++I;
+ if (Shdr.sh_type != ELF::SHT_LLVM_DEPENDENT_LIBRARIES)
+ continue;
+
+ OnSectionStart(Shdr);
+
+ Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr);
+ if (!ContentsOrErr) {
+ Warn(I, toString(ContentsOrErr.takeError()));
+ continue;
+ }
+
+ ArrayRef<uint8_t> Contents = *ContentsOrErr;
+ if (!Contents.empty() && Contents.back() != 0) {
+ Warn(I, "the content is not null-terminated");
+ continue;
+ }
+
+ for (const uint8_t *I = Contents.begin(), *E = Contents.end(); I < E;) {
+ StringRef Lib((const char *)I);
+ OnLibEntry(Lib, I - Contents.begin());
+ I += Lib.size() + 1;
+ }
+ }
+}
+
+template <class ELFT>
void GNUStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) {
- OS << "printDependentLibs not implemented!\n";
+ bool SectionStarted = false;
+ struct NameOffset {
+ StringRef Name;
+ uint64_t Offset;
+ };
+ std::vector<NameOffset> SecEntries;
+ NameOffset Current;
+ auto PrintSection = [&]() {
+ OS << "Dependent libraries section " << Current.Name << " at offset "
+ << format_hex(Current.Offset, 1) << " contains " << SecEntries.size()
+ << " entries:\n";
+ for (NameOffset Entry : SecEntries)
+ OS << " [" << format("%6tx", Entry.Offset) << "] " << Entry.Name
+ << "\n";
+ OS << "\n";
+ SecEntries.clear();
+ };
+
+ auto OnSectionStart = [&](const Elf_Shdr &Shdr) {
+ if (SectionStarted)
+ PrintSection();
+ SectionStarted = true;
+ Current.Offset = Shdr.sh_offset;
+ Expected<StringRef> Name = Obj->getSectionName(&Shdr);
+ if (!Name) {
+ Current.Name = "<?>";
+ this->reportUniqueWarning(
+ createError("cannot get section name of "
+ "SHT_LLVM_DEPENDENT_LIBRARIES section: " +
+ toString(Name.takeError())));
+ } else {
+ Current.Name = *Name;
+ }
+ };
+ auto OnLibEntry = [&](StringRef Lib, uint64_t Offset) {
+ SecEntries.push_back(NameOffset{Lib, Offset});
+ };
+
+ this->printDependentLibsHelper(Obj, OnSectionStart, OnLibEntry);
+ if (SectionStarted)
+ PrintSection();
}
// Used for printing section names in places where possible errors can be
@@ -5005,9 +5657,12 @@ static std::string getSymbolName(const ELFSymbolRef &Sym) {
}
template <class ELFT>
-void DumpStyle<ELFT>::printFunctionStackSize(
- const ELFObjectFile<ELFT> *Obj, uint64_t SymValue, SectionRef FunctionSec,
- const StringRef SectionName, DataExtractor Data, uint64_t *Offset) {
+void DumpStyle<ELFT>::printFunctionStackSize(const ELFObjectFile<ELFT> *Obj,
+ uint64_t SymValue,
+ Optional<SectionRef> FunctionSec,
+ const StringRef SectionName,
+ DataExtractor Data,
+ uint64_t *Offset) {
// This function ignores potentially erroneous input, unless it is directly
// related to stack size reporting.
SymbolRef FuncSym;
@@ -5017,9 +5672,15 @@ void DumpStyle<ELFT>::printFunctionStackSize(
consumeError(SymAddrOrErr.takeError());
continue;
}
+ if (Expected<uint32_t> SymFlags = Symbol.getFlags()) {
+ if (*SymFlags & SymbolRef::SF_Undefined)
+ continue;
+ } else
+ consumeError(SymFlags.takeError());
if (Symbol.getELFType() == ELF::STT_FUNC && *SymAddrOrErr == SymValue) {
- // Check if the symbol is in the right section.
- if (FunctionSec.containsSymbol(Symbol)) {
+ // Check if the symbol is in the right section. FunctionSec == None means
+ // "any section".
+ if (!FunctionSec || FunctionSec->containsSymbol(Symbol)) {
FuncSym = Symbol;
break;
}
@@ -5130,11 +5791,6 @@ void DumpStyle<ELFT>::printNonRelocatableStackSizes(
ArrayRef<uint8_t> Contents =
unwrapOrError(this->FileName, EF->getSectionContents(ElfSec));
DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr));
- // A .stack_sizes section header's sh_link field is supposed to point
- // to the section that contains the functions whose stack sizes are
- // described in it.
- const Elf_Shdr *FunctionELFSec =
- unwrapOrError(this->FileName, EF->getSection(ElfSec->sh_link));
uint64_t Offset = 0;
while (Offset < Contents.size()) {
// The function address is followed by a ULEB representing the stack
@@ -5148,8 +5804,8 @@ void DumpStyle<ELFT>::printNonRelocatableStackSizes(
FileStr);
}
uint64_t SymValue = Data.getAddress(&Offset);
- printFunctionStackSize(Obj, SymValue, Obj->toSectionRef(FunctionELFSec),
- SectionName, Data, &Offset);
+ printFunctionStackSize(Obj, SymValue, /*FunctionSec=*/None, SectionName,
+ Data, &Offset);
}
}
}
@@ -5532,7 +6188,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) {
ListScope D(W, "Relocations");
int SectionNumber = -1;
- for (const Elf_Shdr &Sec : unwrapOrError(this->FileName, Obj->sections())) {
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
++SectionNumber;
if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA &&
@@ -5557,6 +6213,8 @@ template <class ELFT>
void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {
const Elf_Shdr *SymTab =
unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link));
+ unsigned SecNdx = Sec - &cantFail(Obj->sections()).front();
+ unsigned RelNdx = 0;
switch (Sec->sh_type) {
case ELF::SHT_REL:
@@ -5565,12 +6223,12 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {
Rela.r_offset = R.r_offset;
Rela.r_info = R.r_info;
Rela.r_addend = 0;
- printRelocation(Obj, Rela, SymTab);
+ printRelocation(Obj, SecNdx, Rela, ++RelNdx, SymTab);
}
break;
case ELF::SHT_RELA:
for (const Elf_Rela &R : unwrapOrError(this->FileName, Obj->relas(Sec)))
- printRelocation(Obj, R, SymTab);
+ printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab);
break;
case ELF::SHT_RELR:
case ELF::SHT_ANDROID_RELR: {
@@ -5582,7 +6240,7 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {
std::vector<Elf_Rela> RelrRelas =
unwrapOrError(this->FileName, Obj->decode_relrs(Relrs));
for (const Elf_Rela &R : RelrRelas)
- printRelocation(Obj, R, SymTab);
+ printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab);
}
break;
}
@@ -5590,30 +6248,27 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) {
case ELF::SHT_ANDROID_RELA:
for (const Elf_Rela &R :
unwrapOrError(this->FileName, Obj->android_relas(Sec)))
- printRelocation(Obj, R, SymTab);
+ printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab);
break;
}
}
template <class ELFT>
-void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
+void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, unsigned SecIndex,
+ Elf_Rela Rel, unsigned RelIndex,
const Elf_Shdr *SymTab) {
+ Expected<std::pair<const typename ELFT::Sym *, std::string>> Target =
+ this->dumper()->getRelocationTarget(SymTab, Rel);
+ if (!Target) {
+ this->reportUniqueWarning(createError(
+ "unable to print relocation " + Twine(RelIndex) + " in section " +
+ Twine(SecIndex) + ": " + toString(Target.takeError())));
+ return;
+ }
+
+ std::string TargetName = Target->second;
SmallString<32> RelocName;
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
- std::string TargetName;
- const Elf_Sym *Sym =
- unwrapOrError(this->FileName, Obj->getRelocationSymbol(&Rel, SymTab));
- if (Sym && Sym->getType() == ELF::STT_SECTION) {
- const Elf_Shdr *Sec = unwrapOrError(
- this->FileName,
- Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable()));
- TargetName = unwrapOrError(this->FileName, Obj->getSectionName(Sec));
- } else if (Sym) {
- StringRef StrTable =
- unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*SymTab));
- TargetName = this->dumper()->getFullSymbolName(
- Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);
- }
if (opts::ExpandRelocs) {
DictScope Group(W, "Relocation");
@@ -5635,13 +6290,16 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
ListScope SectionsD(W, "Sections");
int SectionIndex = -1;
- ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());
- const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
std::vector<EnumEntry<unsigned>> FlagsList =
getSectionFlagsForTarget(Obj->getHeader()->e_machine);
- for (const Elf_Shdr &Sec : Sections) {
- StringRef Name = unwrapOrError(
- ElfObj->getFileName(), Obj->getSectionName(&Sec, this->WarningHandler));
+ for (const Elf_Shdr &Sec : cantFail(Obj->sections())) {
+ StringRef Name = "<?>";
+ if (Expected<StringRef> SecNameOrErr =
+ Obj->getSectionName(&Sec, this->dumper()->WarningHandler))
+ Name = *SecNameOrErr;
+ else
+ this->reportUniqueWarning(SecNameOrErr.takeError());
+
DictScope SectionD(W, "Section");
W.printNumber("Index", ++SectionIndex);
W.printNumber("Name", Name, Sec.sh_name);
@@ -5709,7 +6367,12 @@ void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol,
Expected<StringRef> SectionName =
this->dumper()->getSymbolSectionName(Symbol, *SectionIndex);
if (!SectionName) {
- this->reportUniqueWarning(SectionName.takeError());
+ // Don't report an invalid section name if the section headers are missing.
+ // In such situations, all sections will be "invalid".
+ if (!this->dumper()->getElfObject()->sections().empty())
+ this->reportUniqueWarning(SectionName.takeError());
+ else
+ consumeError(SectionName.takeError());
W.printHex("Section", "<?>", *SectionIndex);
} else {
W.printHex("Section", *SectionName, *SectionIndex);
@@ -5718,8 +6381,8 @@ void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol,
template <class ELFT>
void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
- const Elf_Sym *First, StringRef StrTable,
- bool IsDynamic,
+ const Elf_Sym *First,
+ Optional<StringRef> StrTable, bool IsDynamic,
bool /*NonVisibilityBitsUsed*/) {
std::string FullSymbolName =
this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
@@ -5785,20 +6448,24 @@ template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Ob
if (Table.empty())
return;
- raw_ostream &OS = W.getOStream();
W.startLine() << "DynamicSection [ (" << Table.size() << " entries)\n";
- bool Is64 = ELFT::Is64Bits;
- if (Is64)
- W.startLine() << " Tag Type Name/Value\n";
- else
- W.startLine() << " Tag Type Name/Value\n";
+ size_t MaxTagSize = getMaxDynamicTagSize(Obj, Table);
+ // The "Name/Value" column should be indented from the "Type" column by N
+ // spaces, where N = MaxTagSize - length of "Type" (4) + trailing
+ // space (1) = -3.
+ W.startLine() << " Tag" << std::string(ELFT::Is64Bits ? 16 : 8, ' ')
+ << "Type" << std::string(MaxTagSize - 3, ' ') << "Name/Value\n";
+
+ std::string ValueFmt = "%-" + std::to_string(MaxTagSize) + "s ";
for (auto Entry : Table) {
uintX_t Tag = Entry.getTag();
- W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " "
- << format("%-21s", Obj->getDynamicTagAsString(Tag).c_str());
- this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());
- OS << "\n";
+ std::string Value = this->dumper()->getDynamicEntry(Tag, Entry.getVal());
+ W.startLine() << " " << format_hex(Tag, ELFT::Is64Bits ? 18 : 10, true)
+ << " "
+ << format(ValueFmt.c_str(),
+ Obj->getDynamicTagAsString(Tag).c_str())
+ << Value << "\n";
}
W.startLine() << "]\n";
}
@@ -5809,14 +6476,14 @@ void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
const DynRegionInfo &DynRelaRegion = this->dumper()->getDynRelaRegion();
const DynRegionInfo &DynRelrRegion = this->dumper()->getDynRelrRegion();
const DynRegionInfo &DynPLTRelRegion = this->dumper()->getDynPLTRelRegion();
- if (DynRelRegion.Size && DynRelaRegion.Size)
- report_fatal_error("There are both REL and RELA dynamic relocations");
+
W.startLine() << "Dynamic Relocations {\n";
W.indent();
- if (DynRelaRegion.Size > 0)
+ if (DynRelaRegion.Size > 0) {
for (const Elf_Rela &Rela : this->dumper()->dyn_relas())
printDynamicRelocation(Obj, Rela);
- else
+ }
+ if (DynRelRegion.Size > 0) {
for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) {
Elf_Rela Rela;
Rela.r_offset = Rel.r_offset;
@@ -5824,6 +6491,8 @@ void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
Rela.r_addend = 0;
printDynamicRelocation(Obj, Rela);
}
+ }
+
if (DynRelrRegion.Size > 0) {
Elf_Relr_Range Relrs = this->dumper()->dyn_relrs();
std::vector<Elf_Rela> RelrRelas =
@@ -5881,8 +6550,14 @@ template <class ELFT>
void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
ListScope L(W, "ProgramHeaders");
- for (const Elf_Phdr &Phdr :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError("unable to dump program headers: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &Phdr : *PhdrsOrErr) {
DictScope P(W, "ProgramHeader");
W.printHex("Type",
getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type),
@@ -5982,7 +6657,7 @@ void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
}
template <class ELFT>
-void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
+void LLVMStyle<ELFT>::printHashHistograms(const ELFFile<ELFT> *Obj) {
W.startLine() << "Hash Histogram not implemented!\n";
}
@@ -5991,21 +6666,23 @@ void LLVMStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) {
ListScope L(W, "CGProfile");
if (!this->dumper()->getDotCGProfileSec())
return;
- auto CGProfile = unwrapOrError(
- this->FileName, Obj->template getSectionContentsAsArray<Elf_CGProfile>(
- this->dumper()->getDotCGProfileSec()));
- for (const Elf_CGProfile &CGPE : CGProfile) {
+
+ Expected<ArrayRef<Elf_CGProfile>> CGProfileOrErr =
+ Obj->template getSectionContentsAsArray<Elf_CGProfile>(
+ this->dumper()->getDotCGProfileSec());
+ if (!CGProfileOrErr) {
+ this->reportUniqueWarning(
+ createError("unable to dump the SHT_LLVM_CALL_GRAPH_PROFILE section: " +
+ toString(CGProfileOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_CGProfile &CGPE : *CGProfileOrErr) {
DictScope D(W, "CGProfileEntry");
- W.printNumber(
- "From",
- unwrapOrError(this->FileName,
- this->dumper()->getStaticSymbolName(CGPE.cgp_from)),
- CGPE.cgp_from);
- W.printNumber(
- "To",
- unwrapOrError(this->FileName,
- this->dumper()->getStaticSymbolName(CGPE.cgp_to)),
- CGPE.cgp_to);
+ W.printNumber("From", this->dumper()->getStaticSymbolName(CGPE.cgp_from),
+ CGPE.cgp_from);
+ W.printNumber("To", this->dumper()->getStaticSymbolName(CGPE.cgp_to),
+ CGPE.cgp_to);
W.printNumber("Weight", CGPE.cgp_weight);
}
}
@@ -6096,8 +6773,10 @@ template <class ELFT>
void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
ListScope L(W, "Notes");
- auto PrintHeader = [&](const typename ELFT::Off Offset,
+ auto PrintHeader = [&](Optional<StringRef> SecName,
+ const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
+ W.printString("Name", SecName ? *SecName : "<?>");
W.printHex("Offset", Offset);
W.printHex("Size", Size);
};
@@ -6158,13 +6837,14 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
}
};
- ArrayRef<Elf_Shdr> Sections = unwrapOrError(this->FileName, Obj->sections());
+ ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections());
if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) {
for (const auto &S : Sections) {
if (S.sh_type != SHT_NOTE)
continue;
DictScope D(W, "NoteSection");
- PrintHeader(S.sh_offset, S.sh_size);
+ PrintHeader(expectedToOptional(Obj->getSectionName(&S)), S.sh_offset,
+ S.sh_size);
Error Err = Error::success();
for (auto Note : Obj->notes(S, Err))
ProcessNote(Note);
@@ -6172,12 +6852,19 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
reportError(std::move(Err), this->FileName);
}
} else {
- for (const auto &P :
- unwrapOrError(this->FileName, Obj->program_headers())) {
+ Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers();
+ if (!PhdrsOrErr) {
+ this->reportUniqueWarning(createError(
+ "unable to read program headers to locate the PT_NOTE segment: " +
+ toString(PhdrsOrErr.takeError())));
+ return;
+ }
+
+ for (const Elf_Phdr &P : *PhdrsOrErr) {
if (P.p_type != PT_NOTE)
continue;
DictScope D(W, "NoteSection");
- PrintHeader(P.p_offset, P.p_filesz);
+ PrintHeader(/*SecName=*/None, P.p_offset, P.p_filesz);
Error Err = Error::success();
for (auto Note : Obj->notes(P, Err))
ProcessNote(Note);
@@ -6192,35 +6879,38 @@ void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
ListScope L(W, "LinkerOptions");
unsigned I = -1;
- for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) {
+ for (const Elf_Shdr &Shdr : cantFail(Obj->sections())) {
++I;
if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS)
continue;
- ArrayRef<uint8_t> Contents =
- unwrapOrError(this->FileName, Obj->getSectionContents(&Shdr));
- if (Contents.empty())
+ Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr);
+ if (!ContentsOrErr) {
+ this->reportUniqueWarning(
+ createError("unable to read the content of the "
+ "SHT_LLVM_LINKER_OPTIONS section: " +
+ toString(ContentsOrErr.takeError())));
+ continue;
+ }
+ if (ContentsOrErr->empty())
continue;
- if (Contents.back() != 0) {
- reportWarning(createError("SHT_LLVM_LINKER_OPTIONS section at index " +
- Twine(I) +
- " is broken: the "
- "content is not null-terminated"),
- this->FileName);
+ if (ContentsOrErr->back() != 0) {
+ this->reportUniqueWarning(
+ createError("SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) +
+ " is broken: the "
+ "content is not null-terminated"));
continue;
}
SmallVector<StringRef, 16> Strings;
- toStringRef(Contents.drop_back()).split(Strings, '\0');
+ toStringRef(ContentsOrErr->drop_back()).split(Strings, '\0');
if (Strings.size() % 2 != 0) {
- reportWarning(
- createError(
- "SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) +
- " is broken: an incomplete "
- "key-value pair was found. The last possible key was: \"" +
- Strings.back() + "\""),
- this->FileName);
+ this->reportUniqueWarning(createError(
+ "SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) +
+ " is broken: an incomplete "
+ "key-value pair was found. The last possible key was: \"" +
+ Strings.back() + "\""));
continue;
}
@@ -6232,37 +6922,9 @@ void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) {
template <class ELFT>
void LLVMStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) {
ListScope L(W, "DependentLibs");
-
- auto Warn = [this](unsigned SecNdx, StringRef Msg) {
- this->reportUniqueWarning(
- createError("SHT_LLVM_DEPENDENT_LIBRARIES section at index " +
- Twine(SecNdx) + " is broken: " + Msg));
- };
-
- unsigned I = -1;
- for (const Elf_Shdr &Shdr : unwrapOrError(this->FileName, Obj->sections())) {
- ++I;
- if (Shdr.sh_type != ELF::SHT_LLVM_DEPENDENT_LIBRARIES)
- continue;
-
- Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr);
- if (!ContentsOrErr) {
- Warn(I, toString(ContentsOrErr.takeError()));
- continue;
- }
-
- ArrayRef<uint8_t> Contents = *ContentsOrErr;
- if (!Contents.empty() && Contents.back() != 0) {
- Warn(I, "the content is not null-terminated");
- continue;
- }
-
- for (const uint8_t *I = Contents.begin(), *E = Contents.end(); I < E;) {
- StringRef Lib((const char *)I);
- W.printString(Lib);
- I += Lib.size() + 1;
- }
- }
+ this->printDependentLibsHelper(
+ Obj, [](const Elf_Shdr &) {},
+ [this](StringRef Lib, uint64_t) { W.printString(Lib); });
}
template <class ELFT>
diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp
index 6229b52693d8..ce61f1c53a4d 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.cpp
+++ b/llvm/tools/llvm-readobj/ObjDumper.cpp
@@ -48,13 +48,13 @@ getSectionRefsByNameOrIndex(const object::ObjectFile *Obj,
if (!Section.getAsInteger(0, SecIndex))
SecIndices.emplace(SecIndex, false);
else
- SecNames.emplace(Section, false);
+ SecNames.emplace(std::string(Section), false);
}
SecIndex = Obj->isELF() ? 0 : 1;
for (object::SectionRef SecRef : Obj->sections()) {
StringRef SecName = unwrapOrError(Obj->getFileName(), SecRef.getName());
- auto NameIt = SecNames.find(SecName);
+ auto NameIt = SecNames.find(std::string(SecName));
if (NameIt != SecNames.end())
NameIt->second = true;
auto IndexIt = SecIndices.find(SecIndex);
diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h
index 3fc8d3e79ac1..57477606d6e8 100644
--- a/llvm/tools/llvm-readobj/ObjDumper.h
+++ b/llvm/tools/llvm-readobj/ObjDumper.h
@@ -59,12 +59,12 @@ public:
virtual void printNeededLibraries() { }
virtual void printSectionAsHex(StringRef SectionName) {}
virtual void printHashTable() { }
- virtual void printGnuHashTable() { }
+ virtual void printGnuHashTable(const object::ObjectFile *Obj) {}
virtual void printHashSymbols() {}
virtual void printLoadName() {}
virtual void printVersionInfo() {}
virtual void printGroupSections() {}
- virtual void printHashHistogram() {}
+ virtual void printHashHistograms() {}
virtual void printCGProfile() {}
virtual void printAddrsig() {}
virtual void printNotes() {}
diff --git a/llvm/tools/llvm-readobj/WasmDumper.cpp b/llvm/tools/llvm-readobj/WasmDumper.cpp
index dfab9f40d71b..a02dbb999826 100644
--- a/llvm/tools/llvm-readobj/WasmDumper.cpp
+++ b/llvm/tools/llvm-readobj/WasmDumper.cpp
@@ -93,18 +93,8 @@ void WasmDumper::printRelocation(const SectionRef &Section,
if (SI != Obj->symbol_end())
SymName = unwrapOrError(Obj->getFileName(), SI->getName());
- bool HasAddend = false;
- switch (RelocType) {
- case wasm::R_WASM_MEMORY_ADDR_LEB:
- case wasm::R_WASM_MEMORY_ADDR_SLEB:
- case wasm::R_WASM_MEMORY_ADDR_I32:
- case wasm::R_WASM_FUNCTION_OFFSET_I32:
- case wasm::R_WASM_SECTION_OFFSET_I32:
- HasAddend = true;
- break;
- default:
- break;
- }
+ bool HasAddend = wasm::relocTypeHasAddend(static_cast<uint32_t>(RelocType));
+
if (opts::ExpandRelocs) {
DictScope Group(W, "Relocation");
W.printNumber("Type", RelocTypeName, RelocType);
@@ -192,6 +182,10 @@ void WasmDumper::printSectionHeaders() {
W.printNumber("Size", static_cast<uint64_t>(Seg.Content.size()));
if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST)
W.printNumber("Offset", Seg.Offset.Value.Int32);
+ else if (Seg.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST)
+ W.printNumber("Offset", Seg.Offset.Value.Int64);
+ else
+ llvm_unreachable("unknown init expr opcode");
}
break;
}
@@ -227,8 +221,12 @@ void WasmDumper::printSymbol(const SymbolRef &Sym) {
W.printFlags("Flags", Symbol.Info.Flags, makeArrayRef(WasmSymbolFlags));
if (Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) {
- W.printString("ImportName", Symbol.Info.ImportName);
- W.printString("ImportModule", Symbol.Info.ImportModule);
+ if (Symbol.Info.ImportName) {
+ W.printString("ImportName", *Symbol.Info.ImportName);
+ }
+ if (Symbol.Info.ImportModule) {
+ W.printString("ImportModule", *Symbol.Info.ImportModule);
+ }
}
if (Symbol.Info.Kind != wasm::WASM_SYMBOL_TYPE_DATA) {
W.printHex("ElementIndex", Symbol.Info.ElementIndex);
diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
index 1f9403665594..dd62f98d9595 100644
--- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp
@@ -22,11 +22,6 @@ using namespace object;
namespace {
class XCOFFDumper : public ObjDumper {
- enum {
- SymbolTypeMask = 0x07,
- SymbolAlignmentMask = 0xF8,
- SymbolAlignmentBitOffset = 3
- };
public:
XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
@@ -211,17 +206,15 @@ void XCOFFDumper::printCsectAuxEnt32(const XCOFFCsectAuxEnt32 *AuxEntPtr) {
DictScope SymDs(W, "CSECT Auxiliary Entry");
W.printNumber("Index",
Obj.getSymbolIndex(reinterpret_cast<uintptr_t>(AuxEntPtr)));
- if ((AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask) == XCOFF::XTY_LD)
+ if (AuxEntPtr->isLabel())
W.printNumber("ContainingCsectSymbolIndex", AuxEntPtr->SectionOrLength);
else
W.printNumber("SectionLen", AuxEntPtr->SectionOrLength);
W.printHex("ParameterHashIndex", AuxEntPtr->ParameterHashIndex);
W.printHex("TypeChkSectNum", AuxEntPtr->TypeChkSectNum);
// Print out symbol alignment and type.
- W.printNumber("SymbolAlignmentLog2",
- (AuxEntPtr->SymbolAlignmentAndType & SymbolAlignmentMask) >>
- SymbolAlignmentBitOffset);
- W.printEnum("SymbolType", AuxEntPtr->SymbolAlignmentAndType & SymbolTypeMask,
+ W.printNumber("SymbolAlignmentLog2", AuxEntPtr->getAlignmentLog2());
+ W.printEnum("SymbolType", AuxEntPtr->getSymbolType(),
makeArrayRef(CsectSymbolTypeClass));
W.printEnum("StorageMappingClass",
static_cast<uint8_t>(AuxEntPtr->StorageMappingClass),
diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp
index fadeec1072d6..b9c6ad2256ae 100644
--- a/llvm/tools/llvm-readobj/llvm-readobj.cpp
+++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp
@@ -345,8 +345,11 @@ namespace opts {
cl::desc("Alias for --elf-hash-histogram"),
cl::aliasopt(HashHistogram));
- // --elf-cg-profile
- cl::opt<bool> CGProfile("elf-cg-profile", cl::desc("Display callgraph profile section"));
+ // --cg-profile
+ cl::opt<bool> CGProfile("cg-profile",
+ cl::desc("Display callgraph profile section"));
+ cl::alias ELFCGProfile("elf-cg-profile", cl::desc("Alias for --cg-profile"),
+ cl::aliasopt(CGProfile));
// -addrsig
cl::opt<bool> Addrsig("addrsig",
@@ -456,8 +459,9 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
Writer.printString("Format", Obj->getFileFormatName());
Writer.printString("Arch", Triple::getArchTypeName(
(llvm::Triple::ArchType)Obj->getArch()));
- Writer.printString("AddressSize",
- formatv("{0}bit", 8 * Obj->getBytesInAddress()));
+ Writer.printString(
+ "AddressSize",
+ std::string(formatv("{0}bit", 8 * Obj->getBytesInAddress())));
Dumper->printLoadName();
}
@@ -465,22 +469,22 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
Dumper->printFileHeaders();
if (opts::SectionHeaders)
Dumper->printSectionHeaders();
- if (opts::Relocations)
- Dumper->printRelocations();
- if (opts::DynRelocs)
- Dumper->printDynamicRelocations();
- if (opts::Symbols || opts::DynamicSymbols)
- Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols);
if (opts::HashSymbols)
Dumper->printHashSymbols();
- if (opts::UnwindInfo)
- Dumper->printUnwindInfo();
+ if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
+ Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping);
if (opts::DynamicTable)
Dumper->printDynamicTable();
if (opts::NeededLibraries)
Dumper->printNeededLibraries();
- if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
- Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping);
+ if (opts::Relocations)
+ Dumper->printRelocations();
+ if (opts::DynRelocs)
+ Dumper->printDynamicRelocations();
+ if (opts::UnwindInfo)
+ Dumper->printUnwindInfo();
+ if (opts::Symbols || opts::DynamicSymbols)
+ Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols);
if (!opts::StringDump.empty())
Dumper->printSectionsAsString(Obj, opts::StringDump);
if (!opts::HexDump.empty())
@@ -488,7 +492,7 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
if (opts::HashTable)
Dumper->printHashTable();
if (opts::GnuHashTable)
- Dumper->printGnuHashTable();
+ Dumper->printGnuHashTable(Obj);
if (opts::VersionInfo)
Dumper->printVersionInfo();
if (Obj->isELF()) {
@@ -501,7 +505,7 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
if (opts::SectionGroups)
Dumper->printGroupSections();
if (opts::HashHistogram)
- Dumper->printHashHistogram();
+ Dumper->printHashHistograms();
if (opts::CGProfile)
Dumper->printCGProfile();
if (opts::Addrsig)
@@ -524,6 +528,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
Dumper->printCOFFResources();
if (opts::COFFLoadConfig)
Dumper->printCOFFLoadConfig();
+ if (opts::CGProfile)
+ Dumper->printCGProfile();
if (opts::Addrsig)
Dumper->printAddrsig();
if (opts::CodeView)