summaryrefslogtreecommitdiff
path: root/tools/llvm-readobj
diff options
context:
space:
mode:
Diffstat (limited to 'tools/llvm-readobj')
-rw-r--r--tools/llvm-readobj/ARMEHABIPrinter.h17
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.cpp21
-rw-r--r--tools/llvm-readobj/ARMWinEHPrinter.h9
-rw-r--r--tools/llvm-readobj/COFFDumper.cpp187
-rw-r--r--tools/llvm-readobj/COFFImportDumper.cpp9
-rw-r--r--tools/llvm-readobj/DwarfCFIEHPrinter.h7
-rw-r--r--tools/llvm-readobj/ELFDumper.cpp2253
-rw-r--r--tools/llvm-readobj/Error.cpp7
-rw-r--r--tools/llvm-readobj/Error.h7
-rw-r--r--tools/llvm-readobj/MachODumper.cpp43
-rw-r--r--tools/llvm-readobj/ObjDumper.cpp202
-rw-r--r--tools/llvm-readobj/ObjDumper.h56
-rw-r--r--tools/llvm-readobj/StackMapPrinter.h19
-rw-r--r--tools/llvm-readobj/WasmDumper.cpp62
-rw-r--r--tools/llvm-readobj/Win64EHDumper.cpp7
-rw-r--r--tools/llvm-readobj/Win64EHDumper.h7
-rw-r--r--tools/llvm-readobj/WindowsResourceDumper.cpp7
-rw-r--r--tools/llvm-readobj/WindowsResourceDumper.h7
-rw-r--r--tools/llvm-readobj/XCOFFDumper.cpp190
-rw-r--r--tools/llvm-readobj/llvm-readobj.cpp272
-rw-r--r--tools/llvm-readobj/llvm-readobj.h14
21 files changed, 2071 insertions, 1332 deletions
diff --git a/tools/llvm-readobj/ARMEHABIPrinter.h b/tools/llvm-readobj/ARMEHABIPrinter.h
index 51128f113c4c2..11f9d6166a59a 100644
--- a/tools/llvm-readobj/ARMEHABIPrinter.h
+++ b/tools/llvm-readobj/ARMEHABIPrinter.h
@@ -1,9 +1,8 @@
//===--- ARMEHABIPrinter.h - ARM EHABI Unwind Information Printer ----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -366,6 +365,8 @@ template <typename ET>
ErrorOr<StringRef>
PrinterContext<ET>::FunctionAtAddress(unsigned Section,
uint64_t Address) const {
+ if (!Symtab)
+ return readobj_error::unknown_symbol;
auto StrTableOrErr = ELF->getStringTableForSymtab(*Symtab);
if (!StrTableOrErr)
error(StrTableOrErr.takeError());
@@ -551,13 +552,15 @@ void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex,
const Elf_Shdr *EHT =
FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4);
- if (auto Name = ELF->getSectionName(EHT))
- SW.printString("ExceptionHandlingTable", *Name);
+ if (EHT)
+ if (auto Name = ELF->getSectionName(EHT))
+ SW.printString("ExceptionHandlingTable", *Name);
uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr);
SW.printHex("TableEntryOffset", TableEntryOffset);
- PrintExceptionTable(IT, EHT, TableEntryOffset);
+ if (EHT)
+ PrintExceptionTable(IT, EHT, TableEntryOffset);
}
}
}
diff --git a/tools/llvm-readobj/ARMWinEHPrinter.cpp b/tools/llvm-readobj/ARMWinEHPrinter.cpp
index 4b823b816c35a..4de14e2e78d52 100644
--- a/tools/llvm-readobj/ARMWinEHPrinter.cpp
+++ b/tools/llvm-readobj/ARMWinEHPrinter.cpp
@@ -1,9 +1,8 @@
//===-- ARMWinEHPrinter.cpp - Windows on ARM EH Data Printer ----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -1095,17 +1094,17 @@ void Decoder::dumpProcedureData(const COFFObjectFile &COFF,
break;
}
-std::error_code Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
+Error Decoder::dumpProcedureData(const COFFObjectFile &COFF) {
for (const auto &Section : COFF.sections()) {
- StringRef SectionName;
- if (std::error_code EC =
- COFF.getSectionName(COFF.getCOFFSection(Section), SectionName))
- return EC;
+ Expected<StringRef> NameOrErr =
+ COFF.getSectionName(COFF.getCOFFSection(Section));
+ if (!NameOrErr)
+ return NameOrErr.takeError();
- if (SectionName.startswith(".pdata"))
+ if (NameOrErr->startswith(".pdata"))
dumpProcedureData(COFF, Section);
}
- return std::error_code();
+ return Error::success();
}
}
}
diff --git a/tools/llvm-readobj/ARMWinEHPrinter.h b/tools/llvm-readobj/ARMWinEHPrinter.h
index e271a1e6fe772..5de7062cb1d7b 100644
--- a/tools/llvm-readobj/ARMWinEHPrinter.h
+++ b/tools/llvm-readobj/ARMWinEHPrinter.h
@@ -1,9 +1,8 @@
//===--- ARMWinEHPrinter.h - Windows on ARM Unwind Information Printer ----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -157,7 +156,7 @@ public:
Decoder(ScopedPrinter &SW, bool isAArch64) : SW(SW),
OS(SW.getOStream()),
isAArch64(isAArch64) {}
- std::error_code dumpProcedureData(const object::COFFObjectFile &COFF);
+ Error dumpProcedureData(const object::COFFObjectFile &COFF);
};
}
}
diff --git a/tools/llvm-readobj/COFFDumper.cpp b/tools/llvm-readobj/COFFDumper.cpp
index 3e2626dad1184..4c2e39dfa3cc6 100644
--- a/tools/llvm-readobj/COFFDumper.cpp
+++ b/tools/llvm-readobj/COFFDumper.cpp
@@ -1,9 +1,8 @@
//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -44,13 +43,14 @@
#include "llvm/DebugInfo/CodeView/TypeTableCollection.h"
#include "llvm/Object/COFF.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/WindowsResource.h"
#include "llvm/Support/BinaryStreamReader.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/Win64EH.h"
#include "llvm/Support/raw_ostream.h"
@@ -81,8 +81,6 @@ public:
void printFileHeaders() override;
void printSectionHeaders() override;
void printRelocations() override;
- void printSymbols() override;
- void printDynamicSymbols() override;
void printUnwindInfo() override;
void printNeededLibraries() override;
@@ -95,12 +93,16 @@ public:
void printCOFFResources() override;
void printCOFFLoadConfig() override;
void printCodeViewDebugInfo() override;
- void
- mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
- llvm::codeview::MergingTypeTableBuilder &CVTypes) override;
+ void mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
+ llvm::codeview::MergingTypeTableBuilder &CVTypes,
+ llvm::codeview::GlobalTypeTableBuilder &GlobalCVIDs,
+ llvm::codeview::GlobalTypeTableBuilder &GlobalCVTypes,
+ bool GHash) override;
void printStackMap() const override;
void printAddrsig() override;
private:
+ void printSymbols() override;
+ void printDynamicSymbols() override;
void printSymbol(const SymbolRef &Sym);
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc,
uint64_t Bias = 0);
@@ -568,29 +570,6 @@ static const EnumEntry<uint8_t> FileChecksumKindNames[] = {
LLVM_READOBJ_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
};
-static const EnumEntry<COFF::ResourceTypeID> ResourceTypeNames[]{
- {"kRT_CURSOR (ID 1)", COFF::RID_Cursor},
- {"kRT_BITMAP (ID 2)", COFF::RID_Bitmap},
- {"kRT_ICON (ID 3)", COFF::RID_Icon},
- {"kRT_MENU (ID 4)", COFF::RID_Menu},
- {"kRT_DIALOG (ID 5)", COFF::RID_Dialog},
- {"kRT_STRING (ID 6)", COFF::RID_String},
- {"kRT_FONTDIR (ID 7)", COFF::RID_FontDir},
- {"kRT_FONT (ID 8)", COFF::RID_Font},
- {"kRT_ACCELERATOR (ID 9)", COFF::RID_Accelerator},
- {"kRT_RCDATA (ID 10)", COFF::RID_RCData},
- {"kRT_MESSAGETABLE (ID 11)", COFF::RID_MessageTable},
- {"kRT_GROUP_CURSOR (ID 12)", COFF::RID_Group_Cursor},
- {"kRT_GROUP_ICON (ID 14)", COFF::RID_Group_Icon},
- {"kRT_VERSION (ID 16)", COFF::RID_Version},
- {"kRT_DLGINCLUDE (ID 17)", COFF::RID_DLGInclude},
- {"kRT_PLUGPLAY (ID 19)", COFF::RID_PlugPlay},
- {"kRT_VXD (ID 20)", COFF::RID_VXD},
- {"kRT_ANICURSOR (ID 21)", COFF::RID_AniCursor},
- {"kRT_ANIICON (ID 22)", COFF::RID_AniIcon},
- {"kRT_HTML (ID 23)", COFF::RID_HTML},
- {"kRT_MANIFEST (ID 24)", COFF::RID_Manifest}};
-
template <typename T>
static std::error_code getSymbolAuxData(const COFFObjectFile *Obj,
COFFSymbolRef Symbol,
@@ -613,11 +592,14 @@ void COFFDumper::cacheRelocations() {
RelocMap[Section].push_back(Reloc);
// Sort relocations by address.
- llvm::sort(RelocMap[Section], relocAddressLess);
+ llvm::sort(RelocMap[Section], [](RelocationRef L, RelocationRef R) {
+ return L.getOffset() < R.getOffset();
+ });
}
}
-void COFFDumper::printDataDirectory(uint32_t Index, const std::string &FieldName) {
+void COFFDumper::printDataDirectory(uint32_t Index,
+ const std::string &FieldName) {
const data_directory *Data;
if (Obj->getDataDirectory(Index, Data))
return;
@@ -951,8 +933,7 @@ void COFFDumper::initializeFileAndStringTables(BinaryStreamReader &Reader) {
void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
const SectionRef &Section) {
- StringRef SectionContents;
- error(Section.getContents(SectionContents));
+ StringRef SectionContents = unwrapOrError(Section.getContents());
StringRef Data = SectionContents;
SmallVector<StringRef, 10> FunctionNames;
@@ -980,6 +961,11 @@ void COFFDumper::printCodeViewSymbolSection(StringRef SectionName,
error(consume(Data, SubSectionSize));
ListScope S(W, "Subsection");
+ // Dump the subsection as normal even if the ignore bit is set.
+ if (SubType & SubsectionIgnoreFlag) {
+ W.printHex("IgnoredSubsectionKind", SubType);
+ SubType &= ~SubsectionIgnoreFlag;
+ }
W.printEnum("SubSectionType", SubType, makeArrayRef(SubSectionTypes));
W.printHex("SubSectionSize", SubSectionSize);
@@ -1228,13 +1214,15 @@ void COFFDumper::printFileNameForOffset(StringRef Label, uint32_t FileOffset) {
}
void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs,
- MergingTypeTableBuilder &CVTypes) {
+ MergingTypeTableBuilder &CVTypes,
+ GlobalTypeTableBuilder &GlobalCVIDs,
+ GlobalTypeTableBuilder &GlobalCVTypes,
+ bool GHash) {
for (const SectionRef &S : Obj->sections()) {
StringRef SectionName;
error(S.getName(SectionName));
if (SectionName == ".debug$T") {
- StringRef Data;
- error(S.getContents(Data));
+ StringRef Data = unwrapOrError(S.getContents());
uint32_t Magic;
error(consume(Data, Magic));
if (Magic != 4)
@@ -1249,9 +1237,18 @@ void COFFDumper::mergeCodeViewTypes(MergingTypeTableBuilder &CVIDs,
}
SmallVector<TypeIndex, 128> SourceToDest;
Optional<uint32_t> PCHSignature;
- if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types,
- PCHSignature))
- return error(std::move(EC));
+ if (GHash) {
+ std::vector<GloballyHashedType> Hashes =
+ GloballyHashedType::hashTypes(Types);
+ if (auto EC =
+ mergeTypeAndIdRecords(GlobalCVIDs, GlobalCVTypes, SourceToDest,
+ Types, Hashes, PCHSignature))
+ return error(std::move(EC));
+ } else {
+ if (auto EC = mergeTypeAndIdRecords(CVIDs, CVTypes, SourceToDest, Types,
+ PCHSignature))
+ return error(std::move(EC));
+ }
}
}
}
@@ -1261,8 +1258,7 @@ void COFFDumper::printCodeViewTypeSection(StringRef SectionName,
ListScope D(W, "CodeViewTypes");
W.printNumber("Section", SectionName, Obj->getSectionID(Section));
- StringRef Data;
- error(Section.getContents(Data));
+ StringRef Data = unwrapOrError(Section.getContents());
if (opts::CodeViewSubsectionBytes)
W.printBinaryBlock("Data", Data);
@@ -1322,9 +1318,7 @@ void COFFDumper::printSectionHeaders() {
if (opts::SectionData &&
!(Section->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)) {
- StringRef Data;
- error(Sec.getContents(Data));
-
+ StringRef Data = unwrapOrError(Sec.getContents());
W.printBinaryBlock("SectionData", Data);
}
}
@@ -1398,15 +1392,11 @@ void COFFDumper::printSymbols() {
void COFFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); }
-static ErrorOr<StringRef>
+static Expected<StringRef>
getSectionName(const llvm::object::COFFObjectFile *Obj, int32_t SectionNumber,
const coff_section *Section) {
- if (Section) {
- StringRef SectionName;
- if (std::error_code EC = Obj->getSectionName(Section, SectionName))
- return EC;
- return SectionName;
- }
+ if (Section)
+ return Obj->getSectionName(Section);
if (SectionNumber == llvm::COFF::IMAGE_SYM_DEBUG)
return StringRef("IMAGE_SYM_DEBUG");
if (SectionNumber == llvm::COFF::IMAGE_SYM_ABSOLUTE)
@@ -1431,11 +1421,10 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
if (Obj->getSymbolName(Symbol, SymbolName))
SymbolName = "";
- StringRef SectionName = "";
- ErrorOr<StringRef> Res =
- getSectionName(Obj, Symbol.getSectionNumber(), Section);
- if (Res)
- SectionName = *Res;
+ StringRef SectionName;
+ if (Expected<StringRef> NameOrErr =
+ getSectionName(Obj, Symbol.getSectionNumber(), Section))
+ SectionName = *NameOrErr;
W.printString("Name", SymbolName);
W.printNumber("Value", Symbol.getValue());
@@ -1503,16 +1492,12 @@ void COFFDumper::printSymbol(const SymbolRef &Sym) {
&& Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
const coff_section *Assoc;
StringRef AssocName = "";
- std::error_code EC = Obj->getSection(AuxNumber, Assoc);
- ErrorOr<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);
- if (Res)
- AssocName = *Res;
- if (!EC)
- EC = Res.getError();
- if (EC) {
- AssocName = "";
+ if (std::error_code EC = Obj->getSection(AuxNumber, Assoc))
error(EC);
- }
+ Expected<StringRef> Res = getSectionName(Obj, AuxNumber, Assoc);
+ if (!Res)
+ error(Res.takeError());
+ AssocName = *Res;
W.printNumber("AssocSection", AssocName, AuxNumber);
}
@@ -1559,7 +1544,8 @@ void COFFDumper::printUnwindInfo() {
case COFF::IMAGE_FILE_MACHINE_ARMNT: {
ARM::WinEH::Decoder Decoder(W, Obj->getMachine() ==
COFF::IMAGE_FILE_MACHINE_ARM64);
- Decoder.dumpProcedureData(*Obj);
+ // TODO Propagate the error.
+ consumeError(Decoder.dumpProcedureData(*Obj));
break;
}
default:
@@ -1581,10 +1567,10 @@ void COFFDumper::printNeededLibraries() {
Libs.push_back(Name);
}
- std::stable_sort(Libs.begin(), Libs.end());
+ llvm::stable_sort(Libs);
for (const auto &L : Libs) {
- outs() << " " << L << "\n";
+ W.startLine() << L << "\n";
}
}
@@ -1674,15 +1660,13 @@ void COFFDumper::printCOFFExports() {
void COFFDumper::printCOFFDirectives() {
for (const SectionRef &Section : Obj->sections()) {
- StringRef Contents;
StringRef Name;
error(Section.getName(Name));
if (Name != ".drectve")
continue;
- error(Section.getContents(Contents));
-
+ StringRef Contents = unwrapOrError(Section.getContents());
W.printString("Directive(s)", Contents);
}
}
@@ -1721,8 +1705,7 @@ void COFFDumper::printCOFFResources() {
if (!Name.startswith(".rsrc"))
continue;
- StringRef Ref;
- error(S.getContents(Ref));
+ StringRef Ref = unwrapOrError(S.getContents());
if ((Name == ".rsrc") || (Name == ".rsrc$01")) {
ResourceSectionRef RSF(Ref);
@@ -1777,7 +1760,8 @@ void COFFDumper::printResourceDirectoryTable(
SmallString<20> IDStr;
raw_svector_ostream OS(IDStr);
if (i < Table.NumberOfNameEntries) {
- ArrayRef<UTF16> RawEntryNameString = unwrapOrError(RSF.getEntryNameString(Entry));
+ ArrayRef<UTF16> RawEntryNameString =
+ unwrapOrError(RSF.getEntryNameString(Entry));
std::vector<UTF16> EndianCorrectedNameString;
if (llvm::sys::IsBigEndianHost) {
EndianCorrectedNameString.resize(RawEntryNameString.size() + 1);
@@ -1793,9 +1777,8 @@ void COFFDumper::printResourceDirectoryTable(
OS << EntryNameString;
} else {
if (Level == "Type") {
- ScopedPrinter Printer(OS);
- Printer.printEnum("", Entry.Identifier.ID,
- makeArrayRef(ResourceTypeNames));
+ OS << ": ";
+ printResourceTypeName(Entry.Identifier.ID, OS);
IDStr = IDStr.slice(0, IDStr.find_first_of(")", 0) + 1);
} else {
OS << ": (ID " << Entry.Identifier.ID << ")";
@@ -1848,18 +1831,16 @@ void COFFDumper::printStackMap() const {
if (StackMapSection == object::SectionRef())
return;
- StringRef StackMapContents;
- StackMapSection.getContents(StackMapContents);
- ArrayRef<uint8_t> StackMapContentsArray(
- reinterpret_cast<const uint8_t*>(StackMapContents.data()),
- StackMapContents.size());
+ StringRef StackMapContents = unwrapOrError(StackMapSection.getContents());
+ ArrayRef<uint8_t> StackMapContentsArray =
+ arrayRefFromStringRef(StackMapContents);
if (Obj->isLittleEndian())
prettyPrintStackMap(
- W, StackMapV2Parser<support::little>(StackMapContentsArray));
+ W, StackMapParser<support::little>(StackMapContentsArray));
else
- prettyPrintStackMap(W,
- StackMapV2Parser<support::big>(StackMapContentsArray));
+ prettyPrintStackMap(
+ W, StackMapParser<support::big>(StackMapContentsArray));
}
void COFFDumper::printAddrsig() {
@@ -1876,15 +1857,13 @@ void COFFDumper::printAddrsig() {
if (AddrsigSection == object::SectionRef())
return;
- StringRef AddrsigContents;
- AddrsigSection.getContents(AddrsigContents);
- ArrayRef<uint8_t> AddrsigContentsArray(
- reinterpret_cast<const uint8_t*>(AddrsigContents.data()),
- AddrsigContents.size());
+ StringRef AddrsigContents = unwrapOrError(AddrsigSection.getContents());
+ ArrayRef<uint8_t> AddrsigContentsArray(AddrsigContents.bytes_begin(),
+ AddrsigContents.size());
ListScope L(W, "Addrsig");
- auto *Cur = reinterpret_cast<const uint8_t *>(AddrsigContents.begin());
- auto *End = reinterpret_cast<const uint8_t *>(AddrsigContents.end());
+ const uint8_t *Cur = AddrsigContents.bytes_begin();
+ const uint8_t *End = AddrsigContents.bytes_end();
while (Cur != End) {
unsigned Size;
const char *Err;
@@ -1905,16 +1884,10 @@ void COFFDumper::printAddrsig() {
}
}
-void llvm::dumpCodeViewMergedTypes(
- ScopedPrinter &Writer, llvm::codeview::MergingTypeTableBuilder &IDTable,
- llvm::codeview::MergingTypeTableBuilder &CVTypes) {
- // Flatten it first, then run our dumper on it.
- SmallString<0> TypeBuf;
- CVTypes.ForEachRecord([&](TypeIndex TI, const CVType &Record) {
- TypeBuf.append(Record.RecordData.begin(), Record.RecordData.end());
- });
-
- TypeTableCollection TpiTypes(CVTypes.records());
+void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+ ArrayRef<ArrayRef<uint8_t>> IpiRecords,
+ ArrayRef<ArrayRef<uint8_t>> TpiRecords) {
+ TypeTableCollection TpiTypes(TpiRecords);
{
ListScope S(Writer, "MergedTypeStream");
TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
@@ -1924,7 +1897,7 @@ void llvm::dumpCodeViewMergedTypes(
// Flatten the id stream and print it next. The ID stream refers to names from
// the type stream.
- TypeTableCollection IpiTypes(IDTable.records());
+ TypeTableCollection IpiTypes(IpiRecords);
{
ListScope S(Writer, "MergedIDStream");
TypeDumpVisitor TDV(TpiTypes, &Writer, opts::CodeViewSubsectionBytes);
diff --git a/tools/llvm-readobj/COFFImportDumper.cpp b/tools/llvm-readobj/COFFImportDumper.cpp
index 18010c34f0f39..c9d5e82263db1 100644
--- a/tools/llvm-readobj/COFFImportDumper.cpp
+++ b/tools/llvm-readobj/COFFImportDumper.cpp
@@ -1,9 +1,8 @@
//===-- COFFImportDumper.cpp - COFF import library dumper -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -51,7 +50,7 @@ void dumpCOFFImportFile(const COFFImportFile *File, ScopedPrinter &Writer) {
for (const object::BasicSymbolRef &Sym : File->symbols()) {
raw_ostream &OS = Writer.startLine();
OS << "Symbol: ";
- Sym.printName(OS);
+ cantFail(Sym.printName(OS));
OS << "\n";
}
}
diff --git a/tools/llvm-readobj/DwarfCFIEHPrinter.h b/tools/llvm-readobj/DwarfCFIEHPrinter.h
index d91d764c4d0a6..7055510ef2f2e 100644
--- a/tools/llvm-readobj/DwarfCFIEHPrinter.h
+++ b/tools/llvm-readobj/DwarfCFIEHPrinter.h
@@ -1,9 +1,8 @@
//===--- DwarfCFIEHPrinter.h - DWARF-based Unwind Information Printer -----===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp
index 93254717e9213..4e1cb7d544e79 100644
--- a/tools/llvm-readobj/ELFDumper.cpp
+++ b/tools/llvm-readobj/ELFDumper.cpp
@@ -1,9 +1,8 @@
//===- ELFDumper.cpp - ELF-specific dumper --------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -20,6 +19,7 @@
#include "llvm-readobj.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/PointerIntPair.h"
#include "llvm/ADT/STLExtras.h"
@@ -30,6 +30,7 @@
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h"
#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Demangle/Demangle.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFObjectFile.h"
#include "llvm/Object/ELFTypes.h"
@@ -66,13 +67,14 @@ using namespace llvm;
using namespace llvm::object;
using namespace ELF;
-#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
- case ns::enum: return #enum;
+#define LLVM_READOBJ_ENUM_CASE(ns, enum) \
+ case ns::enum: \
+ return #enum;
-#define ENUM_ENT(enum, altName) \
+#define ENUM_ENT(enum, altName) \
{ #enum, altName, ELF::enum }
-#define ENUM_ENT_1(enum) \
+#define ENUM_ENT_1(enum) \
{ #enum, #enum, ELF::enum }
#define LLVM_READOBJ_PHDR_ENUM(ns, enum) \
@@ -132,14 +134,17 @@ struct DynRegionInfo {
const Type *Start = reinterpret_cast<const Type *>(Addr);
if (!Start)
return {Start, Start};
- if (EntSize != sizeof(Type) || Size % EntSize)
- reportError("Invalid entity size");
+ if (EntSize != sizeof(Type) || Size % EntSize) {
+ // TODO: Add a section index to this warning.
+ reportWarning("invalid section size (" + Twine(Size) +
+ ") or entity size (" + Twine(EntSize) + ")");
+ return {Start, Start};
+ }
return {Start, Start + (Size / EntSize)};
}
};
-template<typename ELFT>
-class ELFDumper : public ObjDumper {
+template <typename ELFT> class ELFDumper : public ObjDumper {
public:
ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ScopedPrinter &Writer);
@@ -147,13 +152,14 @@ public:
void printSectionHeaders() override;
void printRelocations() override;
void printDynamicRelocations() override;
- void printSymbols() override;
- void printDynamicSymbols() override;
+ void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override;
+ void printHashSymbols() override;
void printUnwindInfo() override;
void printDynamicTable() override;
void printNeededLibraries() override;
- void printProgramHeaders() override;
+ void printProgramHeaders(bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) override;
void printHashTable() override;
void printGnuHashTable() override;
void printLoadName() override;
@@ -177,6 +183,8 @@ public:
void printELFLinkerOptions() override;
+ const object::ELFObjectFile<ELFT> *getElfObject() const { return ObjF; };
+
private:
std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle;
@@ -185,24 +193,25 @@ private:
DynRegionInfo checkDRI(DynRegionInfo DRI) {
const ELFFile<ELFT> *Obj = ObjF->getELFFile();
if (DRI.Addr < Obj->base() ||
- (const uint8_t *)DRI.Addr + DRI.Size > Obj->base() + Obj->getBufSize())
+ reinterpret_cast<const uint8_t *>(DRI.Addr) + DRI.Size >
+ Obj->base() + Obj->getBufSize())
error(llvm::object::object_error::parse_failed);
return DRI;
}
DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) {
- return checkDRI({ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize});
+ return checkDRI(
+ {ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize});
}
DynRegionInfo createDRIFrom(const Elf_Shdr *S) {
- return checkDRI({ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize});
+ return checkDRI(
+ {ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize});
}
- void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments);
+ void loadDynamicTable(const ELFFile<ELFT> *Obj);
+ void parseDynamicTable();
- void printValue(uint64_t Type, uint64_t Value);
-
- StringRef getDynamicString(uint64_t Offset) const;
StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb,
bool &IsDefault) const;
void LoadVersionMap() const;
@@ -217,7 +226,7 @@ private:
DynRegionInfo DynSymRegion;
DynRegionInfo DynamicTable;
StringRef DynamicStringTable;
- StringRef SOName;
+ StringRef SOName = "<Not found>";
const Elf_Hash *HashTable = nullptr;
const Elf_GnuHash *GnuHashTable = nullptr;
const Elf_Shdr *DotSymtabSec = nullptr;
@@ -226,9 +235,9 @@ private:
StringRef DynSymtabName;
ArrayRef<Elf_Word> ShndxTable;
- const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version
- const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r
- const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d
+ const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version
+ const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r
+ const Elf_Shdr *SymbolVersionDefSection = nullptr; // .gnu.version_d
// Records for each version index the corresponding Verdef or Vernaux entry.
// This is filled the first time LoadVersionMap() is called.
@@ -256,7 +265,18 @@ private:
public:
Elf_Dyn_Range dynamic_table() const {
- return DynamicTable.getAsArrayRef<Elf_Dyn>();
+ // A valid .dynamic section contains an array of entries terminated
+ // with a DT_NULL entry. However, sometimes the section content may
+ // continue past the DT_NULL entry, so to dump the section correctly,
+ // we first find the end of the entries by iterating over them.
+ Elf_Dyn_Range Table = DynamicTable.getAsArrayRef<Elf_Dyn>();
+
+ size_t Size = 0;
+ while (Size < Table.size())
+ if (Table[Size++].getTag() == DT_NULL)
+ break;
+
+ return Table.slice(0, Size);
}
Elf_Sym_Range dynamic_symbols() const {
@@ -271,9 +291,14 @@ public:
void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym,
StringRef &SectionName,
unsigned &SectionIndex) const;
- StringRef getStaticSymbolName(uint32_t Index) const;
+ std::string getStaticSymbolName(uint32_t Index) const;
+ StringRef getSymbolVersionByIndex(StringRef StrTab,
+ uint32_t VersionSymbolIndex,
+ bool &IsDefault) const;
void printSymbolsHelper(bool IsDynamic) const;
+ void printDynamicEntry(raw_ostream &OS, uint64_t Type, uint64_t Value) const;
+
const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; }
const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; }
const Elf_Shdr *getDotAddrsigSec() const { return DotAddrsigSec; }
@@ -283,6 +308,7 @@ public:
const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; }
const DynRegionInfo &getDynRelrRegion() const { return DynRelrRegion; }
const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; }
+ const DynRegionInfo &getDynamicTableRegion() const { return DynamicTable; }
const Elf_Hash *getHashTable() const { return HashTable; }
const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; }
};
@@ -328,15 +354,25 @@ public:
virtual void printGroupSections(const ELFFile<ELFT> *Obj) = 0;
virtual void printRelocations(const ELFFile<ELFT> *Obj) = 0;
virtual void printSectionHeaders(const ELFFile<ELFT> *Obj) = 0;
- virtual void printSymbols(const ELFFile<ELFT> *Obj) = 0;
- virtual void printDynamicSymbols(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printSymbols(const ELFFile<ELFT> *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) = 0;
+ virtual void printHashSymbols(const ELFFile<ELFT> *Obj) {}
+ virtual void printDynamic(const ELFFile<ELFT> *Obj) {}
virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0;
- virtual void printSymtabMessage(const ELFFile<ELFT> *obj, StringRef Name,
+ virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name,
size_t Offset) {}
virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol,
const Elf_Sym *FirstSym, StringRef StrTable,
bool IsDynamic) = 0;
- virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0;
+ virtual void printProgramHeaders(const ELFFile<ELFT> *Obj,
+ bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) = 0;
+ virtual void printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) = 0;
+ virtual void printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ 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 printCGProfile(const ELFFile<ELFT> *Obj) = 0;
virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0;
@@ -351,24 +387,36 @@ private:
};
template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> {
- formatted_raw_ostream OS;
+ formatted_raw_ostream &OS;
public:
TYPEDEF_ELF_TYPES(ELFT)
GNUStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper)
- : DumpStyle<ELFT>(Dumper), OS(W.getOStream()) {}
+ : DumpStyle<ELFT>(Dumper),
+ OS(static_cast<formatted_raw_ostream&>(W.getOStream())) {
+ assert (&W.getOStream() == &llvm::fouts());
+ }
void printFileHeaders(const ELFO *Obj) override;
void printGroupSections(const ELFFile<ELFT> *Obj) override;
void printRelocations(const ELFO *Obj) override;
void printSectionHeaders(const ELFO *Obj) override;
- void printSymbols(const ELFO *Obj) override;
- void printDynamicSymbols(const ELFO *Obj) override;
+ void printSymbols(const ELFO *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) override;
+ void printHashSymbols(const ELFO *Obj) override;
+ void printDynamic(const ELFFile<ELFT> *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
void printSymtabMessage(const ELFO *Obj, StringRef Name,
size_t Offset) override;
- void printProgramHeaders(const ELFO *Obj) override;
+ void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) override;
+ void printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
+ void printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
+ void printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
@@ -379,11 +427,11 @@ public:
private:
struct Field {
- StringRef Str;
+ std::string Str;
unsigned Column;
Field(StringRef S, unsigned Col) : Str(S), Column(Col) {}
- Field(unsigned Col) : Str(""), Column(Col) {}
+ Field(unsigned Col) : Column(Col) {}
};
template <typename T, typename TEnum>
@@ -433,6 +481,8 @@ private:
void printRelocHeader(unsigned SType);
void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab,
const Elf_Rela &R, 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) override;
std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol,
@@ -442,6 +492,8 @@ private:
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);
};
template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> {
@@ -456,10 +508,18 @@ public:
void printRelocations(const ELFO *Obj) override;
void printRelocations(const Elf_Shdr *Sec, const ELFO *Obj);
void printSectionHeaders(const ELFO *Obj) override;
- void printSymbols(const ELFO *Obj) override;
- void printDynamicSymbols(const ELFO *Obj) override;
+ void printSymbols(const ELFO *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) override;
+ void printDynamic(const ELFFile<ELFT> *Obj) override;
void printDynamicRelocations(const ELFO *Obj) override;
- void printProgramHeaders(const ELFO *Obj) override;
+ void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) override;
+ void printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
+ void printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
+ void printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) override;
void printHashHistogram(const ELFFile<ELFT> *Obj) override;
void printCGProfile(const ELFFile<ELFT> *Obj) override;
void printAddrsig(const ELFFile<ELFT> *Obj) override;
@@ -471,8 +531,12 @@ public:
private:
void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab);
void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel);
+ void printSymbols(const ELFO *Obj);
+ void printDynamicSymbols(const ELFO *Obj);
void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First,
StringRef StrTable, bool IsDynamic) override;
+ void printProgramHeaders(const ELFO *Obj);
+ void printSectionMapping(const ELFO *Obj) {}
ScopedPrinter &W;
};
@@ -516,65 +580,71 @@ std::error_code createELFDumper(const object::ObjectFile *Obj,
// Iterate through the versions needed section, and place each Elf_Vernaux
// in the VersionMap according to its index.
template <class ELFT>
-void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *sec) const {
- unsigned vn_size = sec->sh_size; // Size of section in bytes
- unsigned vn_count = sec->sh_info; // Number of Verneed entries
- const char *sec_start = (const char *)ObjF->getELFFile()->base() + sec->sh_offset;
- const char *sec_end = sec_start + vn_size;
+void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *Sec) const {
+ unsigned VerneedSize = Sec->sh_size; // Size of section in bytes
+ unsigned VerneedEntries = Sec->sh_info; // Number of Verneed entries
+ const uint8_t *VerneedStart = reinterpret_cast<const uint8_t *>(
+ ObjF->getELFFile()->base() + Sec->sh_offset);
+ const uint8_t *VerneedEnd = VerneedStart + VerneedSize;
// The first Verneed entry is at the start of the section.
- const char *p = sec_start;
- for (unsigned i = 0; i < vn_count; i++) {
- if (p + sizeof(Elf_Verneed) > sec_end)
+ const uint8_t *VerneedBuf = VerneedStart;
+ for (unsigned VerneedIndex = 0; VerneedIndex < VerneedEntries;
+ ++VerneedIndex) {
+ if (VerneedBuf + sizeof(Elf_Verneed) > VerneedEnd)
report_fatal_error("Section ended unexpectedly while scanning "
"version needed records.");
- const Elf_Verneed *vn = reinterpret_cast<const Elf_Verneed *>(p);
- if (vn->vn_version != ELF::VER_NEED_CURRENT)
+ const Elf_Verneed *Verneed =
+ reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
+ if (Verneed->vn_version != ELF::VER_NEED_CURRENT)
report_fatal_error("Unexpected verneed version");
// Iterate through the Vernaux entries
- const char *paux = p + vn->vn_aux;
- for (unsigned j = 0; j < vn->vn_cnt; j++) {
- if (paux + sizeof(Elf_Vernaux) > sec_end)
+ const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
+ for (unsigned VernauxIndex = 0; VernauxIndex < Verneed->vn_cnt;
+ ++VernauxIndex) {
+ if (VernauxBuf + sizeof(Elf_Vernaux) > VerneedEnd)
report_fatal_error("Section ended unexpected while scanning auxiliary "
"version needed records.");
- const Elf_Vernaux *vna = reinterpret_cast<const Elf_Vernaux *>(paux);
- size_t index = vna->vna_other & ELF::VERSYM_VERSION;
- if (index >= VersionMap.size())
- VersionMap.resize(index + 1);
- VersionMap[index] = VersionMapEntry(vna);
- paux += vna->vna_next;
+ const Elf_Vernaux *Vernaux =
+ reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
+ size_t Index = Vernaux->vna_other & ELF::VERSYM_VERSION;
+ if (Index >= VersionMap.size())
+ VersionMap.resize(Index + 1);
+ VersionMap[Index] = VersionMapEntry(Vernaux);
+ VernauxBuf += Vernaux->vna_next;
}
- p += vn->vn_next;
+ VerneedBuf += Verneed->vn_next;
}
}
// Iterate through the version definitions, and place each Elf_Verdef
// in the VersionMap according to its index.
template <class ELFT>
-void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const {
- unsigned vd_size = sec->sh_size; // Size of section in bytes
- unsigned vd_count = sec->sh_info; // Number of Verdef entries
- const char *sec_start = (const char *)ObjF->getELFFile()->base() + sec->sh_offset;
- const char *sec_end = sec_start + vd_size;
+void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *Sec) const {
+ unsigned VerdefSize = Sec->sh_size; // Size of section in bytes
+ unsigned VerdefEntries = Sec->sh_info; // Number of Verdef entries
+ const uint8_t *VerdefStart = reinterpret_cast<const uint8_t *>(
+ ObjF->getELFFile()->base() + Sec->sh_offset);
+ const uint8_t *VerdefEnd = VerdefStart + VerdefSize;
// The first Verdef entry is at the start of the section.
- const char *p = sec_start;
- for (unsigned i = 0; i < vd_count; i++) {
- if (p + sizeof(Elf_Verdef) > sec_end)
+ const uint8_t *VerdefBuf = VerdefStart;
+ for (unsigned VerdefIndex = 0; VerdefIndex < VerdefEntries; ++VerdefIndex) {
+ if (VerdefBuf + sizeof(Elf_Verdef) > VerdefEnd)
report_fatal_error("Section ended unexpectedly while scanning "
"version definitions.");
- const Elf_Verdef *vd = reinterpret_cast<const Elf_Verdef *>(p);
- if (vd->vd_version != ELF::VER_DEF_CURRENT)
+ const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
+ if (Verdef->vd_version != ELF::VER_DEF_CURRENT)
report_fatal_error("Unexpected verdef version");
- size_t index = vd->vd_ndx & ELF::VERSYM_VERSION;
- if (index >= VersionMap.size())
- VersionMap.resize(index + 1);
- VersionMap[index] = VersionMapEntry(vd);
- p += vd->vd_next;
+ size_t Index = Verdef->vd_ndx & ELF::VERSYM_VERSION;
+ if (Index >= VersionMap.size())
+ VersionMap.resize(Index + 1);
+ VersionMap[Index] = VersionMapEntry(Verdef);
+ VerdefBuf += Verdef->vd_next;
}
}
template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const {
// If there is no dynamic symtab or version table, there is nothing to do.
- if (!DynSymRegion.Addr || !dot_gnu_version_sec)
+ if (!DynSymRegion.Addr || !SymbolVersionSection)
return;
// Has the VersionMap already been loaded?
@@ -586,243 +656,111 @@ template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const {
VersionMap.push_back(VersionMapEntry());
VersionMap.push_back(VersionMapEntry());
- if (dot_gnu_version_d_sec)
- LoadVersionDefs(dot_gnu_version_d_sec);
-
- if (dot_gnu_version_r_sec)
- LoadVersionNeeds(dot_gnu_version_r_sec);
-}
-
-template <typename ELFO, class ELFT>
-static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper, const ELFO *Obj,
- const typename ELFO::Elf_Shdr *Sec,
- ScopedPrinter &W) {
- DictScope SS(W, "Version symbols");
- if (!Sec)
- return;
- StringRef Name = unwrapOrError(Obj->getSectionName(Sec));
- W.printNumber("Section Name", Name, Sec->sh_name);
- W.printHex("Address", Sec->sh_addr);
- W.printHex("Offset", Sec->sh_offset);
- W.printNumber("Link", Sec->sh_link);
-
- const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset;
- StringRef StrTable = Dumper->getDynamicStringTable();
-
- // Same number of entries in the dynamic symbol table (DT_SYMTAB).
- ListScope Syms(W, "Symbols");
- for (const typename ELFO::Elf_Sym &Sym : Dumper->dynamic_symbols()) {
- DictScope S(W, "Symbol");
- std::string FullSymbolName =
- Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */);
- W.printNumber("Version", *P);
- W.printString("Name", FullSymbolName);
- P += sizeof(typename ELFO::Elf_Half);
- }
-}
-
-static const EnumEntry<unsigned> SymVersionFlags[] = {
- {"Base", "BASE", VER_FLG_BASE},
- {"Weak", "WEAK", VER_FLG_WEAK},
- {"Info", "INFO", VER_FLG_INFO}};
-
-template <typename ELFO, class ELFT>
-static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper,
- const ELFO *Obj,
- const typename ELFO::Elf_Shdr *Sec,
- ScopedPrinter &W) {
- using VerDef = typename ELFO::Elf_Verdef;
- using VerdAux = typename ELFO::Elf_Verdaux;
-
- DictScope SD(W, "SHT_GNU_verdef");
- if (!Sec)
- return;
-
- // The number of entries in the section SHT_GNU_verdef
- // is determined by DT_VERDEFNUM tag.
- unsigned VerDefsNum = 0;
- for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) {
- if (Dyn.d_tag == DT_VERDEFNUM) {
- VerDefsNum = Dyn.d_un.d_val;
- break;
- }
- }
-
- const uint8_t *SecStartAddress =
- (const uint8_t *)Obj->base() + Sec->sh_offset;
- const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size;
- const uint8_t *P = SecStartAddress;
- const typename ELFO::Elf_Shdr *StrTab =
- unwrapOrError(Obj->getSection(Sec->sh_link));
-
- while (VerDefsNum--) {
- if (P + sizeof(VerDef) > SecEndAddress)
- report_fatal_error("invalid offset in the section");
-
- auto *VD = reinterpret_cast<const VerDef *>(P);
- DictScope Def(W, "Definition");
- W.printNumber("Version", VD->vd_version);
- W.printEnum("Flags", VD->vd_flags, makeArrayRef(SymVersionFlags));
- W.printNumber("Index", VD->vd_ndx);
- W.printNumber("Hash", VD->vd_hash);
- W.printString("Name",
- StringRef((const char *)(Obj->base() + StrTab->sh_offset +
- VD->getAux()->vda_name)));
- if (!VD->vd_cnt)
- report_fatal_error("at least one definition string must exist");
- if (VD->vd_cnt > 2)
- report_fatal_error("more than one predecessor is not expected");
-
- if (VD->vd_cnt == 2) {
- const uint8_t *PAux = P + VD->vd_aux + VD->getAux()->vda_next;
- const VerdAux *Aux = reinterpret_cast<const VerdAux *>(PAux);
- W.printString("Predecessor",
- StringRef((const char *)(Obj->base() + StrTab->sh_offset +
- Aux->vda_name)));
- }
-
- P += VD->vd_next;
- }
-}
-
-template <typename ELFO, class ELFT>
-static void printVersionDependencySection(ELFDumper<ELFT> *Dumper,
- const ELFO *Obj,
- const typename ELFO::Elf_Shdr *Sec,
- ScopedPrinter &W) {
- using VerNeed = typename ELFO::Elf_Verneed;
- using VernAux = typename ELFO::Elf_Vernaux;
-
- DictScope SD(W, "SHT_GNU_verneed");
- if (!Sec)
- return;
-
- unsigned VerNeedNum = 0;
- for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) {
- if (Dyn.d_tag == DT_VERNEEDNUM) {
- VerNeedNum = Dyn.d_un.d_val;
- break;
- }
- }
-
- const uint8_t *SecData = (const uint8_t *)Obj->base() + Sec->sh_offset;
- const typename ELFO::Elf_Shdr *StrTab =
- unwrapOrError(Obj->getSection(Sec->sh_link));
-
- const uint8_t *P = SecData;
- for (unsigned I = 0; I < VerNeedNum; ++I) {
- const VerNeed *Need = reinterpret_cast<const VerNeed *>(P);
- DictScope Entry(W, "Dependency");
- W.printNumber("Version", Need->vn_version);
- W.printNumber("Count", Need->vn_cnt);
- W.printString("FileName",
- StringRef((const char *)(Obj->base() + StrTab->sh_offset +
- Need->vn_file)));
-
- const uint8_t *PAux = P + Need->vn_aux;
- for (unsigned J = 0; J < Need->vn_cnt; ++J) {
- const VernAux *Aux = reinterpret_cast<const VernAux *>(PAux);
- DictScope Entry(W, "Entry");
- W.printNumber("Hash", Aux->vna_hash);
- W.printEnum("Flags", Aux->vna_flags, makeArrayRef(SymVersionFlags));
- W.printNumber("Index", Aux->vna_other);
- W.printString("Name",
- StringRef((const char *)(Obj->base() + StrTab->sh_offset +
- Aux->vna_name)));
- PAux += Aux->vna_next;
- }
- P += Need->vn_next;
- }
-}
-
-template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() {
- // Dump version symbol section.
- printVersionSymbolSection(this, ObjF->getELFFile(), dot_gnu_version_sec, W);
-
- // Dump version definition section.
- printVersionDefinitionSection(this, ObjF->getELFFile(), dot_gnu_version_d_sec, W);
+ if (SymbolVersionDefSection)
+ LoadVersionDefs(SymbolVersionDefSection);
- // Dump version dependency section.
- printVersionDependencySection(this, ObjF->getELFFile(), dot_gnu_version_r_sec, W);
+ if (SymbolVersionNeedSection)
+ LoadVersionNeeds(SymbolVersionNeedSection);
}
template <typename ELFT>
StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab,
- const Elf_Sym *symb,
+ const Elf_Sym *Sym,
bool &IsDefault) const {
// This is a dynamic symbol. Look in the GNU symbol version table.
- if (!dot_gnu_version_sec) {
+ if (!SymbolVersionSection) {
// No version table.
IsDefault = false;
- return StringRef("");
+ return "";
}
// Determine the position in the symbol table of this entry.
- size_t entry_index = (reinterpret_cast<uintptr_t>(symb) -
+ size_t EntryIndex = (reinterpret_cast<uintptr_t>(Sym) -
reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) /
sizeof(Elf_Sym);
- // Get the corresponding version index entry
- const Elf_Versym *vs = unwrapOrError(
- ObjF->getELFFile()->template getEntry<Elf_Versym>(dot_gnu_version_sec, entry_index));
- size_t version_index = vs->vs_index & ELF::VERSYM_VERSION;
+ // Get the corresponding version index entry.
+ const Elf_Versym *Versym =
+ unwrapOrError(ObjF->getELFFile()->template getEntry<Elf_Versym>(
+ SymbolVersionSection, EntryIndex));
+ return this->getSymbolVersionByIndex(StrTab, Versym->vs_index, IsDefault);
+}
+
+static std::string maybeDemangle(StringRef Name) {
+ return opts::Demangle ? demangle(Name) : Name.str();
+}
+
+template <typename ELFT>
+std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
+ const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+ StringRef StrTable =
+ unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
+ Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec));
+ if (Index >= Syms.size())
+ reportError("Invalid symbol index");
+ const Elf_Sym *Sym = &Syms[Index];
+ return maybeDemangle(unwrapOrError(Sym->getName(StrTable)));
+}
+
+template <typename ELFT>
+StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab,
+ uint32_t SymbolVersionIndex,
+ bool &IsDefault) const {
+ size_t VersionIndex = SymbolVersionIndex & VERSYM_VERSION;
// Special markers for unversioned symbols.
- if (version_index == ELF::VER_NDX_LOCAL ||
- version_index == ELF::VER_NDX_GLOBAL) {
+ if (VersionIndex == VER_NDX_LOCAL || VersionIndex == VER_NDX_GLOBAL) {
IsDefault = false;
- return StringRef("");
+ return "";
}
- // Lookup this symbol in the version table
+ // Lookup this symbol in the version table.
LoadVersionMap();
- if (version_index >= VersionMap.size() || VersionMap[version_index].isNull())
+ if (VersionIndex >= VersionMap.size() || VersionMap[VersionIndex].isNull())
reportError("Invalid version entry");
- const VersionMapEntry &entry = VersionMap[version_index];
+ const VersionMapEntry &Entry = VersionMap[VersionIndex];
- // Get the version name string
- size_t name_offset;
- if (entry.isVerdef()) {
+ // Get the version name string.
+ size_t NameOffset;
+ if (Entry.isVerdef()) {
// The first Verdaux entry holds the name.
- name_offset = entry.getVerdef()->getAux()->vda_name;
- IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN);
+ NameOffset = Entry.getVerdef()->getAux()->vda_name;
+ IsDefault = !(SymbolVersionIndex & VERSYM_HIDDEN);
} else {
- name_offset = entry.getVernaux()->vna_name;
+ NameOffset = Entry.getVernaux()->vna_name;
IsDefault = false;
}
- if (name_offset >= StrTab.size())
+ if (NameOffset >= StrTab.size())
reportError("Invalid string offset");
- return StringRef(StrTab.data() + name_offset);
-}
-
-template <typename ELFT>
-StringRef ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const {
- const ELFFile<ELFT> *Obj = ObjF->getELFFile();
- StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec));
- Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec));
- if (Index >= Syms.size())
- reportError("Invalid symbol index");
- const Elf_Sym *Sym = &Syms[Index];
- return unwrapOrError(Sym->getName(StrTable));
+ return StrTab.data() + NameOffset;
}
template <typename ELFT>
std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol,
StringRef StrTable,
bool IsDynamic) const {
- StringRef SymbolName = unwrapOrError(Symbol->getName(StrTable));
+ std::string SymbolName =
+ maybeDemangle(unwrapOrError(Symbol->getName(StrTable)));
+
+ if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) {
+ unsigned SectionIndex;
+ StringRef SectionName;
+ Elf_Sym_Range Syms =
+ unwrapOrError(ObjF->getELFFile()->symbols(DotSymtabSec));
+ getSectionNameIndex(Symbol, Syms.begin(), SectionName, SectionIndex);
+ return SectionName;
+ }
+
if (!IsDynamic)
return SymbolName;
- std::string FullSymbolName(SymbolName);
-
bool IsDefault;
StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault);
if (!Version.empty()) {
- FullSymbolName += (IsDefault ? "@@" : "@");
- FullSymbolName += Version;
+ SymbolName += (IsDefault ? "@@" : "@");
+ SymbolName += Version;
}
- return FullSymbolName;
+ return SymbolName;
}
template <typename ELFT>
@@ -914,6 +852,11 @@ static const EnumEntry<unsigned> ElfOSABI[] = {
{"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE}
};
+static const EnumEntry<unsigned> SymVersionFlags[] = {
+ {"Base", "BASE", VER_FLG_BASE},
+ {"Weak", "WEAK", VER_FLG_WEAK},
+ {"Info", "INFO", VER_FLG_INFO}};
+
static const EnumEntry<unsigned> AMDGPUElfOSABI[] = {
{"AMDGPU_HSA", "AMDGPU - HSA", ELF::ELFOSABI_AMDGPU_HSA},
{"AMDGPU_PAL", "AMDGPU - PAL", ELF::ELFOSABI_AMDGPU_PAL},
@@ -1103,16 +1046,6 @@ static const EnumEntry<unsigned> ElfSymbolVisibilities[] = {
{"HIDDEN", "HIDDEN", ELF::STV_HIDDEN},
{"PROTECTED", "PROTECTED", ELF::STV_PROTECTED}};
-static const EnumEntry<unsigned> ElfSymbolTypes[] = {
- {"None", "NOTYPE", ELF::STT_NOTYPE},
- {"Object", "OBJECT", ELF::STT_OBJECT},
- {"Function", "FUNC", ELF::STT_FUNC},
- {"Section", "SECTION", ELF::STT_SECTION},
- {"File", "FILE", ELF::STT_FILE},
- {"Common", "COMMON", ELF::STT_COMMON},
- {"TLS", "TLS", ELF::STT_TLS},
- {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}};
-
static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = {
{ "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL }
};
@@ -1205,14 +1138,12 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) {
// program header type.
switch (Arch) {
case ELF::EM_ARM:
- switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX);
- }
+ switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); }
break;
case ELF::EM_MIPS:
case ELF::EM_MIPS_RS3_LE:
switch (Type) {
- LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO);
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_RTPROC);
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS);
LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_ABIFLAGS);
@@ -1233,14 +1164,15 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) {
LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_EH_FRAME);
LLVM_READOBJ_ENUM_CASE(ELF, PT_SUNW_UNWIND);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED);
- LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED);
+ LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA);
- default: return "";
+ default:
+ return "";
}
}
@@ -1368,7 +1300,11 @@ static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = {
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX902),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX904),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX906),
+ LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX908),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX909),
+ 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_XNACK),
LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_SRAM_ECC)
};
@@ -1420,68 +1356,118 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) {
}
template <typename ELFT>
-ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
- ScopedPrinter &Writer)
- : ObjDumper(Writer), ObjF(ObjF) {
- SmallVector<const Elf_Phdr *, 4> LoadSegments;
- const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) {
+ // Try to locate the PT_DYNAMIC header.
+ const Elf_Phdr *DynamicPhdr = nullptr;
for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) {
- if (Phdr.p_type == ELF::PT_DYNAMIC) {
- DynamicTable = createDRIFrom(&Phdr, sizeof(Elf_Dyn));
+ if (Phdr.p_type != ELF::PT_DYNAMIC)
continue;
- }
- if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0)
+ DynamicPhdr = &Phdr;
+ break;
+ }
+
+ // Try to locate the .dynamic section in the sections header table.
+ const Elf_Shdr *DynamicSec = nullptr;
+ for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
+ if (Sec.sh_type != ELF::SHT_DYNAMIC)
continue;
- LoadSegments.push_back(&Phdr);
+ DynamicSec = &Sec;
+ break;
+ }
+
+ // Information in the section header has priority over the information
+ // in a PT_DYNAMIC header.
+ // Ignore sh_entsize and use the expected value for entry size explicitly.
+ // This allows us to dump the dynamic sections with a broken sh_entsize
+ // field.
+ if (DynamicSec) {
+ DynamicTable = checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset,
+ DynamicSec->sh_size, sizeof(Elf_Dyn)});
+ parseDynamicTable();
}
+ // If we have a PT_DYNAMIC header, we will either check the found dynamic
+ // section or take the dynamic table data directly from the header.
+ if (!DynamicPhdr)
+ return;
+
+ if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz >
+ ObjF->getMemoryBufferRef().getBufferSize())
+ reportError(
+ "PT_DYNAMIC segment offset + size exceeds the size of the file");
+
+ if (!DynamicSec) {
+ DynamicTable = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn));
+ parseDynamicTable();
+ return;
+ }
+
+ StringRef Name = unwrapOrError(Obj->getSectionName(DynamicSec));
+ if (DynamicSec->sh_addr + DynamicSec->sh_size >
+ DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz ||
+ DynamicSec->sh_addr < DynamicPhdr->p_vaddr)
+ reportWarning("The SHT_DYNAMIC section '" + Name +
+ "' is not contained within the "
+ "PT_DYNAMIC segment");
+
+ if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr)
+ reportWarning("The SHT_DYNAMIC section '" + Name +
+ "' is not at the start of "
+ "PT_DYNAMIC segment");
+}
+
+template <typename ELFT>
+ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
+ ScopedPrinter &Writer)
+ : ObjDumper(Writer), ObjF(ObjF) {
+ const ELFFile<ELFT> *Obj = ObjF->getELFFile();
+
for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
switch (Sec.sh_type) {
case ELF::SHT_SYMTAB:
- if (DotSymtabSec != nullptr)
- reportError("Multiple SHT_SYMTAB");
- DotSymtabSec = &Sec;
+ if (!DotSymtabSec)
+ DotSymtabSec = &Sec;
break;
case ELF::SHT_DYNSYM:
- if (DynSymRegion.Size)
- reportError("Multiple SHT_DYNSYM");
- DynSymRegion = createDRIFrom(&Sec);
- // This is only used (if Elf_Shdr present)for naming section in GNU style
- DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec));
- DynamicStringTable = unwrapOrError(Obj->getStringTableForSymtab(Sec));
+ if (!DynSymRegion.Size) {
+ DynSymRegion = createDRIFrom(&Sec);
+ // This is only used (if Elf_Shdr present)for naming section in GNU
+ // style
+ DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec));
+
+ if (Expected<StringRef> E = Obj->getStringTableForSymtab(Sec))
+ DynamicStringTable = *E;
+ else
+ warn(E.takeError());
+ }
break;
case ELF::SHT_SYMTAB_SHNDX:
ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec));
break;
case ELF::SHT_GNU_versym:
- if (dot_gnu_version_sec != nullptr)
- reportError("Multiple SHT_GNU_versym");
- dot_gnu_version_sec = &Sec;
+ if (!SymbolVersionSection)
+ SymbolVersionSection = &Sec;
break;
case ELF::SHT_GNU_verdef:
- if (dot_gnu_version_d_sec != nullptr)
- reportError("Multiple SHT_GNU_verdef");
- dot_gnu_version_d_sec = &Sec;
+ if (!SymbolVersionDefSection)
+ SymbolVersionDefSection = &Sec;
break;
case ELF::SHT_GNU_verneed:
- if (dot_gnu_version_r_sec != nullptr)
- reportError("Multiple SHT_GNU_verneed");
- dot_gnu_version_r_sec = &Sec;
+ if (!SymbolVersionNeedSection)
+ SymbolVersionNeedSection = &Sec;
break;
case ELF::SHT_LLVM_CALL_GRAPH_PROFILE:
- if (DotCGProfileSec != nullptr)
- reportError("Multiple .llvm.call-graph-profile");
- DotCGProfileSec = &Sec;
+ if (!DotCGProfileSec)
+ DotCGProfileSec = &Sec;
break;
case ELF::SHT_LLVM_ADDRSIG:
- if (DotAddrsigSec != nullptr)
- reportError("Multiple .llvm_addrsig");
- DotAddrsigSec = &Sec;
+ if (!DotAddrsigSec)
+ DotAddrsigSec = &Sec;
break;
}
}
- parseDynamicTable(LoadSegments);
+ loadDynamicTable(Obj);
if (opts::Output == opts::GNU)
ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this));
@@ -1489,13 +1475,84 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF,
ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this));
}
-template <typename ELFT>
-void ELFDumper<ELFT>::parseDynamicTable(
- ArrayRef<const Elf_Phdr *> LoadSegments) {
- auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * {
+static const char *getTypeString(unsigned Arch, uint64_t Type) {
+#define DYNAMIC_TAG(n, v)
+ switch (Arch) {
+
+ case EM_AARCH64:
+ switch (Type) {
+#define AARCH64_DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef AARCH64_DYNAMIC_TAG
+ }
+ break;
+
+ case EM_HEXAGON:
+ switch (Type) {
+#define HEXAGON_DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef HEXAGON_DYNAMIC_TAG
+ }
+ break;
+
+ case EM_MIPS:
+ switch (Type) {
+#define MIPS_DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef MIPS_DYNAMIC_TAG
+ }
+ break;
+
+ case EM_PPC64:
+ switch (Type) {
+#define PPC64_DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef PPC64_DYNAMIC_TAG
+ }
+ break;
+ }
+#undef DYNAMIC_TAG
+ switch (Type) {
+// Now handle all dynamic tags except the architecture specific ones
+#define AARCH64_DYNAMIC_TAG(name, value)
+#define MIPS_DYNAMIC_TAG(name, value)
+#define HEXAGON_DYNAMIC_TAG(name, value)
+#define PPC64_DYNAMIC_TAG(name, value)
+// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc.
+#define DYNAMIC_TAG_MARKER(name, value)
+#define DYNAMIC_TAG(name, value) \
+ case DT_##name: \
+ return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef DYNAMIC_TAG
+#undef AARCH64_DYNAMIC_TAG
+#undef MIPS_DYNAMIC_TAG
+#undef HEXAGON_DYNAMIC_TAG
+#undef PPC64_DYNAMIC_TAG
+#undef DYNAMIC_TAG_MARKER
+ default:
+ return "unknown";
+ }
+}
+
+template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() {
+ auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * {
auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr);
- if (!MappedAddrOrError)
- report_fatal_error(MappedAddrOrError.takeError());
+ if (!MappedAddrOrError) {
+ reportWarning("Unable to parse DT_" +
+ Twine(getTypeString(
+ ObjF->getELFFile()->getHeader()->e_machine, Tag)) +
+ ": " + llvm::toString(MappedAddrOrError.takeError()));
+ return nullptr;
+ }
return MappedAddrOrError.get();
};
@@ -1505,25 +1562,26 @@ void ELFDumper<ELFT>::parseDynamicTable(
for (const Elf_Dyn &Dyn : dynamic_table()) {
switch (Dyn.d_tag) {
case ELF::DT_HASH:
- HashTable =
- reinterpret_cast<const Elf_Hash *>(toMappedAddr(Dyn.getPtr()));
+ HashTable = reinterpret_cast<const Elf_Hash *>(
+ toMappedAddr(Dyn.getTag(), Dyn.getPtr()));
break;
case ELF::DT_GNU_HASH:
- GnuHashTable =
- reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr()));
+ GnuHashTable = reinterpret_cast<const Elf_GnuHash *>(
+ toMappedAddr(Dyn.getTag(), Dyn.getPtr()));
break;
case ELF::DT_STRTAB:
- StringTableBegin = (const char *)toMappedAddr(Dyn.getPtr());
+ StringTableBegin = reinterpret_cast<const char *>(
+ toMappedAddr(Dyn.getTag(), Dyn.getPtr()));
break;
case ELF::DT_STRSZ:
StringTableSize = Dyn.getVal();
break;
case ELF::DT_SYMTAB:
- DynSymRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynSymRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
DynSymRegion.EntSize = sizeof(Elf_Sym);
break;
case ELF::DT_RELA:
- DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELASZ:
DynRelaRegion.Size = Dyn.getVal();
@@ -1535,7 +1593,7 @@ void ELFDumper<ELFT>::parseDynamicTable(
SONameOffset = Dyn.getVal();
break;
case ELF::DT_REL:
- DynRelRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELSZ:
DynRelRegion.Size = Dyn.getVal();
@@ -1545,7 +1603,7 @@ void ELFDumper<ELFT>::parseDynamicTable(
break;
case ELF::DT_RELR:
case ELF::DT_ANDROID_RELR:
- DynRelrRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynRelrRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_RELRSZ:
case ELF::DT_ANDROID_RELRSZ:
@@ -1565,7 +1623,7 @@ void ELFDumper<ELFT>::parseDynamicTable(
Twine((uint64_t)Dyn.getVal()));
break;
case ELF::DT_JMPREL:
- DynPLTRelRegion.Addr = toMappedAddr(Dyn.getPtr());
+ DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr());
break;
case ELF::DT_PLTRELSZ:
DynPLTRelRegion.Size = Dyn.getVal();
@@ -1574,8 +1632,8 @@ void ELFDumper<ELFT>::parseDynamicTable(
}
if (StringTableBegin)
DynamicStringTable = StringRef(StringTableBegin, StringTableSize);
- if (SONameOffset)
- SOName = getDynamicString(SONameOffset);
+ if (SONameOffset && SONameOffset < DynamicStringTable.size())
+ SOName = DynamicStringTable.data() + SONameOffset;
}
template <typename ELFT>
@@ -1593,37 +1651,52 @@ typename ELFDumper<ELFT>::Elf_Relr_Range ELFDumper<ELFT>::dyn_relrs() const {
return DynRelrRegion.getAsArrayRef<Elf_Relr>();
}
-template<class ELFT>
-void ELFDumper<ELFT>::printFileHeaders() {
+template <class ELFT> void ELFDumper<ELFT>::printFileHeaders() {
ELFDumperStyle->printFileHeaders(ObjF->getELFFile());
}
-template<class ELFT>
-void ELFDumper<ELFT>::printSectionHeaders() {
+template <class ELFT> void ELFDumper<ELFT>::printSectionHeaders() {
ELFDumperStyle->printSectionHeaders(ObjF->getELFFile());
}
-template<class ELFT>
-void ELFDumper<ELFT>::printRelocations() {
+template <class ELFT> void ELFDumper<ELFT>::printRelocations() {
ELFDumperStyle->printRelocations(ObjF->getELFFile());
}
-template <class ELFT> void ELFDumper<ELFT>::printProgramHeaders() {
- ELFDumperStyle->printProgramHeaders(ObjF->getELFFile());
+template <class ELFT>
+void ELFDumper<ELFT>::printProgramHeaders(
+ bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) {
+ ELFDumperStyle->printProgramHeaders(ObjF->getELFFile(), PrintProgramHeaders,
+ PrintSectionMapping);
+}
+
+template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() {
+ // Dump version symbol section.
+ ELFDumperStyle->printVersionSymbolSection(ObjF->getELFFile(),
+ SymbolVersionSection);
+
+ // Dump version definition section.
+ ELFDumperStyle->printVersionDefinitionSection(ObjF->getELFFile(),
+ SymbolVersionDefSection);
+
+ // Dump version dependency section.
+ ELFDumperStyle->printVersionDependencySection(ObjF->getELFFile(),
+ SymbolVersionNeedSection);
}
template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() {
ELFDumperStyle->printDynamicRelocations(ObjF->getELFFile());
}
-template<class ELFT>
-void ELFDumper<ELFT>::printSymbols() {
- ELFDumperStyle->printSymbols(ObjF->getELFFile());
+template <class ELFT>
+void ELFDumper<ELFT>::printSymbols(bool PrintSymbols,
+ bool PrintDynamicSymbols) {
+ ELFDumperStyle->printSymbols(ObjF->getELFFile(), PrintSymbols,
+ PrintDynamicSymbols);
}
-template<class ELFT>
-void ELFDumper<ELFT>::printDynamicSymbols() {
- ELFDumperStyle->printDynamicSymbols(ObjF->getELFFile());
+template <class ELFT> void ELFDumper<ELFT>::printHashSymbols() {
+ ELFDumperStyle->printHashSymbols(ObjF->getELFFile());
}
template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() {
@@ -1642,61 +1715,7 @@ template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() {
ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile());
}
-static const char *getTypeString(unsigned Arch, uint64_t Type) {
-#define DYNAMIC_TAG(n, v)
- switch (Arch) {
- case EM_HEXAGON:
- switch (Type) {
-#define HEXAGON_DYNAMIC_TAG(name, value) \
- case DT_##name: \
- return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef HEXAGON_DYNAMIC_TAG
- }
- break;
-
- case EM_MIPS:
- switch (Type) {
-#define MIPS_DYNAMIC_TAG(name, value) \
- case DT_##name: \
- return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef MIPS_DYNAMIC_TAG
- }
- break;
-
- case EM_PPC64:
- switch(Type) {
-#define PPC64_DYNAMIC_TAG(name, value) \
- case DT_##name: \
- return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef PPC64_DYNAMIC_TAG
- }
- break;
- }
-#undef DYNAMIC_TAG
- switch (Type) {
-// Now handle all dynamic tags except the architecture specific ones
-#define MIPS_DYNAMIC_TAG(name, value)
-#define HEXAGON_DYNAMIC_TAG(name, value)
-#define PPC64_DYNAMIC_TAG(name, value)
-// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc.
-#define DYNAMIC_TAG_MARKER(name, value)
-#define DYNAMIC_TAG(name, value) \
- case DT_##name: \
- return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef DYNAMIC_TAG
-#undef MIPS_DYNAMIC_TAG
-#undef HEXAGON_DYNAMIC_TAG
-#undef PPC64_DYNAMIC_TAG
-#undef DYNAMIC_TAG_MARKER
- default: return "unknown";
- }
-}
-
-#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \
+#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \
{ #enum, prefix##_##enum }
static const EnumEntry<unsigned> ElfDynamicDTFlags[] = {
@@ -1724,6 +1743,7 @@ static const EnumEntry<unsigned> ElfDynamicDTFlags1[] = {
LLVM_READOBJ_DT_FLAG_ENT(DF_1, CONFALT),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, ENDFILTEE),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, DISPRELDNE),
+ LLVM_READOBJ_DT_FLAG_ENT(DF_1, DISPRELPND),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODIRECT),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, IGNMULDEF),
LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOKSYMS),
@@ -1776,20 +1796,97 @@ void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) {
}
template <class ELFT>
-StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const {
- if (Value >= DynamicStringTable.size())
- reportError("Invalid dynamic string table reference");
- return StringRef(DynamicStringTable.data() + Value);
-}
+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;
-static void printLibrary(raw_ostream &OS, const Twine &Tag, const Twine &Name) {
- OS << Tag << ": [" << Name << "]";
-}
+ // Handle custom printing of architecture specific tags
+ switch (ObjF->getELFFile()->getHeader()->e_machine) {
+ case EM_AARCH64:
+ switch (Type) {
+ case DT_AARCH64_BTI_PLT:
+ case DT_AARCH64_PAC_PLT:
+ OS << Value;
+ return;
+ default:
+ break;
+ }
+ break;
+ case EM_HEXAGON:
+ switch (Type) {
+ case DT_HEXAGON_VER:
+ OS << Value;
+ return;
+ case DT_HEXAGON_SYMSZ:
+ case DT_HEXAGON_PLT:
+ OS << format(ConvChar, Value);
+ return;
+ default:
+ break;
+ }
+ break;
+ case EM_MIPS:
+ switch (Type) {
+ case DT_MIPS_RLD_VERSION:
+ case DT_MIPS_LOCAL_GOTNO:
+ case DT_MIPS_SYMTABNO:
+ case DT_MIPS_UNREFEXTNO:
+ OS << Value;
+ return;
+ case DT_MIPS_TIME_STAMP:
+ case DT_MIPS_ICHECKSUM:
+ case DT_MIPS_IVERSION:
+ case DT_MIPS_BASE_ADDRESS:
+ case DT_MIPS_MSYM:
+ case DT_MIPS_CONFLICT:
+ case DT_MIPS_LIBLIST:
+ case DT_MIPS_CONFLICTNO:
+ case DT_MIPS_LIBLISTNO:
+ case DT_MIPS_GOTSYM:
+ case DT_MIPS_HIPAGENO:
+ case DT_MIPS_RLD_MAP:
+ case DT_MIPS_DELTA_CLASS:
+ case DT_MIPS_DELTA_CLASS_NO:
+ case DT_MIPS_DELTA_INSTANCE:
+ case DT_MIPS_DELTA_RELOC:
+ case DT_MIPS_DELTA_RELOC_NO:
+ case DT_MIPS_DELTA_SYM:
+ case DT_MIPS_DELTA_SYM_NO:
+ case DT_MIPS_DELTA_CLASSSYM:
+ case DT_MIPS_DELTA_CLASSSYM_NO:
+ case DT_MIPS_CXX_FLAGS:
+ case DT_MIPS_PIXIE_INIT:
+ case DT_MIPS_SYMBOL_LIB:
+ case DT_MIPS_LOCALPAGE_GOTIDX:
+ case DT_MIPS_LOCAL_GOTIDX:
+ case DT_MIPS_HIDDEN_GOTIDX:
+ case DT_MIPS_PROTECTED_GOTIDX:
+ case DT_MIPS_OPTIONS:
+ case DT_MIPS_INTERFACE:
+ case DT_MIPS_DYNSTR_ALIGN:
+ case DT_MIPS_INTERFACE_SIZE:
+ case DT_MIPS_RLD_TEXT_RESOLVE_ADDR:
+ case DT_MIPS_PERF_SUFFIX:
+ case DT_MIPS_COMPACT_SIZE:
+ case DT_MIPS_GP_VALUE:
+ case DT_MIPS_AUX_DYNAMIC:
+ case DT_MIPS_PLTGOT:
+ case DT_MIPS_RWPLT:
+ case DT_MIPS_RLD_MAP_REL:
+ OS << format(ConvChar, Value);
+ return;
+ case DT_MIPS_FLAGS:
+ printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS);
+ return;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
-template <class ELFT>
-void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
- raw_ostream &OS = W.getOStream();
- const char* ConvChar = (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64;
switch (Type) {
case DT_PLTREL:
if (Value == DT_REL) {
@@ -1818,22 +1915,12 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
case DT_VERSYM:
case DT_GNU_HASH:
case DT_NULL:
- case DT_MIPS_BASE_ADDRESS:
- case DT_MIPS_GOTSYM:
- case DT_MIPS_RLD_MAP:
- case DT_MIPS_RLD_MAP_REL:
- case DT_MIPS_PLTGOT:
- case DT_MIPS_OPTIONS:
OS << format(ConvChar, Value);
break;
case DT_RELACOUNT:
case DT_RELCOUNT:
case DT_VERDEFNUM:
case DT_VERNEEDNUM:
- case DT_MIPS_RLD_VERSION:
- case DT_MIPS_LOCAL_GOTNO:
- case DT_MIPS_SYMTABNO:
- case DT_MIPS_UNREFEXTNO:
OS << Value;
break;
case DT_PLTRELSZ:
@@ -1851,24 +1938,30 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
OS << Value << " (bytes)";
break;
case DT_NEEDED:
- printLibrary(OS, "Shared library", getDynamicString(Value));
- break;
case DT_SONAME:
- printLibrary(OS, "Library soname", getDynamicString(Value));
- break;
case DT_AUXILIARY:
- printLibrary(OS, "Auxiliary library", getDynamicString(Value));
- break;
+ case DT_USED:
case DT_FILTER:
- printLibrary(OS, "Filter library", getDynamicString(Value));
- break;
case DT_RPATH:
- case DT_RUNPATH:
- OS << getDynamicString(Value);
- break;
- case DT_MIPS_FLAGS:
- printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS);
+ 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"},
+ };
+ OS << TagNames.at(Type) << ": ";
+ if (DynamicStringTable.empty())
+ OS << "<String table is empty or was not found> ";
+ else if (Value < DynamicStringTable.size())
+ OS << "[" << StringRef(DynamicStringTable.data() + Value) << "]";
+ else
+ OS << "<Invalid offset 0x" << utohexstr(Value) << ">";
break;
+ }
case DT_FLAGS:
printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS);
break;
@@ -1881,14 +1974,9 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) {
}
}
-template<class ELFT>
-void ELFDumper<ELFT>::printUnwindInfo() {
- const unsigned Machine = ObjF->getELFFile()->getHeader()->e_machine;
- if (Machine == EM_386 || Machine == EM_X86_64) {
- DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF);
- return Ctx.printUnwindInformation();
- }
- W.startLine() << "UnwindInfo not implemented.\n";
+template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() {
+ DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF);
+ Ctx.printUnwindInformation();
}
namespace {
@@ -1898,73 +1986,40 @@ template <> void ELFDumper<ELF32LE>::printUnwindInfo() {
const unsigned Machine = Obj->getHeader()->e_machine;
if (Machine == EM_ARM) {
ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, DotSymtabSec);
- return Ctx.PrintUnwindInformation();
+ Ctx.PrintUnwindInformation();
}
- W.startLine() << "UnwindInfo not implemented.\n";
+ DwarfCFIEH::PrinterContext<ELF32LE> Ctx(W, ObjF);
+ Ctx.printUnwindInformation();
}
} // end anonymous namespace
-template<class ELFT>
-void ELFDumper<ELFT>::printDynamicTable() {
- auto I = dynamic_table().begin();
- auto E = dynamic_table().end();
-
- if (I == E)
- return;
-
- --E;
- while (I != E && E->getTag() == ELF::DT_NULL)
- --E;
- if (E->getTag() != ELF::DT_NULL)
- ++E;
- ++E;
-
- ptrdiff_t Total = std::distance(I, E);
- if (Total == 0)
- return;
-
- raw_ostream &OS = W.getOStream();
- W.startLine() << "DynamicSection [ (" << Total << " entries)\n";
-
- bool Is64 = ELFT::Is64Bits;
-
- W.startLine()
- << " Tag" << (Is64 ? " " : " ") << "Type"
- << " " << "Name/Value\n";
- while (I != E) {
- const Elf_Dyn &Entry = *I;
- uintX_t Tag = Entry.getTag();
- ++I;
- W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, opts::Output != opts::GNU) << " "
- << format("%-21s", getTypeString(ObjF->getELFFile()->getHeader()->e_machine, Tag));
- printValue(Tag, Entry.getVal());
- OS << "\n";
- }
-
- W.startLine() << "]\n";
+template <class ELFT> void ELFDumper<ELFT>::printDynamicTable() {
+ ELFDumperStyle->printDynamic(ObjF->getELFFile());
}
-template<class ELFT>
-void ELFDumper<ELFT>::printNeededLibraries() {
+template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() {
ListScope D(W, "NeededLibraries");
using LibsTy = std::vector<StringRef>;
LibsTy Libs;
for (const auto &Entry : dynamic_table())
- if (Entry.d_tag == ELF::DT_NEEDED)
- Libs.push_back(getDynamicString(Entry.d_un.d_val));
+ if (Entry.d_tag == ELF::DT_NEEDED) {
+ uint64_t Value = Entry.d_un.d_val;
+ if (Value < DynamicStringTable.size())
+ Libs.push_back(StringRef(DynamicStringTable.data() + Value));
+ else
+ Libs.push_back("<Library name index out of range>");
+ }
- std::stable_sort(Libs.begin(), Libs.end());
+ llvm::stable_sort(Libs);
for (const auto &L : Libs)
- W.startLine() << L << "\n";
+ W.startLine() << L << "\n";
}
-
-template <typename ELFT>
-void ELFDumper<ELFT>::printHashTable() {
+template <typename ELFT> void ELFDumper<ELFT>::printHashTable() {
DictScope D(W, "HashTable");
if (!HashTable)
return;
@@ -1974,8 +2029,7 @@ void ELFDumper<ELFT>::printHashTable() {
W.printList("Chains", HashTable->chains());
}
-template <typename ELFT>
-void ELFDumper<ELFT>::printGnuHashTable() {
+template <typename ELFT> void ELFDumper<ELFT>::printGnuHashTable() {
DictScope D(W, "GnuHashTable");
if (!GnuHashTable)
return;
@@ -1996,8 +2050,7 @@ template <typename ELFT> void ELFDumper<ELFT>::printLoadName() {
W.printString("LoadName", SOName);
}
-template <class ELFT>
-void ELFDumper<ELFT>::printAttributes() {
+template <class ELFT> void ELFDumper<ELFT>::printAttributes() {
W.startLine() << "Attributes not implemented.\n";
}
@@ -2486,7 +2539,7 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const {
unwrapOrError(Obj->getSectionContents(StackMapSection));
prettyPrintStackMap(
- W, StackMapV2Parser<ELFT::TargetEndianness>(StackMapContentsArray));
+ W, StackMapParser<ELFT::TargetEndianness>(StackMapContentsArray));
}
template <class ELFT> void ELFDumper<ELFT>::printGroupSections() {
@@ -2527,7 +2580,8 @@ static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj) {
ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(Obj->sections());
if (Arr.empty())
return "65535 (corrupt: out of range)";
- return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) + ")";
+ return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) +
+ ")";
}
template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
@@ -2599,7 +2653,7 @@ struct GroupMember {
struct GroupSection {
StringRef Name;
- StringRef Signature;
+ std::string Signature;
uint64_t ShName;
uint64_t Index;
uint32_t Link;
@@ -2630,13 +2684,13 @@ std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) {
StringRef Name = unwrapOrError(Obj->getSectionName(&Sec));
StringRef Signature = StrTable.data() + Sym->st_name;
- Ret.push_back({Name,
- Signature,
- Sec.sh_name,
+ Ret.push_back({Name,
+ maybeDemangle(Signature),
+ Sec.sh_name,
I - 1,
Sec.sh_link,
Sec.sh_info,
- Data[0],
+ Data[0],
{}});
std::vector<GroupMember> &GM = Ret.back().Members;
@@ -2691,53 +2745,57 @@ 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) {
- std::string Offset, Info, Addend, Value;
- SmallString<32> RelocName;
- StringRef TargetName;
- const Elf_Sym *Sym = nullptr;
- unsigned Width = ELFT::Is64Bits ? 16 : 8;
- unsigned Bias = ELFT::Is64Bits ? 8 : 0;
-
- // First two fields are bit width dependent. The rest of them are after are
- // fixed width.
- Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias};
- Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
- Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab));
+ const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab));
+ std::string TargetName;
if (Sym && Sym->getType() == ELF::STT_SECTION) {
const Elf_Shdr *Sec = unwrapOrError(
Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable()));
TargetName = unwrapOrError(Obj->getSectionName(Sec));
} else if (Sym) {
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
- TargetName = unwrapOrError(Sym->getName(StrTable));
+ TargetName = this->dumper()->getFullSymbolName(
+ Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);
}
+ printRelocation(Obj, Sym, TargetName, R, IsRela);
+}
- if (Sym && IsRela) {
- if (R.r_addend < 0)
- Addend = " - ";
- else
- Addend = " + ";
- }
+template <class ELFT>
+void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Sym *Sym,
+ StringRef SymbolName, const Elf_Rela &R,
+ bool IsRela) {
+ // First two fields are bit width dependent. The rest of them are fixed width.
+ unsigned Bias = ELFT::Is64Bits ? 8 : 0;
+ Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias};
+ unsigned Width = ELFT::Is64Bits ? 16 : 8;
- Offset = to_string(format_hex_no_prefix(R.r_offset, Width));
- Info = to_string(format_hex_no_prefix(R.r_info, Width));
+ Fields[0].Str = to_string(format_hex_no_prefix(R.r_offset, Width));
+ Fields[1].Str = to_string(format_hex_no_prefix(R.r_info, Width));
- int64_t RelAddend = R.r_addend;
- if (IsRela)
- Addend += to_hexString(std::abs(RelAddend), false);
+ SmallString<32> RelocName;
+ Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
+ Fields[2].Str = RelocName.c_str();
- if (Sym)
- Value = to_string(format_hex_no_prefix(Sym->getValue(), Width));
+ if (Sym && (!SymbolName.empty() || Sym->getValue() != 0))
+ Fields[3].Str = to_string(format_hex_no_prefix(Sym->getValue(), Width));
- Fields[0].Str = Offset;
- Fields[1].Str = Info;
- Fields[2].Str = RelocName;
- Fields[3].Str = Value;
- Fields[4].Str = TargetName;
- for (auto &field : Fields)
- printField(field);
- OS << Addend;
- OS << "\n";
+ Fields[4].Str = SymbolName;
+ for (const Field &F : Fields)
+ printField(F);
+
+ std::string Addend;
+ if (IsRela) {
+ int64_t RelAddend = R.r_addend;
+ if (!SymbolName.empty()) {
+ if (R.r_addend < 0) {
+ Addend = " - ";
+ RelAddend = std::abs(RelAddend);
+ } else
+ Addend = " + ";
+ }
+
+ Addend += to_hexString(RelAddend, false);
+ }
+ OS << Addend << "\n";
}
template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) {
@@ -2764,10 +2822,8 @@ 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(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 &&
+ 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 &&
Sec.sh_type != ELF::SHT_ANDROID_RELR)
continue;
@@ -2832,7 +2888,21 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) {
OS << "\nThere are no relocations in this file.\n";
}
-std::string getSectionTypeString(unsigned Arch, unsigned Type) {
+// Print the offset of a particular section from anyone of the ranges:
+// [SHT_LOOS, SHT_HIOS], [SHT_LOPROC, SHT_HIPROC], [SHT_LOUSER, SHT_HIUSER].
+// If 'Type' does not fall within any of those ranges, then a string is
+// returned as '<unknown>' followed by the type value.
+static std::string getSectionTypeOffsetString(unsigned Type) {
+ if (Type >= SHT_LOOS && Type <= SHT_HIOS)
+ return "LOOS+0x" + to_hexString(Type - SHT_LOOS);
+ else if (Type >= SHT_LOPROC && Type <= SHT_HIPROC)
+ return "LOPROC+0x" + to_hexString(Type - SHT_LOPROC);
+ else if (Type >= SHT_LOUSER && Type <= SHT_HIUSER)
+ return "LOUSER+0x" + to_hexString(Type - SHT_LOUSER);
+ return "0x" + to_hexString(Type) + ": <unknown>";
+}
+
+static std::string getSectionTypeString(unsigned Arch, unsigned Type) {
using namespace ELF;
switch (Arch) {
@@ -2863,10 +2933,10 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "MIPS_REGINFO";
case SHT_MIPS_OPTIONS:
return "MIPS_OPTIONS";
+ case SHT_MIPS_DWARF:
+ return "MIPS_DWARF";
case SHT_MIPS_ABIFLAGS:
return "MIPS_ABIFLAGS";
- case SHT_MIPS_DWARF:
- return "SHT_MIPS_DWARF";
}
break;
}
@@ -2905,6 +2975,10 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "GROUP";
case SHT_SYMTAB_SHNDX:
return "SYMTAB SECTION INDICES";
+ case SHT_ANDROID_REL:
+ return "ANDROID_REL";
+ case SHT_ANDROID_RELA:
+ return "ANDROID_RELA";
case SHT_RELR:
case SHT_ANDROID_RELR:
return "RELR";
@@ -2916,6 +2990,8 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
return "LLVM_CALL_GRAPH_PROFILE";
case SHT_LLVM_ADDRSIG:
return "LLVM_ADDRSIG";
+ case SHT_LLVM_DEPENDENT_LIBRARIES:
+ return "LLVM_DEPENDENT_LIBRARIES";
// FIXME: Parse processor specific GNU attributes
case SHT_GNU_ATTRIBUTES:
return "ATTRIBUTES";
@@ -2928,69 +3004,65 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) {
case SHT_GNU_versym:
return "VERSYM";
default:
- return "";
+ return getSectionTypeOffsetString(Type);
}
return "";
}
template <class ELFT>
-void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
- size_t SectionIndex = 0;
- std::string Number, Type, Size, Address, Offset, Flags, Link, Info, EntrySize,
- Alignment;
- unsigned Bias;
- unsigned Width;
-
- if (ELFT::Is64Bits) {
- Bias = 0;
- Width = 16;
- } else {
- Bias = 8;
- Width = 8;
- }
+static StringRef getSectionName(const typename ELFT::Shdr &Sec,
+ const ELFObjectFile<ELFT> &ElfObj,
+ ArrayRef<typename ELFT::Shdr> Sections) {
+ const ELFFile<ELFT> &Obj = *ElfObj.getELFFile();
+ uint32_t Index = Obj.getHeader()->e_shstrndx;
+ if (Index == ELF::SHN_XINDEX)
+ Index = Sections[0].sh_link;
+ if (!Index) // no section string table.
+ return "";
+ // TODO: Test a case when the sh_link of the section with index 0 is broken.
+ if (Index >= Sections.size())
+ reportError(ElfObj.getFileName(),
+ createError("section header string table index " +
+ Twine(Index) + " does not exist"));
+ StringRef Data = toStringRef(unwrapOrError(
+ Obj.template getSectionContentsAsArray<uint8_t>(&Sections[Index])));
+ return unwrapOrError(Obj.getSectionName(&Sec, Data));
+}
+template <class ELFT>
+void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
+ unsigned Bias = ELFT::Is64Bits ? 0 : 8;
ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections());
OS << "There are " << to_string(Sections.size())
<< " section headers, starting at offset "
<< "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n";
OS << "Section Headers:\n";
- Field Fields[11] = {{"[Nr]", 2},
- {"Name", 7},
- {"Type", 25},
- {"Address", 41},
- {"Off", 58 - Bias},
- {"Size", 65 - Bias},
- {"ES", 72 - Bias},
- {"Flg", 75 - Bias},
- {"Lk", 79 - Bias},
- {"Inf", 82 - Bias},
- {"Al", 86 - Bias}};
- for (auto &f : Fields)
- printField(f);
+ Field Fields[11] = {
+ {"[Nr]", 2}, {"Name", 7}, {"Type", 25},
+ {"Address", 41}, {"Off", 58 - Bias}, {"Size", 65 - Bias},
+ {"ES", 72 - Bias}, {"Flg", 75 - Bias}, {"Lk", 79 - Bias},
+ {"Inf", 82 - Bias}, {"Al", 86 - Bias}};
+ for (auto &F : Fields)
+ printField(F);
OS << "\n";
+ const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
+ size_t SectionIndex = 0;
for (const Elf_Shdr &Sec : Sections) {
- Number = to_string(SectionIndex);
- Fields[0].Str = Number;
- Fields[1].Str = unwrapOrError(Obj->getSectionName(&Sec));
- Type = getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type);
- Fields[2].Str = Type;
- Address = to_string(format_hex_no_prefix(Sec.sh_addr, Width));
- Fields[3].Str = Address;
- Offset = to_string(format_hex_no_prefix(Sec.sh_offset, 6));
- Fields[4].Str = Offset;
- Size = to_string(format_hex_no_prefix(Sec.sh_size, 6));
- Fields[5].Str = Size;
- EntrySize = to_string(format_hex_no_prefix(Sec.sh_entsize, 2));
- Fields[6].Str = EntrySize;
- Flags = getGNUFlags(Sec.sh_flags);
- Fields[7].Str = Flags;
- Link = to_string(Sec.sh_link);
- Fields[8].Str = Link;
- Info = to_string(Sec.sh_info);
- Fields[9].Str = Info;
- Alignment = to_string(Sec.sh_addralign);
- Fields[10].Str = Alignment;
+ Fields[0].Str = to_string(SectionIndex);
+ Fields[1].Str = getSectionName(Sec, *ElfObj, Sections);
+ Fields[2].Str =
+ getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type);
+ Fields[3].Str =
+ to_string(format_hex_no_prefix(Sec.sh_addr, ELFT::Is64Bits ? 16 : 8));
+ Fields[4].Str = to_string(format_hex_no_prefix(Sec.sh_offset, 6));
+ Fields[5].Str = to_string(format_hex_no_prefix(Sec.sh_size, 6));
+ Fields[6].Str = to_string(format_hex_no_prefix(Sec.sh_entsize, 2));
+ Fields[7].Str = getGNUFlags(Sec.sh_flags);
+ Fields[8].Str = to_string(Sec.sh_link);
+ Fields[9].Str = to_string(Sec.sh_info);
+ Fields[10].Str = to_string(Sec.sh_addralign);
+
OS.PadToColumn(Fields[0].Column);
OS << "[" << right_justify(Fields[0].Str, 2) << "]";
for (int i = 1; i < 7; i++)
@@ -3043,9 +3115,10 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj,
case ELF::SHN_COMMON:
return "COM";
case ELF::SHN_XINDEX:
- SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>(
- Symbol, FirstSym, this->dumper()->getShndxTable()));
- LLVM_FALLTHROUGH;
+ return to_string(
+ format_decimal(unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>(
+ Symbol, FirstSym, this->dumper()->getShndxTable())),
+ 3));
default:
// Find if:
// Processor specific
@@ -3072,7 +3145,6 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
bool IsDynamic) {
static int Idx = 0;
static bool Dynamic = true;
- size_t Width;
// If this function was called with a different value from IsDynamic
// from last call, happens when we move from dynamic to static symbol
@@ -3081,111 +3153,87 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
Idx = 0;
Dynamic = false;
}
- std::string Num, Name, Value, Size, Binding, Type, Visibility, Section;
- unsigned Bias = 0;
- if (ELFT::Is64Bits) {
- Bias = 8;
- Width = 16;
- } else {
- Bias = 0;
- Width = 8;
- }
+
+ unsigned Bias = ELFT::Is64Bits ? 8 : 0;
Field Fields[8] = {0, 8, 17 + Bias, 23 + Bias,
31 + Bias, 38 + Bias, 47 + Bias, 51 + Bias};
- Num = to_string(format_decimal(Idx++, 6)) + ":";
- Value = to_string(format_hex_no_prefix(Symbol->st_value, Width));
- Size = to_string(format_decimal(Symbol->st_size, 5));
+ Fields[0].Str = to_string(format_decimal(Idx++, 6)) + ":";
+ Fields[1].Str = to_string(
+ format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 8));
+ Fields[2].Str = to_string(format_decimal(Symbol->st_size, 5));
+
unsigned char SymbolType = Symbol->getType();
if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU &&
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
- Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
+ Fields[3].Str = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
else
- Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
- unsigned Vis = Symbol->getVisibility();
- Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
- Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities));
- Section = getSymbolSectionNdx(Obj, Symbol, FirstSym);
- Name = this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
- Fields[0].Str = Num;
- Fields[1].Str = Value;
- Fields[2].Str = Size;
- Fields[3].Str = Type;
- Fields[4].Str = Binding;
- Fields[5].Str = Visibility;
- Fields[6].Str = Section;
- Fields[7].Str = Name;
+ Fields[3].Str = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
+
+ Fields[4].Str =
+ printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
+ Fields[5].Str =
+ printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities));
+ Fields[6].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym);
+ Fields[7].Str =
+ this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic);
for (auto &Entry : Fields)
printField(Entry);
OS << "\n";
}
+
template <class ELFT>
void GNUStyle<ELFT>::printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym,
uint32_t Sym, StringRef StrTable,
uint32_t Bucket) {
- std::string Num, Buc, Name, Value, Size, Binding, Type, Visibility, Section;
- unsigned Width, Bias = 0;
- if (ELFT::Is64Bits) {
- Bias = 8;
- Width = 16;
- } else {
- Bias = 0;
- Width = 8;
- }
+ unsigned Bias = ELFT::Is64Bits ? 8 : 0;
Field Fields[9] = {0, 6, 11, 20 + Bias, 25 + Bias,
34 + Bias, 41 + Bias, 49 + Bias, 53 + Bias};
- Num = to_string(format_decimal(Sym, 5));
- Buc = to_string(format_decimal(Bucket, 3)) + ":";
+ Fields[0].Str = to_string(format_decimal(Sym, 5));
+ Fields[1].Str = to_string(format_decimal(Bucket, 3)) + ":";
const auto Symbol = FirstSym + Sym;
- Value = to_string(format_hex_no_prefix(Symbol->st_value, Width));
- Size = to_string(format_decimal(Symbol->st_size, 5));
+ Fields[2].Str = to_string(
+ format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 18 : 8));
+ Fields[3].Str = to_string(format_decimal(Symbol->st_size, 5));
+
unsigned char SymbolType = Symbol->getType();
if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU &&
SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS)
- Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
+ Fields[4].Str = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes));
else
- Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
- unsigned Vis = Symbol->getVisibility();
- Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
- Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities));
- Section = getSymbolSectionNdx(Obj, Symbol, FirstSym);
- Name = this->dumper()->getFullSymbolName(Symbol, StrTable, true);
- Fields[0].Str = Num;
- Fields[1].Str = Buc;
- Fields[2].Str = Value;
- Fields[3].Str = Size;
- Fields[4].Str = Type;
- Fields[5].Str = Binding;
- Fields[6].Str = Visibility;
- Fields[7].Str = Section;
- Fields[8].Str = Name;
+ Fields[4].Str = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes));
+
+ Fields[5].Str =
+ printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings));
+ Fields[6].Str =
+ printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities));
+ Fields[7].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym);
+ Fields[8].Str = this->dumper()->getFullSymbolName(Symbol, StrTable, true);
+
for (auto &Entry : Fields)
printField(Entry);
OS << "\n";
}
-template <class ELFT> void GNUStyle<ELFT>::printSymbols(const ELFO *Obj) {
- if (opts::DynamicSymbols)
+template <class ELFT>
+void GNUStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) {
+ if (!PrintSymbols && !PrintDynamicSymbols)
return;
+ // GNU readelf prints both the .dynsym and .symtab with --symbols.
this->dumper()->printSymbolsHelper(true);
- this->dumper()->printSymbolsHelper(false);
+ if (PrintSymbols)
+ this->dumper()->printSymbolsHelper(false);
}
-template <class ELFT>
-void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
+template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
if (this->dumper()->getDynamicStringTable().empty())
return;
auto StringTable = this->dumper()->getDynamicStringTable();
auto DynSyms = this->dumper()->dynamic_symbols();
- auto GnuHash = this->dumper()->getGnuHashTable();
- auto SysVHash = this->dumper()->getHashTable();
-
- // If no hash or .gnu.hash found, try using symbol table
- if (GnuHash == nullptr && SysVHash == nullptr)
- this->dumper()->printSymbolsHelper(true);
// Try printing .hash
- if (this->dumper()->getHashTable()) {
+ 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";
@@ -3193,14 +3241,12 @@ void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
OS << " Num Buc: Value Size Type Bind Vis Ndx Name";
OS << "\n";
- uint32_t NBuckets = SysVHash->nbucket;
- uint32_t NChains = SysVHash->nchain;
auto Buckets = SysVHash->buckets();
auto Chains = SysVHash->chains();
- for (uint32_t Buc = 0; Buc < NBuckets; Buc++) {
+ for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) {
if (Buckets[Buc] == ELF::STN_UNDEF)
continue;
- for (uint32_t Ch = Buckets[Buc]; Ch < NChains; Ch = Chains[Ch]) {
+ 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);
@@ -3209,16 +3255,15 @@ void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
}
// Try printing .gnu.hash
- if (GnuHash) {
+ if (auto 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";
- uint32_t NBuckets = GnuHash->nbuckets;
auto Buckets = GnuHash->buckets();
- for (uint32_t Buc = 0; Buc < NBuckets; Buc++) {
+ for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) {
if (Buckets[Buc] == ELF::STN_UNDEF)
continue;
uint32_t Index = Buckets[Buc];
@@ -3266,8 +3311,8 @@ bool GNUStyle<ELFT>::checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
(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));
+ /*only non-zero sized sections at end*/
+ && (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz));
return false;
}
@@ -3302,12 +3347,21 @@ bool GNUStyle<ELFT>::checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) {
}
template <class ELFT>
+void GNUStyle<ELFT>::printProgramHeaders(
+ const ELFO *Obj, bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) {
+ if (PrintProgramHeaders)
+ printProgramHeaders(Obj);
+
+ // Display the section mapping along with the program headers, unless
+ // -section-mapping is explicitly set to false.
+ if (PrintSectionMapping != cl::BOU_FALSE)
+ printSectionMapping(Obj);
+}
+
+template <class ELFT>
void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
unsigned Bias = ELFT::Is64Bits ? 8 : 0;
- unsigned Width = ELFT::Is64Bits ? 18 : 10;
- unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7;
- std::string Type, Offset, VMA, LMA, FileSz, MemSz, Flag, Align;
-
const Elf_Ehdr *Header = Obj->getHeader();
Field Fields[8] = {2, 17, 26, 37 + Bias,
48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias};
@@ -3323,23 +3377,18 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
else
OS << " Type Offset VirtAddr PhysAddr FileSiz "
<< "MemSiz Flg Align\n";
+
+ unsigned Width = ELFT::Is64Bits ? 18 : 10;
+ unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7;
for (const auto &Phdr : unwrapOrError(Obj->program_headers())) {
- Type = getElfPtType(Header->e_machine, Phdr.p_type);
- Offset = to_string(format_hex(Phdr.p_offset, 8));
- VMA = to_string(format_hex(Phdr.p_vaddr, Width));
- LMA = to_string(format_hex(Phdr.p_paddr, Width));
- FileSz = to_string(format_hex(Phdr.p_filesz, SizeWidth));
- MemSz = to_string(format_hex(Phdr.p_memsz, SizeWidth));
- Flag = printPhdrFlags(Phdr.p_flags);
- Align = to_string(format_hex(Phdr.p_align, 1));
- Fields[0].Str = Type;
- Fields[1].Str = Offset;
- Fields[2].Str = VMA;
- Fields[3].Str = LMA;
- Fields[4].Str = FileSz;
- Fields[5].Str = MemSz;
- Fields[6].Str = Flag;
- Fields[7].Str = Align;
+ 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));
+ Fields[3].Str = to_string(format_hex(Phdr.p_paddr, Width));
+ Fields[4].Str = to_string(format_hex(Phdr.p_filesz, SizeWidth));
+ Fields[5].Str = to_string(format_hex(Phdr.p_memsz, SizeWidth));
+ Fields[6].Str = printPhdrFlags(Phdr.p_flags);
+ Fields[7].Str = to_string(format_hex(Phdr.p_align, 1));
for (auto Field : Fields)
printField(Field);
if (Phdr.p_type == ELF::PT_INTERP) {
@@ -3348,7 +3397,12 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
}
OS << "\n";
}
+}
+
+template <class ELFT>
+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(Obj->program_headers())) {
std::string Sections;
@@ -3363,58 +3417,66 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
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))
+ checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL)) {
Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + " ";
+ BelongsToSegment.insert(&Sec);
+ }
}
OS << Sections << "\n";
OS.flush();
}
+
+ // Display sections that do not belong to a segment.
+ std::string Sections;
+ for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
+ if (BelongsToSegment.find(&Sec) == BelongsToSegment.end())
+ Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + ' ';
+ }
+ if (!Sections.empty()) {
+ OS << " None " << Sections << '\n';
+ OS.flush();
+ }
}
template <class ELFT>
void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R,
bool IsRela) {
- SmallString<32> RelocName;
- StringRef SymbolName;
- unsigned Width = ELFT::Is64Bits ? 16 : 8;
- unsigned Bias = ELFT::Is64Bits ? 8 : 0;
- // First two fields are bit width dependent. The rest of them are after are
- // fixed width.
- Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias};
-
uint32_t SymIndex = R.getSymbol(Obj->isMips64EL());
const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex;
- Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName);
- SymbolName =
- unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()));
- std::string Addend, Info, Offset, Value;
- Offset = to_string(format_hex_no_prefix(R.r_offset, Width));
- Info = to_string(format_hex_no_prefix(R.r_info, Width));
- Value = to_string(format_hex_no_prefix(Sym->getValue(), Width));
- int64_t RelAddend = R.r_addend;
- if (!SymbolName.empty() && IsRela) {
- if (R.r_addend < 0)
- Addend = " - ";
- else
- Addend = " + ";
- }
+ std::string SymbolName = maybeDemangle(
+ unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())));
+ printRelocation(Obj, Sym, SymbolName, R, IsRela);
+}
- if (SymbolName.empty() && Sym->getValue() == 0)
- Value = "";
+template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) {
+ Elf_Dyn_Range Table = this->dumper()->dynamic_table();
+ if (Table.empty())
+ return;
- if (IsRela)
- Addend += to_string(format_hex_no_prefix(std::abs(RelAddend), 1));
+ const DynRegionInfo &DynamicTableRegion =
+ this->dumper()->getDynamicTableRegion();
+ OS << "Dynamic section at offset "
+ << format_hex(reinterpret_cast<const uint8_t *>(DynamicTableRegion.Addr) -
+ Obj->base(),
+ 1)
+ << " contains " << Table.size() << " entries:\n";
- Fields[0].Str = Offset;
- Fields[1].Str = Info;
- Fields[2].Str = RelocName.c_str();
- Fields[3].Str = Value;
- Fields[4].Str = SymbolName;
- for (auto &Field : Fields)
- printField(Field);
- OS << Addend;
- OS << "\n";
+ bool Is64 = ELFT::Is64Bits;
+ if (Is64)
+ OS << " Tag Type Name/Value\n";
+ else
+ OS << " Tag Type Name/Value\n";
+ for (auto Entry : Table) {
+ uintX_t Tag = Entry.getTag();
+ std::string TypeString = std::string("(") +
+ getTypeString(Obj->getHeader()->e_machine, Tag) +
+ ")";
+ OS << " " << format_hex(Tag, Is64 ? 18 : 10)
+ << format(" %-20s ", TypeString.c_str());
+ this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());
+ OS << "\n";
+ }
}
template <class ELFT>
@@ -3427,7 +3489,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
OS << "\n'RELA' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynRelaRegion.Addr) -
Obj->base(),
- 1) << " contains " << DynRelaRegion.Size << " bytes:\n";
+ 1)
+ << " contains " << DynRelaRegion.Size << " bytes:\n";
printRelocHeader(ELF::SHT_RELA);
for (const Elf_Rela &Rela : this->dumper()->dyn_relas())
printDynamicRelocation(Obj, Rela, true);
@@ -3436,7 +3499,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
OS << "\n'REL' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynRelRegion.Addr) -
Obj->base(),
- 1) << " contains " << DynRelRegion.Size << " bytes:\n";
+ 1)
+ << " contains " << DynRelRegion.Size << " bytes:\n";
printRelocHeader(ELF::SHT_REL);
for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) {
Elf_Rela Rela;
@@ -3450,7 +3514,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
OS << "\n'RELR' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynRelrRegion.Addr) -
Obj->base(),
- 1) << " contains " << DynRelrRegion.Size << " bytes:\n";
+ 1)
+ << " contains " << DynRelrRegion.Size << " bytes:\n";
printRelocHeader(ELF::SHT_REL);
Elf_Relr_Range Relrs = this->dumper()->dyn_relrs();
std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs));
@@ -3462,7 +3527,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
OS << "\n'PLT' relocation section at offset "
<< format_hex(reinterpret_cast<const uint8_t *>(DynPLTRelRegion.Addr) -
Obj->base(),
- 1) << " contains " << DynPLTRelRegion.Size << " bytes:\n";
+ 1)
+ << " contains " << DynPLTRelRegion.Size << " bytes:\n";
}
if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) {
printRelocHeader(ELF::SHT_RELA);
@@ -3480,18 +3546,189 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
}
}
+template <class ELFT>
+static void printGNUVersionSectionProlog(formatted_raw_ostream &OS,
+ const Twine &Name, unsigned EntriesNum,
+ const ELFFile<ELFT> *Obj,
+ const typename ELFT::Shdr *Sec) {
+ StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
+ OS << Name << " section '" << SecName << "' "
+ << "contains " << EntriesNum << " entries:\n";
+
+ const typename ELFT::Shdr *SymTab =
+ unwrapOrError(Obj->getSection(Sec->sh_link));
+ StringRef SymTabName = unwrapOrError(Obj->getSectionName(SymTab));
+ OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16)
+ << " Offset: " << format_hex(Sec->sh_offset, 8)
+ << " Link: " << Sec->sh_link << " (" << SymTabName << ")\n";
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ if (!Sec)
+ return;
+
+ unsigned Entries = Sec->sh_size / sizeof(Elf_Versym);
+ printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec);
+
+ const uint8_t *VersymBuf =
+ reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
+ const ELFDumper<ELFT> *Dumper = this->dumper();
+ StringRef StrTable = Dumper->getDynamicStringTable();
+
+ // readelf prints 4 entries per line.
+ for (uint64_t VersymRow = 0; VersymRow < Entries; VersymRow += 4) {
+ OS << " " << format_hex_no_prefix(VersymRow, 3) << ":";
+
+ for (uint64_t VersymIndex = 0;
+ (VersymIndex < 4) && (VersymIndex + VersymRow) < Entries;
+ ++VersymIndex) {
+ const Elf_Versym *Versym =
+ reinterpret_cast<const Elf_Versym *>(VersymBuf);
+ switch (Versym->vs_index) {
+ case 0:
+ OS << " 0 (*local*) ";
+ break;
+ case 1:
+ OS << " 1 (*global*) ";
+ break;
+ default:
+ OS << format("%4x%c", Versym->vs_index & VERSYM_VERSION,
+ Versym->vs_index & VERSYM_HIDDEN ? 'h' : ' ');
+
+ bool IsDefault = true;
+ std::string VersionName = Dumper->getSymbolVersionByIndex(
+ StrTable, Versym->vs_index, IsDefault);
+
+ if (!VersionName.empty())
+ VersionName = "(" + VersionName + ")";
+ else
+ VersionName = "(*invalid*)";
+ OS << left_justify(VersionName, 13);
+ }
+ VersymBuf += sizeof(Elf_Versym);
+ }
+ OS << '\n';
+ }
+ OS << '\n';
+}
+
+static std::string versionFlagToString(unsigned Flags) {
+ if (Flags == 0)
+ return "none";
+
+ std::string Ret;
+ auto AddFlag = [&Ret, &Flags](unsigned Flag, StringRef Name) {
+ if (!(Flags & Flag))
+ return;
+ if (!Ret.empty())
+ Ret += " | ";
+ Ret += Name;
+ Flags &= ~Flag;
+ };
+
+ AddFlag(VER_FLG_BASE, "BASE");
+ AddFlag(VER_FLG_WEAK, "WEAK");
+ AddFlag(VER_FLG_INFO, "INFO");
+ AddFlag(~0, "<unknown>");
+ return Ret;
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ if (!Sec)
+ return;
+
+ unsigned VerDefsNum = Sec->sh_info;
+ printGNUVersionSectionProlog(OS, "Version definition", VerDefsNum, Obj, Sec);
+
+ const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link));
+ StringRef StringTable(
+ reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset),
+ (size_t)StrTabSec->sh_size);
+
+ const uint8_t *VerdefBuf = unwrapOrError(Obj->getSectionContents(Sec)).data();
+ const uint8_t *Begin = VerdefBuf;
+
+ while (VerDefsNum--) {
+ const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
+ OS << format(" 0x%04x: Rev: %u Flags: %s Index: %u Cnt: %u",
+ VerdefBuf - Begin, (unsigned)Verdef->vd_version,
+ versionFlagToString(Verdef->vd_flags).c_str(),
+ (unsigned)Verdef->vd_ndx, (unsigned)Verdef->vd_cnt);
+
+ const uint8_t *VerdauxBuf = VerdefBuf + Verdef->vd_aux;
+ const Elf_Verdaux *Verdaux =
+ reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
+ OS << format(" Name: %s\n",
+ StringTable.drop_front(Verdaux->vda_name).data());
+
+ for (unsigned I = 1; I < Verdef->vd_cnt; ++I) {
+ VerdauxBuf += Verdaux->vda_next;
+ Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
+ OS << format(" 0x%04x: Parent %u: %s\n", VerdauxBuf - Begin, I,
+ StringTable.drop_front(Verdaux->vda_name).data());
+ }
+
+ VerdefBuf += Verdef->vd_next;
+ }
+ OS << '\n';
+}
+
+template <class ELFT>
+void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ if (!Sec)
+ return;
+
+ unsigned VerneedNum = Sec->sh_info;
+ printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec);
+
+ ArrayRef<uint8_t> SecData = unwrapOrError(Obj->getSectionContents(Sec));
+
+ const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link));
+ StringRef StringTable = {
+ reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset),
+ (size_t)StrTabSec->sh_size};
+
+ const uint8_t *VerneedBuf = SecData.data();
+ for (unsigned I = 0; I < VerneedNum; ++I) {
+ const Elf_Verneed *Verneed =
+ reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
+
+ OS << format(" 0x%04x: Version: %u File: %s Cnt: %u\n",
+ reinterpret_cast<const uint8_t *>(Verneed) - SecData.begin(),
+ (unsigned)Verneed->vn_version,
+ StringTable.drop_front(Verneed->vn_file).data(),
+ (unsigned)Verneed->vn_cnt);
+
+ const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
+ for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
+ const Elf_Vernaux *Vernaux =
+ reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
+
+ OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n",
+ reinterpret_cast<const uint8_t *>(Vernaux) - SecData.begin(),
+ StringTable.drop_front(Vernaux->vna_name).data(),
+ versionFlagToString(Vernaux->vna_flags).c_str(),
+ (unsigned)Vernaux->vna_other);
+ VernauxBuf += Vernaux->vna_next;
+ }
+ VerneedBuf += Verneed->vn_next;
+ }
+ 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) {
-
- const Elf_Hash *HashTable = this->dumper()->getHashTable();
- const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable();
-
// Print histogram for .hash section
- if (HashTable) {
+ if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) {
size_t NBucket = HashTable->nbucket;
size_t NChain = HashTable->nchain;
ArrayRef<Elf_Word> Buckets = HashTable->buckets();
@@ -3535,7 +3772,7 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
}
// Print histogram for .gnu.hash section
- if (GnuHashTable) {
+ 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();
@@ -3595,6 +3832,24 @@ void GNUStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) {
OS << "GNUStyle::printAddrsig not implemented\n";
}
+static StringRef getGenericNoteTypeName(const uint32_t NT) {
+ static const struct {
+ uint32_t ID;
+ const char *Name;
+ } Notes[] = {
+ {ELF::NT_VERSION, "NT_VERSION (version)"},
+ {ELF::NT_ARCH, "NT_ARCH (architecture)"},
+ {ELF::NT_GNU_BUILD_ATTRIBUTE_OPEN, "OPEN"},
+ {ELF::NT_GNU_BUILD_ATTRIBUTE_FUNC, "func"},
+ };
+
+ for (const auto &Note : Notes)
+ if (Note.ID == NT)
+ return Note.Name;
+
+ return "";
+}
+
static std::string getGNUNoteTypeName(const uint32_t NT) {
static const struct {
uint32_t ID;
@@ -3649,14 +3904,11 @@ static std::string getAMDNoteTypeName(const uint32_t NT) {
static const struct {
uint32_t ID;
const char *Name;
- } Notes[] = {
- {ELF::NT_AMD_AMDGPU_HSA_METADATA,
- "NT_AMD_AMDGPU_HSA_METADATA (HSA Metadata)"},
- {ELF::NT_AMD_AMDGPU_ISA,
- "NT_AMD_AMDGPU_ISA (ISA Version)"},
- {ELF::NT_AMD_AMDGPU_PAL_METADATA,
- "NT_AMD_AMDGPU_PAL_METADATA (PAL Metadata)"}
- };
+ } Notes[] = {{ELF::NT_AMD_AMDGPU_HSA_METADATA,
+ "NT_AMD_AMDGPU_HSA_METADATA (HSA Metadata)"},
+ {ELF::NT_AMD_AMDGPU_ISA, "NT_AMD_AMDGPU_ISA (ISA Version)"},
+ {ELF::NT_AMD_AMDGPU_PAL_METADATA,
+ "NT_AMD_AMDGPU_PAL_METADATA (PAL Metadata)"}};
for (const auto &Note : Notes)
if (Note.ID == NT)
@@ -3683,6 +3935,16 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
ArrayRef<uint8_t> Data) {
std::string str;
raw_string_ostream OS(str);
+ uint32_t PrData;
+ auto DumpBit = [&](uint32_t Flag, StringRef Name) {
+ if (PrData & Flag) {
+ PrData &= ~Flag;
+ OS << Name;
+ if (PrData)
+ OS << ", ";
+ }
+ };
+
switch (Type) {
default:
OS << format("<application-specific type 0x%x>", Type);
@@ -3701,41 +3963,101 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize,
if (DataSize)
OS << format(" <corrupt length: 0x%x>", DataSize);
return OS.str();
+ case GNU_PROPERTY_AARCH64_FEATURE_1_AND:
case GNU_PROPERTY_X86_FEATURE_1_AND:
- OS << "X86 features: ";
- if (DataSize != 4 && DataSize != 8) {
+ OS << ((Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) ? "aarch64 feature: "
+ : "x86 feature: ");
+ if (DataSize != 4) {
OS << format("<corrupt length: 0x%x>", DataSize);
return OS.str();
}
- uint64_t CFProtection =
- (DataSize == 4)
- ? support::endian::read32<ELFT::TargetEndianness>(Data.data())
- : support::endian::read64<ELFT::TargetEndianness>(Data.data());
- if (CFProtection == 0) {
- OS << "none";
+ PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data());
+ if (PrData == 0) {
+ OS << "<None>";
return OS.str();
}
- if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_IBT) {
- OS << "IBT";
- CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_IBT;
- if (CFProtection)
- OS << ", ";
+ if (Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) {
+ DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_BTI, "BTI");
+ DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_PAC, "PAC");
+ } else {
+ DumpBit(GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK");
}
- if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_SHSTK) {
- OS << "SHSTK";
- CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK;
- if (CFProtection)
- OS << ", ";
+ if (PrData)
+ OS << format("<unknown flags: 0x%x>", PrData);
+ return OS.str();
+ case GNU_PROPERTY_X86_ISA_1_NEEDED:
+ case GNU_PROPERTY_X86_ISA_1_USED:
+ OS << "x86 ISA "
+ << (Type == GNU_PROPERTY_X86_ISA_1_NEEDED ? "needed: " : "used: ");
+ if (DataSize != 4) {
+ OS << format("<corrupt length: 0x%x>", DataSize);
+ return OS.str();
+ }
+ PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data());
+ if (PrData == 0) {
+ OS << "<None>";
+ return OS.str();
+ }
+ DumpBit(GNU_PROPERTY_X86_ISA_1_CMOV, "CMOV");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE, "SSE");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE2, "SSE2");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE3, "SSE3");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSSE3, "SSSE3");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE4_1, "SSE4_1");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_SSE4_2, "SSE4_2");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX, "AVX");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX2, "AVX2");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_FMA, "FMA");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512F, "AVX512F");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512CD, "AVX512CD");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512ER, "AVX512ER");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512PF, "AVX512PF");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512VL, "AVX512VL");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512DQ, "AVX512DQ");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512BW, "AVX512BW");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_4FMAPS, "AVX512_4FMAPS");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_4VNNIW, "AVX512_4VNNIW");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_BITALG, "AVX512_BITALG");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_IFMA, "AVX512_IFMA");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VBMI, "AVX512_VBMI");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VBMI2, "AVX512_VBMI2");
+ DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VNNI, "AVX512_VNNI");
+ if (PrData)
+ OS << format("<unknown flags: 0x%x>", PrData);
+ return OS.str();
+ break;
+ case GNU_PROPERTY_X86_FEATURE_2_NEEDED:
+ case GNU_PROPERTY_X86_FEATURE_2_USED:
+ OS << "x86 feature "
+ << (Type == GNU_PROPERTY_X86_FEATURE_2_NEEDED ? "needed: " : "used: ");
+ if (DataSize != 4) {
+ OS << format("<corrupt length: 0x%x>", DataSize);
+ return OS.str();
+ }
+ PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data());
+ if (PrData == 0) {
+ OS << "<None>";
+ return OS.str();
}
- if (CFProtection)
- OS << format("<unknown flags: 0x%llx>", CFProtection);
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_X86, "x86");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_X87, "x87");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_MMX, "MMX");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_XMM, "XMM");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_YMM, "YMM");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_ZMM, "ZMM");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_FXSR, "FXSR");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVE, "XSAVE");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT, "XSAVEOPT");
+ DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVEC, "XSAVEC");
+ if (PrData)
+ OS << format("<unknown flags: 0x%x>", PrData);
return OS.str();
}
}
template <typename ELFT>
-static SmallVector<std::string, 4>
-getGNUPropertyList(ArrayRef<uint8_t> Arr) {
+static SmallVector<std::string, 4> getGNUPropertyList(ArrayRef<uint8_t> Arr) {
using Elf_Word = typename ELFT::Word;
SmallVector<std::string, 4> Properties;
@@ -3770,12 +4092,11 @@ struct GNUAbiTag {
bool IsValid;
};
-template <typename ELFT>
-static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) {
+template <typename ELFT> static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) {
typedef typename ELFT::Word Elf_Word;
- ArrayRef<Elf_Word> Words(reinterpret_cast<const Elf_Word*>(Desc.begin()),
- reinterpret_cast<const Elf_Word*>(Desc.end()));
+ ArrayRef<Elf_Word> Words(reinterpret_cast<const Elf_Word *>(Desc.begin()),
+ reinterpret_cast<const Elf_Word *>(Desc.end()));
if (Words.size() < 4)
return {"", "", /*IsValid=*/false};
@@ -3846,24 +4167,13 @@ static AMDNote getAMDNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) {
default:
return {"", ""};
case ELF::NT_AMD_AMDGPU_HSA_METADATA:
- return {"HSA Metadata",
- std::string(reinterpret_cast<const char *>(Desc.data()),
- Desc.size())};
+ return {
+ "HSA Metadata",
+ std::string(reinterpret_cast<const char *>(Desc.data()), Desc.size())};
case ELF::NT_AMD_AMDGPU_ISA:
- return {"ISA Version",
- std::string(reinterpret_cast<const char *>(Desc.data()),
- Desc.size())};
- case ELF::NT_AMD_AMDGPU_PAL_METADATA:
- const uint32_t *PALMetadataBegin =
- reinterpret_cast<const uint32_t *>(Desc.data());
- const uint32_t *PALMetadataEnd = PALMetadataBegin + Desc.size();
- std::vector<uint32_t> PALMetadata(PALMetadataBegin, PALMetadataEnd);
- std::string PALMetadataString;
- auto Error = AMDGPU::PALMD::toString(PALMetadata, PALMetadataString);
- if (Error) {
- return {"PAL Metadata", "Invalid"};
- }
- return {"PAL Metadata", PALMetadataString};
+ return {
+ "ISA Version",
+ std::string(reinterpret_cast<const char *>(Desc.data()), Desc.size())};
}
}
@@ -3877,36 +4187,28 @@ static AMDGPUNote getAMDGPUNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) {
switch (NoteType) {
default:
return {"", ""};
- case ELF::NT_AMDGPU_METADATA:
+ case ELF::NT_AMDGPU_METADATA: {
auto MsgPackString =
StringRef(reinterpret_cast<const char *>(Desc.data()), Desc.size());
- msgpack::Reader MsgPackReader(MsgPackString);
- auto OptMsgPackNodeOrErr = msgpack::Node::read(MsgPackReader);
- if (errorToBool(OptMsgPackNodeOrErr.takeError()))
+ msgpack::Document MsgPackDoc;
+ if (!MsgPackDoc.readFromBlob(MsgPackString, /*Multi=*/false))
return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"};
- auto &OptMsgPackNode = *OptMsgPackNodeOrErr;
- if (!OptMsgPackNode)
- return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"};
- auto &MsgPackNode = *OptMsgPackNode;
AMDGPU::HSAMD::V3::MetadataVerifier Verifier(true);
- if (!Verifier.verify(*MsgPackNode))
+ if (!Verifier.verify(MsgPackDoc.getRoot()))
return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"};
std::string HSAMetadataString;
raw_string_ostream StrOS(HSAMetadataString);
- yaml::Output YOut(StrOS);
- YOut << MsgPackNode;
+ MsgPackDoc.toYAML(StrOS);
return {"AMDGPU Metadata", StrOS.str()};
}
+ }
}
template <class ELFT>
void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
- const Elf_Ehdr *e = Obj->getHeader();
- bool IsCore = e->e_type == ELF::ET_CORE;
-
auto PrintHeader = [&](const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
OS << "Displaying notes found at file offset " << format_hex(Offset, 10)
@@ -3938,12 +4240,16 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
if (!N.Type.empty())
OS << " " << N.Type << ":\n " << N.Value << '\n';
} else {
- OS << "Unknown note type: (" << format_hex(Type, 10) << ')';
+ StringRef NoteType = getGenericNoteTypeName(Type);
+ if (!NoteType.empty())
+ OS << NoteType;
+ else
+ OS << "Unknown note type: (" << format_hex(Type, 10) << ')';
}
OS << '\n';
};
- if (IsCore) {
+ if (Obj->getHeader()->e_type == ELF::ET_CORE) {
for (const auto &P : unwrapOrError(Obj->program_headers())) {
if (P.p_type != PT_NOTE)
continue;
@@ -3992,7 +4298,10 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
<< format_hex_no_prefix(Parser.getGp(), 8 + Bias) << "\n\n";
OS << " Reserved entries:\n";
- OS << " Address Access Initial Purpose\n";
+ if (ELFT::Is64Bits)
+ OS << " Address Access Initial Purpose\n";
+ else
+ OS << " Address Access Initial Purpose\n";
PrintEntry(Parser.getGotLazyResolver(), "Lazy resolver");
if (Parser.getGotModulePointer())
PrintEntry(Parser.getGotModulePointer(), "Module pointer (GNU extension)");
@@ -4000,7 +4309,10 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
if (!Parser.getLocalEntries().empty()) {
OS << "\n";
OS << " Local entries:\n";
- OS << " Address Access Initial\n";
+ if (ELFT::Is64Bits)
+ OS << " Address Access Initial\n";
+ else
+ OS << " Address Access Initial\n";
for (auto &E : Parser.getLocalEntries())
PrintEntry(&E, "");
}
@@ -4011,7 +4323,11 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) {
if (!Parser.getGlobalEntries().empty()) {
OS << "\n";
OS << " Global entries:\n";
- OS << " Address Access Initial Sym.Val. Type Ndx Name\n";
+ if (ELFT::Is64Bits)
+ OS << " Address Access Initial Sym.Val."
+ << " Type Ndx Name\n";
+ else
+ OS << " Address Access Initial Sym.Val. Type Ndx Name\n";
for (auto &E : Parser.getGlobalEntries()) {
const Elf_Sym *Sym = Parser.getGotSym(&E);
std::string SymName = this->dumper()->getFullSymbolName(
@@ -4045,7 +4361,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
size_t Bias = ELFT::Is64Bits ? 8 : 0;
auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) {
OS.PadToColumn(2);
- OS << format_hex_no_prefix(Parser.getGotAddress(E), 8 + Bias);
+ OS << format_hex_no_prefix(Parser.getPltAddress(E), 8 + Bias);
OS.PadToColumn(11 + Bias);
OS << format_hex_no_prefix(*E, 8 + Bias);
OS.PadToColumn(20 + 2 * Bias);
@@ -4058,7 +4374,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
OS << " Address Initial Purpose\n";
PrintEntry(Parser.getPltLazyResolver(), "PLT lazy resolver");
if (Parser.getPltModulePointer())
- PrintEntry(Parser.getGotModulePointer(), "Module pointer");
+ PrintEntry(Parser.getPltModulePointer(), "Module pointer");
if (!Parser.getPltEntries().empty()) {
OS << "\n";
@@ -4070,7 +4386,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
Sym, this->dumper()->getDynamicStringTable(), false);
OS.PadToColumn(2);
- OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias));
+ OS << to_string(format_hex_no_prefix(Parser.getPltAddress(&E), 8 + Bias));
OS.PadToColumn(11 + Bias);
OS << to_string(format_hex_no_prefix(E, 8 + Bias));
OS.PadToColumn(20 + 2 * Bias);
@@ -4087,21 +4403,21 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) {
}
template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
- const Elf_Ehdr *e = Obj->getHeader();
+ const Elf_Ehdr *E = Obj->getHeader();
{
DictScope D(W, "ElfHeader");
{
DictScope D(W, "Ident");
- W.printBinary("Magic", makeArrayRef(e->e_ident).slice(ELF::EI_MAG0, 4));
- W.printEnum("Class", e->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass));
- W.printEnum("DataEncoding", e->e_ident[ELF::EI_DATA],
+ W.printBinary("Magic", makeArrayRef(E->e_ident).slice(ELF::EI_MAG0, 4));
+ W.printEnum("Class", E->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass));
+ W.printEnum("DataEncoding", E->e_ident[ELF::EI_DATA],
makeArrayRef(ElfDataEncoding));
- W.printNumber("FileVersion", e->e_ident[ELF::EI_VERSION]);
+ W.printNumber("FileVersion", E->e_ident[ELF::EI_VERSION]);
auto OSABI = makeArrayRef(ElfOSABI);
- if (e->e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH &&
- e->e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) {
- switch (e->e_machine) {
+ if (E->e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH &&
+ E->e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) {
+ switch (E->e_machine) {
case ELF::EM_AMDGPU:
OSABI = makeArrayRef(AMDGPUElfOSABI);
break;
@@ -4113,34 +4429,35 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) {
break;
}
}
- W.printEnum("OS/ABI", e->e_ident[ELF::EI_OSABI], OSABI);
- W.printNumber("ABIVersion", e->e_ident[ELF::EI_ABIVERSION]);
- W.printBinary("Unused", makeArrayRef(e->e_ident).slice(ELF::EI_PAD));
+ W.printEnum("OS/ABI", E->e_ident[ELF::EI_OSABI], OSABI);
+ W.printNumber("ABIVersion", E->e_ident[ELF::EI_ABIVERSION]);
+ W.printBinary("Unused", makeArrayRef(E->e_ident).slice(ELF::EI_PAD));
}
- W.printEnum("Type", e->e_type, makeArrayRef(ElfObjectFileType));
- W.printEnum("Machine", e->e_machine, makeArrayRef(ElfMachineType));
- W.printNumber("Version", e->e_version);
- W.printHex("Entry", e->e_entry);
- W.printHex("ProgramHeaderOffset", e->e_phoff);
- W.printHex("SectionHeaderOffset", e->e_shoff);
- if (e->e_machine == EM_MIPS)
- W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderMipsFlags),
+ W.printEnum("Type", E->e_type, makeArrayRef(ElfObjectFileType));
+ W.printEnum("Machine", E->e_machine, makeArrayRef(ElfMachineType));
+ W.printNumber("Version", E->e_version);
+ W.printHex("Entry", E->e_entry);
+ W.printHex("ProgramHeaderOffset", E->e_phoff);
+ W.printHex("SectionHeaderOffset", E->e_shoff);
+ if (E->e_machine == EM_MIPS)
+ W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderMipsFlags),
unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI),
unsigned(ELF::EF_MIPS_MACH));
- else if (e->e_machine == EM_AMDGPU)
- W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags),
+ else if (E->e_machine == EM_AMDGPU)
+ W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags),
unsigned(ELF::EF_AMDGPU_MACH));
- else if (e->e_machine == EM_RISCV)
- W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderRISCVFlags));
+ else if (E->e_machine == EM_RISCV)
+ W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderRISCVFlags));
else
- W.printFlags("Flags", e->e_flags);
- W.printNumber("HeaderSize", e->e_ehsize);
- W.printNumber("ProgramHeaderEntrySize", e->e_phentsize);
- W.printNumber("ProgramHeaderCount", e->e_phnum);
- W.printNumber("SectionHeaderEntrySize", e->e_shentsize);
+ W.printFlags("Flags", E->e_flags);
+ W.printNumber("HeaderSize", E->e_ehsize);
+ W.printNumber("ProgramHeaderEntrySize", E->e_phentsize);
+ W.printNumber("ProgramHeaderCount", E->e_phnum);
+ W.printNumber("SectionHeaderEntrySize", E->e_shentsize);
W.printString("SectionHeaderCount", getSectionHeadersNumString(Obj));
- W.printString("StringTableSectionIndex", getSectionHeaderTableIndexString(Obj));
+ W.printString("StringTableSectionIndex",
+ getSectionHeaderTableIndexString(Obj));
}
}
@@ -4185,10 +4502,8 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) {
for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
++SectionNumber;
- 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 &&
+ 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 &&
Sec.sh_type != ELF::SHT_ANDROID_RELR)
continue;
@@ -4249,7 +4564,7 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
const Elf_Shdr *SymTab) {
SmallString<32> RelocName;
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
- StringRef TargetName;
+ std::string TargetName;
const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTab));
if (Sym && Sym->getType() == ELF::STT_SECTION) {
const Elf_Shdr *Sec = unwrapOrError(
@@ -4257,7 +4572,8 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
TargetName = unwrapOrError(Obj->getSectionName(Sec));
} else if (Sym) {
StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab));
- TargetName = unwrapOrError(Sym->getName(StrTable));
+ TargetName = this->dumper()->getFullSymbolName(
+ Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */);
}
if (opts::ExpandRelocs) {
@@ -4270,8 +4586,8 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel,
} else {
raw_ostream &OS = W.startLine();
OS << W.hex(Rel.r_offset) << " " << RelocName << " "
- << (!TargetName.empty() ? TargetName : "-") << " "
- << W.hex(Rel.r_addend) << "\n";
+ << (!TargetName.empty() ? TargetName : "-") << " " << W.hex(Rel.r_addend)
+ << "\n";
}
}
@@ -4280,13 +4596,12 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
ListScope SectionsD(W, "Sections");
int SectionIndex = -1;
- for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) {
- ++SectionIndex;
-
- StringRef Name = unwrapOrError(Obj->getSectionName(&Sec));
-
+ ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections());
+ const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject();
+ for (const Elf_Shdr &Sec : Sections) {
+ StringRef Name = getSectionName(Sec, *ElfObj, Sections);
DictScope SectionD(W, "Section");
- W.printNumber("Index", SectionIndex);
+ W.printNumber("Index", ++SectionIndex);
W.printNumber("Name", Name, Sec.sh_name);
W.printHex(
"Type",
@@ -4350,8 +4665,9 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) {
if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) {
ArrayRef<uint8_t> Data = unwrapOrError(Obj->getSectionContents(&Sec));
- W.printBinaryBlock("SectionData",
- StringRef((const char *)Data.data(), Data.size()));
+ W.printBinaryBlock(
+ "SectionData",
+ StringRef(reinterpret_cast<const char *>(Data.data()), Data.size()));
}
}
}
@@ -4402,6 +4718,15 @@ void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol,
W.printHex("Section", SectionName, SectionIndex);
}
+template <class ELFT>
+void LLVMStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols,
+ bool PrintDynamicSymbols) {
+ if (PrintSymbols)
+ printSymbols(Obj);
+ if (PrintDynamicSymbols)
+ printDynamicSymbols(Obj);
+}
+
template <class ELFT> void LLVMStyle<ELFT>::printSymbols(const ELFO *Obj) {
ListScope Group(W, "Symbols");
this->dumper()->printSymbolsHelper(false);
@@ -4413,6 +4738,31 @@ void LLVMStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) {
this->dumper()->printSymbolsHelper(true);
}
+template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Obj) {
+ Elf_Dyn_Range Table = this->dumper()->dynamic_table();
+ 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";
+ for (auto Entry : Table) {
+ uintX_t Tag = Entry.getTag();
+ W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " "
+ << format("%-21s",
+ getTypeString(Obj->getHeader()->e_machine, Tag));
+ this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal());
+ OS << "\n";
+ }
+
+ W.startLine() << "]\n";
+}
+
template <class ELFT>
void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) {
const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion();
@@ -4459,11 +4809,11 @@ template <class ELFT>
void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) {
SmallString<32> RelocName;
Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName);
- StringRef SymbolName;
+ std::string SymbolName;
uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL());
const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex;
- SymbolName =
- unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()));
+ SymbolName = maybeDemangle(
+ unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())));
if (opts::ExpandRelocs) {
DictScope Group(W, "Relocation");
W.printHex("Offset", Rel.r_offset);
@@ -4473,12 +4823,22 @@ void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) {
} else {
raw_ostream &OS = W.startLine();
OS << W.hex(Rel.r_offset) << " " << RelocName << " "
- << (!SymbolName.empty() ? SymbolName : "-") << " "
- << W.hex(Rel.r_addend) << "\n";
+ << (!SymbolName.empty() ? SymbolName : "-") << " " << W.hex(Rel.r_addend)
+ << "\n";
}
}
template <class ELFT>
+void LLVMStyle<ELFT>::printProgramHeaders(
+ const ELFO *Obj, bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) {
+ if (PrintProgramHeaders)
+ printProgramHeaders(Obj);
+ if (PrintSectionMapping == cl::BOU_TRUE)
+ printSectionMapping(Obj);
+}
+
+template <class ELFT>
void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
ListScope L(W, "ProgramHeaders");
@@ -4498,6 +4858,125 @@ void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) {
}
template <class ELFT>
+void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ DictScope SS(W, "Version symbols");
+ if (!Sec)
+ return;
+
+ StringRef SecName = unwrapOrError(Obj->getSectionName(Sec));
+ W.printNumber("Section Name", SecName, Sec->sh_name);
+ W.printHex("Address", Sec->sh_addr);
+ W.printHex("Offset", Sec->sh_offset);
+ W.printNumber("Link", Sec->sh_link);
+
+ const uint8_t *VersymBuf =
+ reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
+ const ELFDumper<ELFT> *Dumper = this->dumper();
+ StringRef StrTable = Dumper->getDynamicStringTable();
+
+ // Same number of entries in the dynamic symbol table (DT_SYMTAB).
+ ListScope Syms(W, "Symbols");
+ for (const Elf_Sym &Sym : Dumper->dynamic_symbols()) {
+ DictScope S(W, "Symbol");
+ const Elf_Versym *Versym = reinterpret_cast<const Elf_Versym *>(VersymBuf);
+ std::string FullSymbolName =
+ Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */);
+ W.printNumber("Version", Versym->vs_index & VERSYM_VERSION);
+ W.printString("Name", FullSymbolName);
+ VersymBuf += sizeof(Elf_Versym);
+ }
+}
+
+template <class ELFT>
+void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ DictScope SD(W, "SHT_GNU_verdef");
+ if (!Sec)
+ return;
+
+ const uint8_t *SecStartAddress =
+ reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
+ const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size;
+ const uint8_t *VerdefBuf = SecStartAddress;
+ const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link));
+
+ unsigned VerDefsNum = Sec->sh_info;
+ while (VerDefsNum--) {
+ if (VerdefBuf + sizeof(Elf_Verdef) > SecEndAddress)
+ // FIXME: report_fatal_error is not a good way to report error. We should
+ // emit a parsing error here and below.
+ report_fatal_error("invalid offset in the section");
+
+ const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf);
+ DictScope Def(W, "Definition");
+ W.printNumber("Version", Verdef->vd_version);
+ W.printEnum("Flags", Verdef->vd_flags, makeArrayRef(SymVersionFlags));
+ W.printNumber("Index", Verdef->vd_ndx);
+ W.printNumber("Hash", Verdef->vd_hash);
+ W.printString("Name", StringRef(reinterpret_cast<const char *>(
+ Obj->base() + StrTab->sh_offset +
+ Verdef->getAux()->vda_name)));
+ if (!Verdef->vd_cnt)
+ report_fatal_error("at least one definition string must exist");
+ if (Verdef->vd_cnt > 2)
+ report_fatal_error("more than one predecessor is not expected");
+
+ if (Verdef->vd_cnt == 2) {
+ const uint8_t *VerdauxBuf =
+ VerdefBuf + Verdef->vd_aux + Verdef->getAux()->vda_next;
+ const Elf_Verdaux *Verdaux =
+ reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf);
+ W.printString("Predecessor",
+ StringRef(reinterpret_cast<const char *>(
+ Obj->base() + StrTab->sh_offset + Verdaux->vda_name)));
+ }
+ VerdefBuf += Verdef->vd_next;
+ }
+}
+
+template <class ELFT>
+void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj,
+ const Elf_Shdr *Sec) {
+ DictScope SD(W, "SHT_GNU_verneed");
+ if (!Sec)
+ return;
+
+ const uint8_t *SecData =
+ reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset);
+ const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link));
+
+ const uint8_t *VerneedBuf = SecData;
+ unsigned VerneedNum = Sec->sh_info;
+ for (unsigned I = 0; I < VerneedNum; ++I) {
+ const Elf_Verneed *Verneed =
+ reinterpret_cast<const Elf_Verneed *>(VerneedBuf);
+ DictScope Entry(W, "Dependency");
+ W.printNumber("Version", Verneed->vn_version);
+ W.printNumber("Count", Verneed->vn_cnt);
+ W.printString("FileName",
+ StringRef(reinterpret_cast<const char *>(
+ Obj->base() + StrTab->sh_offset + Verneed->vn_file)));
+
+ const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux;
+ ListScope L(W, "Entries");
+ for (unsigned J = 0; J < Verneed->vn_cnt; ++J) {
+ const Elf_Vernaux *Vernaux =
+ reinterpret_cast<const Elf_Vernaux *>(VernauxBuf);
+ DictScope Entry(W, "Entry");
+ W.printNumber("Hash", Vernaux->vna_hash);
+ W.printEnum("Flags", Vernaux->vna_flags, makeArrayRef(SymVersionFlags));
+ W.printNumber("Index", Vernaux->vna_other);
+ W.printString("Name",
+ StringRef(reinterpret_cast<const char *>(
+ Obj->base() + StrTab->sh_offset + Vernaux->vna_name)));
+ VernauxBuf += Vernaux->vna_next;
+ }
+ VerneedBuf += Verneed->vn_next;
+ }
+}
+
+template <class ELFT>
void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) {
W.startLine() << "Hash Histogram not implemented!\n";
}
@@ -4542,8 +5021,7 @@ void LLVMStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) {
}
template <typename ELFT>
-static void printGNUNoteLLVMStyle(uint32_t NoteType,
- ArrayRef<uint8_t> Desc,
+static void printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc,
ScopedPrinter &W) {
switch (NoteType) {
default:
@@ -4576,8 +5054,6 @@ static void printGNUNoteLLVMStyle(uint32_t NoteType,
template <class ELFT>
void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
ListScope L(W, "Notes");
- const Elf_Ehdr *e = Obj->getHeader();
- bool IsCore = e->e_type == ELF::ET_CORE;
auto PrintHeader = [&](const typename ELFT::Off Offset,
const typename ELFT::Addr Size) {
@@ -4609,11 +5085,16 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) {
if (!N.Type.empty())
W.printString(N.Type, N.Value);
} else {
- W.getOStream() << "Unknown note type: (" << format_hex(Type, 10) << ')';
+ StringRef NoteType = getGenericNoteTypeName(Type);
+ if (!NoteType.empty())
+ W.printString("Type", NoteType);
+ else
+ W.printString("Type",
+ "Unknown (" + to_string(format_hex(Type, 10)) + ")");
}
};
- if (IsCore) {
+ if (Obj->getHeader()->e_type == ELF::ET_CORE) {
for (const auto &P : unwrapOrError(Obj->program_headers())) {
if (P.p_type != PT_NOTE)
continue;
diff --git a/tools/llvm-readobj/Error.cpp b/tools/llvm-readobj/Error.cpp
index 03d349440e6b6..1010f18a58c84 100644
--- a/tools/llvm-readobj/Error.cpp
+++ b/tools/llvm-readobj/Error.cpp
@@ -1,9 +1,8 @@
//===- Error.cpp - system_error extensions for llvm-readobj -----*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/tools/llvm-readobj/Error.h b/tools/llvm-readobj/Error.h
index f3e24bbe5dbfd..f390e1b96f8a2 100644
--- a/tools/llvm-readobj/Error.h
+++ b/tools/llvm-readobj/Error.h
@@ -1,9 +1,8 @@
//===- Error.h - system_error extensions for llvm-readobj -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/tools/llvm-readobj/MachODumper.cpp b/tools/llvm-readobj/MachODumper.cpp
index 35e4cfcb6b10d..32a3866eb2f2f 100644
--- a/tools/llvm-readobj/MachODumper.cpp
+++ b/tools/llvm-readobj/MachODumper.cpp
@@ -1,9 +1,8 @@
-//===-- MachODump.cpp - Object file dumping utility for llvm --------------===//
+//===- MachODumper.cpp - Object file dumping utility for llvm -------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -34,8 +33,6 @@ public:
void printFileHeaders() override;
void printSectionHeaders() override;
void printRelocations() override;
- void printSymbols() override;
- void printDynamicSymbols() override;
void printUnwindInfo() override;
void printStackMap() const override;
@@ -53,6 +50,8 @@ private:
template<class MachHeader>
void printFileHeaders(const MachHeader &Header);
+ void printSymbols() override;
+ void printDynamicSymbols() override;
void printSymbol(const SymbolRef &Symbol);
void printRelocation(const RelocationRef &Reloc);
@@ -163,6 +162,7 @@ static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM[] = {
static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesARM64[] = {
LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_ALL),
+ LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64E),
};
static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesSPARC[] = {
@@ -483,15 +483,8 @@ void MachODumper::printSectionHeaders(const MachOObjectFile *Obj) {
}
}
- if (opts::SectionData) {
- bool IsBSS = Section.isBSS();
- if (!IsBSS) {
- StringRef Data;
- error(Section.getContents(Data));
-
- W.printBinaryBlock("SectionData", Data);
- }
- }
+ if (opts::SectionData && !Section.isBSS())
+ W.printBinaryBlock("SectionData", unwrapOrError(Section.getContents()));
}
}
@@ -660,18 +653,16 @@ void MachODumper::printStackMap() const {
if (StackMapSection == object::SectionRef())
return;
- StringRef StackMapContents;
- StackMapSection.getContents(StackMapContents);
- ArrayRef<uint8_t> StackMapContentsArray(
- reinterpret_cast<const uint8_t*>(StackMapContents.data()),
- StackMapContents.size());
+ StringRef StackMapContents = unwrapOrError(StackMapSection.getContents());
+ ArrayRef<uint8_t> StackMapContentsArray =
+ arrayRefFromStringRef(StackMapContents);
if (Obj->isLittleEndian())
prettyPrintStackMap(
- W, StackMapV2Parser<support::little>(StackMapContentsArray));
+ W, StackMapParser<support::little>(StackMapContentsArray));
else
- prettyPrintStackMap(W,
- StackMapV2Parser<support::big>(StackMapContentsArray));
+ prettyPrintStackMap(
+ W, StackMapParser<support::big>(StackMapContentsArray));
}
void MachODumper::printNeededLibraries() {
@@ -695,10 +686,10 @@ void MachODumper::printNeededLibraries() {
}
}
- std::stable_sort(Libs.begin(), Libs.end());
+ llvm::stable_sort(Libs);
for (const auto &L : Libs) {
- outs() << " " << L << "\n";
+ W.startLine() << L << "\n";
}
}
diff --git a/tools/llvm-readobj/ObjDumper.cpp b/tools/llvm-readobj/ObjDumper.cpp
index a725140c9d33f..0a9e22c8a71c2 100644
--- a/tools/llvm-readobj/ObjDumper.cpp
+++ b/tools/llvm-readobj/ObjDumper.cpp
@@ -1,9 +1,8 @@
//===-- ObjDumper.cpp - Base dumper class -----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
@@ -17,8 +16,10 @@
#include "llvm-readobj.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/raw_ostream.h"
+#include <map>
namespace llvm {
@@ -32,116 +33,127 @@ static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) {
W << (isPrint(Start[i]) ? static_cast<char>(Start[i]) : '.');
}
-static Expected<object::SectionRef>
-getSecNameOrIndexAsSecRef(const object::ObjectFile *Obj, StringRef SecName) {
- char *StrPtr;
- long SectionIndex = strtol(SecName.data(), &StrPtr, 10);
- object::SectionRef Section;
- long SecIndex;
- if (Obj->isELF())
- SecIndex = 0;
- else
- SecIndex = 1;
- for (object::SectionRef SecRef : Obj->sections()) {
- if (*StrPtr) {
- StringRef SectionName;
-
- if (std::error_code E = SecRef.getName(SectionName))
- return errorCodeToError(E);
-
- if (SectionName == SecName)
- return SecRef;
- } else if (SecIndex == SectionIndex)
- return SecRef;
+static std::vector<object::SectionRef>
+getSectionRefsByNameOrIndex(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections) {
+ std::vector<object::SectionRef> Ret;
+ std::map<std::string, bool> SecNames;
+ std::map<unsigned, bool> SecIndices;
+ unsigned SecIndex;
+ for (StringRef Section : Sections) {
+ if (!Section.getAsInteger(0, SecIndex))
+ SecIndices.emplace(SecIndex, false);
+ else
+ SecNames.emplace(Section, false);
+ }
+ SecIndex = Obj->isELF() ? 0 : 1;
+ for (object::SectionRef SecRef : Obj->sections()) {
+ StringRef SecName;
+ error(SecRef.getName(SecName));
+ auto NameIt = SecNames.find(SecName);
+ if (NameIt != SecNames.end())
+ NameIt->second = true;
+ auto IndexIt = SecIndices.find(SecIndex);
+ if (IndexIt != SecIndices.end())
+ IndexIt->second = true;
+ if (NameIt != SecNames.end() || IndexIt != SecIndices.end())
+ Ret.push_back(SecRef);
SecIndex++;
}
- return make_error<StringError>("invalid section reference",
- object::object_error::parse_failed);
-}
-void ObjDumper::printSectionAsString(const object::ObjectFile *Obj,
- StringRef SecName) {
- Expected<object::SectionRef> SectionRefOrError =
- getSecNameOrIndexAsSecRef(Obj, SecName);
- if (!SectionRefOrError)
- error(std::move(SectionRefOrError));
- object::SectionRef Section = *SectionRefOrError;
- StringRef SectionName;
+ for (const std::pair<std::string, bool> &S : SecNames)
+ if (!S.second)
+ reportWarning(formatv("could not find section '{0}'", S.first).str());
+ for (std::pair<unsigned, bool> S : SecIndices)
+ if (!S.second)
+ reportWarning(formatv("could not find section {0}", S.first).str());
- if (std::error_code E = Section.getName(SectionName))
- error(E);
- W.startLine() << "String dump of section '" << SectionName << "':\n";
+ return Ret;
+}
- StringRef SectionContent;
- Section.getContents(SectionContent);
+void ObjDumper::printSectionsAsString(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections) {
+ bool First = true;
+ for (object::SectionRef Section :
+ getSectionRefsByNameOrIndex(Obj, Sections)) {
+ StringRef SectionName;
+ error(Section.getName(SectionName));
+ if (!First)
+ W.startLine() << '\n';
+ First = false;
+ W.startLine() << "String dump of section '" << SectionName << "':\n";
- const uint8_t *SecContent = SectionContent.bytes_begin();
- const uint8_t *CurrentWord = SecContent;
- const uint8_t *SecEnd = SectionContent.bytes_end();
+ StringRef SectionContent = unwrapOrError(Section.getContents());
- while (CurrentWord <= SecEnd) {
- size_t WordSize = strnlen(reinterpret_cast<const char *>(CurrentWord),
- SecEnd - CurrentWord);
- if (!WordSize) {
- CurrentWord++;
- continue;
+ const uint8_t *SecContent = SectionContent.bytes_begin();
+ const uint8_t *CurrentWord = SecContent;
+ const uint8_t *SecEnd = SectionContent.bytes_end();
+
+ while (CurrentWord <= SecEnd) {
+ size_t WordSize = strnlen(reinterpret_cast<const char *>(CurrentWord),
+ SecEnd - CurrentWord);
+ if (!WordSize) {
+ CurrentWord++;
+ continue;
+ }
+ W.startLine() << format("[%6tx] ", CurrentWord - SecContent);
+ printAsPrintable(W.startLine(), CurrentWord, WordSize);
+ W.startLine() << '\n';
+ CurrentWord += WordSize + 1;
}
- W.startLine() << format("[%6tx] ", CurrentWord - SecContent);
- printAsPrintable(W.startLine(), CurrentWord, WordSize);
- W.startLine() << '\n';
- CurrentWord += WordSize + 1;
}
}
-void ObjDumper::printSectionAsHex(const object::ObjectFile *Obj,
- StringRef SecName) {
- Expected<object::SectionRef> SectionRefOrError =
- getSecNameOrIndexAsSecRef(Obj, SecName);
- if (!SectionRefOrError)
- error(std::move(SectionRefOrError));
- object::SectionRef Section = *SectionRefOrError;
- StringRef SectionName;
+void ObjDumper::printSectionsAsHex(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections) {
+ bool First = true;
+ for (object::SectionRef Section :
+ getSectionRefsByNameOrIndex(Obj, Sections)) {
+ StringRef SectionName;
+ error(Section.getName(SectionName));
+ if (!First)
+ W.startLine() << '\n';
+ First = false;
+ W.startLine() << "Hex dump of section '" << SectionName << "':\n";
- if (std::error_code E = Section.getName(SectionName))
- error(E);
- W.startLine() << "Hex dump of section '" << SectionName << "':\n";
+ StringRef SectionContent = unwrapOrError(Section.getContents());
+ const uint8_t *SecContent = SectionContent.bytes_begin();
+ const uint8_t *SecEnd = SecContent + SectionContent.size();
- StringRef SectionContent;
- Section.getContents(SectionContent);
- const uint8_t *SecContent = SectionContent.bytes_begin();
- const uint8_t *SecEnd = SecContent + SectionContent.size();
+ for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) {
+ const uint8_t *TmpSecPtr = SecPtr;
+ uint8_t i;
+ uint8_t k;
- for (const uint8_t *SecPtr = SecContent; SecPtr < SecEnd; SecPtr += 16) {
- const uint8_t *TmpSecPtr = SecPtr;
- uint8_t i;
- uint8_t k;
-
- W.startLine() << format_hex(SecPtr - SecContent, 10);
- W.startLine() << ' ';
- for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) {
- for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) {
- uint8_t Val = *(reinterpret_cast<const uint8_t *>(TmpSecPtr));
- W.startLine() << format_hex_no_prefix(Val, 2);
- }
+ W.startLine() << format_hex(Section.getAddress() + (SecPtr - SecContent),
+ 10);
W.startLine() << ' ';
- }
+ for (i = 0; TmpSecPtr < SecEnd && i < 4; ++i) {
+ for (k = 0; TmpSecPtr < SecEnd && k < 4; k++, TmpSecPtr++) {
+ uint8_t Val = *(reinterpret_cast<const uint8_t *>(TmpSecPtr));
+ W.startLine() << format_hex_no_prefix(Val, 2);
+ }
+ W.startLine() << ' ';
+ }
- // We need to print the correct amount of spaces to match the format.
- // We are adding the (4 - i) last rows that are 8 characters each.
- // Then, the (4 - i) spaces that are in between the rows.
- // Least, if we cut in a middle of a row, we add the remaining characters,
- // which is (8 - (k * 2))
- if (i < 4)
- W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)),
- ' ');
+ // We need to print the correct amount of spaces to match the format.
+ // We are adding the (4 - i) last rows that are 8 characters each.
+ // Then, the (4 - i) spaces that are in between the rows.
+ // Least, if we cut in a middle of a row, we add the remaining characters,
+ // which is (8 - (k * 2)).
+ if (i < 4)
+ W.startLine() << format("%*c", (4 - i) * 8 + (4 - i) + (8 - (k * 2)),
+ ' ');
- TmpSecPtr = SecPtr;
- for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i)
- W.startLine() << (isPrint(TmpSecPtr[i]) ? static_cast<char>(TmpSecPtr[i])
- : '.');
+ TmpSecPtr = SecPtr;
+ for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i)
+ W.startLine() << (isPrint(TmpSecPtr[i])
+ ? static_cast<char>(TmpSecPtr[i])
+ : '.');
- W.startLine() << '\n';
+ W.startLine() << '\n';
+ }
}
}
diff --git a/tools/llvm-readobj/ObjDumper.h b/tools/llvm-readobj/ObjDumper.h
index 13de563469abd..aaabfa2ca2e88 100644
--- a/tools/llvm-readobj/ObjDumper.h
+++ b/tools/llvm-readobj/ObjDumper.h
@@ -1,9 +1,8 @@
//===-- ObjDumper.h ---------------------------------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -15,6 +14,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/CommandLine.h"
namespace llvm {
namespace object {
@@ -22,8 +22,9 @@ class COFFImportFile;
class ObjectFile;
}
namespace codeview {
+class GlobalTypeTableBuilder;
class MergingTypeTableBuilder;
-}
+} // namespace codeview
class ScopedPrinter;
@@ -35,18 +36,30 @@ public:
virtual void printFileHeaders() = 0;
virtual void printSectionHeaders() = 0;
virtual void printRelocations() = 0;
- virtual void printSymbols() = 0;
- virtual void printDynamicSymbols() = 0;
+ virtual void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) {
+ if (PrintSymbols)
+ printSymbols();
+ if (PrintDynamicSymbols)
+ printDynamicSymbols();
+ }
+ virtual void printProgramHeaders(bool PrintProgramHeaders,
+ cl::boolOrDefault PrintSectionMapping) {
+ if (PrintProgramHeaders)
+ printProgramHeaders();
+ if (PrintSectionMapping == cl::BOU_TRUE)
+ printSectionMapping();
+ }
+
virtual void printUnwindInfo() = 0;
// Only implemented for ELF at this time.
virtual void printDynamicRelocations() { }
virtual void printDynamicTable() { }
virtual void printNeededLibraries() { }
- virtual void printProgramHeaders() { }
virtual void printSectionAsHex(StringRef SectionName) {}
virtual void printHashTable() { }
virtual void printGnuHashTable() { }
+ virtual void printHashSymbols() {}
virtual void printLoadName() {}
virtual void printVersionInfo() {}
virtual void printGroupSections() {}
@@ -76,7 +89,10 @@ public:
virtual void printCodeViewDebugInfo() { }
virtual void
mergeCodeViewTypes(llvm::codeview::MergingTypeTableBuilder &CVIDs,
- llvm::codeview::MergingTypeTableBuilder &CVTypes) {}
+ llvm::codeview::MergingTypeTableBuilder &CVTypes,
+ llvm::codeview::GlobalTypeTableBuilder &GlobalCVIDs,
+ llvm::codeview::GlobalTypeTableBuilder &GlobalCVTypes,
+ bool GHash) {}
// Only implemented for MachO.
virtual void printMachODataInCode() { }
@@ -88,11 +104,19 @@ public:
virtual void printStackMap() const = 0;
- void printSectionAsString(const object::ObjectFile *Obj, StringRef SecName);
- void printSectionAsHex(const object::ObjectFile *Obj, StringRef SecName);
+ void printSectionsAsString(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections);
+ void printSectionsAsHex(const object::ObjectFile *Obj,
+ ArrayRef<std::string> Sections);
protected:
ScopedPrinter &W;
+
+private:
+ virtual void printSymbols() {}
+ virtual void printDynamicSymbols() {}
+ virtual void printProgramHeaders() {}
+ virtual void printSectionMapping() {}
};
std::error_code createCOFFDumper(const object::ObjectFile *Obj,
@@ -111,12 +135,16 @@ std::error_code createWasmDumper(const object::ObjectFile *Obj,
ScopedPrinter &Writer,
std::unique_ptr<ObjDumper> &Result);
+std::error_code createXCOFFDumper(const object::ObjectFile *Obj,
+ ScopedPrinter &Writer,
+ std::unique_ptr<ObjDumper> &Result);
+
void dumpCOFFImportFile(const object::COFFImportFile *File,
ScopedPrinter &Writer);
-void dumpCodeViewMergedTypes(
- ScopedPrinter &Writer, llvm::codeview::MergingTypeTableBuilder &IDTable,
- llvm::codeview::MergingTypeTableBuilder &TypeTable);
+void dumpCodeViewMergedTypes(ScopedPrinter &Writer,
+ ArrayRef<ArrayRef<uint8_t>> IpiRecords,
+ ArrayRef<ArrayRef<uint8_t>> TpiRecords);
} // namespace llvm
diff --git a/tools/llvm-readobj/StackMapPrinter.h b/tools/llvm-readobj/StackMapPrinter.h
index 77a054b178a52..ef75756402688 100644
--- a/tools/llvm-readobj/StackMapPrinter.h
+++ b/tools/llvm-readobj/StackMapPrinter.h
@@ -1,9 +1,8 @@
//===-------- StackMapPrinter.h - Pretty-print stackmaps --------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -48,24 +47,24 @@ void prettyPrintStackMap(ScopedPrinter &W, const StackMapParserT &SMP) {
OS << " #" << ++LocationIndex << ": ";
switch (Loc.getKind()) {
case StackMapParserT::LocationKind::Register:
- OS << "Register R#" << Loc.getDwarfRegNum() << "\n";
+ OS << "Register R#" << Loc.getDwarfRegNum();
break;
case StackMapParserT::LocationKind::Direct:
- OS << "Direct R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset()
- << "\n";
+ OS << "Direct R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset();
break;
case StackMapParserT::LocationKind::Indirect:
OS << "Indirect [R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset()
- << "]\n";
+ << "]";
break;
case StackMapParserT::LocationKind::Constant:
- OS << "Constant " << Loc.getSmallConstant() << "\n";
+ OS << "Constant " << Loc.getSmallConstant();
break;
case StackMapParserT::LocationKind::ConstantIndex:
OS << "ConstantIndex #" << Loc.getConstantIndex() << " ("
- << SMP.getConstant(Loc.getConstantIndex()).getValue() << ")\n";
+ << SMP.getConstant(Loc.getConstantIndex()).getValue() << ")";
break;
}
+ OS << ", size: " << Loc.getSizeInBytes() << "\n";
}
raw_ostream &OS = W.startLine();
diff --git a/tools/llvm-readobj/WasmDumper.cpp b/tools/llvm-readobj/WasmDumper.cpp
index 79d3db4e2d291..041a9a15bdb64 100644
--- a/tools/llvm-readobj/WasmDumper.cpp
+++ b/tools/llvm-readobj/WasmDumper.cpp
@@ -1,9 +1,8 @@
//===-- WasmDumper.cpp - Wasm-specific object file dumper -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -33,11 +32,25 @@ static const EnumEntry<unsigned> WasmSymbolTypes[] = {
static const EnumEntry<uint32_t> WasmSectionTypes[] = {
#define ENUM_ENTRY(X) \
{ #X, wasm::WASM_SEC_##X }
- ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT),
- ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY),
- ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT),
- ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE),
- ENUM_ENTRY(DATA),
+ ENUM_ENTRY(CUSTOM), ENUM_ENTRY(TYPE), ENUM_ENTRY(IMPORT),
+ ENUM_ENTRY(FUNCTION), ENUM_ENTRY(TABLE), ENUM_ENTRY(MEMORY),
+ ENUM_ENTRY(GLOBAL), ENUM_ENTRY(EVENT), ENUM_ENTRY(EXPORT),
+ ENUM_ENTRY(START), ENUM_ENTRY(ELEM), ENUM_ENTRY(CODE),
+ ENUM_ENTRY(DATA), ENUM_ENTRY(DATACOUNT),
+#undef ENUM_ENTRY
+};
+
+static const EnumEntry<unsigned> WasmSymbolFlags[] = {
+#define ENUM_ENTRY(X) \
+ { #X, wasm::WASM_SYMBOL_##X }
+ ENUM_ENTRY(BINDING_GLOBAL),
+ ENUM_ENTRY(BINDING_WEAK),
+ ENUM_ENTRY(BINDING_LOCAL),
+ ENUM_ENTRY(VISIBILITY_DEFAULT),
+ ENUM_ENTRY(VISIBILITY_HIDDEN),
+ ENUM_ENTRY(UNDEFINED),
+ ENUM_ENTRY(EXPORTED),
+ ENUM_ENTRY(EXPLICIT_NAME),
#undef ENUM_ENTRY
};
@@ -49,8 +62,6 @@ public:
void printFileHeaders() override;
void printSectionHeaders() override;
void printRelocations() override;
- void printSymbols() override;
- void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
void printUnwindInfo() override { llvm_unreachable("unimplemented"); }
void printStackMap() const override { llvm_unreachable("unimplemented"); }
@@ -59,6 +70,9 @@ protected:
void printRelocation(const SectionRef &Section, const RelocationRef &Reloc);
private:
+ void printSymbols() override;
+ void printDynamicSymbols() override { llvm_unreachable("unimplemented"); }
+
const WasmObjectFile *Obj;
};
@@ -80,11 +94,11 @@ void WasmDumper::printRelocation(const SectionRef &Section,
bool HasAddend = false;
switch (RelocType) {
- case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
- case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
- case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
- case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
- case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
+ 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:
@@ -209,7 +223,19 @@ void WasmDumper::printSymbol(const SymbolRef &Sym) {
WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl());
W.printString("Name", Symbol.Info.Name);
W.printEnum("Type", Symbol.Info.Kind, makeArrayRef(WasmSymbolTypes));
- W.printHex("Flags", Symbol.Info.Flags);
+ 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.Kind != wasm::WASM_SYMBOL_TYPE_DATA) {
+ W.printHex("ElementIndex", Symbol.Info.ElementIndex);
+ } else if (!(Symbol.Info.Flags & wasm::WASM_SYMBOL_UNDEFINED)) {
+ W.printHex("Offset", Symbol.Info.DataRef.Offset);
+ W.printHex("Segment", Symbol.Info.DataRef.Segment);
+ W.printHex("Size", Symbol.Info.DataRef.Size);
+ }
}
} // namespace
@@ -219,7 +245,7 @@ namespace llvm {
std::error_code createWasmDumper(const object::ObjectFile *Obj,
ScopedPrinter &Writer,
std::unique_ptr<ObjDumper> &Result) {
- const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(Obj);
+ const auto *WasmObj = dyn_cast<WasmObjectFile>(Obj);
assert(WasmObj && "createWasmDumper called with non-wasm object");
Result.reset(new WasmDumper(WasmObj, Writer));
diff --git a/tools/llvm-readobj/Win64EHDumper.cpp b/tools/llvm-readobj/Win64EHDumper.cpp
index f7e56b3615425..e64b8f157180b 100644
--- a/tools/llvm-readobj/Win64EHDumper.cpp
+++ b/tools/llvm-readobj/Win64EHDumper.cpp
@@ -1,9 +1,8 @@
//===- Win64EHDumper.cpp - Win64 EH Printer ---------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/tools/llvm-readobj/Win64EHDumper.h b/tools/llvm-readobj/Win64EHDumper.h
index 772f68bf283f7..97458c916bec6 100644
--- a/tools/llvm-readobj/Win64EHDumper.h
+++ b/tools/llvm-readobj/Win64EHDumper.h
@@ -1,9 +1,8 @@
//===- Win64EHDumper.h - Win64 EH Printing ----------------------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/tools/llvm-readobj/WindowsResourceDumper.cpp b/tools/llvm-readobj/WindowsResourceDumper.cpp
index 1f568a9636712..13989f696d9de 100644
--- a/tools/llvm-readobj/WindowsResourceDumper.cpp
+++ b/tools/llvm-readobj/WindowsResourceDumper.cpp
@@ -1,9 +1,8 @@
//===-- WindowsResourceDumper.cpp - Windows Resource printer --------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
diff --git a/tools/llvm-readobj/WindowsResourceDumper.h b/tools/llvm-readobj/WindowsResourceDumper.h
index ca6da40466052..6a5878804eb1e 100644
--- a/tools/llvm-readobj/WindowsResourceDumper.h
+++ b/tools/llvm-readobj/WindowsResourceDumper.h
@@ -1,9 +1,8 @@
//===- WindowsResourceDumper.h - Windows Resource printer -------*- C++ -*-===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
diff --git a/tools/llvm-readobj/XCOFFDumper.cpp b/tools/llvm-readobj/XCOFFDumper.cpp
new file mode 100644
index 0000000000000..6f260f91537fa
--- /dev/null
+++ b/tools/llvm-readobj/XCOFFDumper.cpp
@@ -0,0 +1,190 @@
+//===-- XCOFFDumper.cpp - XCOFF dumping utility -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements an XCOFF specific dumper for llvm-readobj.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Error.h"
+#include "ObjDumper.h"
+#include "llvm-readobj.h"
+#include "llvm/Object/XCOFFObjectFile.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+
+class XCOFFDumper : public ObjDumper {
+public:
+ XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer)
+ : ObjDumper(Writer), Obj(Obj) {}
+
+ void printFileHeaders() override;
+ void printSectionHeaders() override;
+ void printRelocations() override;
+ void printSymbols() override;
+ void printDynamicSymbols() override;
+ void printUnwindInfo() override;
+ void printStackMap() const override;
+ void printNeededLibraries() override;
+
+private:
+ template <typename T> void printSectionHeaders(ArrayRef<T> Sections);
+
+ const XCOFFObjectFile &Obj;
+
+ // Least significant 3 bits are reserved.
+ static constexpr unsigned SectionFlagsReservedMask = 0x7;
+};
+} // anonymous namespace
+
+void XCOFFDumper::printFileHeaders() {
+ DictScope DS(W, "FileHeader");
+ W.printHex("Magic", Obj.getMagic());
+ W.printNumber("NumberOfSections", Obj.getNumberOfSections());
+
+ // Negative timestamp values are reserved for future use.
+ int32_t TimeStamp = Obj.getTimeStamp();
+ if (TimeStamp > 0) {
+ // This handling of the time stamp assumes that the host system's time_t is
+ // compatible with AIX time_t. If a platform is not compatible, the lit
+ // tests will let us know.
+ time_t TimeDate = TimeStamp;
+
+ char FormattedTime[21] = {};
+ size_t BytesWritten =
+ strftime(FormattedTime, 21, "%Y-%m-%dT%H:%M:%SZ", gmtime(&TimeDate));
+ if (BytesWritten)
+ W.printHex("TimeStamp", FormattedTime, TimeStamp);
+ else
+ W.printHex("Timestamp", TimeStamp);
+ } else {
+ W.printHex("TimeStamp", TimeStamp == 0 ? "None" : "Reserved Value",
+ TimeStamp);
+ }
+
+ // The number of symbol table entries is an unsigned value in 64-bit objects
+ // and a signed value (with negative values being 'reserved') in 32-bit
+ // objects.
+ if (Obj.is64Bit()) {
+ W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64());
+ W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64());
+ } else {
+ W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32());
+ int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32();
+ if (SymTabEntries >= 0)
+ W.printNumber("SymbolTableEntries", SymTabEntries);
+ else
+ W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries);
+ }
+
+ W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize());
+ W.printHex("Flags", Obj.getFlags());
+
+ // TODO FIXME Add support for the auxiliary header (if any) once
+ // XCOFFObjectFile has the necessary support.
+}
+
+void XCOFFDumper::printSectionHeaders() {
+ if (Obj.is64Bit())
+ printSectionHeaders(Obj.sections64());
+ else
+ printSectionHeaders(Obj.sections32());
+}
+
+void XCOFFDumper::printRelocations() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printSymbols() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printDynamicSymbols() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printUnwindInfo() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printStackMap() const {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+void XCOFFDumper::printNeededLibraries() {
+ llvm_unreachable("Unimplemented functionality for XCOFFDumper");
+}
+
+static const EnumEntry<XCOFF::SectionTypeFlags> SectionTypeFlagsNames[] = {
+#define ECase(X) \
+ { #X, XCOFF::X }
+ ECase(STYP_PAD), ECase(STYP_DWARF), ECase(STYP_TEXT),
+ ECase(STYP_DATA), ECase(STYP_BSS), ECase(STYP_EXCEPT),
+ ECase(STYP_INFO), ECase(STYP_TDATA), ECase(STYP_TBSS),
+ ECase(STYP_LOADER), ECase(STYP_DEBUG), ECase(STYP_TYPCHK),
+ ECase(STYP_OVRFLO)
+#undef ECase
+};
+
+template <typename T>
+void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) {
+ ListScope Group(W, "Sections");
+
+ uint16_t Index = 1;
+ for (const T &Sec : Sections) {
+ DictScope SecDS(W, "Section");
+
+ W.printNumber("Index", Index++);
+ W.printString("Name", Sec.getName());
+
+ W.printHex("PhysicalAddress", Sec.PhysicalAddress);
+ W.printHex("VirtualAddress", Sec.VirtualAddress);
+ W.printHex("Size", Sec.SectionSize);
+ W.printHex("RawDataOffset", Sec.FileOffsetToRawData);
+ W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo);
+ W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo);
+
+ // TODO Need to add overflow handling when NumberOfX == _OVERFLOW_MARKER
+ // in 32-bit object files.
+ W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations);
+ W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers);
+
+ // The most significant 16-bits represent the DWARF section subtype. For
+ // now we just dump the section type flags.
+ uint16_t Flags = Sec.Flags & 0xffffu;
+ if (Flags & SectionFlagsReservedMask)
+ W.printHex("Flags", "Reserved", Flags);
+ else
+ W.printEnum("Type", Flags, makeArrayRef(SectionTypeFlagsNames));
+ }
+
+ if (opts::SectionRelocations)
+ report_fatal_error("Dumping section relocations is unimplemented");
+
+ if (opts::SectionSymbols)
+ report_fatal_error("Dumping symbols is unimplemented");
+
+ if (opts::SectionData)
+ report_fatal_error("Dumping section data is unimplemented");
+}
+
+namespace llvm {
+std::error_code createXCOFFDumper(const object::ObjectFile *Obj,
+ ScopedPrinter &Writer,
+ std::unique_ptr<ObjDumper> &Result) {
+ const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(Obj);
+ if (!XObj)
+ return readobj_error::unsupported_obj_file_format;
+
+ Result.reset(new XCOFFDumper(*XObj, Writer));
+ return readobj_error::success;
+}
+} // namespace llvm
diff --git a/tools/llvm-readobj/llvm-readobj.cpp b/tools/llvm-readobj/llvm-readobj.cpp
index 81ce7a5903640..1bd5bb74bf290 100644
--- a/tools/llvm-readobj/llvm-readobj.cpp
+++ b/tools/llvm-readobj/llvm-readobj.cpp
@@ -1,9 +1,8 @@
//===- llvm-readobj.cpp - Dump contents of an Object File -----------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -23,6 +22,7 @@
#include "Error.h"
#include "ObjDumper.h"
#include "WindowsResourceDumper.h"
+#include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h"
#include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/COFFImportFile.h"
@@ -39,6 +39,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/WithColor.h"
using namespace llvm;
using namespace llvm::object;
@@ -48,7 +49,7 @@ namespace opts {
cl::desc("<input object files>"),
cl::ZeroOrMore);
- // -all, -a
+ // --all, -a
cl::opt<bool>
All("all",
cl::desc("Equivalent to setting: --file-headers, --program-headers, "
@@ -65,7 +66,7 @@ namespace opts {
cl::alias HeadersShort("e", cl::desc("Alias for --headers"),
cl::aliasopt(Headers));
- // -wide, -W
+ // --wide, -W
cl::opt<bool>
WideOutput("wide", cl::desc("Ignored for compatibility with GNU readelf"),
cl::Hidden);
@@ -73,7 +74,7 @@ namespace opts {
cl::desc("Alias for --wide"),
cl::aliasopt(WideOutput));
- // -file-headers, -file-header, -h
+ // --file-headers, --file-header, -h
cl::opt<bool> FileHeaders("file-headers",
cl::desc("Display file headers "));
cl::alias FileHeadersShort("h", cl::desc("Alias for --file-headers"),
@@ -82,7 +83,7 @@ namespace opts {
cl::desc("Alias for --file-headers"),
cl::aliasopt(FileHeaders));
- // -section-headers, -sections, -S
+ // --section-headers, --sections, -S
// Also -s in llvm-readobj mode.
cl::opt<bool> SectionHeaders("section-headers",
cl::desc("Display all section headers."));
@@ -92,22 +93,27 @@ namespace opts {
cl::desc("Alias for --section-headers"),
cl::aliasopt(SectionHeaders), cl::NotHidden);
- // -section-relocations
- // Also -sr in llvm-readobj mode.
+ // --section-relocations
+ // Also --sr in llvm-readobj mode.
cl::opt<bool> SectionRelocations("section-relocations",
cl::desc("Display relocations for each section shown."));
- // -section-symbols
- // Also -st in llvm-readobj mode.
+ // --section-symbols
+ // Also --st in llvm-readobj mode.
cl::opt<bool> SectionSymbols("section-symbols",
cl::desc("Display symbols for each section shown."));
- // -section-data
- // Also -sd in llvm-readobj mode.
+ // --section-data
+ // Also --sd in llvm-readobj mode.
cl::opt<bool> SectionData("section-data",
cl::desc("Display section data for each section shown."));
- // -relocations, -relocs, -r
+ // --section-mapping
+ cl::opt<cl::boolOrDefault>
+ SectionMapping("section-mapping",
+ cl::desc("Display the section to segment mapping."));
+
+ // --relocations, --relocs, -r
cl::opt<bool> Relocations("relocations",
cl::desc("Display the relocation entries in the file"));
cl::alias RelocationsShort("r", cl::desc("Alias for --relocations"),
@@ -115,36 +121,43 @@ namespace opts {
cl::alias RelocationsGNU("relocs", cl::desc("Alias for --relocations"),
cl::aliasopt(Relocations));
- // -notes, -n
+ // --notes, -n
cl::opt<bool> Notes("notes", cl::desc("Display the ELF notes in the file"));
cl::alias NotesShort("n", cl::desc("Alias for --notes"), cl::aliasopt(Notes));
- // -dyn-relocations
+ // --dyn-relocations
cl::opt<bool> DynRelocs("dyn-relocations",
cl::desc("Display the dynamic relocation entries in the file"));
- // -symbols
+ // --symbols
// Also -s in llvm-readelf mode, or -t in llvm-readobj mode.
- cl::opt<bool> Symbols("symbols",
- cl::desc("Display the symbol table"));
+ cl::opt<bool>
+ Symbols("symbols",
+ cl::desc("Display the symbol table. Also display the dynamic "
+ "symbol table when using GNU output style for ELF"));
cl::alias SymbolsGNU("syms", cl::desc("Alias for --symbols"),
cl::aliasopt(Symbols));
- // -dyn-symbols, -dyn-syms
- // Also -dt in llvm-readobj mode.
+ // --dyn-symbols, --dyn-syms
+ // Also --dt in llvm-readobj mode.
cl::opt<bool> DynamicSymbols("dyn-symbols",
cl::desc("Display the dynamic symbol table"));
cl::alias DynSymsGNU("dyn-syms", cl::desc("Alias for --dyn-symbols"),
cl::aliasopt(DynamicSymbols));
- // -unwind, -u
+ // --hash-symbols
+ cl::opt<bool> HashSymbols(
+ "hash-symbols",
+ cl::desc("Display the dynamic symbols derived from the hash section"));
+
+ // --unwind, -u
cl::opt<bool> UnwindInfo("unwind",
cl::desc("Display unwind information"));
cl::alias UnwindInfoShort("u",
cl::desc("Alias for --unwind"),
cl::aliasopt(UnwindInfo));
- // -dynamic-table, -dynamic, -d
+ // --dynamic-table, --dynamic, -d
cl::opt<bool> DynamicTable("dynamic-table",
cl::desc("Display the ELF .dynamic section table"));
cl::alias DynamicTableShort("d", cl::desc("Alias for --dynamic-table"),
@@ -152,11 +165,11 @@ namespace opts {
cl::alias DynamicTableAlias("dynamic", cl::desc("Alias for --dynamic-table"),
cl::aliasopt(DynamicTable));
- // -needed-libs
+ // --needed-libs
cl::opt<bool> NeededLibraries("needed-libs",
cl::desc("Display the needed libraries"));
- // -program-headers, -segments, -l
+ // --program-headers, --segments, -l
cl::opt<bool> ProgramHeaders("program-headers",
cl::desc("Display ELF program headers"));
cl::alias ProgramHeadersShort("l", cl::desc("Alias for --program-headers"),
@@ -164,149 +177,161 @@ namespace opts {
cl::alias SegmentsAlias("segments", cl::desc("Alias for --program-headers"),
cl::aliasopt(ProgramHeaders));
- // -string-dump, -p
+ // --string-dump, -p
cl::list<std::string> StringDump("string-dump", cl::desc("<number|name>"),
cl::ZeroOrMore);
cl::alias StringDumpShort("p", cl::desc("Alias for --string-dump"),
- cl::aliasopt(StringDump));
+ cl::aliasopt(StringDump), cl::Prefix);
- // -hex-dump, -x
+ // --hex-dump, -x
cl::list<std::string> HexDump("hex-dump", cl::desc("<number|name>"),
cl::ZeroOrMore);
cl::alias HexDumpShort("x", cl::desc("Alias for --hex-dump"),
- cl::aliasopt(HexDump));
+ cl::aliasopt(HexDump), cl::Prefix);
- // -hash-table
+ // --demangle, -C
+ cl::opt<bool> Demangle("demangle",
+ cl::desc("Demangle symbol names in output"));
+ cl::alias DemangleShort("C", cl::desc("Alias for --demangle"),
+ cl::aliasopt(Demangle), cl::NotHidden);
+
+ // --hash-table
cl::opt<bool> HashTable("hash-table",
cl::desc("Display ELF hash table"));
- // -gnu-hash-table
+ // --gnu-hash-table
cl::opt<bool> GnuHashTable("gnu-hash-table",
cl::desc("Display ELF .gnu.hash section"));
- // -expand-relocs
+ // --expand-relocs
cl::opt<bool> ExpandRelocs("expand-relocs",
cl::desc("Expand each shown relocation to multiple lines"));
- // -raw-relr
+ // --raw-relr
cl::opt<bool> RawRelr("raw-relr",
cl::desc("Do not decode relocations in SHT_RELR section, display raw contents"));
- // -codeview
+ // --codeview
cl::opt<bool> CodeView("codeview",
cl::desc("Display CodeView debug information"));
- // -codeview-merged-types
+ // --codeview-merged-types
cl::opt<bool>
CodeViewMergedTypes("codeview-merged-types",
cl::desc("Display the merged CodeView type stream"));
- // -codeview-subsection-bytes
+ // --codeview-ghash
+ cl::opt<bool> CodeViewEnableGHash(
+ "codeview-ghash",
+ cl::desc(
+ "Enable global hashing for CodeView type stream de-duplication"));
+
+ // --codeview-subsection-bytes
cl::opt<bool> CodeViewSubsectionBytes(
"codeview-subsection-bytes",
cl::desc("Dump raw contents of codeview debug sections and records"));
- // -arm-attributes
+ // --arm-attributes
cl::opt<bool> ARMAttributes("arm-attributes",
cl::desc("Display the ARM attributes section"));
- // -mips-plt-got
+ // --mips-plt-got
cl::opt<bool>
MipsPLTGOT("mips-plt-got",
cl::desc("Display the MIPS GOT and PLT GOT sections"));
- // -mips-abi-flags
+ // --mips-abi-flags
cl::opt<bool> MipsABIFlags("mips-abi-flags",
cl::desc("Display the MIPS.abiflags section"));
- // -mips-reginfo
+ // --mips-reginfo
cl::opt<bool> MipsReginfo("mips-reginfo",
cl::desc("Display the MIPS .reginfo section"));
- // -mips-options
+ // --mips-options
cl::opt<bool> MipsOptions("mips-options",
cl::desc("Display the MIPS .MIPS.options section"));
- // -coff-imports
+ // --coff-imports
cl::opt<bool>
COFFImports("coff-imports", cl::desc("Display the PE/COFF import table"));
- // -coff-exports
+ // --coff-exports
cl::opt<bool>
COFFExports("coff-exports", cl::desc("Display the PE/COFF export table"));
- // -coff-directives
+ // --coff-directives
cl::opt<bool>
COFFDirectives("coff-directives",
cl::desc("Display the PE/COFF .drectve section"));
- // -coff-basereloc
+ // --coff-basereloc
cl::opt<bool>
COFFBaseRelocs("coff-basereloc",
cl::desc("Display the PE/COFF .reloc section"));
- // -coff-debug-directory
+ // --coff-debug-directory
cl::opt<bool>
COFFDebugDirectory("coff-debug-directory",
cl::desc("Display the PE/COFF debug directory"));
- // -coff-resources
+ // --coff-resources
cl::opt<bool> COFFResources("coff-resources",
cl::desc("Display the PE/COFF .rsrc section"));
- // -coff-load-config
+ // --coff-load-config
cl::opt<bool>
COFFLoadConfig("coff-load-config",
cl::desc("Display the PE/COFF load config"));
- // -elf-linker-options
+ // --elf-linker-options
cl::opt<bool>
ELFLinkerOptions("elf-linker-options",
cl::desc("Display the ELF .linker-options section"));
- // -macho-data-in-code
+ // --macho-data-in-code
cl::opt<bool>
MachODataInCode("macho-data-in-code",
cl::desc("Display MachO Data in Code command"));
- // -macho-indirect-symbols
+ // --macho-indirect-symbols
cl::opt<bool>
MachOIndirectSymbols("macho-indirect-symbols",
cl::desc("Display MachO indirect symbols"));
- // -macho-linker-options
+ // --macho-linker-options
cl::opt<bool>
MachOLinkerOptions("macho-linker-options",
cl::desc("Display MachO linker options"));
- // -macho-segment
+ // --macho-segment
cl::opt<bool>
MachOSegment("macho-segment",
cl::desc("Display MachO Segment command"));
- // -macho-version-min
+ // --macho-version-min
cl::opt<bool>
MachOVersionMin("macho-version-min",
cl::desc("Display MachO version min command"));
- // -macho-dysymtab
+ // --macho-dysymtab
cl::opt<bool>
MachODysymtab("macho-dysymtab",
cl::desc("Display MachO Dysymtab command"));
- // -stackmap
+ // --stackmap
cl::opt<bool>
PrintStackMap("stackmap",
cl::desc("Display contents of stackmap section"));
- // -version-info, -V
+ // --version-info, -V
cl::opt<bool>
VersionInfo("version-info",
cl::desc("Display ELF version sections (if present)"));
cl::alias VersionInfoShort("V", cl::desc("Alias for -version-info"),
cl::aliasopt(VersionInfo));
- // -elf-section-groups, -section-groups, -g
+ // --elf-section-groups, --section-groups, -g
cl::opt<bool> SectionGroups("elf-section-groups",
cl::desc("Display ELF section group contents"));
cl::alias SectionGroupsAlias("section-groups",
@@ -315,7 +340,7 @@ namespace opts {
cl::alias SectionGroupsShort("g", cl::desc("Alias for -elf-sections-groups"),
cl::aliasopt(SectionGroups));
- // -elf-hash-histogram, -histogram, -I
+ // --elf-hash-histogram, --histogram, -I
cl::opt<bool> HashHistogram(
"elf-hash-histogram",
cl::desc("Display bucket list histogram for hash sections"));
@@ -325,7 +350,7 @@ namespace opts {
cl::desc("Alias for --elf-hash-histogram"),
cl::aliasopt(HashHistogram));
- // -elf-cg-profile
+ // --elf-cg-profile
cl::opt<bool> CGProfile("elf-cg-profile", cl::desc("Display callgraph profile section"));
// -addrsig
@@ -338,16 +363,38 @@ namespace opts {
cl::values(clEnumVal(LLVM, "LLVM default style"),
clEnumVal(GNU, "GNU readelf style")),
cl::init(LLVM));
+
+ cl::extrahelp
+ HelpResponse("\nPass @FILE as argument to read options from FILE.\n");
} // namespace opts
namespace llvm {
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg) {
- errs() << "\nError reading file: " << Msg << ".\n";
- errs().flush();
+ fouts().flush();
+ errs() << "\n";
+ WithColor::error(errs()) << Msg << "\n";
exit(1);
}
+void reportError(StringRef Input, Error Err) {
+ if (Input == "-")
+ Input = "<stdin>";
+ error(createFileError(Input, std::move(Err)));
+}
+
+void reportWarning(Twine Msg) {
+ fouts().flush();
+ errs() << "\n";
+ WithColor::warning(errs()) << Msg << "\n";
+}
+
+void warn(Error Err) {
+ handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) {
+ reportWarning(EI.message());
+ });
+}
+
void error(Error EC) {
if (!EC)
return;
@@ -361,28 +408,10 @@ void error(std::error_code EC) {
reportError(EC.message());
}
-bool relocAddressLess(RelocationRef a, RelocationRef b) {
- return a.getOffset() < b.getOffset();
-}
-
} // namespace llvm
static void reportError(StringRef Input, std::error_code EC) {
- if (Input == "-")
- Input = "<stdin>";
-
- reportError(Twine(Input) + ": " + EC.message());
-}
-
-static void reportError(StringRef Input, Error Err) {
- if (Input == "-")
- Input = "<stdin>";
- std::string ErrMsg;
- {
- raw_string_ostream ErrStream(ErrMsg);
- logAllUnhandledErrors(std::move(Err), ErrStream, Input + ": ");
- }
- reportError(ErrMsg);
+ reportError(Input, errorCodeToError(EC));
}
static bool isMipsArch(unsigned Arch) {
@@ -399,13 +428,17 @@ static bool isMipsArch(unsigned Arch) {
namespace {
struct ReadObjTypeTableBuilder {
ReadObjTypeTableBuilder()
- : Allocator(), IDTable(Allocator), TypeTable(Allocator) {}
+ : Allocator(), IDTable(Allocator), TypeTable(Allocator),
+ GlobalIDTable(Allocator), GlobalTypeTable(Allocator) {}
llvm::BumpPtrAllocator Allocator;
llvm::codeview::MergingTypeTableBuilder IDTable;
llvm::codeview::MergingTypeTableBuilder TypeTable;
+ llvm::codeview::GlobalTypeTableBuilder GlobalIDTable;
+ llvm::codeview::GlobalTypeTableBuilder GlobalTypeTable;
+ std::vector<OwningBinary<Binary>> Binaries;
};
-}
+} // namespace
static ReadObjTypeTableBuilder CVTypes;
/// Creates an format-specific object file dumper.
@@ -423,25 +456,34 @@ static std::error_code createDumper(const ObjectFile *Obj,
return createMachODumper(Obj, Writer, Result);
if (Obj->isWasm())
return createWasmDumper(Obj, Writer, Result);
+ if (Obj->isXCOFF())
+ return createXCOFFDumper(Obj, Writer, Result);
return readobj_error::unsupported_obj_file_format;
}
/// Dumps the specified object file.
-static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) {
+static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer,
+ const Archive *A = nullptr) {
+ std::string FileStr =
+ A ? Twine(A->getFileName() + "(" + Obj->getFileName() + ")").str()
+ : Obj->getFileName().str();
+
std::unique_ptr<ObjDumper> Dumper;
if (std::error_code EC = createDumper(Obj, Writer, Dumper))
- reportError(Obj->getFileName(), EC);
+ reportError(FileStr, EC);
+ Writer.startLine() << "\n";
if (opts::Output == opts::LLVM) {
- Writer.startLine() << "\n";
- Writer.printString("File", Obj->getFileName());
+ Writer.printString("File", FileStr);
Writer.printString("Format", Obj->getFileFormatName());
Writer.printString("Arch", Triple::getArchTypeName(
(llvm::Triple::ArchType)Obj->getArch()));
Writer.printString("AddressSize",
formatv("{0}bit", 8 * Obj->getBytesInAddress()));
Dumper->printLoadName();
+ } else if (opts::Output == opts::GNU && A) {
+ Writer.printString("File", FileStr);
}
if (opts::FileHeaders)
@@ -452,26 +494,22 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) {
Dumper->printRelocations();
if (opts::DynRelocs)
Dumper->printDynamicRelocations();
- if (opts::Symbols)
- Dumper->printSymbols();
- if (opts::DynamicSymbols)
- Dumper->printDynamicSymbols();
+ if (opts::Symbols || opts::DynamicSymbols)
+ Dumper->printSymbols(opts::Symbols, opts::DynamicSymbols);
+ if (opts::HashSymbols)
+ Dumper->printHashSymbols();
if (opts::UnwindInfo)
Dumper->printUnwindInfo();
if (opts::DynamicTable)
Dumper->printDynamicTable();
if (opts::NeededLibraries)
Dumper->printNeededLibraries();
- if (opts::ProgramHeaders)
- Dumper->printProgramHeaders();
+ if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE)
+ Dumper->printProgramHeaders(opts::ProgramHeaders, opts::SectionMapping);
if (!opts::StringDump.empty())
- llvm::for_each(opts::StringDump, [&Dumper, Obj](StringRef SectionName) {
- Dumper->printSectionAsString(Obj, SectionName);
- });
+ Dumper->printSectionsAsString(Obj, opts::StringDump);
if (!opts::HexDump.empty())
- llvm::for_each(opts::HexDump, [&Dumper, Obj](StringRef SectionName) {
- Dumper->printSectionAsHex(Obj, SectionName);
- });
+ Dumper->printSectionsAsHex(Obj, opts::HexDump);
if (opts::HashTable)
Dumper->printHashTable();
if (opts::GnuHashTable)
@@ -525,7 +563,9 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) {
if (opts::CodeView)
Dumper->printCodeViewDebugInfo();
if (opts::CodeViewMergedTypes)
- Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable);
+ Dumper->mergeCodeViewTypes(CVTypes.IDTable, CVTypes.TypeTable,
+ CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable,
+ opts::CodeViewEnableGHash);
}
if (Obj->isMachO()) {
if (opts::MachODataInCode)
@@ -552,12 +592,12 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) {
Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary();
if (!ChildOrErr) {
if (auto E = isNotObjectErrorInvalidFileType(ChildOrErr.takeError())) {
- reportError(Arc->getFileName(), ChildOrErr.takeError());
+ reportError(Arc->getFileName(), std::move(E));
}
continue;
}
if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get()))
- dumpObject(Obj, Writer);
+ dumpObject(Obj, Writer, Arc);
else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(&*ChildOrErr.get()))
dumpCOFFImportFile(Imp, Writer);
else
@@ -583,8 +623,8 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary,
}
/// Dumps \a WinRes, Windows Resource (.res) file;
-static void dumpWindowsResourceFile(WindowsResource *WinRes) {
- ScopedPrinter Printer{outs()};
+static void dumpWindowsResourceFile(WindowsResource *WinRes,
+ ScopedPrinter &Printer) {
WindowsRes::Dumper Dumper(WinRes, Printer);
if (auto Err = Dumper.printData())
reportError(WinRes->getFileName(), std::move(Err));
@@ -592,9 +632,7 @@ static void dumpWindowsResourceFile(WindowsResource *WinRes) {
/// Opens \a File and dumps it.
-static void dumpInput(StringRef File) {
- ScopedPrinter Writer(outs());
-
+static void dumpInput(StringRef File, ScopedPrinter &Writer) {
// Attempt to open the binary.
Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File);
if (!BinaryOrErr)
@@ -611,9 +649,11 @@ static void dumpInput(StringRef File) {
else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary))
dumpCOFFImportFile(Import, Writer);
else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary))
- dumpWindowsResourceFile(WinRes);
+ dumpWindowsResourceFile(WinRes, Writer);
else
reportError(File, readobj_error::unrecognized_file_format);
+
+ CVTypes.Binaries.push_back(std::move(*BinaryOrErr));
}
/// Registers aliases that should only be allowed by readobj.
@@ -656,7 +696,7 @@ static void registerReadelfAliases() {
StringRef ArgName = OptEntry.getKey();
cl::Option *Option = OptEntry.getValue();
if (ArgName.size() == 1)
- Option->setFormattingFlag(cl::Grouping);
+ apply(Option, cl::Grouping);
}
}
@@ -699,11 +739,17 @@ int main(int argc, const char *argv[]) {
if (opts::InputFilenames.empty())
opts::InputFilenames.push_back("-");
- llvm::for_each(opts::InputFilenames, dumpInput);
+ ScopedPrinter Writer(fouts());
+ for (const std::string &I : opts::InputFilenames)
+ dumpInput(I, Writer);
if (opts::CodeViewMergedTypes) {
- ScopedPrinter W(outs());
- dumpCodeViewMergedTypes(W, CVTypes.IDTable, CVTypes.TypeTable);
+ if (opts::CodeViewEnableGHash)
+ dumpCodeViewMergedTypes(Writer, CVTypes.GlobalIDTable.records(),
+ CVTypes.GlobalTypeTable.records());
+ else
+ dumpCodeViewMergedTypes(Writer, CVTypes.IDTable.records(),
+ CVTypes.TypeTable.records());
}
return 0;
diff --git a/tools/llvm-readobj/llvm-readobj.h b/tools/llvm-readobj/llvm-readobj.h
index 92ed098dc6421..0e02da4cb847a 100644
--- a/tools/llvm-readobj/llvm-readobj.h
+++ b/tools/llvm-readobj/llvm-readobj.h
@@ -1,9 +1,8 @@
//===-- llvm-readobj.h ----------------------------------------------------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
@@ -23,6 +22,9 @@ namespace llvm {
// Various helper functions.
LLVM_ATTRIBUTE_NORETURN void reportError(Twine Msg);
+ void reportError(StringRef Input, Error Err);
+ void reportWarning(Twine Msg);
+ void warn(llvm::Error Err);
void error(std::error_code EC);
void error(llvm::Error EC);
template <typename T> T error(llvm::Expected<T> &&E) {
@@ -44,18 +46,16 @@ namespace llvm {
OS.flush();
reportError(Buf);
}
- bool relocAddressLess(object::RelocationRef A,
- object::RelocationRef B);
} // namespace llvm
namespace opts {
extern llvm::cl::opt<bool> SectionRelocations;
extern llvm::cl::opt<bool> SectionSymbols;
extern llvm::cl::opt<bool> SectionData;
- extern llvm::cl::opt<bool> DynamicSymbols;
extern llvm::cl::opt<bool> ExpandRelocs;
extern llvm::cl::opt<bool> RawRelr;
extern llvm::cl::opt<bool> CodeViewSubsectionBytes;
+ extern llvm::cl::opt<bool> Demangle;
enum OutputStyleTy { LLVM, GNU };
extern llvm::cl::opt<OutputStyleTy> Output;
} // namespace opts