diff options
Diffstat (limited to 'tools/llvm-readobj')
| -rw-r--r-- | tools/llvm-readobj/ARMEHABIPrinter.h | 17 | ||||
| -rw-r--r-- | tools/llvm-readobj/ARMWinEHPrinter.cpp | 21 | ||||
| -rw-r--r-- | tools/llvm-readobj/ARMWinEHPrinter.h | 9 | ||||
| -rw-r--r-- | tools/llvm-readobj/COFFDumper.cpp | 187 | ||||
| -rw-r--r-- | tools/llvm-readobj/COFFImportDumper.cpp | 9 | ||||
| -rw-r--r-- | tools/llvm-readobj/DwarfCFIEHPrinter.h | 7 | ||||
| -rw-r--r-- | tools/llvm-readobj/ELFDumper.cpp | 2253 | ||||
| -rw-r--r-- | tools/llvm-readobj/Error.cpp | 7 | ||||
| -rw-r--r-- | tools/llvm-readobj/Error.h | 7 | ||||
| -rw-r--r-- | tools/llvm-readobj/MachODumper.cpp | 43 | ||||
| -rw-r--r-- | tools/llvm-readobj/ObjDumper.cpp | 202 | ||||
| -rw-r--r-- | tools/llvm-readobj/ObjDumper.h | 56 | ||||
| -rw-r--r-- | tools/llvm-readobj/StackMapPrinter.h | 19 | ||||
| -rw-r--r-- | tools/llvm-readobj/WasmDumper.cpp | 62 | ||||
| -rw-r--r-- | tools/llvm-readobj/Win64EHDumper.cpp | 7 | ||||
| -rw-r--r-- | tools/llvm-readobj/Win64EHDumper.h | 7 | ||||
| -rw-r--r-- | tools/llvm-readobj/WindowsResourceDumper.cpp | 7 | ||||
| -rw-r--r-- | tools/llvm-readobj/WindowsResourceDumper.h | 7 | ||||
| -rw-r--r-- | tools/llvm-readobj/XCOFFDumper.cpp | 190 | ||||
| -rw-r--r-- | tools/llvm-readobj/llvm-readobj.cpp | 272 | ||||
| -rw-r--r-- | tools/llvm-readobj/llvm-readobj.h | 14 |
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 |
