diff options
Diffstat (limited to 'contrib/llvm/tools/llvm-readobj')
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h | 13 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/COFFDumper.cpp | 29 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp | 40 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h | 245 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ELFDumper.cpp | 734 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/MachODumper.cpp | 9 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ObjDumper.cpp | 122 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ObjDumper.h | 13 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/StackMapPrinter.h | 49 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/WasmDumper.cpp | 40 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp | 102 | ||||
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/llvm-readobj.h | 1 |
13 files changed, 1096 insertions, 303 deletions
diff --git a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h index 4417aa60fe90..51128f113c4c 100644 --- a/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/contrib/llvm/tools/llvm-readobj/ARMEHABIPrinter.h @@ -323,10 +323,10 @@ inline void OpcodeDecoder::Decode(const uint8_t *Opcodes, off_t Offset, template <typename ET> class PrinterContext { - typedef typename object::ELFFile<ET>::Elf_Sym Elf_Sym; - typedef typename object::ELFFile<ET>::Elf_Shdr Elf_Shdr; - typedef typename object::ELFFile<ET>::Elf_Rel Elf_Rel; - typedef typename object::ELFFile<ET>::Elf_Word Elf_Word; + typedef typename ET::Sym Elf_Sym; + typedef typename ET::Shdr Elf_Shdr; + typedef typename ET::Rel Elf_Rel; + typedef typename ET::Word Elf_Word; ScopedPrinter &SW; const object::ELFFile<ET> *ELF; @@ -386,7 +386,7 @@ PrinterContext<ET>::FunctionAtAddress(unsigned Section, } template <typename ET> -const typename object::ELFFile<ET>::Elf_Shdr * +const typename ET::Shdr * PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, off_t IndexTableOffset) const { /// Iterate through the sections, searching for the relocation section @@ -410,7 +410,7 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, if (R.r_offset != static_cast<unsigned>(IndexTableOffset)) continue; - typename object::ELFFile<ET>::Elf_Rela RelA; + typename ET::Rela RelA; RelA.r_offset = R.r_offset; RelA.r_info = R.r_info; RelA.r_addend = 0; @@ -586,4 +586,3 @@ void PrinterContext<ET>::PrintUnwindInformation() const { } #endif - diff --git a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp index 1a033b1eb42e..a90840b22c8d 100644 --- a/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/contrib/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -33,7 +33,7 @@ // (.pdata) entry. // // The exception data contains information about the frame setup, all of the -// epilouge scopes (for functions for which there are multiple exit points) and +// epilogue scopes (for functions for which there are multiple exit points) and // the associated exception handler. Additionally, the entry contains byte-code // describing how to unwind the function (c.f. Decoder::decodeOpcodes). // diff --git a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp index 0e76e75c085d..0ed4ccd09f6f 100644 --- a/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief This file implements the COFF-specific dumper for llvm-readobj. +/// This file implements the COFF-specific dumper for llvm-readobj. /// //===----------------------------------------------------------------------===// @@ -67,6 +67,8 @@ struct LoadConfigTables { uint32_t GuardFlags = 0; uint64_t GuardFidTableVA = 0; uint64_t GuardFidTableCount = 0; + uint64_t GuardLJmpTableVA = 0; + uint64_t GuardLJmpTableCount = 0; }; class COFFDumper : public ObjDumper { @@ -242,7 +244,7 @@ std::error_code createCOFFDumper(const object::ObjectFile *Obj, } // namespace llvm -// Given a a section and an offset into this section the function returns the +// Given a section and an offset into this section the function returns the // symbol used for the relocation at the offset. std::error_code COFFDumper::resolveSymbol(const coff_section *Section, uint64_t Offset, SymbolRef &Sym) { @@ -605,8 +607,8 @@ void COFFDumper::cacheRelocations() { RelocMap[Section].push_back(Reloc); // Sort relocations by address. - std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), - relocAddressLess); + llvm::sort(RelocMap[Section].begin(), RelocMap[Section].end(), + relocAddressLess); } } @@ -767,7 +769,7 @@ void COFFDumper::printRVATable(uint64_t TableVA, uint64_t Count, for (uintptr_t I = TableStart; I < TableEnd; I += EntrySize) { uint32_t RVA = *reinterpret_cast<const ulittle32_t *>(I); raw_ostream &OS = W.startLine(); - OS << "0x" << W.hex(Obj->getImageBase() + RVA); + OS << W.hex(Obj->getImageBase() + RVA); if (PrintExtra) PrintExtra(OS, reinterpret_cast<const uint8_t *>(I)); OS << '\n'; @@ -800,6 +802,11 @@ void COFFDumper::printCOFFLoadConfig() { printRVATable(Tables.GuardFidTableVA, Tables.GuardFidTableCount, 4); } } + + if (Tables.GuardLJmpTableVA) { + ListScope LS(W, "GuardLJmpTable"); + printRVATable(Tables.GuardLJmpTableVA, Tables.GuardLJmpTableCount, 4); + } } template <typename T> @@ -879,6 +886,9 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) { W.printHex("GuardRFVerifyStackPointerFunctionPointer", Conf->GuardRFVerifyStackPointerFunctionPointer); W.printHex("HotPatchTableOffset", Conf->HotPatchTableOffset); + + Tables.GuardLJmpTableVA = Conf->GuardLongJumpTargetTable; + Tables.GuardLJmpTableCount = Conf->GuardLongJumpTargetCount; } void COFFDumper::printBaseOfDataField(const pe32_header *Hdr) { @@ -892,7 +902,9 @@ void COFFDumper::printCodeViewDebugInfo() { for (const SectionRef &S : Obj->sections()) { StringRef SectionName; error(S.getName(SectionName)); - if (SectionName == ".debug$T") + // .debug$T is a standard CodeView type section, while .debug$P is the same + // format but used for MSVC precompiled header object files. + if (SectionName == ".debug$T" || SectionName == ".debug$P") printCodeViewTypeSection(SectionName, S); } for (const SectionRef &S : Obj->sections()) { @@ -1812,10 +1824,9 @@ void COFFDumper::printStackMap() const { if (Obj->isLittleEndian()) prettyPrintStackMap( - llvm::outs(), - StackMapV2Parser<support::little>(StackMapContentsArray)); + W, StackMapV2Parser<support::little>(StackMapContentsArray)); else - prettyPrintStackMap(llvm::outs(), + prettyPrintStackMap(W, StackMapV2Parser<support::big>(StackMapContentsArray)); } diff --git a/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp index 3b546b3ef508..18010c34f0f3 100644 --- a/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/COFFImportDumper.cpp @@ -8,41 +8,51 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief This file implements the COFF import library dumper for llvm-readobj. +/// This file implements the COFF import library dumper for llvm-readobj. /// //===----------------------------------------------------------------------===// #include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/COFF.h" #include "llvm/Object/COFFImportFile.h" +#include "llvm/Support/ScopedPrinter.h" using namespace llvm::object; namespace llvm { -void dumpCOFFImportFile(const COFFImportFile *File) { - outs() << '\n'; - outs() << "File: " << File->getFileName() << "\n"; - outs() << "Format: COFF-import-file\n"; +void dumpCOFFImportFile(const COFFImportFile *File, ScopedPrinter &Writer) { + Writer.startLine() << '\n'; + Writer.printString("File", File->getFileName()); + Writer.printString("Format", "COFF-import-file"); const coff_import_header *H = File->getCOFFImportHeader(); switch (H->getType()) { - case COFF::IMPORT_CODE: outs() << "Type: code\n"; break; - case COFF::IMPORT_DATA: outs() << "Type: data\n"; break; - case COFF::IMPORT_CONST: outs() << "Type: const\n"; break; + case COFF::IMPORT_CODE: Writer.printString("Type", "code"); break; + case COFF::IMPORT_DATA: Writer.printString("Type", "data"); break; + case COFF::IMPORT_CONST: Writer.printString("Type", "const"); break; } switch (H->getNameType()) { - case COFF::IMPORT_ORDINAL: outs() << "Name type: ordinal\n"; break; - case COFF::IMPORT_NAME: outs() << "Name type: name\n"; break; - case COFF::IMPORT_NAME_NOPREFIX: outs() << "Name type: noprefix\n"; break; - case COFF::IMPORT_NAME_UNDECORATE: outs() << "Name type: undecorate\n"; break; + case COFF::IMPORT_ORDINAL: + Writer.printString("Name type", "ordinal"); + break; + case COFF::IMPORT_NAME: + Writer.printString("Name type", "name"); + break; + case COFF::IMPORT_NAME_NOPREFIX: + Writer.printString("Name type", "noprefix"); + break; + case COFF::IMPORT_NAME_UNDECORATE: + Writer.printString("Name type", "undecorate"); + break; } for (const object::BasicSymbolRef &Sym : File->symbols()) { - outs() << "Symbol: "; - Sym.printName(outs()); - outs() << "\n"; + raw_ostream &OS = Writer.startLine(); + OS << "Symbol: "; + Sym.printName(OS); + OS << "\n"; } } diff --git a/contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h b/contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h new file mode 100644 index 000000000000..5a1eef1d007d --- /dev/null +++ b/contrib/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h @@ -0,0 +1,245 @@ +//===--- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H +#define LLVM_TOOLS_LLVM_READOBJ_DWARFCFIEHPRINTER_H + +#include "Error.h" +#include "llvm-readobj.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/BinaryFormat/Dwarf.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/Debug.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/type_traits.h" + +namespace llvm { +namespace DwarfCFIEH { + +template <typename ELFT> +class PrinterContext { + ScopedPrinter &W; + const object::ELFFile<ELFT> *Obj; + + void printEHFrameHdr(uint64_t Offset, uint64_t Address, uint64_t Size) const; + + void printEHFrame(const typename ELFT::Shdr *EHFrameShdr) const; + +public: + PrinterContext(ScopedPrinter &W, const object::ELFFile<ELFT> *Obj) + : W(W), Obj(Obj) {} + + void printUnwindInformation() const; +}; + +template <class ELFO> +static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj, + uint64_t Addr) { + auto Sections = Obj->sections(); + if (Error E = Sections.takeError()) + reportError(toString(std::move(E))); + + for (const auto &Shdr : *Sections) + if (Shdr.sh_addr == Addr) + return &Shdr; + return nullptr; +} + +template <typename ELFT> +void PrinterContext<ELFT>::printUnwindInformation() const { + const typename ELFT::Phdr *EHFramePhdr = nullptr; + + auto PHs = Obj->program_headers(); + if (Error E = PHs.takeError()) + reportError(toString(std::move(E))); + + for (const auto &Phdr : *PHs) { + if (Phdr.p_type == ELF::PT_GNU_EH_FRAME) { + EHFramePhdr = &Phdr; + if (Phdr.p_memsz != Phdr.p_filesz) + reportError("p_memsz does not match p_filesz for GNU_EH_FRAME"); + break; + } + } + + if (EHFramePhdr) + printEHFrameHdr(EHFramePhdr->p_offset, EHFramePhdr->p_vaddr, + EHFramePhdr->p_memsz); + + auto Sections = Obj->sections(); + if (Error E = Sections.takeError()) + reportError(toString(std::move(E))); + + for (const auto &Shdr : *Sections) { + auto SectionName = Obj->getSectionName(&Shdr); + if (Error E = SectionName.takeError()) + reportError(toString(std::move(E))); + + if (*SectionName == ".eh_frame") + printEHFrame(&Shdr); + } +} + +template <typename ELFT> +void PrinterContext<ELFT>::printEHFrameHdr(uint64_t EHFrameHdrOffset, + uint64_t EHFrameHdrAddress, + uint64_t EHFrameHdrSize) const { + ListScope L(W, "EH_FRAME Header"); + W.startLine() << format("Address: 0x%" PRIx64 "\n", EHFrameHdrAddress); + W.startLine() << format("Offset: 0x%" PRIx64 "\n", EHFrameHdrOffset); + W.startLine() << format("Size: 0x%" PRIx64 "\n", EHFrameHdrSize); + + const auto *EHFrameHdrShdr = findSectionByAddress(Obj, EHFrameHdrAddress); + if (EHFrameHdrShdr) { + auto SectionName = Obj->getSectionName(EHFrameHdrShdr); + if (Error E = SectionName.takeError()) + reportError(toString(std::move(E))); + + W.printString("Corresponding Section", *SectionName); + } + + DataExtractor DE( + StringRef(reinterpret_cast<const char *>(Obj->base()) + EHFrameHdrOffset, + EHFrameHdrSize), + ELFT::TargetEndianness == support::endianness::little, + ELFT::Is64Bits ? 8 : 4); + + DictScope D(W, "Header"); + uint32_t Offset = 0; + + auto Version = DE.getU8(&Offset); + W.printNumber("version", Version); + if (Version != 1) + reportError("only version 1 of .eh_frame_hdr is supported"); + + uint64_t EHFramePtrEnc = DE.getU8(&Offset); + W.startLine() << format("eh_frame_ptr_enc: 0x%" PRIx64 "\n", EHFramePtrEnc); + if (EHFramePtrEnc != (dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4)) + reportError("unexpected encoding eh_frame_ptr_enc"); + + uint64_t FDECountEnc = DE.getU8(&Offset); + W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc); + if (FDECountEnc != dwarf::DW_EH_PE_udata4) + reportError("unexpected encoding fde_count_enc"); + + uint64_t TableEnc = DE.getU8(&Offset); + W.startLine() << format("table_enc: 0x%" PRIx64 "\n", TableEnc); + if (TableEnc != (dwarf::DW_EH_PE_datarel | dwarf::DW_EH_PE_sdata4)) + reportError("unexpected encoding table_enc"); + + auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4; + W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr); + + auto FDECount = DE.getUnsigned(&Offset, 4); + W.printNumber("fde_count", FDECount); + + unsigned NumEntries = 0; + uint64_t PrevPC = 0; + while (Offset + 8 <= EHFrameHdrSize && NumEntries < FDECount) { + DictScope D(W, std::string("entry ") + std::to_string(NumEntries)); + + auto InitialPC = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; + W.startLine() << format("initial_location: 0x%" PRIx64 "\n", InitialPC); + auto Address = DE.getSigned(&Offset, 4) + EHFrameHdrAddress; + W.startLine() << format("address: 0x%" PRIx64 "\n", Address); + + if (InitialPC < PrevPC) + reportError("initial_location is out of order"); + + PrevPC = InitialPC; + ++NumEntries; + } +} + +template <typename ELFT> +void PrinterContext<ELFT>::printEHFrame( + const typename ELFT::Shdr *EHFrameShdr) const { + uint64_t Address = EHFrameShdr->sh_addr; + uint64_t ShOffset = EHFrameShdr->sh_offset; + W.startLine() << format(".eh_frame section at offset 0x%" PRIx64 + " address 0x%" PRIx64 ":\n", + ShOffset, Address); + W.indent(); + + auto Result = Obj->getSectionContents(EHFrameShdr); + if (Error E = Result.takeError()) + reportError(toString(std::move(E))); + + auto Contents = Result.get(); + DWARFDataExtractor DE( + StringRef(reinterpret_cast<const char *>(Contents.data()), + Contents.size()), + ELFT::TargetEndianness == support::endianness::little, + ELFT::Is64Bits ? 8 : 4); + DWARFDebugFrame EHFrame(/*IsEH=*/true, /*EHFrameAddress=*/Address); + EHFrame.parse(DE); + + for (const auto &Entry : EHFrame) { + if (const auto *CIE = dyn_cast<dwarf::CIE>(&Entry)) { + W.startLine() << format("[0x%" PRIx64 "] CIE length=%" PRIu64 "\n", + Address + CIE->getOffset(), + CIE->getLength()); + W.indent(); + + W.printNumber("version", CIE->getVersion()); + W.printString("augmentation", CIE->getAugmentationString()); + W.printNumber("code_alignment_factor", CIE->getCodeAlignmentFactor()); + W.printNumber("data_alignment_factor", CIE->getDataAlignmentFactor()); + W.printNumber("return_address_register", CIE->getReturnAddressRegister()); + + W.getOStream() << "\n"; + W.startLine() << "Program:\n"; + W.indent(); + CIE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); + W.unindent(); + + W.unindent(); + W.getOStream() << "\n"; + + } else if (const auto *FDE = dyn_cast<dwarf::FDE>(&Entry)) { + W.startLine() << format("[0x%" PRIx64 "] FDE length=%" PRIu64 + " cie=[0x%" PRIx64 "]\n", + Address + FDE->getOffset(), + FDE->getLength(), + Address + FDE->getLinkedCIE()->getOffset()); + W.indent(); + + W.startLine() << format("initial_location: 0x%" PRIx64 "\n", + FDE->getInitialLocation()); + W.startLine() + << format("address_range: 0x%" PRIx64 " (end : 0x%" PRIx64 ")\n", + FDE->getAddressRange(), + FDE->getInitialLocation() + FDE->getAddressRange()); + + W.getOStream() << "\n"; + W.startLine() << "Program:\n"; + W.indent(); + FDE->cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); + W.unindent(); + + W.unindent(); + W.getOStream() << "\n"; + } else { + llvm_unreachable("unexpected DWARF frame kind"); + } + } + + W.unindent(); +} + +} +} + +#endif diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp index 5605eaea7555..645ec2d7e04b 100644 --- a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -8,11 +8,12 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief This file implements the ELF-specific dumper for llvm-readobj. +/// This file implements the ELF-specific dumper for llvm-readobj. /// //===----------------------------------------------------------------------===// #include "ARMEHABIPrinter.h" +#include "DwarfCFIEHPrinter.h" #include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" @@ -43,6 +44,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" #include "llvm/Support/FormattedStream.h" +#include "llvm/Support/LEB128.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MipsABIFlags.h" #include "llvm/Support/ScopedPrinter.h" @@ -77,28 +79,32 @@ using namespace ELF; #define TYPEDEF_ELF_TYPES(ELFT) \ using ELFO = ELFFile<ELFT>; \ - using Elf_Addr = typename ELFO::Elf_Addr; \ - using Elf_Shdr = typename ELFO::Elf_Shdr; \ - using Elf_Sym = typename ELFO::Elf_Sym; \ - using Elf_Dyn = typename ELFO::Elf_Dyn; \ - using Elf_Dyn_Range = typename ELFO::Elf_Dyn_Range; \ - using Elf_Rel = typename ELFO::Elf_Rel; \ - using Elf_Rela = typename ELFO::Elf_Rela; \ - using Elf_Rel_Range = typename ELFO::Elf_Rel_Range; \ - using Elf_Rela_Range = typename ELFO::Elf_Rela_Range; \ - using Elf_Phdr = typename ELFO::Elf_Phdr; \ - using Elf_Half = typename ELFO::Elf_Half; \ - using Elf_Ehdr = typename ELFO::Elf_Ehdr; \ - using Elf_Word = typename ELFO::Elf_Word; \ - using Elf_Hash = typename ELFO::Elf_Hash; \ - using Elf_GnuHash = typename ELFO::Elf_GnuHash; \ - using Elf_Sym_Range = typename ELFO::Elf_Sym_Range; \ - using Elf_Versym = typename ELFO::Elf_Versym; \ - using Elf_Verneed = typename ELFO::Elf_Verneed; \ - using Elf_Vernaux = typename ELFO::Elf_Vernaux; \ - using Elf_Verdef = typename ELFO::Elf_Verdef; \ - using Elf_Verdaux = typename ELFO::Elf_Verdaux; \ - using uintX_t = typename ELFO::uintX_t; + using Elf_Addr = typename ELFT::Addr; \ + using Elf_Shdr = typename ELFT::Shdr; \ + using Elf_Sym = typename ELFT::Sym; \ + using Elf_Dyn = typename ELFT::Dyn; \ + using Elf_Dyn_Range = typename ELFT::DynRange; \ + using Elf_Rel = typename ELFT::Rel; \ + using Elf_Rela = typename ELFT::Rela; \ + using Elf_Relr = typename ELFT::Relr; \ + using Elf_Rel_Range = typename ELFT::RelRange; \ + using Elf_Rela_Range = typename ELFT::RelaRange; \ + using Elf_Relr_Range = typename ELFT::RelrRange; \ + using Elf_Phdr = typename ELFT::Phdr; \ + using Elf_Half = typename ELFT::Half; \ + using Elf_Ehdr = typename ELFT::Ehdr; \ + using Elf_Word = typename ELFT::Word; \ + using Elf_Hash = typename ELFT::Hash; \ + using Elf_GnuHash = typename ELFT::GnuHash; \ + using Elf_Note = typename ELFT::Note; \ + using Elf_Sym_Range = typename ELFT::SymRange; \ + using Elf_Versym = typename ELFT::Versym; \ + using Elf_Verneed = typename ELFT::Verneed; \ + using Elf_Vernaux = typename ELFT::Vernaux; \ + using Elf_Verdef = typename ELFT::Verdef; \ + using Elf_Verdaux = typename ELFT::Verdaux; \ + using Elf_CGProfile = typename ELFT::CGProfile; \ + using uintX_t = typename ELFT::uint; namespace { @@ -113,11 +119,11 @@ struct DynRegionInfo { DynRegionInfo(const void *A, uint64_t S, uint64_t ES) : Addr(A), Size(S), EntSize(ES) {} - /// \brief Address in current address space. + /// Address in current address space. const void *Addr = nullptr; - /// \brief Size in bytes of the region. + /// Size in bytes of the region. uint64_t Size = 0; - /// \brief Size of each entity in the region. + /// Size of each entity in the region. uint64_t EntSize = 0; template <typename Type> ArrayRef<Type> getAsArrayRef() const { @@ -162,8 +168,13 @@ public: void printHashHistogram() override; + void printCGProfile() override; + void printAddrsig() override; + void printNotes() override; + void printELFLinkerOptions() override; + private: std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle; @@ -198,6 +209,7 @@ private: const ELFO *Obj; DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; + DynRegionInfo DynRelrRegion; DynRegionInfo DynPLTRelRegion; DynRegionInfo DynSymRegion; DynRegionInfo DynamicTable; @@ -206,6 +218,8 @@ private: const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; + const Elf_Shdr *DotCGProfileSec = nullptr; + const Elf_Shdr *DotAddrsigSec = nullptr; StringRef DynSymtabName; ArrayRef<Elf_Word> ShndxTable; @@ -248,18 +262,23 @@ public: Elf_Rel_Range dyn_rels() const; Elf_Rela_Range dyn_relas() const; + Elf_Relr_Range dyn_relrs() const; std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic) const; void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef &SectionName, unsigned &SectionIndex) const; + StringRef getStaticSymbolName(uint32_t Index) const; void printSymbolsHelper(bool IsDynamic) const; const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } + const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; } + const Elf_Shdr *getDotAddrsigSec() const { return DotAddrsigSec; } ArrayRef<Elf_Word> getShndxTable() const { return ShndxTable; } StringRef getDynamicStringTable() const { return DynamicStringTable; } const DynRegionInfo &getDynRelRegion() const { return DynRelRegion; } const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; } + const DynRegionInfo &getDynRelrRegion() const { return DynRelrRegion; } const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; } const Elf_Hash *getHashTable() const { return HashTable; } const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; } @@ -295,8 +314,8 @@ template <class ELFT> class MipsGOTParser; template <typename ELFT> class DumpStyle { public: - using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr; - using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Sym = typename ELFT::Sym; DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) {} virtual ~DumpStyle() = default; @@ -315,7 +334,10 @@ public: bool IsDynamic) = 0; virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 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; virtual void printNotes(const ELFFile<ELFT> *Obj) = 0; + virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0; virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; const ELFDumper<ELFT> *dumper() const { return Dumper; } @@ -344,7 +366,10 @@ public: size_t Offset) override; void printProgramHeaders(const ELFO *Obj) override; void printHashHistogram(const ELFFile<ELFT> *Obj) override; + void printCGProfile(const ELFFile<ELFT> *Obj) override; + void printAddrsig(const ELFFile<ELFT> *Obj) override; void printNotes(const ELFFile<ELFT> *Obj) override; + void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override; void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; @@ -374,6 +399,7 @@ private: } void printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym, StringRef StrTable, uint32_t Bucket); + void printRelocHeader(unsigned SType); void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, const Elf_Rela &R, bool IsRela); void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, @@ -404,7 +430,10 @@ public: void printDynamicRelocations(const ELFO *Obj) override; void printProgramHeaders(const ELFO *Obj) override; void printHashHistogram(const ELFFile<ELFT> *Obj) override; + void printCGProfile(const ELFFile<ELFT> *Obj) override; + void printAddrsig(const ELFFile<ELFT> *Obj) override; void printNotes(const ELFFile<ELFT> *Obj) override; + void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override; void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; @@ -730,6 +759,16 @@ StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, } template <typename ELFT> +StringRef ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { + 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)); +} + +template <typename ELFT> std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic) const { @@ -1007,7 +1046,6 @@ static const EnumEntry<unsigned> ElfMachineType[] = { ENUM_ENT(EM_56800EX, "EM_56800EX"), ENUM_ENT(EM_AMDGPU, "EM_AMDGPU"), ENUM_ENT(EM_RISCV, "RISC-V"), - ENUM_ENT(EM_WEBASSEMBLY, "EM_WEBASSEMBLY"), ENUM_ENT(EM_LANAI, "EM_LANAI"), ENUM_ENT(EM_BPF, "EM_BPF"), }; @@ -1255,9 +1293,39 @@ static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = { }; static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = { - LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_NONE), - LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_R600), - LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_ARCH_GCN) + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_NONE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R600), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R630), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RS880), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV670), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV710), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV730), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV770), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CEDAR), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CYPRESS), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_JUNIPER), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_REDWOOD), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_SUMO), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_BARTS), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAICOS), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAYMAN), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_TURKS), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX600), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX601), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX700), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX701), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX702), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX703), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX704), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX801), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX802), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX803), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX810), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX900), + 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_XNACK) }; static const EnumEntry<unsigned> ElfHeaderRISCVFlags[] = { @@ -1353,6 +1421,16 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, ScopedPrinter &Writer) reportError("Multiple SHT_GNU_verneed"); dot_gnu_version_r_sec = &Sec; break; + case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: + if (DotCGProfileSec != nullptr) + reportError("Multiple .note.llvm.cgprofile"); + DotCGProfileSec = &Sec; + break; + case ELF::SHT_LLVM_ADDRSIG: + if (DotAddrsigSec != nullptr) + reportError("Multiple .llvm_addrsig"); + DotAddrsigSec = &Sec; + break; } } @@ -1427,6 +1505,18 @@ void ELFDumper<ELFT>::parseDynamicTable( case ELF::DT_RELENT: DynRelRegion.EntSize = Dyn.getVal(); break; + case ELF::DT_RELR: + case ELF::DT_ANDROID_RELR: + DynRelrRegion.Addr = toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_RELRSZ: + case ELF::DT_ANDROID_RELRSZ: + DynRelrRegion.Size = Dyn.getVal(); + break; + case ELF::DT_RELRENT: + case ELF::DT_ANDROID_RELRENT: + DynRelrRegion.EntSize = Dyn.getVal(); + break; case ELF::DT_PLTREL: if (Dyn.getVal() == DT_REL) DynPLTRelRegion.EntSize = sizeof(Elf_Rel); @@ -1460,6 +1550,11 @@ typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const { return DynRelaRegion.getAsArrayRef<Elf_Rela>(); } +template <typename ELFT> +typename ELFDumper<ELFT>::Elf_Relr_Range ELFDumper<ELFT>::dyn_relrs() const { + return DynRelrRegion.getAsArrayRef<Elf_Relr>(); +} + template<class ELFT> void ELFDumper<ELFT>::printFileHeaders() { ELFDumperStyle->printFileHeaders(Obj); @@ -1497,93 +1592,69 @@ template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() { ELFDumperStyle->printHashHistogram(Obj); } +template <class ELFT> void ELFDumper<ELFT>::printCGProfile() { + ELFDumperStyle->printCGProfile(Obj); +} + template <class ELFT> void ELFDumper<ELFT>::printNotes() { ELFDumperStyle->printNotes(Obj); } -#define LLVM_READOBJ_TYPE_CASE(name) \ - case DT_##name: return #name +template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() { + ELFDumperStyle->printELFLinkerOptions(Obj); +} static const char *getTypeString(unsigned Arch, uint64_t Type) { +#define DYNAMIC_TAG(n, v) switch (Arch) { case EM_HEXAGON: switch (Type) { - LLVM_READOBJ_TYPE_CASE(HEXAGON_SYMSZ); - LLVM_READOBJ_TYPE_CASE(HEXAGON_VER); - LLVM_READOBJ_TYPE_CASE(HEXAGON_PLT); +#define HEXAGON_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef HEXAGON_DYNAMIC_TAG } + case EM_MIPS: switch (Type) { - LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP_REL); - LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION); - LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS); - LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS); - LLVM_READOBJ_TYPE_CASE(MIPS_LOCAL_GOTNO); - LLVM_READOBJ_TYPE_CASE(MIPS_SYMTABNO); - LLVM_READOBJ_TYPE_CASE(MIPS_UNREFEXTNO); - LLVM_READOBJ_TYPE_CASE(MIPS_GOTSYM); - LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP); - LLVM_READOBJ_TYPE_CASE(MIPS_PLTGOT); - LLVM_READOBJ_TYPE_CASE(MIPS_OPTIONS); +#define MIPS_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef MIPS_DYNAMIC_TAG + } + + 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 } } +#undef DYNAMIC_TAG switch (Type) { - LLVM_READOBJ_TYPE_CASE(ANDROID_REL); - LLVM_READOBJ_TYPE_CASE(ANDROID_RELSZ); - LLVM_READOBJ_TYPE_CASE(ANDROID_RELA); - LLVM_READOBJ_TYPE_CASE(ANDROID_RELASZ); - LLVM_READOBJ_TYPE_CASE(BIND_NOW); - LLVM_READOBJ_TYPE_CASE(DEBUG); - LLVM_READOBJ_TYPE_CASE(FINI); - LLVM_READOBJ_TYPE_CASE(FINI_ARRAY); - LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ); - LLVM_READOBJ_TYPE_CASE(FLAGS); - LLVM_READOBJ_TYPE_CASE(FLAGS_1); - LLVM_READOBJ_TYPE_CASE(HASH); - LLVM_READOBJ_TYPE_CASE(INIT); - LLVM_READOBJ_TYPE_CASE(INIT_ARRAY); - LLVM_READOBJ_TYPE_CASE(INIT_ARRAYSZ); - LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAY); - LLVM_READOBJ_TYPE_CASE(PREINIT_ARRAYSZ); - LLVM_READOBJ_TYPE_CASE(JMPREL); - LLVM_READOBJ_TYPE_CASE(NEEDED); - LLVM_READOBJ_TYPE_CASE(NULL); - LLVM_READOBJ_TYPE_CASE(PLTGOT); - LLVM_READOBJ_TYPE_CASE(PLTREL); - LLVM_READOBJ_TYPE_CASE(PLTRELSZ); - LLVM_READOBJ_TYPE_CASE(REL); - LLVM_READOBJ_TYPE_CASE(RELA); - LLVM_READOBJ_TYPE_CASE(RELENT); - LLVM_READOBJ_TYPE_CASE(RELSZ); - LLVM_READOBJ_TYPE_CASE(RELAENT); - LLVM_READOBJ_TYPE_CASE(RELASZ); - LLVM_READOBJ_TYPE_CASE(RPATH); - LLVM_READOBJ_TYPE_CASE(RUNPATH); - LLVM_READOBJ_TYPE_CASE(SONAME); - LLVM_READOBJ_TYPE_CASE(STRSZ); - LLVM_READOBJ_TYPE_CASE(STRTAB); - LLVM_READOBJ_TYPE_CASE(SYMBOLIC); - LLVM_READOBJ_TYPE_CASE(SYMENT); - LLVM_READOBJ_TYPE_CASE(SYMTAB); - LLVM_READOBJ_TYPE_CASE(TEXTREL); - LLVM_READOBJ_TYPE_CASE(VERDEF); - LLVM_READOBJ_TYPE_CASE(VERDEFNUM); - LLVM_READOBJ_TYPE_CASE(VERNEED); - LLVM_READOBJ_TYPE_CASE(VERNEEDNUM); - LLVM_READOBJ_TYPE_CASE(VERSYM); - LLVM_READOBJ_TYPE_CASE(RELACOUNT); - LLVM_READOBJ_TYPE_CASE(RELCOUNT); - LLVM_READOBJ_TYPE_CASE(GNU_HASH); - LLVM_READOBJ_TYPE_CASE(TLSDESC_PLT); - LLVM_READOBJ_TYPE_CASE(TLSDESC_GOT); - LLVM_READOBJ_TYPE_CASE(AUXILIARY); - LLVM_READOBJ_TYPE_CASE(FILTER); +// 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"; } } -#undef LLVM_READOBJ_TYPE_CASE - #define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ { #enum, prefix##_##enum } @@ -1771,16 +1842,20 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { template<class ELFT> void ELFDumper<ELFT>::printUnwindInfo() { + const unsigned Machine = Obj->getHeader()->e_machine; + if (Machine == EM_386 || Machine == EM_X86_64) { + DwarfCFIEH::PrinterContext<ELFT> Ctx(W, Obj); + return Ctx.printUnwindInformation(); + } W.startLine() << "UnwindInfo not implemented.\n"; } namespace { -template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() { +template <> void ELFDumper<ELF32LE>::printUnwindInfo() { const unsigned Machine = Obj->getHeader()->e_machine; if (Machine == EM_ARM) { - ARM::EHABI::PrinterContext<ELFType<support::little, false>> Ctx( - W, Obj, DotSymtabSec); + ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, DotSymtabSec); return Ctx.PrintUnwindInformation(); } W.startLine() << "UnwindInfo not implemented.\n"; @@ -1841,9 +1916,8 @@ void ELFDumper<ELFT>::printNeededLibraries() { std::stable_sort(Libs.begin(), Libs.end()); - for (const auto &L : Libs) { - outs() << " " << L << "\n"; - } + for (const auto &L : Libs) + W.startLine() << L << "\n"; } @@ -1877,7 +1951,7 @@ void ELFDumper<ELFT>::printGnuHashTable() { } template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { - outs() << "LoadName: " << SOName << '\n'; + W.printString("LoadName", SOName); } template <class ELFT> @@ -1887,7 +1961,7 @@ void ELFDumper<ELFT>::printAttributes() { namespace { -template <> void ELFDumper<ELFType<support::little, false>>::printAttributes() { +template <> void ELFDumper<ELF32LE>::printAttributes() { if (Obj->getHeader()->e_machine != EM_ARM) { W.startLine() << "Attributes not implemented.\n"; return; @@ -2219,7 +2293,9 @@ static const EnumEntry<unsigned> ElfMipsASEFlags[] = { {"MSA", Mips::AFL_ASE_MSA}, {"MIPS16", Mips::AFL_ASE_MIPS16}, {"microMIPS", Mips::AFL_ASE_MICROMIPS}, - {"XPA", Mips::AFL_ASE_XPA} + {"XPA", Mips::AFL_ASE_XPA}, + {"CRC", Mips::AFL_ASE_CRC}, + {"GINV", Mips::AFL_ASE_GINV}, }; static const EnumEntry<unsigned> ElfMipsFpABIType[] = { @@ -2361,14 +2437,18 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { ArrayRef<uint8_t> StackMapContentsArray = unwrapOrError(Obj->getSectionContents(StackMapSection)); - prettyPrintStackMap(outs(), StackMapV2Parser<ELFT::TargetEndianness>( - StackMapContentsArray)); + prettyPrintStackMap( + W, StackMapV2Parser<ELFT::TargetEndianness>(StackMapContentsArray)); } template <class ELFT> void ELFDumper<ELFT>::printGroupSections() { ELFDumperStyle->printGroupSections(Obj); } +template <class ELFT> void ELFDumper<ELFT>::printAddrsig() { + ELFDumperStyle->printAddrsig(Obj); +} + static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, StringRef Str2) { OS.PadToColumn(2u); @@ -2378,6 +2458,30 @@ static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, OS.flush(); } +template <class ELFT> +static std::string getSectionHeadersNumString(const ELFFile<ELFT> *Obj) { + const typename ELFT::Ehdr *ElfHeader = Obj->getHeader(); + if (ElfHeader->e_shnum != 0) + return to_string(ElfHeader->e_shnum); + + ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(Obj->sections()); + if (Arr.empty()) + return "0"; + return "0 (" + to_string(Arr[0].sh_size) + ")"; +} + +template <class ELFT> +static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj) { + const typename ELFT::Ehdr *ElfHeader = Obj->getHeader(); + if (ElfHeader->e_shstrndx != SHN_XINDEX) + return to_string(ElfHeader->e_shstrndx); + + 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) + ")"; +} + template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) { const Elf_Ehdr *e = Obj->getHeader(); OS << "ELF Header:\n"; @@ -2423,9 +2527,9 @@ template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) { printFields(OS, "Number of program headers:", Str); Str = to_string(e->e_shentsize) + " (bytes)"; printFields(OS, "Size of section headers:", Str); - Str = to_string(e->e_shnum); + Str = getSectionHeadersNumString(Obj); printFields(OS, "Number of section headers:", Str); - Str = to_string(e->e_shstrndx); + Str = getSectionHeaderTableIndexString(Obj); printFields(OS, "Section header string table index:", Str); } @@ -2440,15 +2544,17 @@ struct GroupSection { StringRef Signature; uint64_t ShName; uint64_t Index; + uint32_t Link; + uint32_t Info; uint32_t Type; std::vector<GroupMember> Members; }; template <class ELFT> std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) { - using Elf_Shdr = typename ELFFile<ELFT>::Elf_Shdr; - using Elf_Sym = typename ELFFile<ELFT>::Elf_Sym; - using Elf_Word = typename ELFFile<ELFT>::Elf_Word; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Sym = typename ELFT::Sym; + using Elf_Word = typename ELFT::Word; std::vector<GroupSection> Ret; uint64_t I = 0; @@ -2466,7 +2572,14 @@ 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, I - 1, Data[0], {}}); + Ret.push_back({Name, + Signature, + Sec.sh_name, + I - 1, + Sec.sh_link, + Sec.sh_info, + Data[0], + {}}); std::vector<GroupMember> &GM = Ret.back().Members; for (uint32_t Ndx : Data.slice(1)) { @@ -2522,7 +2635,6 @@ 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 StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); StringRef TargetName; const Elf_Sym *Sym = nullptr; unsigned Width = ELFT::Is64Bits ? 16 : 8; @@ -2538,6 +2650,7 @@ void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, 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)); } @@ -2569,35 +2682,62 @@ void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, OS << "\n"; } -static inline void printRelocHeader(raw_ostream &OS, bool Is64, bool IsRela) { - if (Is64) - OS << " Offset Info Type" +template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) { + bool IsRela = SType == ELF::SHT_RELA || SType == ELF::SHT_ANDROID_RELA; + bool IsRelr = SType == ELF::SHT_RELR || SType == ELF::SHT_ANDROID_RELR; + if (ELFT::Is64Bits) + OS << " "; + else + OS << " "; + if (IsRelr && opts::RawRelr) + OS << "Data "; + else + OS << "Offset"; + if (ELFT::Is64Bits) + OS << " Info Type" << " Symbol's Value Symbol's Name"; else - OS << " Offset Info Type Sym. Value " - << "Symbol's Name"; + OS << " Info Type Sym. Value Symbol's Name"; if (IsRela) - OS << (IsRela ? " + Addend" : ""); + OS << " + Addend"; OS << "\n"; } 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 && + 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_RELA && + Sec.sh_type != ELF::SHT_ANDROID_RELR) continue; HasRelocSections = true; StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); unsigned Entries = Sec.getEntityCount(); + std::vector<Elf_Rela> AndroidRelas; + if (Sec.sh_type == ELF::SHT_ANDROID_REL || + Sec.sh_type == ELF::SHT_ANDROID_RELA) { + // Android's packed relocation section needs to be unpacked first + // to get the actual number of entries. + AndroidRelas = unwrapOrError(Obj->android_relas(&Sec)); + Entries = AndroidRelas.size(); + } + std::vector<Elf_Rela> RelrRelas; + if (!opts::RawRelr && (Sec.sh_type == ELF::SHT_RELR || + Sec.sh_type == ELF::SHT_ANDROID_RELR)) { + // .relr.dyn relative relocation section needs to be unpacked first + // to get the actual number of entries. + Elf_Relr_Range Relrs = unwrapOrError(Obj->relrs(&Sec)); + RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); + Entries = RelrRelas.size(); + } uintX_t Offset = Sec.sh_offset; OS << "\nRelocation section '" << Name << "' at offset 0x" << to_hexString(Offset, false) << " contains " << Entries << " entries:\n"; - printRelocHeader(OS, ELFT::Is64Bits, - Sec.sh_type == ELF::SHT_RELA || - Sec.sh_type == ELF::SHT_ANDROID_RELA); + printRelocHeader(Sec.sh_type); const Elf_Shdr *SymTab = unwrapOrError(Obj->getSection(Sec.sh_link)); switch (Sec.sh_type) { case ELF::SHT_REL: @@ -2613,9 +2753,19 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { for (const auto &R : unwrapOrError(Obj->relas(&Sec))) printRelocation(Obj, SymTab, R, true); break; + case ELF::SHT_RELR: + case ELF::SHT_ANDROID_RELR: + if (opts::RawRelr) + for (const auto &R : unwrapOrError(Obj->relrs(&Sec))) + OS << to_string(format_hex_no_prefix(R, ELFT::Is64Bits ? 16 : 8)) + << "\n"; + else + for (const auto &R : RelrRelas) + printRelocation(Obj, SymTab, R, false); + break; case ELF::SHT_ANDROID_REL: case ELF::SHT_ANDROID_RELA: - for (const auto &R : unwrapOrError(Obj->android_relas(&Sec))) + for (const auto &R : AndroidRelas) printRelocation(Obj, SymTab, R, Sec.sh_type == ELF::SHT_ANDROID_RELA); break; } @@ -2694,8 +2844,17 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) { return "GROUP"; case SHT_SYMTAB_SHNDX: return "SYMTAB SECTION INDICES"; + case SHT_RELR: + case SHT_ANDROID_RELR: + return "RELR"; case SHT_LLVM_ODRTAB: return "LLVM_ODRTAB"; + case SHT_LLVM_LINKER_OPTIONS: + return "LLVM_LINKER_OPTIONS"; + case SHT_LLVM_CALL_GRAPH_PROFILE: + return "LLVM_CALL_GRAPH_PROFILE"; + case SHT_LLVM_ADDRSIG: + return "LLVM_ADDRSIG"; // FIXME: Parse processor specific GNU attributes case SHT_GNU_ATTRIBUTES: return "ATTRIBUTES"; @@ -2727,7 +2886,9 @@ template <class ELFT> void GNUStyle<ELFT>::printSections(const ELFO *Obj) { Bias = 8; Width = 8; } - OS << "There are " << to_string(Obj->getHeader()->e_shnum) + + 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"; @@ -2746,7 +2907,7 @@ template <class ELFT> void GNUStyle<ELFT>::printSections(const ELFO *Obj) { printField(f); OS << "\n"; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + for (const Elf_Shdr &Sec : Sections) { Number = to_string(SectionIndex); Fields[0].Str = Number; Fields[1].Str = unwrapOrError(Obj->getSectionName(&Sec)); @@ -3198,13 +3359,14 @@ template <class ELFT> void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion(); const DynRegionInfo &DynRelaRegion = this->dumper()->getDynRelaRegion(); + const DynRegionInfo &DynRelrRegion = this->dumper()->getDynRelrRegion(); const DynRegionInfo &DynPLTRelRegion = this->dumper()->getDynPLTRelRegion(); if (DynRelaRegion.Size > 0) { OS << "\n'RELA' relocation section at offset " << format_hex(reinterpret_cast<const uint8_t *>(DynRelaRegion.Addr) - Obj->base(), 1) << " contains " << DynRelaRegion.Size << " bytes:\n"; - printRelocHeader(OS, ELFT::Is64Bits, true); + printRelocHeader(ELF::SHT_RELA); for (const Elf_Rela &Rela : this->dumper()->dyn_relas()) printDynamicRelocation(Obj, Rela, true); } @@ -3213,7 +3375,7 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { << format_hex(reinterpret_cast<const uint8_t *>(DynRelRegion.Addr) - Obj->base(), 1) << " contains " << DynRelRegion.Size << " bytes:\n"; - printRelocHeader(OS, ELFT::Is64Bits, false); + printRelocHeader(ELF::SHT_REL); for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) { Elf_Rela Rela; Rela.r_offset = Rel.r_offset; @@ -3222,6 +3384,18 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { printDynamicRelocation(Obj, Rela, false); } } + if (DynRelrRegion.Size > 0) { + OS << "\n'RELR' relocation section at offset " + << format_hex(reinterpret_cast<const uint8_t *>(DynRelrRegion.Addr) - + Obj->base(), + 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)); + for (const Elf_Rela &Rela : RelrRelas) { + printDynamicRelocation(Obj, Rela, false); + } + } if (DynPLTRelRegion.Size) { OS << "\n'PLT' relocation section at offset " << format_hex(reinterpret_cast<const uint8_t *>(DynPLTRelRegion.Addr) - @@ -3229,11 +3403,11 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { 1) << " contains " << DynPLTRelRegion.Size << " bytes:\n"; } if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) { - printRelocHeader(OS, ELFT::Is64Bits, true); + printRelocHeader(ELF::SHT_RELA); for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>()) printDynamicRelocation(Obj, Rela, true); } else { - printRelocHeader(OS, ELFT::Is64Bits, false); + printRelocHeader(ELF::SHT_REL); for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef<Elf_Rel>()) { Elf_Rela Rela; Rela.r_offset = Rel.r_offset; @@ -3349,6 +3523,16 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) { } } +template <class ELFT> +void GNUStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) { + OS << "GNUStyle::printCGProfile not implemented\n"; +} + +template <class ELFT> +void GNUStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { + OS << "GNUStyle::printAddrsig not implemented\n"; +} + static std::string getGNUNoteTypeName(const uint32_t NT) { static const struct { uint32_t ID; @@ -3358,6 +3542,7 @@ static std::string getGNUNoteTypeName(const uint32_t NT) { {ELF::NT_GNU_HWCAP, "NT_GNU_HWCAP (DSO-supplied software HWCAP info)"}, {ELF::NT_GNU_BUILD_ID, "NT_GNU_BUILD_ID (unique build ID bitstring)"}, {ELF::NT_GNU_GOLD_VERSION, "NT_GNU_GOLD_VERSION (gold version)"}, + {ELF::NT_GNU_PROPERTY_TYPE_0, "NT_GNU_PROPERTY_TYPE_0 (property note)"}, }; for (const auto &Note : Notes) @@ -3422,9 +3607,65 @@ static std::string getAMDGPUNoteTypeName(const uint32_t NT) { } template <typename ELFT> +static void printGNUProperty(raw_ostream &OS, uint32_t Type, uint32_t DataSize, + ArrayRef<uint8_t> Data) { + switch (Type) { + default: + OS << format(" <application-specific type 0x%x>\n", Type); + return; + case GNU_PROPERTY_STACK_SIZE: { + OS << " stack size: "; + if (DataSize == sizeof(typename ELFT::uint)) + OS << format("0x%llx\n", + (uint64_t)(*(const typename ELFT::Addr *)Data.data())); + else + OS << format("<corrupt length: 0x%x>\n", DataSize); + break; + } + case GNU_PROPERTY_NO_COPY_ON_PROTECTED: + OS << " no copy on protected"; + if (DataSize) + OS << format(" <corrupt length: 0x%x>", DataSize); + OS << "\n"; + break; + case GNU_PROPERTY_X86_FEATURE_1_AND: + OS << " X86 features: "; + if (DataSize != 4 && DataSize != 8) { + OS << format("<corrupt length: 0x%x>\n", DataSize); + break; + } + uint64_t CFProtection = + (DataSize == 4) + ? support::endian::read32<ELFT::TargetEndianness>(Data.data()) + : support::endian::read64<ELFT::TargetEndianness>(Data.data()); + if (CFProtection == 0) { + OS << "none\n"; + break; + } + if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_IBT) { + OS << "IBT"; + CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_IBT; + if (CFProtection) + OS << ", "; + } + if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_SHSTK) { + OS << "SHSTK"; + CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK; + if (CFProtection) + OS << ", "; + } + if (CFProtection) + OS << format("<unknown flags: 0x%llx>", CFProtection); + OS << "\n"; + break; + } +} + +template <typename ELFT> static void printGNUNote(raw_ostream &OS, uint32_t NoteType, - ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words, - size_t Size) { + ArrayRef<typename ELFT::Word> Words, size_t Size) { + using Elf_Word = typename ELFT::Word; + switch (NoteType) { default: return; @@ -3456,15 +3697,37 @@ static void printGNUNote(raw_ostream &OS, uint32_t NoteType, OS << " Version: " << StringRef(reinterpret_cast<const char *>(Words.data()), Size); break; - } + case ELF::NT_GNU_PROPERTY_TYPE_0: + OS << " Properties:"; + + ArrayRef<uint8_t> Arr(reinterpret_cast<const uint8_t *>(Words.data()), + Size); + while (Arr.size() >= 8) { + uint32_t Type = *reinterpret_cast<const Elf_Word *>(Arr.data()); + uint32_t DataSize = *reinterpret_cast<const Elf_Word *>(Arr.data() + 4); + Arr = Arr.drop_front(8); + + // Take padding size into account if present. + uint64_t PaddedSize = alignTo(DataSize, sizeof(typename ELFT::uint)); + if (Arr.size() < PaddedSize) { + OS << format(" <corrupt type (0x%x) datasz: 0x%x>\n", Type, + DataSize); + break; + } + printGNUProperty<ELFT>(OS, Type, DataSize, Arr.take_front(PaddedSize)); + Arr = Arr.drop_front(PaddedSize); + } + if (!Arr.empty()) + OS << " <corrupted GNU_PROPERTY_TYPE_0>"; + break; + } OS << '\n'; } template <typename ELFT> static void printAMDGPUNote(raw_ostream &OS, uint32_t NoteType, - ArrayRef<typename ELFFile<ELFT>::Elf_Word> Words, - size_t Size) { + ArrayRef<typename ELFT::Word> Words, size_t Size) { switch (NoteType) { default: return; @@ -3499,66 +3762,66 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { const Elf_Ehdr *e = Obj->getHeader(); bool IsCore = e->e_type == ELF::ET_CORE; - auto process = [&](const typename ELFFile<ELFT>::Elf_Off Offset, - const typename ELFFile<ELFT>::Elf_Addr Size) { - if (Size <= 0) - return; - - const auto *P = static_cast<const uint8_t *>(Obj->base() + Offset); - const auto *E = P + Size; - + auto PrintHeader = [&](const typename ELFT::Off Offset, + const typename ELFT::Addr Size) { OS << "Displaying notes found at file offset " << format_hex(Offset, 10) << " with length " << format_hex(Size, 10) << ":\n" << " Owner Data size\tDescription\n"; + }; - while (P < E) { - const Elf_Word *Words = reinterpret_cast<const Elf_Word *>(&P[0]); - - uint32_t NameSize = Words[0]; - uint32_t DescriptorSize = Words[1]; - uint32_t Type = Words[2]; - - ArrayRef<Elf_Word> Descriptor(&Words[3 + (alignTo<4>(NameSize) / 4)], - alignTo<4>(DescriptorSize) / 4); - - StringRef Name; - if (NameSize) - Name = - StringRef(reinterpret_cast<const char *>(&Words[3]), NameSize - 1); - - OS << " " << Name << std::string(22 - NameSize, ' ') - << format_hex(DescriptorSize, 10) << '\t'; - - if (Name == "GNU") { - OS << getGNUNoteTypeName(Type) << '\n'; - printGNUNote<ELFT>(OS, Type, Descriptor, DescriptorSize); - } else if (Name == "FreeBSD") { - OS << getFreeBSDNoteTypeName(Type) << '\n'; - } else if (Name == "AMD") { - OS << getAMDGPUNoteTypeName(Type) << '\n'; - printAMDGPUNote<ELFT>(OS, Type, Descriptor, DescriptorSize); - } else { - OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; - } - OS << '\n'; - - P = P + 3 * sizeof(Elf_Word) + alignTo<4>(NameSize) + - alignTo<4>(DescriptorSize); + auto ProcessNote = [&](const Elf_Note &Note) { + StringRef Name = Note.getName(); + ArrayRef<Elf_Word> Descriptor = Note.getDesc(); + Elf_Word Type = Note.getType(); + + OS << " " << Name << std::string(22 - Name.size(), ' ') + << format_hex(Descriptor.size(), 10) << '\t'; + + if (Name == "GNU") { + OS << getGNUNoteTypeName(Type) << '\n'; + printGNUNote<ELFT>(OS, Type, Descriptor, Descriptor.size()); + } else if (Name == "FreeBSD") { + OS << getFreeBSDNoteTypeName(Type) << '\n'; + } else if (Name == "AMD") { + OS << getAMDGPUNoteTypeName(Type) << '\n'; + printAMDGPUNote<ELFT>(OS, Type, Descriptor, Descriptor.size()); + } else { + OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; } + OS << '\n'; }; if (IsCore) { - for (const auto &P : unwrapOrError(Obj->program_headers())) - if (P.p_type == PT_NOTE) - process(P.p_offset, P.p_filesz); + for (const auto &P : unwrapOrError(Obj->program_headers())) { + if (P.p_type != PT_NOTE) + continue; + PrintHeader(P.p_offset, P.p_filesz); + Error Err = Error::success(); + for (const auto &Note : Obj->notes(P, Err)) + ProcessNote(Note); + if (Err) + error(std::move(Err)); + } } else { - for (const auto &S : unwrapOrError(Obj->sections())) - if (S.sh_type == SHT_NOTE) - process(S.sh_offset, S.sh_size); + for (const auto &S : unwrapOrError(Obj->sections())) { + if (S.sh_type != SHT_NOTE) + continue; + PrintHeader(S.sh_offset, S.sh_size); + Error Err = Error::success(); + for (const auto &Note : Obj->notes(S, Err)) + ProcessNote(Note); + if (Err) + error(std::move(Err)); + } } } template <class ELFT> +void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { + OS << "printELFLinkerOptions not implemented!\n"; +} + +template <class ELFT> void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { size_t Bias = ELFT::Is64Bits ? 8 : 0; auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) { @@ -3715,7 +3978,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { unsigned(ELF::EF_MIPS_MACH)); else if (e->e_machine == EM_AMDGPU) W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags), - unsigned(ELF::EF_AMDGPU_ARCH)); + unsigned(ELF::EF_AMDGPU_MACH)); else if (e->e_machine == EM_RISCV) W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderRISCVFlags)); else @@ -3724,8 +3987,8 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { W.printNumber("ProgramHeaderEntrySize", e->e_phentsize); W.printNumber("ProgramHeaderCount", e->e_phnum); W.printNumber("SectionHeaderEntrySize", e->e_shentsize); - W.printNumber("SectionHeaderCount", e->e_shnum); - W.printNumber("StringTableSectionIndex", e->e_shstrndx); + W.printString("SectionHeaderCount", getSectionHeadersNumString(Obj)); + W.printString("StringTableSectionIndex", getSectionHeaderTableIndexString(Obj)); } } @@ -3738,6 +4001,8 @@ void LLVMStyle<ELFT>::printGroupSections(const ELFO *Obj) { DictScope D(W, "Group"); W.printNumber("Name", G.Name, G.ShName); W.printNumber("Index", G.Index); + W.printNumber("Link", G.Link); + W.printNumber("Info", G.Info); W.printHex("Type", getGroupType(G.Type), G.Type); W.startLine() << "Signature: " << G.Signature << "\n"; @@ -3768,9 +4033,12 @@ 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 && + 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_RELA && + Sec.sh_type != ELF::SHT_ANDROID_RELR) continue; StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); @@ -3803,6 +4071,19 @@ void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { for (const Elf_Rela &R : unwrapOrError(Obj->relas(Sec))) printRelocation(Obj, R, SymTab); break; + case ELF::SHT_RELR: + case ELF::SHT_ANDROID_RELR: { + Elf_Relr_Range Relrs = unwrapOrError(Obj->relrs(Sec)); + if (opts::RawRelr) { + for (const Elf_Relr &R : Relrs) + W.startLine() << W.hex(R) << "\n"; + } else { + std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); + for (const Elf_Rela &R : RelrRelas) + printRelocation(Obj, R, SymTab); + } + break; + } case ELF::SHT_ANDROID_REL: case ELF::SHT_ANDROID_RELA: for (const Elf_Rela &R : unwrapOrError(Obj->android_relas(Sec))) @@ -3983,6 +4264,7 @@ template <class ELFT> void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion(); const DynRegionInfo &DynRelaRegion = this->dumper()->getDynRelaRegion(); + const DynRegionInfo &DynRelrRegion = this->dumper()->getDynRelrRegion(); const DynRegionInfo &DynPLTRelRegion = this->dumper()->getDynPLTRelRegion(); if (DynRelRegion.Size && DynRelaRegion.Size) report_fatal_error("There are both REL and RELA dynamic relocations"); @@ -3999,6 +4281,12 @@ void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { Rela.r_addend = 0; printDynamicRelocation(Obj, Rela); } + if (DynRelrRegion.Size > 0) { + Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); + std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); + for (const Elf_Rela &Rela : RelrRelas) + printDynamicRelocation(Obj, Rela); + } if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>()) printDynamicRelocation(Obj, Rela); @@ -4062,11 +4350,71 @@ void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) { } template <class ELFT> +void LLVMStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) { + ListScope L(W, "CGProfile"); + if (!this->dumper()->getDotCGProfileSec()) + return; + auto CGProfile = + unwrapOrError(Obj->template getSectionContentsAsArray<Elf_CGProfile>( + this->dumper()->getDotCGProfileSec())); + for (const Elf_CGProfile &CGPE : CGProfile) { + DictScope D(W, "CGProfileEntry"); + W.printNumber("From", this->dumper()->getStaticSymbolName(CGPE.cgp_from), + CGPE.cgp_from); + W.printNumber("To", this->dumper()->getStaticSymbolName(CGPE.cgp_to), + CGPE.cgp_to); + W.printNumber("Weight", CGPE.cgp_weight); + } +} + +template <class ELFT> +void LLVMStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { + ListScope L(W, "Addrsig"); + if (!this->dumper()->getDotAddrsigSec()) + return; + ArrayRef<uint8_t> Contents = unwrapOrError( + Obj->getSectionContents(this->dumper()->getDotAddrsigSec())); + const uint8_t *Cur = Contents.begin(); + const uint8_t *End = Contents.end(); + while (Cur != End) { + unsigned Size; + const char *Err; + uint64_t SymIndex = decodeULEB128(Cur, &Size, Contents.end(), &Err); + if (Err) + reportError(Err); + W.printNumber("Sym", this->dumper()->getStaticSymbolName(SymIndex), + SymIndex); + Cur += Size; + } +} + +template <class ELFT> void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { W.startLine() << "printNotes not implemented!\n"; } template <class ELFT> +void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { + ListScope L(W, "LinkerOptions"); + + for (const Elf_Shdr &Shdr : unwrapOrError(Obj->sections())) { + if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS) + continue; + + ArrayRef<uint8_t> Contents = unwrapOrError(Obj->getSectionContents(&Shdr)); + for (const uint8_t *P = Contents.begin(), *E = Contents.end(); P < E; ) { + StringRef Key = StringRef(reinterpret_cast<const char *>(P)); + StringRef Value = + StringRef(reinterpret_cast<const char *>(P) + Key.size() + 1); + + W.printString(Key, Value); + + P = P + Key.size() + Value.size() + 2; + } + } +} + +template <class ELFT> void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { auto PrintEntry = [&](const Elf_Addr *E) { W.printHex("Address", Parser.getGotAddress(E)); diff --git a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp index 64178d7b33ad..69ef1556f78d 100644 --- a/contrib/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/MachODumper.cpp @@ -669,12 +669,11 @@ void MachODumper::printStackMap() const { StackMapContents.size()); if (Obj->isLittleEndian()) - prettyPrintStackMap( - llvm::outs(), - StackMapV2Parser<support::little>(StackMapContentsArray)); + prettyPrintStackMap( + W, StackMapV2Parser<support::little>(StackMapContentsArray)); else - prettyPrintStackMap(llvm::outs(), - StackMapV2Parser<support::big>(StackMapContentsArray)); + prettyPrintStackMap(W, + StackMapV2Parser<support::big>(StackMapContentsArray)); } void MachODumper::printNeededLibraries() { diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp index 2a0a90e5cfd5..a725140c9d33 100644 --- a/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.cpp @@ -8,13 +8,15 @@ //===----------------------------------------------------------------------===// /// /// \file -/// \brief This file implements ObjDumper. +/// This file implements ObjDumper. /// //===----------------------------------------------------------------------===// #include "ObjDumper.h" #include "Error.h" +#include "llvm-readobj.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/Support/raw_ostream.h" @@ -25,4 +27,122 @@ ObjDumper::ObjDumper(ScopedPrinter &Writer) : W(Writer) {} ObjDumper::~ObjDumper() { } +static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) { + for (size_t i = 0; i < Len; i++) + 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; + + 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; + + if (std::error_code E = Section.getName(SectionName)) + error(E); + W.startLine() << "String dump of section '" << SectionName << "':\n"; + + StringRef SectionContent; + Section.getContents(SectionContent); + + 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; + } +} + +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; + + if (std::error_code E = Section.getName(SectionName)) + error(E); + W.startLine() << "Hex dump of section '" << SectionName << "':\n"; + + 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; + + 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() << ' '; + } + + // 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]) + : '.'); + + W.startLine() << '\n'; + } +} + } // namespace llvm diff --git a/contrib/llvm/tools/llvm-readobj/ObjDumper.h b/contrib/llvm/tools/llvm-readobj/ObjDumper.h index c5b331d944a2..8c3a7bec73be 100644 --- a/contrib/llvm/tools/llvm-readobj/ObjDumper.h +++ b/contrib/llvm/tools/llvm-readobj/ObjDumper.h @@ -13,6 +13,9 @@ #include <memory> #include <system_error> +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/ObjectFile.h" + namespace llvm { namespace object { class COFFImportFile; @@ -41,13 +44,17 @@ public: virtual void printDynamicTable() { } virtual void printNeededLibraries() { } virtual void printProgramHeaders() { } + virtual void printSectionAsHex(StringRef SectionName) {} virtual void printHashTable() { } virtual void printGnuHashTable() { } virtual void printLoadName() {} virtual void printVersionInfo() {} virtual void printGroupSections() {} virtual void printHashHistogram() {} + virtual void printCGProfile() {} + virtual void printAddrsig() {} virtual void printNotes() {} + virtual void printELFLinkerOptions() {} // Only implemented for ARM ELF at this time. virtual void printAttributes() { } @@ -81,6 +88,9 @@ public: virtual void printStackMap() const = 0; + void printSectionAsString(const object::ObjectFile *Obj, StringRef SecName); + void printSectionAsHex(const object::ObjectFile *Obj, StringRef SecName); + protected: ScopedPrinter &W; }; @@ -101,7 +111,8 @@ std::error_code createWasmDumper(const object::ObjectFile *Obj, ScopedPrinter &Writer, std::unique_ptr<ObjDumper> &Result); -void dumpCOFFImportFile(const object::COFFImportFile *File); +void dumpCOFFImportFile(const object::COFFImportFile *File, + ScopedPrinter &Writer); void dumpCodeViewMergedTypes( ScopedPrinter &Writer, llvm::codeview::MergingTypeTableBuilder &IDTable, diff --git a/contrib/llvm/tools/llvm-readobj/StackMapPrinter.h b/contrib/llvm/tools/llvm-readobj/StackMapPrinter.h index f4ed68e92d78..77a054b178a5 100644 --- a/contrib/llvm/tools/llvm-readobj/StackMapPrinter.h +++ b/contrib/llvm/tools/llvm-readobj/StackMapPrinter.h @@ -11,69 +11,70 @@ #define LLVM_TOOLS_LLVM_READOBJ_STACKMAPPRINTER_H #include "llvm/Object/StackMapParser.h" +#include "llvm/Support/ScopedPrinter.h" namespace llvm { // Pretty print a stackmap to the given ostream. -template <typename OStreamT, typename StackMapParserT> -void prettyPrintStackMap(OStreamT &OS, const StackMapParserT &SMP) { +template <typename StackMapParserT> +void prettyPrintStackMap(ScopedPrinter &W, const StackMapParserT &SMP) { - OS << "LLVM StackMap Version: " << SMP.getVersion() - << "\nNum Functions: " << SMP.getNumFunctions(); + W.printNumber("LLVM StackMap Version", SMP.getVersion()); + W.printNumber("Num Functions", SMP.getNumFunctions()); // Functions: for (const auto &F : SMP.functions()) - OS << "\n Function address: " << F.getFunctionAddress() + W.startLine() << " Function address: " << F.getFunctionAddress() << ", stack size: " << F.getStackSize() - << ", callsite record count: " << F.getRecordCount(); + << ", callsite record count: " << F.getRecordCount() << "\n"; // Constants: - OS << "\nNum Constants: " << SMP.getNumConstants(); + W.printNumber("Num Constants", SMP.getNumConstants()); unsigned ConstantIndex = 0; for (const auto &C : SMP.constants()) - OS << "\n #" << ++ConstantIndex << ": " << C.getValue(); + W.startLine() << " #" << ++ConstantIndex << ": " << C.getValue() << "\n"; // Records: - OS << "\nNum Records: " << SMP.getNumRecords(); + W.printNumber("Num Records", SMP.getNumRecords()); for (const auto &R : SMP.records()) { - OS << "\n Record ID: " << R.getID() - << ", instruction offset: " << R.getInstructionOffset() - << "\n " << R.getNumLocations() << " locations:"; + W.startLine() << " Record ID: " << R.getID() + << ", instruction offset: " << R.getInstructionOffset() + << "\n"; + W.startLine() << " " << R.getNumLocations() << " locations:\n"; unsigned LocationIndex = 0; for (const auto &Loc : R.locations()) { - OS << "\n #" << ++LocationIndex << ": "; + raw_ostream &OS = W.startLine(); + OS << " #" << ++LocationIndex << ": "; switch (Loc.getKind()) { case StackMapParserT::LocationKind::Register: - OS << "Register R#" << Loc.getDwarfRegNum(); + OS << "Register R#" << Loc.getDwarfRegNum() << "\n"; break; case StackMapParserT::LocationKind::Direct: - OS << "Direct R#" << Loc.getDwarfRegNum() << " + " - << Loc.getOffset(); + OS << "Direct R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset() + << "\n"; break; case StackMapParserT::LocationKind::Indirect: - OS << "Indirect [R#" << Loc.getDwarfRegNum() << " + " - << Loc.getOffset() << "]"; + OS << "Indirect [R#" << Loc.getDwarfRegNum() << " + " << Loc.getOffset() + << "]\n"; break; case StackMapParserT::LocationKind::Constant: - OS << "Constant " << Loc.getSmallConstant(); + OS << "Constant " << Loc.getSmallConstant() << "\n"; break; case StackMapParserT::LocationKind::ConstantIndex: OS << "ConstantIndex #" << Loc.getConstantIndex() << " (" - << SMP.getConstant(Loc.getConstantIndex()).getValue() << ")"; + << SMP.getConstant(Loc.getConstantIndex()).getValue() << ")\n"; break; } } - OS << "\n " << R.getNumLiveOuts() << " live-outs: [ "; + raw_ostream &OS = W.startLine(); + OS << " " << R.getNumLiveOuts() << " live-outs: [ "; for (const auto &LO : R.liveouts()) OS << "R#" << LO.getDwarfRegNum() << " (" << LO.getSizeInBytes() << "-bytes) "; OS << "]\n"; } - - OS << "\n"; - } } diff --git a/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp b/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp index 223c1c752469..ce224836225e 100644 --- a/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/WasmDumper.cpp @@ -23,12 +23,11 @@ using namespace object; namespace { static const EnumEntry<unsigned> WasmSymbolTypes[] = { -#define ENUM_ENTRY(X) { #X, static_cast<unsigned>(WasmSymbol::SymbolType::X) } - ENUM_ENTRY(FUNCTION_IMPORT), - ENUM_ENTRY(FUNCTION_EXPORT), - ENUM_ENTRY(GLOBAL_IMPORT), - ENUM_ENTRY(GLOBAL_EXPORT), - ENUM_ENTRY(DEBUG_FUNCTION_NAME), +#define ENUM_ENTRY(X) { #X, wasm::WASM_SYMBOL_TYPE_##X } + ENUM_ENTRY(FUNCTION), + ENUM_ENTRY(DATA), + ENUM_ENTRY(GLOBAL), + ENUM_ENTRY(SECTION), #undef ENUM_ENTRY }; @@ -81,11 +80,18 @@ void WasmDumper::printRelocation(const SectionRef &Section, Reloc.getTypeName(RelocTypeName); const wasm::WasmRelocation &WasmReloc = Obj->getWasmRelocation(Reloc); + StringRef SymName; + symbol_iterator SI = Reloc.getSymbol(); + if (SI != Obj->symbol_end()) + SymName = error(SI->getName()); + 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: HasAddend = true; break; default: @@ -95,13 +101,19 @@ void WasmDumper::printRelocation(const SectionRef &Section, DictScope Group(W, "Relocation"); W.printNumber("Type", RelocTypeName, RelocType); W.printHex("Offset", Reloc.getOffset()); - W.printHex("Index", WasmReloc.Index); + if (!SymName.empty()) + W.printString("Symbol", SymName); + else + W.printHex("Index", WasmReloc.Index); if (HasAddend) W.printNumber("Addend", WasmReloc.Addend); } else { raw_ostream& OS = W.startLine(); - OS << W.hex(Reloc.getOffset()) << " " << RelocTypeName << "[" - << WasmReloc.Index << "]"; + OS << W.hex(Reloc.getOffset()) << " " << RelocTypeName << " "; + if (!SymName.empty()) + OS << SymName; + else + OS << WasmReloc.Index; if (HasAddend) OS << " " << WasmReloc.Addend; OS << "\n"; @@ -155,12 +167,10 @@ void WasmDumper::printSections() { W.printString("Name", WasmSec.Name); if (WasmSec.Name == "linking") { const wasm::WasmLinkingData &LinkingData = Obj->linkingData(); - W.printNumber("DataSize", LinkingData.DataSize); if (!LinkingData.InitFunctions.empty()) { ListScope Group(W, "InitFunctions"); for (const wasm::WasmInitFunc &F: LinkingData.InitFunctions) - W.startLine() << F.FunctionIndex << " (priority=" << F.Priority - << ")\n"; + W.startLine() << F.Symbol << " (priority=" << F.Priority << ")\n"; } } break; @@ -204,9 +214,9 @@ void WasmDumper::printSections() { void WasmDumper::printSymbol(const SymbolRef &Sym) { DictScope D(W, "Symbol"); WasmSymbol Symbol = Obj->getWasmSymbol(Sym.getRawDataRefImpl()); - W.printString("Name", Symbol.Name); - W.printEnum("Type", static_cast<unsigned>(Symbol.Type), makeArrayRef(WasmSymbolTypes)); - W.printHex("Flags", Symbol.Flags); + W.printString("Name", Symbol.Info.Name); + W.printEnum("Type", Symbol.Info.Kind, makeArrayRef(WasmSymbolTypes)); + W.printHex("Flags", Symbol.Info.Flags); } } diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp index c076582794fe..a7236c02b8ae 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -34,11 +34,10 @@ #include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/ManagedStatic.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/InitLLVM.h" #include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/Signals.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; @@ -147,6 +146,18 @@ namespace opts { cl::alias ProgramHeadersShort("l", cl::desc("Alias for --program-headers"), cl::aliasopt(ProgramHeaders)); + // -string-dump + 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)); + + // -hex-dump + 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)); + // -hash-table cl::opt<bool> HashTable("hash-table", cl::desc("Display ELF hash table")); @@ -159,6 +170,10 @@ namespace opts { cl::opt<bool> ExpandRelocs("expand-relocs", cl::desc("Expand each shown relocation to multiple lines")); + // -raw-relr + cl::opt<bool> RawRelr("raw-relr", + cl::desc("Do not decode relocations in SHT_RELR section, display raw contents")); + // -codeview cl::opt<bool> CodeView("codeview", cl::desc("Display CodeView debug information")); @@ -228,6 +243,11 @@ namespace opts { COFFLoadConfig("coff-load-config", cl::desc("Display the PE/COFF load config")); + // -elf-linker-options + cl::opt<bool> + ELFLinkerOptions("elf-linker-options", + cl::desc("Display the ELF .linker-options section")); + // -macho-data-in-code cl::opt<bool> MachODataInCode("macho-data-in-code", @@ -280,6 +300,11 @@ namespace opts { cl::alias HashHistogramShort("I", cl::desc("Alias for -elf-hash-histogram"), cl::aliasopt(HashHistogram)); + cl::opt<bool> CGProfile("elf-cg-profile", cl::desc("Display callgraph profile section")); + + cl::opt<bool> Addrsig("elf-addrsig", + cl::desc("Display address-significance table")); + cl::opt<OutputStyleTy> Output("elf-output-style", cl::desc("Specify ELF dump style"), cl::values(clEnumVal(LLVM, "LLVM default style"), @@ -355,7 +380,7 @@ struct ReadObjTypeTableBuilder { } static ReadObjTypeTableBuilder CVTypes; -/// @brief Creates an format-specific object file dumper. +/// Creates an format-specific object file dumper. static std::error_code createDumper(const ObjectFile *Obj, ScopedPrinter &Writer, std::unique_ptr<ObjDumper> &Result) { @@ -374,20 +399,20 @@ static std::error_code createDumper(const ObjectFile *Obj, return readobj_error::unsupported_obj_file_format; } -/// @brief Dumps the specified object file. -static void dumpObject(const ObjectFile *Obj) { - ScopedPrinter Writer(outs()); +/// Dumps the specified object file. +static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer) { std::unique_ptr<ObjDumper> Dumper; if (std::error_code EC = createDumper(Obj, Writer, Dumper)) reportError(Obj->getFileName(), EC); if (opts::Output == opts::LLVM) { - outs() << '\n'; - outs() << "File: " << Obj->getFileName() << "\n"; - outs() << "Format: " << Obj->getFileFormatName() << "\n"; - outs() << "Arch: " << Triple::getArchTypeName( - (llvm::Triple::ArchType)Obj->getArch()) << "\n"; - outs() << "AddressSize: " << (8 * Obj->getBytesInAddress()) << "bit\n"; + Writer.startLine() << "\n"; + Writer.printString("File", Obj->getFileName()); + 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(); } @@ -411,6 +436,14 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printNeededLibraries(); if (opts::ProgramHeaders) Dumper->printProgramHeaders(); + if (!opts::StringDump.empty()) + llvm::for_each(opts::StringDump, [&Dumper, Obj](StringRef SectionName) { + Dumper->printSectionAsString(Obj, SectionName); + }); + if (!opts::HexDump.empty()) + llvm::for_each(opts::HexDump, [&Dumper, Obj](StringRef SectionName) { + Dumper->printSectionAsHex(Obj, SectionName); + }); if (opts::HashTable) Dumper->printHashTable(); if (opts::GnuHashTable) @@ -418,6 +451,8 @@ static void dumpObject(const ObjectFile *Obj) { if (opts::VersionInfo) Dumper->printVersionInfo(); if (Obj->isELF()) { + if (opts::ELFLinkerOptions) + Dumper->printELFLinkerOptions(); if (Obj->getArch() == llvm::Triple::arm) if (opts::ARMAttributes) Dumper->printAttributes(); @@ -435,6 +470,10 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printGroupSections(); if (opts::HashHistogram) Dumper->printHashHistogram(); + if (opts::CGProfile) + Dumper->printCGProfile(); + if (opts::Addrsig) + Dumper->printAddrsig(); if (opts::Notes) Dumper->printNotes(); } @@ -476,8 +515,8 @@ static void dumpObject(const ObjectFile *Obj) { Dumper->printStackMap(); } -/// @brief Dumps each object file in \a Arc; -static void dumpArchive(const Archive *Arc) { +/// Dumps each object file in \a Arc; +static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) { Error Err = Error::success(); for (auto &Child : Arc->children(Err)) { Expected<std::unique_ptr<Binary>> ChildOrErr = Child.getAsBinary(); @@ -488,9 +527,9 @@ static void dumpArchive(const Archive *Arc) { continue; } if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) - dumpObject(Obj); + dumpObject(Obj, Writer); else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(&*ChildOrErr.get())) - dumpCOFFImportFile(Imp); + dumpCOFFImportFile(Imp, Writer); else reportError(Arc->getFileName(), readobj_error::unrecognized_file_format); } @@ -498,21 +537,22 @@ static void dumpArchive(const Archive *Arc) { reportError(Arc->getFileName(), std::move(Err)); } -/// @brief Dumps each object file in \a MachO Universal Binary; -static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary) { +/// Dumps each object file in \a MachO Universal Binary; +static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary, + ScopedPrinter &Writer) { for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) { Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile(); if (ObjOrErr) - dumpObject(&*ObjOrErr.get()); + dumpObject(&*ObjOrErr.get(), Writer); else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) { reportError(UBinary->getFileName(), ObjOrErr.takeError()); } else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive()) - dumpArchive(&*AOrErr.get()); + dumpArchive(&*AOrErr.get(), Writer); } } -/// @brief Dumps \a WinRes, Windows Resource (.res) file; +/// Dumps \a WinRes, Windows Resource (.res) file; static void dumpWindowsResourceFile(WindowsResource *WinRes) { ScopedPrinter Printer{outs()}; WindowsRes::Dumper Dumper(WinRes, Printer); @@ -521,8 +561,9 @@ static void dumpWindowsResourceFile(WindowsResource *WinRes) { } -/// @brief Opens \a File and dumps it. +/// Opens \a File and dumps it. static void dumpInput(StringRef File) { + ScopedPrinter Writer(outs()); // Attempt to open the binary. Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File); @@ -531,14 +572,14 @@ static void dumpInput(StringRef File) { Binary &Binary = *BinaryOrErr.get().getBinary(); if (Archive *Arc = dyn_cast<Archive>(&Binary)) - dumpArchive(Arc); + dumpArchive(Arc, Writer); else if (MachOUniversalBinary *UBinary = dyn_cast<MachOUniversalBinary>(&Binary)) - dumpMachOUniversalBinary(UBinary); + dumpMachOUniversalBinary(UBinary, Writer); else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) - dumpObject(Obj); + dumpObject(Obj, Writer); else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary)) - dumpCOFFImportFile(Import); + dumpCOFFImportFile(Import, Writer); else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary)) dumpWindowsResourceFile(WinRes); else @@ -546,17 +587,14 @@ static void dumpInput(StringRef File) { } int main(int argc, const char *argv[]) { - StringRef ToolName = argv[0]; - sys::PrintStackTraceOnErrorSignal(ToolName); - PrettyStackTraceProgram X(argc, argv); - llvm_shutdown_obj Y; + InitLLVM X(argc, argv); // Register the target printer for --version. cl::AddExtraVersionPrinter(TargetRegistry::printRegisteredTargetsForVersion); opts::WideOutput.setHiddenFlag(cl::Hidden); - if (sys::path::stem(ToolName).find("readelf") != StringRef::npos) + if (sys::path::stem(argv[0]).find("readelf") != StringRef::npos) opts::Output = opts::GNU; cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n"); diff --git a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h index 840ddbabdc59..374ffd03e13a 100644 --- a/contrib/llvm/tools/llvm-readobj/llvm-readobj.h +++ b/contrib/llvm/tools/llvm-readobj/llvm-readobj.h @@ -60,6 +60,7 @@ namespace opts { extern llvm::cl::opt<bool> DynamicSymbols; extern llvm::cl::opt<bool> UnwindInfo; extern llvm::cl::opt<bool> ExpandRelocs; + extern llvm::cl::opt<bool> RawRelr; extern llvm::cl::opt<bool> CodeView; extern llvm::cl::opt<bool> CodeViewSubsectionBytes; extern llvm::cl::opt<bool> ARMAttributes; |