diff options
Diffstat (limited to 'llvm/tools/llvm-readobj')
| -rw-r--r-- | llvm/tools/llvm-readobj/ARMEHABIPrinter.h | 135 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp | 211 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/ARMWinEHPrinter.h | 12 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/COFFDumper.cpp | 64 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h | 82 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 5206 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/Error.cpp | 56 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/Error.h | 40 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/MachODumper.cpp | 39 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/ObjDumper.cpp | 52 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/ObjDumper.h | 49 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/WasmDumper.cpp | 16 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/Win64EHDumper.cpp | 5 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/WindowsResourceDumper.cpp | 1 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/XCOFFDumper.cpp | 15 | ||||
| -rw-r--r-- | llvm/tools/llvm-readobj/llvm-readobj.cpp | 153 |
16 files changed, 3030 insertions, 3106 deletions
diff --git a/llvm/tools/llvm-readobj/ARMEHABIPrinter.h b/llvm/tools/llvm-readobj/ARMEHABIPrinter.h index 2c0912038c31..3d8acbf48fa9 100644 --- a/llvm/tools/llvm-readobj/ARMEHABIPrinter.h +++ b/llvm/tools/llvm-readobj/ARMEHABIPrinter.h @@ -9,7 +9,6 @@ #ifndef LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H #define LLVM_TOOLS_LLVM_READOBJ_ARMEHABIPRINTER_H -#include "Error.h" #include "llvm-readobj.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Object/ELF.h" @@ -328,7 +327,7 @@ class PrinterContext { typedef typename ET::Word Elf_Word; ScopedPrinter &SW; - const object::ELFFile<ET> *ELF; + const object::ELFFile<ET> &ELF; StringRef FileName; const Elf_Shdr *Symtab; ArrayRef<Elf_Word> ShndxTable; @@ -337,22 +336,23 @@ class PrinterContext { static uint64_t PREL31(uint32_t Address, uint32_t Place) { uint64_t Location = Address & 0x7fffffff; - if (Location & 0x04000000) + if (Location & 0x40000000) Location |= (uint64_t) ~0x7fffffff; return Location + Place; } - ErrorOr<StringRef> FunctionAtAddress(unsigned Section, uint64_t Address) const; + ErrorOr<StringRef> FunctionAtAddress(uint64_t Address, + Optional<unsigned> SectionIndex) const; const Elf_Shdr *FindExceptionTable(unsigned IndexTableIndex, off_t IndexTableOffset) const; void PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const; - void PrintExceptionTable(const Elf_Shdr *IT, const Elf_Shdr *EHT, + void PrintExceptionTable(const Elf_Shdr &EHT, uint64_t TableEntryOffset) const; void PrintOpcodes(const uint8_t *Entry, size_t Length, off_t Offset) const; public: - PrinterContext(ScopedPrinter &SW, const object::ELFFile<ET> *ELF, + PrinterContext(ScopedPrinter &SW, const object::ELFFile<ET> &ELF, StringRef FileName, const Elf_Shdr *Symtab) : SW(SW), ELF(ELF), FileName(FileName), Symtab(Symtab) {} @@ -364,27 +364,31 @@ const size_t PrinterContext<ET>::IndexTableEntrySize = 8; template <typename ET> ErrorOr<StringRef> -PrinterContext<ET>::FunctionAtAddress(unsigned Section, - uint64_t Address) const { +PrinterContext<ET>::FunctionAtAddress(uint64_t Address, + Optional<unsigned> SectionIndex) const { if (!Symtab) - return readobj_error::unknown_symbol; - auto StrTableOrErr = ELF->getStringTableForSymtab(*Symtab); + return inconvertibleErrorCode(); + auto StrTableOrErr = ELF.getStringTableForSymtab(*Symtab); if (!StrTableOrErr) reportError(StrTableOrErr.takeError(), FileName); StringRef StrTable = *StrTableOrErr; - for (const Elf_Sym &Sym : unwrapOrError(FileName, ELF->symbols(Symtab))) - if (Sym.st_shndx == Section && Sym.st_value == Address && - Sym.getType() == ELF::STT_FUNC) { + for (const Elf_Sym &Sym : unwrapOrError(FileName, ELF.symbols(Symtab))) { + if (SectionIndex && *SectionIndex != Sym.st_shndx) + continue; + + if (Sym.st_value == Address && Sym.getType() == ELF::STT_FUNC) { auto NameOrErr = Sym.getName(StrTable); if (!NameOrErr) { // TODO: Actually report errors helpfully. consumeError(NameOrErr.takeError()); - return readobj_error::unknown_symbol; + return inconvertibleErrorCode(); } return *NameOrErr; } - return readobj_error::unknown_symbol; + } + + return inconvertibleErrorCode(); } template <typename ET> @@ -399,16 +403,16 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, /// handling table. Use this symbol to recover the actual exception handling /// table. - for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF.sections())) { if (Sec.sh_type != ELF::SHT_REL || Sec.sh_info != IndexSectionIndex) continue; - auto SymTabOrErr = ELF->getSection(Sec.sh_link); + auto SymTabOrErr = ELF.getSection(Sec.sh_link); if (!SymTabOrErr) reportError(SymTabOrErr.takeError(), FileName); const Elf_Shdr *SymTab = *SymTabOrErr; - for (const Elf_Rel &R : unwrapOrError(FileName, ELF->rels(&Sec))) { + for (const Elf_Rel &R : unwrapOrError(FileName, ELF.rels(Sec))) { if (R.r_offset != static_cast<unsigned>(IndexTableOffset)) continue; @@ -418,9 +422,9 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, RelA.r_addend = 0; const Elf_Sym *Symbol = - unwrapOrError(FileName, ELF->getRelocationSymbol(&RelA, SymTab)); + unwrapOrError(FileName, ELF.getRelocationSymbol(RelA, SymTab)); - auto Ret = ELF->getSection(Symbol, SymTab, ShndxTable); + auto Ret = ELF.getSection(*Symbol, SymTab, ShndxTable); if (!Ret) report_fatal_error(errorToErrorCode(Ret.takeError()).message()); return *Ret; @@ -430,10 +434,20 @@ PrinterContext<ET>::FindExceptionTable(unsigned IndexSectionIndex, } template <typename ET> -void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT, - const Elf_Shdr *EHT, +static const typename ET::Shdr * +findSectionContainingAddress(const object::ELFFile<ET> &Obj, StringRef FileName, + uint64_t Address) { + for (const typename ET::Shdr &Sec : unwrapOrError(FileName, Obj.sections())) + if (Address >= Sec.sh_addr && Address < Sec.sh_addr + Sec.sh_size) + return &Sec; + return nullptr; +} + +template <typename ET> +void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr &EHT, uint64_t TableEntryOffset) const { - Expected<ArrayRef<uint8_t>> Contents = ELF->getSectionContents(EHT); + // TODO: handle failure. + Expected<ArrayRef<uint8_t>> Contents = ELF.getSectionContents(EHT); if (!Contents) return; @@ -482,10 +496,14 @@ void PrinterContext<ET>::PrintExceptionTable(const Elf_Shdr *IT, } } else { SW.printString("Model", StringRef("Generic")); - - uint64_t Address = PREL31(Word, EHT->sh_addr); + const bool IsRelocatable = ELF.getHeader().e_type == ELF::ET_REL; + uint64_t Address = IsRelocatable + ? PREL31(Word, EHT.sh_addr) + : PREL31(Word, EHT.sh_addr + TableEntryOffset); SW.printHex("PersonalityRoutineAddress", Address); - if (ErrorOr<StringRef> Name = FunctionAtAddress(EHT->sh_link, Address)) + Optional<unsigned> SecIndex = + IsRelocatable ? Optional<unsigned>(EHT.sh_link) : None; + if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex)) SW.printString("PersonalityRoutineName", *Name); } } @@ -500,7 +518,8 @@ void PrinterContext<ET>::PrintOpcodes(const uint8_t *Entry, template <typename ET> void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex, const Elf_Shdr *IT) const { - Expected<ArrayRef<uint8_t>> Contents = ELF->getSectionContents(IT); + // TODO: handle failure. + Expected<ArrayRef<uint8_t>> Contents = ELF.getSectionContents(*IT); if (!Contents) return; @@ -517,6 +536,7 @@ void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex, const support::ulittle32_t *Data = reinterpret_cast<const support::ulittle32_t *>(Contents->data()); const unsigned Entries = IT->sh_size / IndexTableEntrySize; + const bool IsRelocatable = ELF.getHeader().e_type == ELF::ET_REL; ListScope E(SW, "Entries"); for (unsigned Entry = 0; Entry < Entries; ++Entry) { @@ -532,9 +552,31 @@ void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex, continue; } - const uint64_t Offset = PREL31(Word0, IT->sh_addr); - SW.printHex("FunctionAddress", Offset); - if (ErrorOr<StringRef> Name = FunctionAtAddress(IT->sh_link, Offset)) + // FIXME: For a relocatable object ideally we might want to: + // 1) Find a relocation for the offset of Word0. + // 2) Verify this relocation is of an expected type (R_ARM_PREL31) and + // verify the symbol index. + // 3) Resolve the relocation using it's symbol value, addend etc. + // Currently the code assumes that Word0 contains an addend of a + // R_ARM_PREL31 REL relocation that references a section symbol. RELA + // relocations are not supported and it works because addresses of sections + // are nulls in relocatable objects. + // + // For a non-relocatable object, Word0 contains a place-relative signed + // offset to the referenced entity. + const uint64_t Address = + IsRelocatable + ? PREL31(Word0, IT->sh_addr) + : PREL31(Word0, IT->sh_addr + Entry * IndexTableEntrySize); + SW.printHex("FunctionAddress", Address); + + // In a relocatable output we might have many .ARM.exidx sections linked to + // their code sections via the sh_link field. For a non-relocatable ELF file + // the sh_link field is not reliable, because we have one .ARM.exidx section + // normally, but might have many code sections. + Optional<unsigned> SecIndex = + IsRelocatable ? Optional<unsigned>(IT->sh_link) : None; + if (ErrorOr<StringRef> Name = FunctionAtAddress(Address, SecIndex)) SW.printString("FunctionName", *Name); if (Word1 == EXIDX_CANTUNWIND) { @@ -550,18 +592,30 @@ void PrinterContext<ET>::PrintIndexTable(unsigned SectionIndex, PrintOpcodes(Contents->data() + Entry * IndexTableEntrySize + 4, 3, 1); } else { - const Elf_Shdr *EHT = - FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4); + const Elf_Shdr *EHT; + uint64_t TableEntryAddress; + if (IsRelocatable) { + TableEntryAddress = PREL31(Word1, IT->sh_addr); + EHT = FindExceptionTable(SectionIndex, Entry * IndexTableEntrySize + 4); + } else { + TableEntryAddress = + PREL31(Word1, IT->sh_addr + Entry * IndexTableEntrySize + 4); + EHT = findSectionContainingAddress(ELF, FileName, TableEntryAddress); + } if (EHT) - if (auto Name = ELF->getSectionName(EHT)) + // TODO: handle failure. + if (Expected<StringRef> Name = ELF.getSectionName(*EHT)) SW.printString("ExceptionHandlingTable", *Name); - uint64_t TableEntryOffset = PREL31(Word1, IT->sh_addr); - SW.printHex("TableEntryOffset", TableEntryOffset); - - if (EHT) - PrintExceptionTable(IT, EHT, TableEntryOffset); + SW.printHex(IsRelocatable ? "TableEntryOffset" : "TableEntryAddress", + TableEntryAddress); + if (EHT) { + if (IsRelocatable) + PrintExceptionTable(*EHT, TableEntryAddress); + else + PrintExceptionTable(*EHT, TableEntryAddress - EHT->sh_addr); + } } } } @@ -571,12 +625,13 @@ void PrinterContext<ET>::PrintUnwindInformation() const { DictScope UI(SW, "UnwindInformation"); int SectionIndex = 0; - for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF->sections())) { + for (const Elf_Shdr &Sec : unwrapOrError(FileName, ELF.sections())) { if (Sec.sh_type == ELF::SHT_ARM_EXIDX) { DictScope UIT(SW, "UnwindIndexTable"); SW.printNumber("SectionIndex", SectionIndex); - if (auto SectionName = ELF->getSectionName(&Sec)) + // TODO: handle failure. + if (Expected<StringRef> SectionName = ELF.getSectionName(Sec)) SW.printString("SectionName", *SectionName); SW.printHex("SectionOffset", Sec.sh_offset); diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp index 8f365c5ad082..5995a09514c8 100644 --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.cpp @@ -62,7 +62,6 @@ // epilogue of the function. #include "ARMWinEHPrinter.h" -#include "Error.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/ARMWinEH.h" @@ -168,6 +167,11 @@ const Decoder::RingEntry Decoder::Ring64[] = { { 0xff, 0xe3, 1, &Decoder::opcode_nop }, { 0xff, 0xe4, 1, &Decoder::opcode_end }, { 0xff, 0xe5, 1, &Decoder::opcode_end_c }, + { 0xff, 0xe6, 1, &Decoder::opcode_save_next }, + { 0xff, 0xe8, 1, &Decoder::opcode_trap_frame }, + { 0xff, 0xe9, 1, &Decoder::opcode_machine_frame }, + { 0xff, 0xea, 1, &Decoder::opcode_context }, + { 0xff, 0xec, 1, &Decoder::opcode_clear_unwound_to_call }, }; void Decoder::printRegisters(const std::pair<uint16_t, uint32_t> &RegisterMask) { @@ -217,7 +221,7 @@ Decoder::getSectionContaining(const COFFObjectFile &COFF, uint64_t VA) { if (VA >= Address && (VA - Address) <= Size) return Section; } - return readobj_error::unknown_symbol; + return inconvertibleErrorCode(); } ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, @@ -235,7 +239,7 @@ ErrorOr<object::SymbolRef> Decoder::getSymbol(const COFFObjectFile &COFF, if (*Address == VA) return Symbol; } - return readobj_error::unknown_symbol; + return inconvertibleErrorCode(); } ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, @@ -246,7 +250,7 @@ ErrorOr<SymbolRef> Decoder::getRelocatedSymbol(const COFFObjectFile &, if (RelocationOffset == Offset) return *Relocation.getSymbol(); } - return readobj_error::unknown_symbol; + return inconvertibleErrorCode(); } bool Decoder::opcode_0xxxxxxx(const uint8_t *OC, unsigned &Offset, @@ -637,7 +641,7 @@ bool Decoder::opcode_save_reg_x(const uint8_t *OC, unsigned &Offset, Reg += 19; uint32_t Off = ((OC[Offset + 1] & 0x1F) + 1) << 3; if (Prologue) - SW.startLine() << format("0x%02x%02x ; str x%u, [sp, #%u]!\n", + SW.startLine() << format("0x%02x%02x ; str x%u, [sp, #-%u]!\n", OC[Offset], OC[Offset + 1], Reg, Off); else SW.startLine() << format("0x%02x%02x ; ldr x%u, [sp], #%u\n", @@ -703,7 +707,7 @@ bool Decoder::opcode_save_freg(const uint8_t *OC, unsigned &Offset, Reg >>= 6; Reg += 8; uint32_t Off = (OC[Offset + 1] & 0x3F) << 3; - SW.startLine() << format("0x%02x%02x ; %s d%u, [sp, #%u]\n", + SW.startLine() << format("0x%02x%02x ; %s d%u, [sp, #%u]\n", OC[Offset], OC[Offset + 1], static_cast<const char *>(Prologue ? "str" : "ldr"), Reg, Off); @@ -742,7 +746,9 @@ bool Decoder::opcode_alloc_l(const uint8_t *OC, unsigned &Offset, bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { - SW.startLine() << format("0x%02x ; mov fp, sp\n", OC[Offset]); + SW.startLine() << format("0x%02x ; mov %s, %s\n", OC[Offset], + static_cast<const char *>(Prologue ? "fp" : "sp"), + static_cast<const char *>(Prologue ? "sp" : "fp")); ++Offset; return false; } @@ -750,8 +756,11 @@ bool Decoder::opcode_setfp(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Decoder::opcode_addfp(const uint8_t *OC, unsigned &Offset, unsigned Length, bool Prologue) { unsigned NumBytes = OC[Offset + 1] << 3; - SW.startLine() << format("0x%02x%02x ; add fp, sp, #%u\n", - OC[Offset], OC[Offset + 1], NumBytes); + SW.startLine() << format( + "0x%02x%02x ; %s %s, %s, #%u\n", OC[Offset], OC[Offset + 1], + static_cast<const char *>(Prologue ? "add" : "sub"), + static_cast<const char *>(Prologue ? "fp" : "sp"), + static_cast<const char *>(Prologue ? "sp" : "fp"), NumBytes); Offset += 2; return false; } @@ -777,6 +786,47 @@ bool Decoder::opcode_end_c(const uint8_t *OC, unsigned &Offset, unsigned Length, return true; } +bool Decoder::opcode_save_next(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + if (Prologue) + SW.startLine() << format("0x%02x ; save next\n", OC[Offset]); + else + SW.startLine() << format("0x%02x ; restore next\n", + OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_trap_frame(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; trap frame\n", OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_machine_frame(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; machine frame\n", + OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_context(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; context\n", OC[Offset]); + ++Offset; + return false; +} + +bool Decoder::opcode_clear_unwound_to_call(const uint8_t *OC, unsigned &Offset, + unsigned Length, bool Prologue) { + SW.startLine() << format("0x%02x ; clear unwound to call\n", + OC[Offset]); + ++Offset; + return false; +} + void Decoder::decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset, bool Prologue) { assert((!Prologue || Offset == 0) && "prologue should always use offset 0"); @@ -1061,6 +1111,145 @@ bool Decoder::dumpPackedEntry(const object::COFFObjectFile &COFF, return true; } +bool Decoder::dumpPackedARM64Entry(const object::COFFObjectFile &COFF, + const SectionRef Section, uint64_t Offset, + unsigned Index, + const RuntimeFunctionARM64 &RF) { + assert((RF.Flag() == RuntimeFunctionFlag::RFF_Packed || + RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment) && + "unpacked entry cannot be treated as a packed entry"); + + ErrorOr<SymbolRef> Function = getRelocatedSymbol(COFF, Section, Offset); + if (!Function) + Function = getSymbol(COFF, RF.BeginAddress, /*FunctionOnly=*/true); + + StringRef FunctionName; + uint64_t FunctionAddress; + if (Function) { + Expected<StringRef> FunctionNameOrErr = Function->getName(); + if (!FunctionNameOrErr) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(FunctionNameOrErr.takeError(), OS); + OS.flush(); + report_fatal_error(Buf); + } + FunctionName = *FunctionNameOrErr; + Expected<uint64_t> FunctionAddressOrErr = Function->getAddress(); + if (!FunctionAddressOrErr) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + logAllUnhandledErrors(FunctionAddressOrErr.takeError(), OS); + OS.flush(); + report_fatal_error(Buf); + } + FunctionAddress = *FunctionAddressOrErr; + } else { + FunctionAddress = COFF.getPE32PlusHeader()->ImageBase + RF.BeginAddress; + } + + SW.printString("Function", formatSymbol(FunctionName, FunctionAddress)); + SW.printBoolean("Fragment", + RF.Flag() == RuntimeFunctionFlag::RFF_PackedFragment); + SW.printNumber("FunctionLength", RF.FunctionLength()); + SW.printNumber("RegF", RF.RegF()); + SW.printNumber("RegI", RF.RegI()); + SW.printBoolean("HomedParameters", RF.H()); + SW.printNumber("CR", RF.CR()); + SW.printNumber("FrameSize", RF.FrameSize() << 4); + ListScope PS(SW, "Prologue"); + + // Synthesize the equivalent prologue according to the documentation + // at https://docs.microsoft.com/en-us/cpp/build/arm64-exception-handling, + // printed in reverse order compared to the docs, to match how prologues + // are printed for the non-packed case. + int IntSZ = 8 * RF.RegI(); + if (RF.CR() == 1) + IntSZ += 8; + int FpSZ = 8 * RF.RegF(); + if (RF.RegF()) + FpSZ += 8; + int SavSZ = (IntSZ + FpSZ + 8 * 8 * RF.H() + 0xf) & ~0xf; + int LocSZ = (RF.FrameSize() << 4) - SavSZ; + + if (RF.CR() == 3) { + SW.startLine() << "mov x29, sp\n"; + if (LocSZ <= 512) { + SW.startLine() << format("stp x29, lr, [sp, #-%d]!\n", LocSZ); + } else { + SW.startLine() << "stp x29, lr, [sp, #0]\n"; + } + } + if (LocSZ > 4080) { + SW.startLine() << format("sub sp, sp, #%d\n", LocSZ - 4080); + SW.startLine() << "sub sp, sp, #4080\n"; + } else if ((RF.CR() != 3 && LocSZ > 0) || LocSZ > 512) { + SW.startLine() << format("sub sp, sp, #%d\n", LocSZ); + } + if (RF.H()) { + SW.startLine() << format("stp x6, x7, [sp, #%d]\n", IntSZ + FpSZ + 48); + SW.startLine() << format("stp x4, x5, [sp, #%d]\n", IntSZ + FpSZ + 32); + SW.startLine() << format("stp x2, x3, [sp, #%d]\n", IntSZ + FpSZ + 16); + if (RF.RegI() > 0 || RF.RegF() > 0 || RF.CR() == 1) { + SW.startLine() << format("stp x0, x1, [sp, #%d]\n", IntSZ + FpSZ); + } else { + // This case isn't documented; if neither RegI nor RegF nor CR=1 + // have decremented the stack pointer by SavSZ, we need to do it here + // (as the final stack adjustment of LocSZ excludes SavSZ). + SW.startLine() << format("stp x0, x1, [sp, #-%d]!\n", SavSZ); + } + } + int FloatRegs = RF.RegF() > 0 ? RF.RegF() + 1 : 0; + for (int I = (FloatRegs + 1) / 2 - 1; I >= 0; I--) { + if (I == (FloatRegs + 1) / 2 - 1 && FloatRegs % 2 == 1) { + // The last register, an odd register without a pair + SW.startLine() << format("str d%d, [sp, #%d]\n", 8 + 2 * I, + IntSZ + 16 * I); + } else if (I == 0 && RF.RegI() == 0 && RF.CR() != 1) { + SW.startLine() << format("stp d%d, d%d, [sp, #-%d]!\n", 8 + 2 * I, + 8 + 2 * I + 1, SavSZ); + } else { + SW.startLine() << format("stp d%d, d%d, [sp, #%d]\n", 8 + 2 * I, + 8 + 2 * I + 1, IntSZ + 16 * I); + } + } + if (RF.CR() == 1 && (RF.RegI() % 2) == 0) { + if (RF.RegI() == 0) + SW.startLine() << format("str lr, [sp, #-%d]!\n", SavSZ); + else + SW.startLine() << format("str lr, [sp, #%d]\n", IntSZ - 8); + } + for (int I = (RF.RegI() + 1) / 2 - 1; I >= 0; I--) { + if (I == (RF.RegI() + 1) / 2 - 1 && RF.RegI() % 2 == 1) { + // The last register, an odd register without a pair + if (RF.CR() == 1) { + if (I == 0) { // If this is the only register pair + // CR=1 combined with RegI=1 doesn't map to a documented case; + // it doesn't map to any regular unwind info opcode, and the + // actual unwinder doesn't support it. + SW.startLine() << "INVALID!\n"; + } else + SW.startLine() << format("stp x%d, lr, [sp, #%d]\n", 19 + 2 * I, + 16 * I); + } else { + if (I == 0) + SW.startLine() << format("str x%d, [sp, #-%d]!\n", 19 + 2 * I, SavSZ); + else + SW.startLine() << format("str x%d, [sp, #%d]\n", 19 + 2 * I, 16 * I); + } + } else if (I == 0) { + // The first register pair + SW.startLine() << format("stp x19, x20, [sp, #-%d]!\n", SavSZ); + } else { + SW.startLine() << format("stp x%d, x%d, [sp, #%d]\n", 19 + 2 * I, + 19 + 2 * I + 1, 16 * I); + } + } + SW.startLine() << "end\n"; + + return true; +} + bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, const SectionRef Section, unsigned Index, ArrayRef<uint8_t> Contents) { @@ -1073,8 +1262,8 @@ bool Decoder::dumpProcedureDataEntry(const COFFObjectFile &COFF, if (Entry.Flag() == RuntimeFunctionFlag::RFF_Unpacked) return dumpUnpackedEntry(COFF, Section, Offset, Index, Entry); if (isAArch64) { - SW.startLine() << "Packed unwind data not yet supported for ARM64\n"; - return true; + const RuntimeFunctionARM64 EntryARM64(Data); + return dumpPackedARM64Entry(COFF, Section, Offset, Index, EntryARM64); } return dumpPackedEntry(COFF, Section, Offset, Index, Entry); } diff --git a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h index 5de7062cb1d7..3263841a267b 100644 --- a/llvm/tools/llvm-readobj/ARMWinEHPrinter.h +++ b/llvm/tools/llvm-readobj/ARMWinEHPrinter.h @@ -17,6 +17,7 @@ namespace llvm { namespace ARM { namespace WinEH { class RuntimeFunction; +class RuntimeFunctionARM64; class Decoder { static const size_t PDataEntrySize; @@ -120,6 +121,14 @@ class Decoder { bool Prologue); bool opcode_save_next(const uint8_t *Opcodes, unsigned &Offset, unsigned Length, bool Prologue); + bool opcode_trap_frame(const uint8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_machine_frame(const uint8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); + bool opcode_context(const uint8_t *Opcodes, unsigned &Offset, unsigned Length, + bool Prologue); + bool opcode_clear_unwound_to_call(const uint8_t *Opcodes, unsigned &Offset, + unsigned Length, bool Prologue); void decodeOpcodes(ArrayRef<uint8_t> Opcodes, unsigned Offset, bool Prologue); @@ -146,6 +155,9 @@ class Decoder { bool dumpPackedEntry(const object::COFFObjectFile &COFF, const object::SectionRef Section, uint64_t Offset, unsigned Index, const RuntimeFunction &Entry); + bool dumpPackedARM64Entry(const object::COFFObjectFile &COFF, + const object::SectionRef Section, uint64_t Offset, + unsigned Index, const RuntimeFunctionARM64 &Entry); bool dumpProcedureDataEntry(const object::COFFObjectFile &COFF, const object::SectionRef Section, unsigned Entry, ArrayRef<uint8_t> Contents); diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp index 89a904f53ae7..684967f93393 100644 --- a/llvm/tools/llvm-readobj/COFFDumper.cpp +++ b/llvm/tools/llvm-readobj/COFFDumper.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "ARMWinEHPrinter.h" -#include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" #include "Win64EHDumper.h" @@ -60,10 +59,6 @@ using namespace llvm::codeview; using namespace llvm::support; using namespace llvm::Win64EH; -static inline Error createError(const Twine &Err) { - return make_error<StringError>(Err, object_error::parse_failed); -} - namespace { struct LoadConfigTables { @@ -72,6 +67,8 @@ struct LoadConfigTables { uint32_t GuardFlags = 0; uint64_t GuardFidTableVA = 0; uint64_t GuardFidTableCount = 0; + uint64_t GuardIatTableVA = 0; + uint64_t GuardIatTableCount = 0; uint64_t GuardLJmpTableVA = 0; uint64_t GuardLJmpTableCount = 0; }; @@ -80,7 +77,8 @@ class COFFDumper : public ObjDumper { public: friend class COFFObjectDumpDelegate; COFFDumper(const llvm::object::COFFObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer), Obj(Obj), Writer(Writer), Types(100) {} + : ObjDumper(Writer, Obj->getFileName()), Obj(Obj), Writer(Writer), + Types(100) {} void printFileHeaders() override; void printSectionHeaders() override; @@ -94,6 +92,7 @@ public: void printCOFFDirectives() override; void printCOFFBaseReloc() override; void printCOFFDebugDirectory() override; + void printCOFFTLSDirectory() override; void printCOFFResources() override; void printCOFFLoadConfig() override; void printCodeViewDebugInfo() override; @@ -121,13 +120,14 @@ private: void printBaseOfDataField(const pe32plus_header *Hdr); template <typename T> void printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables); + template <typename IntTy> + void printCOFFTLSDirectory(const coff_tls_directory<IntTy> *TlsTable); typedef void (*PrintExtraCB)(raw_ostream &, const uint8_t *); void printRVATable(uint64_t TableVA, uint64_t Count, uint64_t EntrySize, PrintExtraCB PrintExtra = 0); void printCodeViewSymbolSection(StringRef SectionName, const SectionRef &Section); void printCodeViewTypeSection(StringRef SectionName, const SectionRef &Section); - StringRef getTypeName(TypeIndex Ty); StringRef getFileNameForFileOffset(uint32_t FileOffset); void printFileNameForOffset(StringRef Label, uint32_t FileOffset); void printTypeIndex(StringRef FieldName, TypeIndex TI) { @@ -243,15 +243,9 @@ private: namespace llvm { -std::error_code createCOFFDumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result) { - const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj); - if (!COFFObj) - return readobj_error::unsupported_obj_file_format; - - Result.reset(new COFFDumper(COFFObj, Writer)); - return readobj_error::success; +std::unique_ptr<ObjDumper> createCOFFDumper(const object::COFFObjectFile &Obj, + ScopedPrinter &Writer) { + return std::make_unique<COFFDumper>(&Obj, Writer); } } // namespace llvm @@ -272,9 +266,9 @@ std::error_code COFFDumper::resolveSymbol(const coff_section *Section, } } if (SymI == Obj->symbol_end()) - return readobj_error::unknown_symbol; + return inconvertibleErrorCode(); Sym = *SymI; - return readobj_error::success; + return std::error_code(); } // Given a section and an offset into this section the function returns the name @@ -588,7 +582,7 @@ static std::error_code getSymbolAuxData(const COFFObjectFile *Obj, ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); AuxData = AuxData.slice(AuxSymbolIdx * Obj->getSymbolTableEntrySize()); Aux = reinterpret_cast<const T*>(AuxData.data()); - return readobj_error::success; + return std::error_code(); } void COFFDumper::cacheRelocations() { @@ -815,6 +809,11 @@ void COFFDumper::printCOFFLoadConfig() { } } + if (Tables.GuardIatTableVA) { + ListScope LS(W, "GuardIatTable"); + printRVATable(Tables.GuardIatTableVA, Tables.GuardIatTableCount, 4); + } + if (Tables.GuardLJmpTableVA) { ListScope LS(W, "GuardLJmpTable"); printRVATable(Tables.GuardLJmpTableVA, Tables.GuardLJmpTableCount, 4); @@ -899,6 +898,9 @@ void COFFDumper::printCOFFLoadConfig(const T *Conf, LoadConfigTables &Tables) { Conf->GuardRFVerifyStackPointerFunctionPointer); W.printHex("HotPatchTableOffset", Conf->HotPatchTableOffset); + Tables.GuardIatTableVA = Conf->GuardAddressTakenIatEntryTable; + Tables.GuardIatTableCount = Conf->GuardAddressTakenIatEntryCount; + Tables.GuardLJmpTableVA = Conf->GuardLongJumpTargetTable; Tables.GuardLJmpTableCount = Conf->GuardLongJumpTargetCount; } @@ -2029,3 +2031,27 @@ void llvm::dumpCodeViewMergedTypes(ScopedPrinter &Writer, Writer.flush(); } } + +void COFFDumper::printCOFFTLSDirectory() { + if (Obj->is64()) + printCOFFTLSDirectory(Obj->getTLSDirectory64()); + else + printCOFFTLSDirectory(Obj->getTLSDirectory32()); +} + +template <typename IntTy> +void COFFDumper::printCOFFTLSDirectory( + const coff_tls_directory<IntTy> *TlsTable) { + DictScope D(W, "TLSDirectory"); + if (!TlsTable) + return; + + W.printHex("StartAddressOfRawData", TlsTable->StartAddressOfRawData); + W.printHex("EndAddressOfRawData", TlsTable->EndAddressOfRawData); + W.printHex("AddressOfIndex", TlsTable->AddressOfIndex); + W.printHex("AddressOfCallBacks", TlsTable->AddressOfCallBacks); + W.printHex("SizeOfZeroFill", TlsTable->SizeOfZeroFill); + W.printFlags("Characteristics", TlsTable->Characteristics, + makeArrayRef(ImageSectionCharacteristics), + COFF::SectionCharacteristics(COFF::IMAGE_SCN_ALIGN_MASK)); +} diff --git a/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h b/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h index 27942224053f..2dfe21684a62 100644 --- a/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h +++ b/llvm/tools/llvm-readobj/DwarfCFIEHPrinter.h @@ -9,38 +9,37 @@ #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/DebugInfo/DWARF/DWARFContext.h" +#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h" +#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h" #include "llvm/Object/ELF.h" -#include "llvm/Object/ELFTypes.h" #include "llvm/Object/ELFObjectFile.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/ScopedPrinter.h" #include "llvm/Support/type_traits.h" namespace llvm { namespace DwarfCFIEH { -template <typename ELFT> -class PrinterContext { +template <typename ELFT> class PrinterContext { using Elf_Shdr = typename ELFT::Shdr; using Elf_Phdr = typename ELFT::Phdr; ScopedPrinter &W; - const object::ELFObjectFile<ELFT> *ObjF; + const object::ELFObjectFile<ELFT> &ObjF; void printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const; void printEHFrame(const Elf_Shdr *EHFrameShdr) const; public: - PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> *ObjF) + PrinterContext(ScopedPrinter &W, const object::ELFObjectFile<ELFT> &ObjF) : W(W), ObjF(ObjF) {} void printUnwindInformation() const; @@ -48,11 +47,11 @@ public: template <class ELFT> static const typename ELFT::Shdr * -findSectionByAddress(const object::ELFObjectFile<ELFT> *ObjF, uint64_t Addr) { +findSectionByAddress(const object::ELFObjectFile<ELFT> &ObjF, uint64_t Addr) { Expected<typename ELFT::ShdrRange> SectionsOrErr = - ObjF->getELFFile()->sections(); + ObjF.getELFFile().sections(); if (!SectionsOrErr) - reportError(SectionsOrErr.takeError(), ObjF->getFileName()); + reportError(SectionsOrErr.takeError(), ObjF.getFileName()); for (const typename ELFT::Shdr &Shdr : *SectionsOrErr) if (Shdr.sh_addr == Addr) @@ -62,11 +61,11 @@ findSectionByAddress(const object::ELFObjectFile<ELFT> *ObjF, uint64_t Addr) { template <typename ELFT> void PrinterContext<ELFT>::printUnwindInformation() const { - const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); + const object::ELFFile<ELFT> &Obj = ObjF.getELFFile(); - Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj->program_headers(); + Expected<typename ELFT::PhdrRange> PhdrsOrErr = Obj.program_headers(); if (!PhdrsOrErr) - reportError(PhdrsOrErr.takeError(), ObjF->getFileName()); + reportError(PhdrsOrErr.takeError(), ObjF.getFileName()); for (const Elf_Phdr &Phdr : *PhdrsOrErr) { if (Phdr.p_type != ELF::PT_GNU_EH_FRAME) @@ -75,20 +74,19 @@ void PrinterContext<ELFT>::printUnwindInformation() const { if (Phdr.p_memsz != Phdr.p_filesz) reportError(object::createError( "p_memsz does not match p_filesz for GNU_EH_FRAME"), - ObjF->getFileName()); + ObjF.getFileName()); printEHFrameHdr(&Phdr); break; } - Expected<typename ELFT::ShdrRange> SectionsOrErr = - ObjF->getELFFile()->sections(); + Expected<typename ELFT::ShdrRange> SectionsOrErr = Obj.sections(); if (!SectionsOrErr) - reportError(SectionsOrErr.takeError(), ObjF->getFileName()); + reportError(SectionsOrErr.takeError(), ObjF.getFileName()); for (const Elf_Shdr &Shdr : *SectionsOrErr) { - Expected<StringRef> NameOrErr = Obj->getSectionName(&Shdr); + Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr); if (!NameOrErr) - reportError(NameOrErr.takeError(), ObjF->getFileName()); + reportError(NameOrErr.takeError(), ObjF.getFileName()); if (*NameOrErr == ".eh_frame") printEHFrame(&Shdr); } @@ -102,18 +100,18 @@ void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const { W.startLine() << format("Offset: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_offset); W.startLine() << format("Size: 0x%" PRIx64 "\n", (uint64_t)EHFramePHdr->p_memsz); - const object::ELFFile<ELFT> *Obj = ObjF->getELFFile(); + const object::ELFFile<ELFT> &Obj = ObjF.getELFFile(); if (const Elf_Shdr *EHFrameHdr = findSectionByAddress(ObjF, EHFramePHdr->p_vaddr)) { - Expected<StringRef> NameOrErr = Obj->getSectionName(EHFrameHdr); + Expected<StringRef> NameOrErr = Obj.getSectionName(*EHFrameHdr); if (!NameOrErr) - reportError(NameOrErr.takeError(), ObjF->getFileName()); + reportError(NameOrErr.takeError(), ObjF.getFileName()); W.printString("Corresponding Section", *NameOrErr); } - Expected<ArrayRef<uint8_t>> Content = Obj->getSegmentContents(EHFramePHdr); + Expected<ArrayRef<uint8_t>> Content = Obj.getSegmentContents(*EHFramePHdr); if (!Content) - reportError(Content.takeError(), ObjF->getFileName()); + reportError(Content.takeError(), ObjF.getFileName()); DataExtractor DE(*Content, ELFT::TargetEndianness == support::endianness::little, @@ -127,25 +125,25 @@ void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const { if (Version != 1) reportError( object::createError("only version 1 of .eh_frame_hdr is supported"), - ObjF->getFileName()); + ObjF.getFileName()); 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(object::createError("unexpected encoding eh_frame_ptr_enc"), - ObjF->getFileName()); + ObjF.getFileName()); uint64_t FDECountEnc = DE.getU8(&Offset); W.startLine() << format("fde_count_enc: 0x%" PRIx64 "\n", FDECountEnc); if (FDECountEnc != dwarf::DW_EH_PE_udata4) reportError(object::createError("unexpected encoding fde_count_enc"), - ObjF->getFileName()); + ObjF.getFileName()); 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(object::createError("unexpected encoding table_enc"), - ObjF->getFileName()); + ObjF.getFileName()); auto EHFramePtr = DE.getSigned(&Offset, 4) + EHFrameHdrAddress + 4; W.startLine() << format("eh_frame_ptr: 0x%" PRIx64 "\n", EHFramePtr); @@ -156,7 +154,7 @@ void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const { unsigned NumEntries = 0; uint64_t PrevPC = 0; while (Offset + 8 <= EHFramePHdr->p_memsz && NumEntries < FDECount) { - DictScope D(W, std::string("entry ") + std::to_string(NumEntries)); + 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); @@ -165,7 +163,7 @@ void PrinterContext<ELFT>::printEHFrameHdr(const Elf_Phdr *EHFramePHdr) const { if (InitialPC < PrevPC) reportError(object::createError("initial_location is out of order"), - ObjF->getFileName()); + ObjF.getFileName()); PrevPC = InitialPC; ++NumEntries; @@ -182,17 +180,20 @@ void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const { W.indent(); Expected<ArrayRef<uint8_t>> DataOrErr = - ObjF->getELFFile()->getSectionContents(EHFrameShdr); + ObjF.getELFFile().getSectionContents(*EHFrameShdr); if (!DataOrErr) - reportError(DataOrErr.takeError(), ObjF->getFileName()); + reportError(DataOrErr.takeError(), ObjF.getFileName()); - DWARFDataExtractor DE(*DataOrErr, + // Construct DWARFDataExtractor to handle relocations ("PC Begin" fields). + std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(ObjF, nullptr); + DWARFDataExtractor DE(DICtx->getDWARFObj(), + DICtx->getDWARFObj().getEHFrameSection(), ELFT::TargetEndianness == support::endianness::little, ELFT::Is64Bits ? 8 : 4); - DWARFDebugFrame EHFrame(Triple::ArchType(ObjF->getArch()), /*IsEH=*/true, + DWARFDebugFrame EHFrame(Triple::ArchType(ObjF.getArch()), /*IsEH=*/true, /*EHFrameAddress=*/Address); if (Error E = EHFrame.parse(DE)) - reportError(std::move(E), ObjF->getFileName()); + reportError(std::move(E), ObjF.getFileName()); for (const dwarf::FrameEntry &Entry : EHFrame) { if (const dwarf::CIE *CIE = dyn_cast<dwarf::CIE>(&Entry)) { @@ -224,7 +225,8 @@ void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const { W.getOStream() << "\n"; W.startLine() << "Program:\n"; W.indent(); - Entry.cfis().dump(W.getOStream(), nullptr, W.getIndentLevel()); + Entry.cfis().dump(W.getOStream(), DIDumpOptions(), nullptr, + W.getIndentLevel()); W.unindent(); W.unindent(); W.getOStream() << "\n"; @@ -232,7 +234,7 @@ void PrinterContext<ELFT>::printEHFrame(const Elf_Shdr *EHFrameShdr) const { W.unindent(); } -} -} +} // namespace DwarfCFIEH +} // namespace llvm #endif diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 15076f1f8933..0f508f8dc0f2 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -13,7 +13,6 @@ #include "ARMEHABIPrinter.h" #include "DwarfCFIEHPrinter.h" -#include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" #include "llvm-readobj.h" @@ -65,7 +64,6 @@ #include <memory> #include <string> #include <system_error> -#include <unordered_set> #include <vector> using namespace llvm; @@ -82,61 +80,37 @@ using namespace ELF; #define ENUM_ENT_1(enum) \ { #enum, #enum, ELF::enum } -#define LLVM_READOBJ_PHDR_ENUM(ns, enum) \ - case ns::enum: \ - return std::string(#enum).substr(3); - -#define TYPEDEF_ELF_TYPES(ELFT) \ - using ELFO = ELFFile<ELFT>; \ - 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 { -template <class ELFT> class DumpStyle; +template <class ELFT> struct RelSymbol { + RelSymbol(const typename ELFT::Sym *S, StringRef N) + : Sym(S), Name(N.str()) {} + const typename ELFT::Sym *Sym; + std::string Name; +}; /// Represents a contiguous uniform range in the file. We cannot just create a /// range directly because when creating one of these from the .dynamic table /// the size, entity size and virtual address are different entries in arbitrary /// order (DT_REL, DT_RELSZ, DT_RELENT for example). struct DynRegionInfo { - DynRegionInfo(StringRef ObjName) : FileName(ObjName) {} - DynRegionInfo(const void *A, uint64_t S, uint64_t ES, StringRef ObjName) - : Addr(A), Size(S), EntSize(ES), FileName(ObjName) {} + DynRegionInfo(const Binary &Owner, const ObjDumper &D) + : Obj(&Owner), Dumper(&D) {} + DynRegionInfo(const Binary &Owner, const ObjDumper &D, const uint8_t *A, + uint64_t S, uint64_t ES) + : Addr(A), Size(S), EntSize(ES), Obj(&Owner), Dumper(&D) {} /// Address in current address space. - const void *Addr = nullptr; + const uint8_t *Addr = nullptr; /// Size in bytes of the region. uint64_t Size = 0; /// Size of each entity in the region. uint64_t EntSize = 0; - /// Name of the file. Used for error reporting. - StringRef FileName; + /// Owner object. Used for error reporting. + const Binary *Obj; + /// Dumper used for error reporting. + const ObjDumper *Dumper; /// Error prefix. Used for error reporting to provide more information. std::string Context; /// Region size name. Used for error reporting. @@ -149,6 +123,20 @@ struct DynRegionInfo { const Type *Start = reinterpret_cast<const Type *>(Addr); if (!Start) return {Start, Start}; + + const uint64_t Offset = + Addr - (const uint8_t *)Obj->getMemoryBufferRef().getBufferStart(); + const uint64_t ObjSize = Obj->getMemoryBufferRef().getBufferSize(); + + if (Size > ObjSize - Offset) { + Dumper->reportUniqueWarning( + "unable to read data at 0x" + Twine::utohexstr(Offset) + + " of size 0x" + Twine::utohexstr(Size) + " (" + SizePrintName + + "): it goes past the end of the file of size 0x" + + Twine::utohexstr(ObjSize)); + return {Start, Start}; + } + if (EntSize == sizeof(Type) && (Size % EntSize == 0)) return {Start, Start + (Size / EntSize)}; @@ -163,697 +151,415 @@ struct DynRegionInfo { (" or " + EntSizePrintName + " (0x" + Twine::utohexstr(EntSize) + ")") .str(); - reportWarning(createError(Msg.c_str()), FileName); + Dumper->reportUniqueWarning(Msg); return {Start, Start}; } }; -namespace { -struct VerdAux { - unsigned Offset; - std::string Name; +struct GroupMember { + StringRef Name; + uint64_t Index; }; -struct VerDef { - unsigned Offset; - unsigned Version; - unsigned Flags; - unsigned Ndx; - unsigned Cnt; - unsigned Hash; - std::string Name; - std::vector<VerdAux> AuxV; +struct GroupSection { + StringRef Name; + std::string Signature; + uint64_t ShName; + uint64_t Index; + uint32_t Link; + uint32_t Info; + uint32_t Type; + std::vector<GroupMember> Members; }; -struct VernAux { - unsigned Hash; - unsigned Flags; - unsigned Other; - unsigned Offset; - std::string Name; -}; +namespace { -struct VerNeed { - unsigned Version; - unsigned Cnt; - unsigned Offset; - std::string File; - std::vector<VernAux> AuxV; +struct NoteType { + uint32_t ID; + StringRef Name; }; } // namespace +template <class ELFT> class Relocation { +public: + Relocation(const typename ELFT::Rel &R, bool IsMips64EL) + : Type(R.getType(IsMips64EL)), Symbol(R.getSymbol(IsMips64EL)), + Offset(R.r_offset), Info(R.r_info) {} + + Relocation(const typename ELFT::Rela &R, bool IsMips64EL) + : Relocation((const typename ELFT::Rel &)R, IsMips64EL) { + Addend = R.r_addend; + } + + uint32_t Type; + uint32_t Symbol; + typename ELFT::uint Offset; + typename ELFT::uint Info; + Optional<int64_t> Addend; +}; + +template <class ELFT> class MipsGOTParser; + template <typename ELFT> class ELFDumper : public ObjDumper { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + public: - ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ScopedPrinter &Writer); + ELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer); - void printFileHeaders() override; - void printSectionHeaders() override; - void printRelocations() override; - void printDependentLibs() override; - void printDynamicRelocations() override; - void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override; - void printHashSymbols() override; void printUnwindInfo() override; - - void printDynamicTable() override; void printNeededLibraries() override; - void printProgramHeaders(bool PrintProgramHeaders, - cl::boolOrDefault PrintSectionMapping) override; void printHashTable() override; - void printGnuHashTable(const object::ObjectFile *Obj) override; + void printGnuHashTable() override; void printLoadName() override; void printVersionInfo() override; - void printGroupSections() override; - void printArchSpecificInfo() override; - void printStackMap() const override; - void printHashHistograms() override; + const object::ELFObjectFile<ELFT> &getElfObject() const { return ObjF; }; - void printCGProfile() override; - void printAddrsig() override; + std::string describe(const Elf_Shdr &Sec) const; - void printNotes() override; - - void printELFLinkerOptions() override; - void printStackSizes() override; - - const object::ELFObjectFile<ELFT> *getElfObject() const { return ObjF; }; + unsigned getHashTableEntSize() const { + // EM_S390 and ELF::EM_ALPHA platforms use 8-bytes entries in SHT_HASH + // sections. This violates the ELF specification. + if (Obj.getHeader().e_machine == ELF::EM_S390 || + Obj.getHeader().e_machine == ELF::EM_ALPHA) + return 8; + return 4; + } -private: - std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle; + Elf_Dyn_Range dynamic_table() const { + // 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.template getAsArrayRef<Elf_Dyn>(); - TYPEDEF_ELF_TYPES(ELFT) + size_t Size = 0; + while (Size < Table.size()) + if (Table[Size++].getTag() == DT_NULL) + break; - DynRegionInfo checkDRI(DynRegionInfo DRI) { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - if (DRI.Addr < Obj->base() || - reinterpret_cast<const uint8_t *>(DRI.Addr) + DRI.Size > - Obj->base() + Obj->getBufSize()) - reportError(errorCodeToError(llvm::object::object_error::parse_failed), - ObjF->getFileName()); - return DRI; + return Table.slice(0, Size); } - DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) { - return checkDRI({ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, - EntSize, ObjF->getFileName()}); + Elf_Sym_Range dynamic_symbols() const { + if (!DynSymRegion) + return Elf_Sym_Range(); + return DynSymRegion->template getAsArrayRef<Elf_Sym>(); } - DynRegionInfo createDRIFrom(const Elf_Shdr *S) { - return checkDRI({ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, - S->sh_entsize, ObjF->getFileName()}); + const Elf_Shdr *findSectionByName(StringRef Name) const; + + StringRef getDynamicStringTable() const { return DynamicStringTable; } + +protected: + virtual void printVersionSymbolSection(const Elf_Shdr *Sec) = 0; + virtual void printVersionDefinitionSection(const Elf_Shdr *Sec) = 0; + virtual void printVersionDependencySection(const Elf_Shdr *Sec) = 0; + + void + printDependentLibsHelper(function_ref<void(const Elf_Shdr &)> OnSectionStart, + function_ref<void(StringRef, uint64_t)> OnLibEntry); + + virtual void printRelRelaReloc(const Relocation<ELFT> &R, + const RelSymbol<ELFT> &RelSym) = 0; + virtual void printRelrReloc(const Elf_Relr &R) = 0; + virtual void printDynamicRelocHeader(unsigned Type, StringRef Name, + const DynRegionInfo &Reg) {} + void printReloc(const Relocation<ELFT> &R, unsigned RelIndex, + const Elf_Shdr &Sec, const Elf_Shdr *SymTab); + void printDynamicReloc(const Relocation<ELFT> &R); + void printDynamicRelocationsHelper(); + void printRelocationsHelper(const Elf_Shdr &Sec); + void forEachRelocationDo( + const Elf_Shdr &Sec, bool RawRelr, + llvm::function_ref<void(const Relocation<ELFT> &, unsigned, + const Elf_Shdr &, const Elf_Shdr *)> + RelRelaFn, + llvm::function_ref<void(const Elf_Relr &)> RelrFn); + + virtual void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, + bool NonVisibilityBitsUsed) const {}; + virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, + Optional<StringRef> StrTable, bool IsDynamic, + bool NonVisibilityBitsUsed) const = 0; + + virtual void printMipsABIFlags() = 0; + virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; + virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; + + Expected<ArrayRef<Elf_Versym>> + getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab, + StringRef *StrTab, const Elf_Shdr **SymTabSec) const; + StringRef getPrintableSectionName(const Elf_Shdr &Sec) const; + + std::vector<GroupSection> getGroups(); + + bool printFunctionStackSize(uint64_t SymValue, + Optional<const Elf_Shdr *> FunctionSec, + const Elf_Shdr &StackSizeSec, DataExtractor Data, + uint64_t *Offset); + void printStackSize(const Relocation<ELFT> &R, const Elf_Shdr &RelocSec, + unsigned Ndx, const Elf_Shdr *SymTab, + const Elf_Shdr *FunctionSec, const Elf_Shdr &StackSizeSec, + const RelocationResolver &Resolver, DataExtractor Data); + virtual void printStackSizeEntry(uint64_t Size, StringRef FuncName) = 0; + + void printRelocatableStackSizes(std::function<void()> PrintHeader); + void printNonRelocatableStackSizes(std::function<void()> PrintHeader); + + const object::ELFObjectFile<ELFT> &ObjF; + const ELFFile<ELFT> &Obj; + StringRef FileName; + + Expected<DynRegionInfo> createDRI(uint64_t Offset, uint64_t Size, + uint64_t EntSize) { + if (Offset + Size < Offset || Offset + Size > Obj.getBufSize()) + return createError("offset (0x" + Twine::utohexstr(Offset) + + ") + size (0x" + Twine::utohexstr(Size) + + ") is greater than the file size (0x" + + Twine::utohexstr(Obj.getBufSize()) + ")"); + return DynRegionInfo(ObjF, *this, Obj.base() + Offset, Size, EntSize); } void printAttributes(); void printMipsReginfo(); void printMipsOptions(); - std::pair<const Elf_Phdr *, const Elf_Shdr *> - findDynamic(const ELFFile<ELFT> *Obj); - void loadDynamicTable(const ELFFile<ELFT> *Obj); - void parseDynamicTable(const ELFFile<ELFT> *Obj); + std::pair<const Elf_Phdr *, const Elf_Shdr *> findDynamic(); + void loadDynamicTable(); + void parseDynamicTable(); - Expected<StringRef> getSymbolVersion(const Elf_Sym *symb, + Expected<StringRef> getSymbolVersion(const Elf_Sym &Sym, bool &IsDefault) const; - Error LoadVersionMap() const; + Expected<SmallVector<Optional<VersionEntry>, 0> *> getVersionMap() const; - const object::ELFObjectFile<ELFT> *ObjF; DynRegionInfo DynRelRegion; DynRegionInfo DynRelaRegion; DynRegionInfo DynRelrRegion; DynRegionInfo DynPLTRelRegion; Optional<DynRegionInfo> DynSymRegion; + DynRegionInfo DynSymTabShndxRegion; DynRegionInfo DynamicTable; StringRef DynamicStringTable; - StringRef SOName = "<Not found>"; const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; + const Elf_Shdr *DotDynsymSec = nullptr; const Elf_Shdr *DotCGProfileSec = nullptr; const Elf_Shdr *DotAddrsigSec = nullptr; - StringRef DynSymtabName; - ArrayRef<Elf_Word> ShndxTable; + DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables; + Optional<uint64_t> SONameOffset; const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r const Elf_Shdr *SymbolVersionDefSection = nullptr; // .gnu.version_d - struct VersionEntry { - std::string Name; - bool IsVerDef; - }; - mutable SmallVector<Optional<VersionEntry>, 16> VersionMap; - - std::unordered_set<std::string> Warnings; - -public: - Elf_Dyn_Range dynamic_table() const { - // A valid .dynamic section contains an array of entries terminated - // 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); - } - - Optional<DynRegionInfo> getDynSymRegion() const { return DynSymRegion; } - - Elf_Sym_Range dynamic_symbols() const { - if (!DynSymRegion) - return Elf_Sym_Range(); - return DynSymRegion->getAsArrayRef<Elf_Sym>(); - } - - Elf_Rel_Range dyn_rels() const; - Elf_Rela_Range dyn_relas() const; - Elf_Relr_Range dyn_relrs() const; - std::string getFullSymbolName(const Elf_Sym *Symbol, + std::string getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, Optional<StringRef> StrTable, bool IsDynamic) const; - Expected<unsigned> getSymbolSectionIndex(const Elf_Sym *Symbol, - const Elf_Sym *FirstSym) const; - Expected<StringRef> getSymbolSectionName(const Elf_Sym *Symbol, + Expected<unsigned> + getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable) const; + Expected<StringRef> getSymbolSectionName(const Elf_Sym &Symbol, unsigned SectionIndex) const; std::string getStaticSymbolName(uint32_t Index) const; StringRef getDynamicString(uint64_t Value) const; - Expected<StringRef> getSymbolVersionByIndex(uint32_t VersionSymbolIndex, - bool &IsDefault) const; void printSymbolsHelper(bool IsDynamic) const; std::string getDynamicEntry(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; } - 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 DynRegionInfo &getDynamicTableRegion() const { return DynamicTable; } - const Elf_Hash *getHashTable() const { return HashTable; } - const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; } - - Expected<ArrayRef<Elf_Versym>> getVersionTable(const Elf_Shdr *Sec, - ArrayRef<Elf_Sym> *SymTab, - StringRef *StrTab) const; - Expected<std::vector<VerDef>> - getVersionDefinitions(const Elf_Shdr *Sec) const; - Expected<std::vector<VerNeed>> - getVersionDependencies(const Elf_Shdr *Sec) const; + Expected<RelSymbol<ELFT>> getRelocationTarget(const Relocation<ELFT> &R, + const Elf_Shdr *SymTab) const; - Expected<std::pair<const Elf_Sym *, std::string>> - getRelocationTarget(const Elf_Shdr *SymTab, const Elf_Rela &R) const; + ArrayRef<Elf_Word> getShndxTable(const Elf_Shdr *Symtab) const; - std::function<Error(const Twine &Msg)> WarningHandler; - void reportUniqueWarning(Error Err) const; +private: + mutable SmallVector<Optional<VersionEntry>, 0> VersionMap; }; template <class ELFT> -static Expected<StringRef> getLinkAsStrtab(const ELFFile<ELFT> *Obj, - const typename ELFT::Shdr *Sec, - unsigned SecNdx) { - Expected<const typename ELFT::Shdr *> StrTabSecOrErr = - Obj->getSection(Sec->sh_link); - if (!StrTabSecOrErr) - return createError("invalid section linked to " + - object::getELFSectionTypeName( - Obj->getHeader()->e_machine, Sec->sh_type) + - " section with index " + Twine(SecNdx) + ": " + - toString(StrTabSecOrErr.takeError())); - - Expected<StringRef> StrTabOrErr = Obj->getStringTable(*StrTabSecOrErr); - if (!StrTabOrErr) - return createError("invalid string table linked to " + - object::getELFSectionTypeName( - Obj->getHeader()->e_machine, Sec->sh_type) + - " section with index " + Twine(SecNdx) + ": " + - toString(StrTabOrErr.takeError())); - return *StrTabOrErr; +std::string ELFDumper<ELFT>::describe(const Elf_Shdr &Sec) const { + return ::describe(Obj, Sec); } -// Returns the linked symbol table and associated string table for a given section. +namespace { + +template <class ELFT> struct SymtabLink { + typename ELFT::SymRange Symbols; + StringRef StringTable; + const typename ELFT::Shdr *SymTab; +}; + +// Returns the linked symbol table, symbols and associated string table for a +// given section. template <class ELFT> -static Expected<std::pair<typename ELFT::SymRange, StringRef>> -getLinkAsSymtab(const ELFFile<ELFT> *Obj, const typename ELFT::Shdr *Sec, - unsigned SecNdx, unsigned ExpectedType) { +Expected<SymtabLink<ELFT>> getLinkAsSymtab(const ELFFile<ELFT> &Obj, + const typename ELFT::Shdr &Sec, + unsigned ExpectedType) { Expected<const typename ELFT::Shdr *> SymtabOrErr = - Obj->getSection(Sec->sh_link); + Obj.getSection(Sec.sh_link); if (!SymtabOrErr) - return createError("invalid section linked to " + - object::getELFSectionTypeName( - Obj->getHeader()->e_machine, Sec->sh_type) + - " section with index " + Twine(SecNdx) + ": " + - toString(SymtabOrErr.takeError())); + return createError("invalid section linked to " + describe(Obj, Sec) + + ": " + toString(SymtabOrErr.takeError())); if ((*SymtabOrErr)->sh_type != ExpectedType) return createError( - "invalid section linked to " + - object::getELFSectionTypeName(Obj->getHeader()->e_machine, - Sec->sh_type) + - " section with index " + Twine(SecNdx) + ": expected " + - object::getELFSectionTypeName(Obj->getHeader()->e_machine, - ExpectedType) + + "invalid section linked to " + describe(Obj, Sec) + ": expected " + + object::getELFSectionTypeName(Obj.getHeader().e_machine, ExpectedType) + ", but got " + - object::getELFSectionTypeName(Obj->getHeader()->e_machine, + object::getELFSectionTypeName(Obj.getHeader().e_machine, (*SymtabOrErr)->sh_type)); - Expected<StringRef> StrTabOrErr = - getLinkAsStrtab(Obj, *SymtabOrErr, Sec->sh_link); + Expected<StringRef> StrTabOrErr = Obj.getLinkAsStrtab(**SymtabOrErr); if (!StrTabOrErr) return createError( "can't get a string table for the symbol table linked to " + - object::getELFSectionTypeName(Obj->getHeader()->e_machine, - Sec->sh_type) + - " section with index " + Twine(SecNdx) + ": " + - toString(StrTabOrErr.takeError())); + describe(Obj, Sec) + ": " + toString(StrTabOrErr.takeError())); - Expected<typename ELFT::SymRange> SymsOrErr = Obj->symbols(*SymtabOrErr); + Expected<typename ELFT::SymRange> SymsOrErr = Obj.symbols(*SymtabOrErr); if (!SymsOrErr) - return createError( - "unable to read symbols from the symbol table with index " + - Twine(Sec->sh_link) + ": " + toString(SymsOrErr.takeError())); + return createError("unable to read symbols from the " + describe(Obj, Sec) + + ": " + toString(SymsOrErr.takeError())); - return std::make_pair(*SymsOrErr, *StrTabOrErr); + return SymtabLink<ELFT>{*SymsOrErr, *StrTabOrErr, *SymtabOrErr}; } +} // namespace + template <class ELFT> Expected<ArrayRef<typename ELFT::Versym>> -ELFDumper<ELFT>::getVersionTable(const Elf_Shdr *Sec, ArrayRef<Elf_Sym> *SymTab, - StringRef *StrTab) const { - assert((!SymTab && !StrTab) || (SymTab && StrTab)); - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); - - if (uintptr_t(Obj->base() + Sec->sh_offset) % sizeof(uint16_t) != 0) - return createError("the SHT_GNU_versym section with index " + - Twine(SecNdx) + " is misaligned"); +ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab, + StringRef *StrTab, + const Elf_Shdr **SymTabSec) const { + assert((!SymTab && !StrTab && !SymTabSec) || (SymTab && StrTab && SymTabSec)); + if (reinterpret_cast<uintptr_t>(Obj.base() + Sec.sh_offset) % + sizeof(uint16_t) != + 0) + return createError("the " + describe(Sec) + " is misaligned"); Expected<ArrayRef<Elf_Versym>> VersionsOrErr = - Obj->template getSectionContentsAsArray<Elf_Versym>(Sec); + Obj.template getSectionContentsAsArray<Elf_Versym>(Sec); if (!VersionsOrErr) - return createError( - "cannot read content of SHT_GNU_versym section with index " + - Twine(SecNdx) + ": " + toString(VersionsOrErr.takeError())); + return createError("cannot read content of " + describe(Sec) + ": " + + toString(VersionsOrErr.takeError())); - Expected<std::pair<ArrayRef<Elf_Sym>, StringRef>> SymTabOrErr = - getLinkAsSymtab(Obj, Sec, SecNdx, SHT_DYNSYM); + Expected<SymtabLink<ELFT>> SymTabOrErr = + getLinkAsSymtab(Obj, Sec, SHT_DYNSYM); if (!SymTabOrErr) { reportUniqueWarning(SymTabOrErr.takeError()); return *VersionsOrErr; } - if (SymTabOrErr->first.size() != VersionsOrErr->size()) - reportUniqueWarning( - createError("SHT_GNU_versym section with index " + Twine(SecNdx) + - ": the number of entries (" + Twine(VersionsOrErr->size()) + - ") does not match the number of symbols (" + - Twine(SymTabOrErr->first.size()) + - ") in the symbol table with index " + Twine(Sec->sh_link))); - - if (SymTab) - std::tie(*SymTab, *StrTab) = *SymTabOrErr; - return *VersionsOrErr; -} - -template <class ELFT> -Expected<std::vector<VerDef>> -ELFDumper<ELFT>::getVersionDefinitions(const Elf_Shdr *Sec) const { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); - - Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx); - if (!StrTabOrErr) - return StrTabOrErr.takeError(); - - Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(Sec); - if (!ContentsOrErr) - return createError( - "cannot read content of SHT_GNU_verdef section with index " + - Twine(SecNdx) + ": " + toString(ContentsOrErr.takeError())); - - const uint8_t *Start = ContentsOrErr->data(); - const uint8_t *End = Start + ContentsOrErr->size(); - - auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf, - unsigned VerDefNdx) -> Expected<VerdAux> { - if (VerdauxBuf + sizeof(Elf_Verdaux) > End) - return createError("invalid SHT_GNU_verdef section with index " + - Twine(SecNdx) + ": version definition " + - Twine(VerDefNdx) + - " refers to an auxiliary entry that goes past the end " - "of the section"); - - auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); - VerdauxBuf += Verdaux->vda_next; - - VerdAux Aux; - Aux.Offset = VerdauxBuf - Start; - if (Verdaux->vda_name <= StrTabOrErr->size()) - Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name)); - else - Aux.Name = "<invalid vda_name: " + to_string(Verdaux->vda_name) + ">"; - return Aux; - }; - - std::vector<VerDef> Ret; - const uint8_t *VerdefBuf = Start; - for (unsigned I = 1; I <= /*VerDefsNum=*/Sec->sh_info; ++I) { - if (VerdefBuf + sizeof(Elf_Verdef) > End) - return createError("invalid SHT_GNU_verdef section with index " + - Twine(SecNdx) + ": version definition " + Twine(I) + - " goes past the end of the section"); - - if (uintptr_t(VerdefBuf) % sizeof(uint32_t) != 0) - return createError( - "invalid SHT_GNU_verdef section with index " + Twine(SecNdx) + - ": found a misaligned version definition entry at offset 0x" + - Twine::utohexstr(VerdefBuf - Start)); - - unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf); - if (Version != 1) - return createError("unable to dump SHT_GNU_verdef section with index " + - Twine(SecNdx) + ": version " + Twine(Version) + - " is not yet supported"); - - const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); - VerDef &VD = *Ret.emplace(Ret.end()); - VD.Offset = VerdefBuf - Start; - VD.Version = D->vd_version; - VD.Flags = D->vd_flags; - VD.Ndx = D->vd_ndx; - VD.Cnt = D->vd_cnt; - VD.Hash = D->vd_hash; - - const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux; - for (unsigned J = 0; J < D->vd_cnt; ++J) { - if (uintptr_t(VerdauxBuf) % sizeof(uint32_t) != 0) - return createError("invalid SHT_GNU_verdef section with index " + - Twine(SecNdx) + - ": found a misaligned auxiliary entry at offset 0x" + - Twine::utohexstr(VerdauxBuf - Start)); - - Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I); - if (!AuxOrErr) - return AuxOrErr.takeError(); - - if (J == 0) - VD.Name = AuxOrErr->Name; - else - VD.AuxV.push_back(*AuxOrErr); - } - - VerdefBuf += D->vd_next; - } - - return Ret; -} - -template <class ELFT> -Expected<std::vector<VerNeed>> -ELFDumper<ELFT>::getVersionDependencies(const Elf_Shdr *Sec) const { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); - - StringRef StrTab; - Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Obj, Sec, SecNdx); - if (!StrTabOrErr) - reportUniqueWarning(StrTabOrErr.takeError()); - else - StrTab = *StrTabOrErr; - - Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(Sec); - if (!ContentsOrErr) - return createError( - "cannot read content of SHT_GNU_verneed section with index " + - Twine(SecNdx) + ": " + toString(ContentsOrErr.takeError())); - - const uint8_t *Start = ContentsOrErr->data(); - const uint8_t *End = Start + ContentsOrErr->size(); - const uint8_t *VerneedBuf = Start; - - std::vector<VerNeed> Ret; - for (unsigned I = 1; I <= /*VerneedNum=*/Sec->sh_info; ++I) { - if (VerneedBuf + sizeof(Elf_Verdef) > End) - return createError("invalid SHT_GNU_verneed section with index " + - Twine(SecNdx) + ": version dependency " + Twine(I) + - " goes past the end of the section"); - - if (uintptr_t(VerneedBuf) % sizeof(uint32_t) != 0) - return createError( - "invalid SHT_GNU_verneed section with index " + Twine(SecNdx) + - ": found a misaligned version dependency entry at offset 0x" + - Twine::utohexstr(VerneedBuf - Start)); - - unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf); - if (Version != 1) - return createError("unable to dump SHT_GNU_verneed section with index " + - Twine(SecNdx) + ": version " + Twine(Version) + - " is not yet supported"); - - const Elf_Verneed *Verneed = - reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + if (SymTabOrErr->Symbols.size() != VersionsOrErr->size()) + reportUniqueWarning(describe(Sec) + ": the number of entries (" + + Twine(VersionsOrErr->size()) + + ") does not match the number of symbols (" + + Twine(SymTabOrErr->Symbols.size()) + + ") in the symbol table with index " + + Twine(Sec.sh_link)); - VerNeed &VN = *Ret.emplace(Ret.end()); - VN.Version = Verneed->vn_version; - VN.Cnt = Verneed->vn_cnt; - VN.Offset = VerneedBuf - Start; - - if (Verneed->vn_file < StrTab.size()) - VN.File = std::string(StrTab.drop_front(Verneed->vn_file)); - else - VN.File = "<corrupt vn_file: " + to_string(Verneed->vn_file) + ">"; - - const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; - for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { - if (uintptr_t(VernauxBuf) % sizeof(uint32_t) != 0) - return createError("invalid SHT_GNU_verneed section with index " + - Twine(SecNdx) + - ": found a misaligned auxiliary entry at offset 0x" + - Twine::utohexstr(VernauxBuf - Start)); - - if (VernauxBuf + sizeof(Elf_Vernaux) > End) - return createError( - "invalid SHT_GNU_verneed section with index " + Twine(SecNdx) + - ": version dependency " + Twine(I) + - " refers to an auxiliary entry that goes past the end " - "of the section"); - - const Elf_Vernaux *Vernaux = - reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); - - VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end()); - Aux.Hash = Vernaux->vna_hash; - Aux.Flags = Vernaux->vna_flags; - Aux.Other = Vernaux->vna_other; - Aux.Offset = VernauxBuf - Start; - if (StrTab.size() <= Vernaux->vna_name) - Aux.Name = "<corrupt>"; - else - Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name)); - - VernauxBuf += Vernaux->vna_next; - } - VerneedBuf += Verneed->vn_next; + if (SymTab) { + *SymTab = SymTabOrErr->Symbols; + *StrTab = SymTabOrErr->StringTable; + *SymTabSec = SymTabOrErr->SymTab; } - return Ret; + return *VersionsOrErr; } template <class ELFT> void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) const { Optional<StringRef> StrTable; - StringRef SymtabName; size_t Entries = 0; Elf_Sym_Range Syms(nullptr, nullptr); - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + const Elf_Shdr *SymtabSec = IsDynamic ? DotDynsymSec : DotSymtabSec; + if (IsDynamic) { StrTable = DynamicStringTable; Syms = dynamic_symbols(); - SymtabName = DynSymtabName; Entries = Syms.size(); - } else { - if (!DotSymtabSec) - return; - + } else if (DotSymtabSec) { if (Expected<StringRef> StrTableOrErr = - Obj->getStringTableForSymtab(*DotSymtabSec)) + Obj.getStringTableForSymtab(*DotSymtabSec)) StrTable = *StrTableOrErr; else - reportUniqueWarning(createError( + reportUniqueWarning( "unable to get the string table for the SHT_SYMTAB section: " + - toString(StrTableOrErr.takeError()))); + toString(StrTableOrErr.takeError())); - if (Expected<Elf_Sym_Range> SymsOrErr = Obj->symbols(DotSymtabSec)) + if (Expected<Elf_Sym_Range> SymsOrErr = Obj.symbols(DotSymtabSec)) Syms = *SymsOrErr; else reportUniqueWarning( - createError("unable to read symbols from the SHT_SYMTAB section: " + - toString(SymsOrErr.takeError()))); - - if (Expected<StringRef> SymtabNameOrErr = - Obj->getSectionName(DotSymtabSec)) { - SymtabName = *SymtabNameOrErr; - } else { - reportUniqueWarning( - createError("unable to get the name of the SHT_SYMTAB section: " + - toString(SymtabNameOrErr.takeError()))); - SymtabName = "<?>"; - } - + "unable to read symbols from the SHT_SYMTAB section: " + + toString(SymsOrErr.takeError())); Entries = DotSymtabSec->getEntityCount(); } - if (Syms.begin() == Syms.end()) + if (Syms.empty()) return; // The st_other field has 2 logical parts. The first two bits hold the symbol // visibility (STV_*) and the remainder hold other platform-specific values. - bool NonVisibilityBitsUsed = llvm::find_if(Syms, [](const Elf_Sym &S) { - return S.st_other & ~0x3; - }) != Syms.end(); - - ELFDumperStyle->printSymtabMessage(Obj, SymtabName, Entries, - NonVisibilityBitsUsed); - for (const auto &Sym : Syms) - ELFDumperStyle->printSymbol(Obj, &Sym, Syms.begin(), StrTable, IsDynamic, - NonVisibilityBitsUsed); -} - -template <class ELFT> class MipsGOTParser; - -template <typename ELFT> class DumpStyle { -public: - using Elf_Shdr = typename ELFT::Shdr; - using Elf_Sym = typename ELFT::Sym; - using Elf_Addr = typename ELFT::Addr; - - DumpStyle(ELFDumper<ELFT> *Dumper) : Dumper(Dumper) { - FileName = this->Dumper->getElfObject()->getFileName(); - } - - virtual ~DumpStyle() = default; - - virtual void printFileHeaders(const ELFFile<ELFT> *Obj) = 0; - 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, bool PrintSymbols, - bool PrintDynamicSymbols) = 0; - virtual void printHashSymbols(const ELFFile<ELFT> *Obj) {} - virtual void printDependentLibs(const ELFFile<ELFT> *Obj) = 0; - virtual void printDynamic(const ELFFile<ELFT> *Obj) {} - virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0; - virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name, - size_t Offset, bool NonVisibilityBitsUsed) {} - virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol, - const Elf_Sym *FirstSym, - Optional<StringRef> StrTable, bool IsDynamic, - bool NonVisibilityBitsUsed) = 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 printHashHistograms(const ELFFile<ELFT> *Obj) = 0; - virtual void printCGProfile(const ELFFile<ELFT> *Obj) = 0; - virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0; - virtual void printNotes(const ELFFile<ELFT> *Obj) = 0; - virtual void printELFLinkerOptions(const ELFFile<ELFT> *Obj) = 0; - virtual void printStackSizes(const ELFObjectFile<ELFT> *Obj) = 0; - void printNonRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj, - std::function<void()> PrintHeader); - void printRelocatableStackSizes(const ELFObjectFile<ELFT> *Obj, - std::function<void()> PrintHeader); - void printFunctionStackSize(const ELFObjectFile<ELFT> *Obj, uint64_t SymValue, - Optional<SectionRef> FunctionSec, - const StringRef SectionName, DataExtractor Data, - uint64_t *Offset); - void printStackSize(const ELFObjectFile<ELFT> *Obj, RelocationRef Rel, - SectionRef FunctionSec, - const StringRef &StackSizeSectionName, - const RelocationResolver &Resolver, DataExtractor Data); - virtual void printStackSizeEntry(uint64_t Size, StringRef FuncName) = 0; - virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; - virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; - virtual void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) = 0; - const ELFDumper<ELFT> *dumper() const { return Dumper; } + bool NonVisibilityBitsUsed = + llvm::any_of(Syms, [](const Elf_Sym &S) { return S.st_other & ~0x3; }); -protected: - void printDependentLibsHelper( - const ELFFile<ELFT> *Obj, - function_ref<void(const Elf_Shdr &)> OnSectionStart, - function_ref<void(StringRef, uint64_t)> OnSectionEntry); + DataRegion<Elf_Word> ShndxTable = + IsDynamic ? DataRegion<Elf_Word>( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, + this->getElfObject().getELFFile().end()) + : DataRegion<Elf_Word>(this->getShndxTable(SymtabSec)); - void reportUniqueWarning(Error Err) const; - StringRef FileName; - -private: - const ELFDumper<ELFT> *Dumper; -}; + printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed); + for (const Elf_Sym &Sym : Syms) + printSymbol(Sym, &Sym - Syms.begin(), ShndxTable, StrTable, IsDynamic, + NonVisibilityBitsUsed); +} -template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> { +template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> { formatted_raw_ostream &OS; public: - TYPEDEF_ELF_TYPES(ELFT) + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) - GNUStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper) - : DumpStyle<ELFT>(Dumper), - OS(static_cast<formatted_raw_ostream&>(W.getOStream())) { - assert (&W.getOStream() == &llvm::fouts()); + GNUELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer) + : ELFDumper<ELFT>(ObjF, Writer), + OS(static_cast<formatted_raw_ostream &>(Writer.getOStream())) { + assert(&this->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, bool PrintSymbols, - bool PrintDynamicSymbols) override; - void printHashSymbols(const ELFO *Obj) override; - void printDependentLibs(const ELFFile<ELFT> *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, - bool NonVisibilityBitsUsed) override; - void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, + void printFileHeaders() override; + void printGroupSections() override; + void printRelocations() override; + void printSectionHeaders() override; + void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override; + void printHashSymbols() override; + void printSectionDetails() override; + void printDependentLibs() override; + void printDynamicTable() override; + void printDynamicRelocations() override; + void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, + bool NonVisibilityBitsUsed) const override; + void printProgramHeaders(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 printHashHistograms(const ELFFile<ELFT> *Obj) override; - void printCGProfile(const ELFFile<ELFT> *Obj) override; - void printAddrsig(const ELFFile<ELFT> *Obj) override; - void printNotes(const ELFFile<ELFT> *Obj) override; - void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override; - void printStackSizes(const ELFObjectFile<ELFT> *Obj) override; - void printStackSizeEntry(uint64_t Size, StringRef FuncName) override; - void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; - void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; - void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override; + void printVersionSymbolSection(const Elf_Shdr *Sec) override; + void printVersionDefinitionSection(const Elf_Shdr *Sec) override; + void printVersionDependencySection(const Elf_Shdr *Sec) override; + void printHashHistograms() override; + void printCGProfile() override; + void printAddrsig() override; + void printNotes() override; + void printELFLinkerOptions() override; + void printStackSizes() override; private: void printHashHistogram(const Elf_Hash &HashTable); void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable); - - void printHashTableSymbols(const ELFO *Obj, const Elf_Hash &HashTable); - void printGnuHashTableSymbols(const ELFO *Obj, - const Elf_GnuHash &GnuHashTable); + void printHashTableSymbols(const Elf_Hash &HashTable); + void printGnuHashTableSymbols(const Elf_GnuHash &GnuHashTable); struct Field { std::string Str; @@ -864,8 +570,8 @@ private: }; template <typename T, typename TEnum> - std::string printEnum(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues) { - for (const auto &EnumItem : EnumValues) + std::string printEnum(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues) const { + for (const EnumEntry<TEnum> &EnumItem : EnumValues) if (EnumItem.Value == Value) return std::string(EnumItem.AltName); return to_hexString(Value, false); @@ -874,9 +580,9 @@ private: template <typename T, typename TEnum> std::string printFlags(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues, TEnum EnumMask1 = {}, TEnum EnumMask2 = {}, - TEnum EnumMask3 = {}) { + TEnum EnumMask3 = {}) const { std::string Str; - for (const auto &Flag : EnumValues) { + for (const EnumEntry<TEnum> &Flag : EnumValues) { if (Flag.Value == 0) continue; @@ -898,95 +604,85 @@ private: return Str; } - formatted_raw_ostream &printField(struct Field F) { + formatted_raw_ostream &printField(struct Field F) const { if (F.Column != 0) OS.PadToColumn(F.Column); OS << F.Str; OS.flush(); return OS; } - 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, unsigned SecIndex, - const Elf_Shdr *SymTab, const Elf_Rela &R, - unsigned RelIndex, bool IsRela); - void printRelocation(const ELFO *Obj, const Elf_Sym *Sym, - StringRef SymbolName, const Elf_Rela &R, bool IsRela); - void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, + void printHashedSymbol(const Elf_Sym *Sym, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, StringRef StrTable, + uint32_t Bucket); + void printRelrReloc(const Elf_Relr &R) override; + void printRelRelaReloc(const Relocation<ELFT> &R, + const RelSymbol<ELFT> &RelSym) override; + void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, Optional<StringRef> StrTable, bool IsDynamic, - bool NonVisibilityBitsUsed) override; - std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol, - const Elf_Sym *FirstSym); - void printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela); - void printProgramHeaders(const ELFO *Obj); - void printSectionMapping(const ELFO *Obj); - void printGNUVersionSectionProlog(const ELFFile<ELFT> *Obj, - const typename ELFT::Shdr *Sec, + bool NonVisibilityBitsUsed) const override; + void printDynamicRelocHeader(unsigned Type, StringRef Name, + const DynRegionInfo &Reg) override; + + std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable) const; + void printProgramHeaders() override; + void printSectionMapping() override; + void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec, const Twine &Label, unsigned EntriesNum); -}; -template <class ELFT> -void ELFDumper<ELFT>::reportUniqueWarning(Error Err) const { - handleAllErrors(std::move(Err), [&](const ErrorInfoBase &EI) { - cantFail(WarningHandler(EI.message()), - "WarningHandler should always return ErrorSuccess"); - }); -} + void printStackSizeEntry(uint64_t Size, StringRef FuncName) override; -template <class ELFT> -void DumpStyle<ELFT>::reportUniqueWarning(Error Err) const { - this->dumper()->reportUniqueWarning(std::move(Err)); -} + void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; + void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; + void printMipsABIFlags() override; +}; -template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> { +template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> { public: - TYPEDEF_ELF_TYPES(ELFT) + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) - LLVMStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper) - : DumpStyle<ELFT>(Dumper), W(W) {} + LLVMELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer) + : ELFDumper<ELFT>(ObjF, Writer), W(Writer) {} - void printFileHeaders(const ELFO *Obj) override; - void printGroupSections(const ELFFile<ELFT> *Obj) override; - 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, bool PrintSymbols, - bool PrintDynamicSymbols) override; - void printDependentLibs(const ELFFile<ELFT> *Obj) override; - void printDynamic(const ELFFile<ELFT> *Obj) override; - void printDynamicRelocations(const ELFO *Obj) override; - void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, + void printFileHeaders() override; + void printGroupSections() override; + void printRelocations() override; + void printSectionHeaders() override; + void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override; + void printDependentLibs() override; + void printDynamicTable() override; + void printDynamicRelocations() override; + void printProgramHeaders(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 printHashHistograms(const ELFFile<ELFT> *Obj) override; - void printCGProfile(const ELFFile<ELFT> *Obj) override; - void printAddrsig(const ELFFile<ELFT> *Obj) override; - void printNotes(const ELFFile<ELFT> *Obj) override; - void printELFLinkerOptions(const ELFFile<ELFT> *Obj) override; - void printStackSizes(const ELFObjectFile<ELFT> *Obj) override; - void printStackSizeEntry(uint64_t Size, StringRef FuncName) override; - void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; - void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; - void printMipsABIFlags(const ELFObjectFile<ELFT> *Obj) override; + void printVersionSymbolSection(const Elf_Shdr *Sec) override; + void printVersionDefinitionSection(const Elf_Shdr *Sec) override; + void printVersionDependencySection(const Elf_Shdr *Sec) override; + void printHashHistograms() override; + void printCGProfile() override; + void printAddrsig() override; + void printNotes() override; + void printELFLinkerOptions() override; + void printStackSizes() override; private: - void printRelocation(const ELFO *Obj, unsigned SecIndex, Elf_Rela Rel, - unsigned RelIndex, const Elf_Shdr *SymTab); - void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel); - void printSymbols(const ELFO *Obj); - void printDynamicSymbols(const ELFO *Obj); - void printSymbolSection(const Elf_Sym *Symbol, const Elf_Sym *First); - void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, + void printRelrReloc(const Elf_Relr &R) override; + void printRelRelaReloc(const Relocation<ELFT> &R, + const RelSymbol<ELFT> &RelSym) override; + + void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable) const; + void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, Optional<StringRef> StrTable, bool IsDynamic, - bool /*NonVisibilityBitsUsed*/) override; - void printProgramHeaders(const ELFO *Obj); - void printSectionMapping(const ELFO *Obj) {} + bool /*NonVisibilityBitsUsed*/) const override; + void printProgramHeaders() override; + void printSectionMapping() override {} + void printStackSizeEntry(uint64_t Size, StringRef FuncName) override; + + void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; + void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; + void printMipsABIFlags() override; ScopedPrinter &W; }; @@ -996,81 +692,53 @@ private: namespace llvm { template <class ELFT> -static std::error_code createELFDumper(const ELFObjectFile<ELFT> *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result) { - Result.reset(new ELFDumper<ELFT>(Obj, Writer)); - return readobj_error::success; +static std::unique_ptr<ObjDumper> +createELFDumper(const ELFObjectFile<ELFT> &Obj, ScopedPrinter &Writer) { + if (opts::Output == opts::GNU) + return std::make_unique<GNUELFDumper<ELFT>>(Obj, Writer); + return std::make_unique<LLVMELFDumper<ELFT>>(Obj, Writer); } -std::error_code createELFDumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result) { +std::unique_ptr<ObjDumper> createELFDumper(const object::ELFObjectFileBase &Obj, + ScopedPrinter &Writer) { // Little-endian 32-bit - if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(Obj)) - return createELFDumper(ELFObj, Writer, Result); + if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(&Obj)) + return createELFDumper(*ELFObj, Writer); // Big-endian 32-bit - if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(Obj)) - return createELFDumper(ELFObj, Writer, Result); + if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(&Obj)) + return createELFDumper(*ELFObj, Writer); // Little-endian 64-bit - if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(Obj)) - return createELFDumper(ELFObj, Writer, Result); + if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(&Obj)) + return createELFDumper(*ELFObj, Writer); // Big-endian 64-bit - if (const ELF64BEObjectFile *ELFObj = dyn_cast<ELF64BEObjectFile>(Obj)) - return createELFDumper(ELFObj, Writer, Result); - - return readobj_error::unsupported_obj_file_format; + return createELFDumper(*cast<ELF64BEObjectFile>(&Obj), Writer); } } // end namespace llvm -template <class ELFT> Error ELFDumper<ELFT>::LoadVersionMap() const { - // If there is no dynamic symtab or version table, there is nothing to do. - if (!DynSymRegion || !SymbolVersionSection) - return Error::success(); - - // Has the VersionMap already been loaded? - if (!VersionMap.empty()) - return Error::success(); - - // The first two version indexes are reserved. - // Index 0 is LOCAL, index 1 is GLOBAL. - VersionMap.push_back(VersionEntry()); - VersionMap.push_back(VersionEntry()); - - auto InsertEntry = [this](unsigned N, StringRef Version, bool IsVerdef) { - if (N >= VersionMap.size()) - VersionMap.resize(N + 1); - VersionMap[N] = {std::string(Version), IsVerdef}; - }; - - if (SymbolVersionDefSection) { - Expected<std::vector<VerDef>> Defs = - this->getVersionDefinitions(SymbolVersionDefSection); - if (!Defs) - return Defs.takeError(); - for (const VerDef &Def : *Defs) - InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true); - } +template <class ELFT> +Expected<SmallVector<Optional<VersionEntry>, 0> *> +ELFDumper<ELFT>::getVersionMap() const { + // If the VersionMap has already been loaded or if there is no dynamic symtab + // or version table, there is nothing to do. + if (!VersionMap.empty() || !DynSymRegion || !SymbolVersionSection) + return &VersionMap; - if (SymbolVersionNeedSection) { - Expected<std::vector<VerNeed>> Deps = - this->getVersionDependencies(SymbolVersionNeedSection); - if (!Deps) - return Deps.takeError(); - for (const VerNeed &Dep : *Deps) - for (const VernAux &Aux : Dep.AuxV) - InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false); - } + Expected<SmallVector<Optional<VersionEntry>, 0>> MapOrErr = + Obj.loadVersionMap(SymbolVersionNeedSection, SymbolVersionDefSection); + if (MapOrErr) + VersionMap = *MapOrErr; + else + return MapOrErr.takeError(); - return Error::success(); + return &VersionMap; } template <typename ELFT> -Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym *Sym, +Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym &Sym, bool &IsDefault) const { // This is a dynamic symbol. Look in the GNU symbol version table. if (!SymbolVersionSection) { @@ -1081,55 +749,69 @@ Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym *Sym, assert(DynSymRegion && "DynSymRegion has not been initialised"); // Determine the position in the symbol table of this entry. - size_t EntryIndex = (reinterpret_cast<uintptr_t>(Sym) - + size_t EntryIndex = (reinterpret_cast<uintptr_t>(&Sym) - reinterpret_cast<uintptr_t>(DynSymRegion->Addr)) / sizeof(Elf_Sym); // Get the corresponding version index entry. - if (Expected<const Elf_Versym *> EntryOrErr = - ObjF->getELFFile()->template getEntry<Elf_Versym>( - SymbolVersionSection, EntryIndex)) - return this->getSymbolVersionByIndex((*EntryOrErr)->vs_index, IsDefault); - else + Expected<const Elf_Versym *> EntryOrErr = + Obj.template getEntry<Elf_Versym>(*SymbolVersionSection, EntryIndex); + if (!EntryOrErr) return EntryOrErr.takeError(); + + unsigned Version = (*EntryOrErr)->vs_index; + if (Version == VER_NDX_LOCAL || Version == VER_NDX_GLOBAL) { + IsDefault = false; + return ""; + } + + Expected<SmallVector<Optional<VersionEntry>, 0> *> MapOrErr = + getVersionMap(); + if (!MapOrErr) + return MapOrErr.takeError(); + + return Obj.getSymbolVersionByIndex(Version, IsDefault, **MapOrErr, + Sym.st_shndx == ELF::SHN_UNDEF); } template <typename ELFT> -Expected<std::pair<const typename ELFT::Sym *, std::string>> -ELFDumper<ELFT>::getRelocationTarget(const Elf_Shdr *SymTab, - const Elf_Rela &R) const { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - Expected<const Elf_Sym *> SymOrErr = Obj->getRelocationSymbol(&R, SymTab); +Expected<RelSymbol<ELFT>> +ELFDumper<ELFT>::getRelocationTarget(const Relocation<ELFT> &R, + const Elf_Shdr *SymTab) const { + if (R.Symbol == 0) + return RelSymbol<ELFT>(nullptr, ""); + + Expected<const Elf_Sym *> SymOrErr = + Obj.template getEntry<Elf_Sym>(*SymTab, R.Symbol); if (!SymOrErr) - return SymOrErr.takeError(); + return createError("unable to read an entry with index " + Twine(R.Symbol) + + " from " + describe(*SymTab) + ": " + + toString(SymOrErr.takeError())); const Elf_Sym *Sym = *SymOrErr; if (!Sym) - return std::make_pair(nullptr, ""); - - // The st_name field of a STT_SECTION is usually 0 (empty string). - // This code block returns the section name. - if (Sym->getType() == ELF::STT_SECTION) { - Expected<const Elf_Shdr *> SecOrErr = - Obj->getSection(Sym, SymTab, ShndxTable); - if (!SecOrErr) - return SecOrErr.takeError(); - // A section symbol describes the section at index 0. - if (*SecOrErr == nullptr) - return std::make_pair(Sym, ""); + return RelSymbol<ELFT>(nullptr, ""); - Expected<StringRef> NameOrErr = Obj->getSectionName(*SecOrErr); - if (!NameOrErr) - return NameOrErr.takeError(); - return std::make_pair(Sym, NameOrErr->str()); - } - - Expected<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*SymTab); + Expected<StringRef> StrTableOrErr = Obj.getStringTableForSymtab(*SymTab); if (!StrTableOrErr) return StrTableOrErr.takeError(); + const Elf_Sym *FirstSym = + cantFail(Obj.template getEntry<Elf_Sym>(*SymTab, 0)); std::string SymbolName = - getFullSymbolName(Sym, *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM); - return std::make_pair(Sym, SymbolName); + getFullSymbolName(*Sym, Sym - FirstSym, getShndxTable(SymTab), + *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM); + return RelSymbol<ELFT>(Sym, SymbolName); +} + +template <typename ELFT> +ArrayRef<typename ELFT::Word> +ELFDumper<ELFT>::getShndxTable(const Elf_Shdr *Symtab) const { + if (Symtab) { + auto It = ShndxTables.find(Symtab); + if (It != ShndxTables.end()) + return It->second; + } + return {}; } static std::string maybeDemangle(StringRef Name) { @@ -1139,19 +821,17 @@ static std::string maybeDemangle(StringRef Name) { template <typename ELFT> std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { auto Warn = [&](Error E) -> std::string { - this->reportUniqueWarning( - createError("unable to read the name of symbol with index " + - Twine(Index) + ": " + toString(std::move(E)))); + reportUniqueWarning("unable to read the name of symbol with index " + + Twine(Index) + ": " + toString(std::move(E))); return "<?>"; }; - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); Expected<const typename ELFT::Sym *> SymOrErr = - Obj->getSymbol(DotSymtabSec, Index); + Obj.getSymbol(DotSymtabSec, Index); if (!SymOrErr) return Warn(SymOrErr.takeError()); - Expected<StringRef> StrTabOrErr = Obj->getStringTableForSymtab(*DotSymtabSec); + Expected<StringRef> StrTabOrErr = Obj.getStringTableForSymtab(*DotSymtabSec); if (!StrTabOrErr) return Warn(StrTabOrErr.takeError()); @@ -1162,52 +842,25 @@ std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { } template <typename ELFT> -Expected<StringRef> -ELFDumper<ELFT>::getSymbolVersionByIndex(uint32_t SymbolVersionIndex, - bool &IsDefault) const { - size_t VersionIndex = SymbolVersionIndex & VERSYM_VERSION; - - // Special markers for unversioned symbols. - if (VersionIndex == VER_NDX_LOCAL || VersionIndex == VER_NDX_GLOBAL) { - IsDefault = false; - return ""; - } - - // Lookup this symbol in the version table. - if (Error E = LoadVersionMap()) - return std::move(E); - if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex]) - return createError("SHT_GNU_versym section refers to a version index " + - Twine(VersionIndex) + " which is missing"); - - const VersionEntry &Entry = *VersionMap[VersionIndex]; - if (Entry.IsVerDef) - IsDefault = !(SymbolVersionIndex & VERSYM_HIDDEN); - else - IsDefault = false; - return Entry.Name.c_str(); -} - -template <typename ELFT> -std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, +std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym &Symbol, + unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, Optional<StringRef> StrTable, bool IsDynamic) const { if (!StrTable) return "<?>"; std::string SymbolName; - if (Expected<StringRef> NameOrErr = Symbol->getName(*StrTable)) { + if (Expected<StringRef> NameOrErr = Symbol.getName(*StrTable)) { SymbolName = maybeDemangle(*NameOrErr); } else { reportUniqueWarning(NameOrErr.takeError()); return "<?>"; } - if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) { - Elf_Sym_Range Syms = unwrapOrError( - ObjF->getFileName(), ObjF->getELFFile()->symbols(DotSymtabSec)); + if (SymbolName.empty() && Symbol.getType() == ELF::STT_SECTION) { Expected<unsigned> SectionIndex = - getSymbolSectionIndex(Symbol, Syms.begin()); + getSymbolSectionIndex(Symbol, SymIndex, ShndxTable); if (!SectionIndex) { reportUniqueWarning(SectionIndex.takeError()); return "<?>"; @@ -1224,7 +877,7 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, return SymbolName; bool IsDefault; - Expected<StringRef> VersionOrErr = getSymbolVersion(&*Symbol, IsDefault); + Expected<StringRef> VersionOrErr = getSymbolVersion(Symbol, IsDefault); if (!VersionOrErr) { reportUniqueWarning(VersionOrErr.takeError()); return SymbolName + "@<corrupt>"; @@ -1239,59 +892,55 @@ std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, template <typename ELFT> Expected<unsigned> -ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym *Symbol, - const Elf_Sym *FirstSym) const { - return Symbol->st_shndx == SHN_XINDEX - ? object::getExtendedSymbolTableIndex<ELFT>(Symbol, FirstSym, - ShndxTable) - : Symbol->st_shndx; +ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable) const { + unsigned Ndx = Symbol.st_shndx; + if (Ndx == SHN_XINDEX) + return object::getExtendedSymbolTableIndex<ELFT>(Symbol, SymIndex, + ShndxTable); + if (Ndx != SHN_UNDEF && Ndx < SHN_LORESERVE) + return Ndx; + + auto CreateErr = [&](const Twine &Name, Optional<unsigned> Offset = None) { + std::string Desc; + if (Offset) + Desc = (Name + "+0x" + Twine::utohexstr(*Offset)).str(); + else + Desc = Name.str(); + return createError( + "unable to get section index for symbol with st_shndx = 0x" + + Twine::utohexstr(Ndx) + " (" + Desc + ")"); + }; + + if (Ndx >= ELF::SHN_LOPROC && Ndx <= ELF::SHN_HIPROC) + return CreateErr("SHN_LOPROC", Ndx - ELF::SHN_LOPROC); + if (Ndx >= ELF::SHN_LOOS && Ndx <= ELF::SHN_HIOS) + return CreateErr("SHN_LOOS", Ndx - ELF::SHN_LOOS); + if (Ndx == ELF::SHN_UNDEF) + return CreateErr("SHN_UNDEF"); + if (Ndx == ELF::SHN_ABS) + return CreateErr("SHN_ABS"); + if (Ndx == ELF::SHN_COMMON) + return CreateErr("SHN_COMMON"); + return CreateErr("SHN_LORESERVE", Ndx - SHN_LORESERVE); } -// If the Symbol has a reserved st_shndx other than SHN_XINDEX, return a -// descriptive interpretation of the st_shndx value. Otherwise, return the name -// of the section with index SectionIndex. This function assumes that if the -// Symbol has st_shndx == SHN_XINDEX the SectionIndex will be the value derived -// from the SHT_SYMTAB_SHNDX section. template <typename ELFT> Expected<StringRef> -ELFDumper<ELFT>::getSymbolSectionName(const Elf_Sym *Symbol, +ELFDumper<ELFT>::getSymbolSectionName(const Elf_Sym &Symbol, unsigned SectionIndex) const { - if (Symbol->isUndefined()) - return "Undefined"; - if (Symbol->isProcessorSpecific()) - return "Processor Specific"; - if (Symbol->isOSSpecific()) - return "Operating System Specific"; - if (Symbol->isAbsolute()) - return "Absolute"; - if (Symbol->isCommon()) - return "Common"; - if (Symbol->isReserved() && Symbol->st_shndx != SHN_XINDEX) - return "Reserved"; - - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - Expected<const Elf_Shdr *> SecOrErr = - Obj->getSection(SectionIndex); + Expected<const Elf_Shdr *> SecOrErr = Obj.getSection(SectionIndex); if (!SecOrErr) return SecOrErr.takeError(); - return Obj->getSectionName(*SecOrErr); + return Obj.getSectionName(**SecOrErr); } template <class ELFO> static const typename ELFO::Elf_Shdr * -findNotEmptySectionByAddress(const ELFO *Obj, StringRef FileName, +findNotEmptySectionByAddress(const ELFO &Obj, StringRef FileName, uint64_t Addr) { - for (const typename ELFO::Elf_Shdr &Shdr : cantFail(Obj->sections())) - if (Shdr.sh_addr == Addr && Shdr.sh_size > 0) - return &Shdr; - return nullptr; -} - -template <class ELFO> -static const typename ELFO::Elf_Shdr * -findSectionByName(const ELFO &Obj, StringRef FileName, StringRef Name) { for (const typename ELFO::Elf_Shdr &Shdr : cantFail(Obj.sections())) - if (Name == unwrapOrError(FileName, Obj.getSectionName(&Shdr))) + if (Shdr.sh_addr == Addr && Shdr.sh_size > 0) return &Shdr; return nullptr; } @@ -1337,11 +986,6 @@ 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}, @@ -1671,9 +1315,8 @@ static std::string getGNUFlags(unsigned EMachine, uint64_t Flags) { return Str; } -static const char *getElfSegmentType(unsigned Arch, unsigned Type) { - // Check potentially overlapped processor-specific - // program header type. +static StringRef segmentTypeToString(unsigned Arch, unsigned Type) { + // Check potentially overlapped processor-specific program header type. switch (Arch) { case ELF::EM_ARM: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); } @@ -1682,25 +1325,25 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) { case ELF::EM_MIPS_RS3_LE: switch (Type) { 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); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_RTPROC); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_ABIFLAGS); } break; } switch (Type) { - LLVM_READOBJ_ENUM_CASE(ELF, PT_NULL ); - LLVM_READOBJ_ENUM_CASE(ELF, PT_LOAD ); - LLVM_READOBJ_ENUM_CASE(ELF, PT_DYNAMIC); - LLVM_READOBJ_ENUM_CASE(ELF, PT_INTERP ); - LLVM_READOBJ_ENUM_CASE(ELF, PT_NOTE ); - LLVM_READOBJ_ENUM_CASE(ELF, PT_SHLIB ); - LLVM_READOBJ_ENUM_CASE(ELF, PT_PHDR ); - LLVM_READOBJ_ENUM_CASE(ELF, PT_TLS ); + LLVM_READOBJ_ENUM_CASE(ELF, PT_NULL); + LLVM_READOBJ_ENUM_CASE(ELF, PT_LOAD); + LLVM_READOBJ_ENUM_CASE(ELF, PT_DYNAMIC); + LLVM_READOBJ_ENUM_CASE(ELF, PT_INTERP); + LLVM_READOBJ_ENUM_CASE(ELF, PT_NOTE); + LLVM_READOBJ_ENUM_CASE(ELF, PT_SHLIB); + LLVM_READOBJ_ENUM_CASE(ELF, PT_PHDR); + LLVM_READOBJ_ENUM_CASE(ELF, PT_TLS); - LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_EH_FRAME); - LLVM_READOBJ_ENUM_CASE(ELF, PT_SUNW_UNWIND); + 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); @@ -1709,50 +1352,27 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) { 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 ""; } } -static std::string getElfPtType(unsigned Arch, unsigned Type) { - switch (Type) { - LLVM_READOBJ_PHDR_ENUM(ELF, PT_NULL) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_LOAD) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_DYNAMIC) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_INTERP) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_NOTE) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_SHLIB) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_PHDR) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_TLS) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_EH_FRAME) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_SUNW_UNWIND) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_STACK) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_RELRO) - LLVM_READOBJ_PHDR_ENUM(ELF, PT_GNU_PROPERTY) - default: - // All machine specific PT_* types - switch (Arch) { - case ELF::EM_ARM: - if (Type == ELF::PT_ARM_EXIDX) - return "EXIDX"; - break; - case ELF::EM_MIPS: - case ELF::EM_MIPS_RS3_LE: - switch (Type) { - case PT_MIPS_REGINFO: - return "REGINFO"; - case PT_MIPS_RTPROC: - return "RTPROC"; - case PT_MIPS_OPTIONS: - return "OPTIONS"; - case PT_MIPS_ABIFLAGS: - return "ABIFLAGS"; - } - break; - } - } - return std::string("<unknown>: ") + to_string(format_hex(Type, 1)); +static std::string getGNUPtType(unsigned Arch, unsigned Type) { + StringRef Seg = segmentTypeToString(Arch, Type); + if (Seg.empty()) + return std::string("<unknown>: ") + to_string(format_hex(Type, 1)); + + // E.g. "PT_ARM_EXIDX" -> "EXIDX". + if (Seg.startswith("PT_ARM_")) + return Seg.drop_front(7).str(); + + // E.g. "PT_MIPS_REGINFO" -> "REGINFO". + if (Seg.startswith("PT_MIPS_")) + return Seg.drop_front(8).str(); + + // E.g. "PT_LOAD" -> "LOAD". + assert(Seg.startswith("PT_")); + return Seg.drop_front(3).str(); } static const EnumEntry<unsigned> ElfSegmentFlags[] = { @@ -1827,14 +1447,17 @@ static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = { 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_GFX602), 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_GFX705), 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_GFX805), 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), @@ -1842,10 +1465,14 @@ static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = { 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_GFX90C), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1030), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1031), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1032), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1033), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_XNACK), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_SRAM_ECC) }; @@ -1871,6 +1498,10 @@ static const EnumEntry<unsigned> ElfMipsSymOtherFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_MICROMIPS) }; +static const EnumEntry<unsigned> ElfAArch64SymOtherFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, STO_AARCH64_VARIANT_PCS) +}; + static const EnumEntry<unsigned> ElfMips16SymOtherFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_OPTIONAL), LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_PLT), @@ -1898,10 +1529,10 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) { template <typename ELFT> std::pair<const typename ELFT::Phdr *, const typename ELFT::Shdr *> -ELFDumper<ELFT>::findDynamic(const ELFFile<ELFT> *Obj) { +ELFDumper<ELFT>::findDynamic() { // Try to locate the PT_DYNAMIC header. const Elf_Phdr *DynamicPhdr = nullptr; - if (Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers()) { + if (Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj.program_headers()) { for (const Elf_Phdr &Phdr : *PhdrsOrErr) { if (Phdr.p_type != ELF::PT_DYNAMIC) continue; @@ -1909,85 +1540,89 @@ ELFDumper<ELFT>::findDynamic(const ELFFile<ELFT> *Obj) { break; } } else { - this->reportUniqueWarning(createError( + reportUniqueWarning( "unable to read program headers to locate the PT_DYNAMIC segment: " + - toString(PhdrsOrErr.takeError()))); + toString(PhdrsOrErr.takeError())); } // Try to locate the .dynamic section in the sections header table. const Elf_Shdr *DynamicSec = nullptr; - for (const Elf_Shdr &Sec : cantFail(Obj->sections())) { + for (const Elf_Shdr &Sec : cantFail(Obj.sections())) { if (Sec.sh_type != ELF::SHT_DYNAMIC) continue; DynamicSec = &Sec; break; } - if (DynamicPhdr && DynamicPhdr->p_offset + DynamicPhdr->p_filesz > - ObjF->getMemoryBufferRef().getBufferSize()) { - reportWarning( - createError( - "PT_DYNAMIC segment offset + size exceeds the size of the file"), - ObjF->getFileName()); + if (DynamicPhdr && ((DynamicPhdr->p_offset + DynamicPhdr->p_filesz > + ObjF.getMemoryBufferRef().getBufferSize()) || + (DynamicPhdr->p_offset + DynamicPhdr->p_filesz < + DynamicPhdr->p_offset))) { + reportUniqueWarning( + "PT_DYNAMIC segment offset (0x" + + Twine::utohexstr(DynamicPhdr->p_offset) + ") + file size (0x" + + Twine::utohexstr(DynamicPhdr->p_filesz) + + ") exceeds the size of the file (0x" + + Twine::utohexstr(ObjF.getMemoryBufferRef().getBufferSize()) + ")"); // Don't use the broken dynamic header. DynamicPhdr = nullptr; } if (DynamicPhdr && DynamicSec) { - StringRef Name = - unwrapOrError(ObjF->getFileName(), Obj->getSectionName(DynamicSec)); if (DynamicSec->sh_addr + DynamicSec->sh_size > DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || DynamicSec->sh_addr < DynamicPhdr->p_vaddr) - reportWarning(createError("The SHT_DYNAMIC section '" + Name + - "' is not contained within the " - "PT_DYNAMIC segment"), - ObjF->getFileName()); + reportUniqueWarning(describe(*DynamicSec) + + " is not contained within the " + "PT_DYNAMIC segment"); if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr) - reportWarning(createError("The SHT_DYNAMIC section '" + Name + - "' is not at the start of " - "PT_DYNAMIC segment"), - ObjF->getFileName()); + reportUniqueWarning(describe(*DynamicSec) + " is not at the start of " + "PT_DYNAMIC segment"); } return std::make_pair(DynamicPhdr, DynamicSec); } template <typename ELFT> -void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { +void ELFDumper<ELFT>::loadDynamicTable() { const Elf_Phdr *DynamicPhdr; const Elf_Shdr *DynamicSec; - std::tie(DynamicPhdr, DynamicSec) = findDynamic(Obj); + std::tie(DynamicPhdr, DynamicSec) = findDynamic(); if (!DynamicPhdr && !DynamicSec) return; - DynRegionInfo FromPhdr(ObjF->getFileName()); + DynRegionInfo FromPhdr(ObjF, *this); bool IsPhdrTableValid = false; if (DynamicPhdr) { - FromPhdr = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn)); + // Use cantFail(), because p_offset/p_filesz fields of a PT_DYNAMIC are + // validated in findDynamic() and so createDRI() is not expected to fail. + FromPhdr = cantFail(createDRI(DynamicPhdr->p_offset, DynamicPhdr->p_filesz, + sizeof(Elf_Dyn))); FromPhdr.SizePrintName = "PT_DYNAMIC size"; FromPhdr.EntSizePrintName = ""; - - IsPhdrTableValid = !FromPhdr.getAsArrayRef<Elf_Dyn>().empty(); + IsPhdrTableValid = !FromPhdr.template getAsArrayRef<Elf_Dyn>().empty(); } // Locate the dynamic table described in a section header. // Ignore sh_entsize and use the expected value for entry size explicitly. // This allows us to dump dynamic sections with a broken sh_entsize // field. - DynRegionInfo FromSec(ObjF->getFileName()); + DynRegionInfo FromSec(ObjF, *this); bool IsSecTableValid = false; if (DynamicSec) { - FromSec = - checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset, - DynamicSec->sh_size, sizeof(Elf_Dyn), ObjF->getFileName()}); - FromSec.Context = ("section with index " + - Twine(DynamicSec - &cantFail(Obj->sections()).front())) - .str(); - FromSec.EntSizePrintName = ""; - - IsSecTableValid = !FromSec.getAsArrayRef<Elf_Dyn>().empty(); + Expected<DynRegionInfo> RegOrErr = + createDRI(DynamicSec->sh_offset, DynamicSec->sh_size, sizeof(Elf_Dyn)); + if (RegOrErr) { + FromSec = *RegOrErr; + FromSec.Context = describe(*DynamicSec); + FromSec.EntSizePrintName = ""; + IsSecTableValid = !FromSec.template getAsArrayRef<Elf_Dyn>().empty(); + } else { + reportUniqueWarning("unable to read the dynamic table from " + + describe(*DynamicSec) + ": " + + toString(RegOrErr.takeError())); + } } // When we only have information from one of the SHT_DYNAMIC section header or @@ -1995,10 +1630,9 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { if (!DynamicPhdr || !DynamicSec) { if ((DynamicPhdr && IsPhdrTableValid) || (DynamicSec && IsSecTableValid)) { DynamicTable = DynamicPhdr ? FromPhdr : FromSec; - parseDynamicTable(Obj); + parseDynamicTable(); } else { - reportWarning(createError("no valid dynamic table was found"), - ObjF->getFileName()); + reportUniqueWarning("no valid dynamic table was found"); } return; } @@ -2008,58 +1642,43 @@ void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { // verify that. if (FromPhdr.Addr != FromSec.Addr) - reportWarning(createError("SHT_DYNAMIC section header and PT_DYNAMIC " - "program header disagree about " - "the location of the dynamic table"), - ObjF->getFileName()); + reportUniqueWarning("SHT_DYNAMIC section header and PT_DYNAMIC " + "program header disagree about " + "the location of the dynamic table"); if (!IsPhdrTableValid && !IsSecTableValid) { - reportWarning(createError("no valid dynamic table was found"), - ObjF->getFileName()); + reportUniqueWarning("no valid dynamic table was found"); return; } - // Information in the PT_DYNAMIC program header has priority over the information - // in a section header. + // Information in the PT_DYNAMIC program header has priority over the + // information in a section header. if (IsPhdrTableValid) { if (!IsSecTableValid) - reportWarning( - createError( - "SHT_DYNAMIC dynamic table is invalid: PT_DYNAMIC will be used"), - ObjF->getFileName()); + reportUniqueWarning( + "SHT_DYNAMIC dynamic table is invalid: PT_DYNAMIC will be used"); DynamicTable = FromPhdr; } else { - reportWarning( - createError( - "PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used"), - ObjF->getFileName()); + reportUniqueWarning( + "PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used"); DynamicTable = FromSec; } - parseDynamicTable(Obj); + parseDynamicTable(); } template <typename ELFT> -ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, +ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O, ScopedPrinter &Writer) - : ObjDumper(Writer), ObjF(ObjF), DynRelRegion(ObjF->getFileName()), - DynRelaRegion(ObjF->getFileName()), DynRelrRegion(ObjF->getFileName()), - DynPLTRelRegion(ObjF->getFileName()), DynamicTable(ObjF->getFileName()) { - // Dumper reports all non-critical errors as warnings. - // It does not print the same warning more than once. - WarningHandler = [this](const Twine &Msg) { - if (Warnings.insert(Msg.str()).second) - reportWarning(createError(Msg), this->ObjF->getFileName()); - return Error::success(); - }; - - if (opts::Output == opts::GNU) - ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this)); - else - ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this)); + : ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()), + FileName(O.getFileName()), DynRelRegion(O, *this), + DynRelaRegion(O, *this), DynRelrRegion(O, *this), + DynPLTRelRegion(O, *this), DynSymTabShndxRegion(O, *this), + DynamicTable(O, *this) { + if (!O.IsContentValid()) + return; - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - typename ELFT::ShdrRange Sections = cantFail(Obj->sections()); + typename ELFT::ShdrRange Sections = cantFail(Obj.sections()); for (const Elf_Shdr &Sec : Sections) { switch (Sec.sh_type) { case ELF::SHT_SYMTAB: @@ -2067,24 +1686,51 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, DotSymtabSec = &Sec; break; case ELF::SHT_DYNSYM: + if (!DotDynsymSec) + DotDynsymSec = &Sec; + if (!DynSymRegion) { - DynSymRegion = createDRIFrom(&Sec); - DynSymRegion->Context = - ("section with index " + Twine(&Sec - &Sections.front())).str(); - // This is only used (if Elf_Shdr present)for naming section in GNU - // style - DynSymtabName = - unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec)); + Expected<DynRegionInfo> RegOrErr = + createDRI(Sec.sh_offset, Sec.sh_size, Sec.sh_entsize); + if (RegOrErr) { + DynSymRegion = *RegOrErr; + DynSymRegion->Context = describe(Sec); - if (Expected<StringRef> E = Obj->getStringTableForSymtab(Sec)) - DynamicStringTable = *E; - else - reportWarning(E.takeError(), ObjF->getFileName()); + if (Expected<StringRef> E = Obj.getStringTableForSymtab(Sec)) + DynamicStringTable = *E; + else + reportUniqueWarning("unable to get the string table for the " + + describe(Sec) + ": " + toString(E.takeError())); + } else { + reportUniqueWarning("unable to read dynamic symbols from " + + describe(Sec) + ": " + + toString(RegOrErr.takeError())); + } } break; - case ELF::SHT_SYMTAB_SHNDX: - ShndxTable = unwrapOrError(ObjF->getFileName(), Obj->getSHNDXTable(Sec)); + case ELF::SHT_SYMTAB_SHNDX: { + uint32_t SymtabNdx = Sec.sh_link; + if (SymtabNdx >= Sections.size()) { + reportUniqueWarning( + "unable to get the associated symbol table for " + describe(Sec) + + ": sh_link (" + Twine(SymtabNdx) + + ") is greater than or equal to the total number of sections (" + + Twine(Sections.size()) + ")"); + continue; + } + + if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr = + Obj.getSHNDXTable(Sec)) { + if (!ShndxTables.insert({&Sections[SymtabNdx], *ShndxTableOrErr}) + .second) + reportUniqueWarning( + "multiple SHT_SYMTAB_SHNDX sections are linked to " + + describe(Sec)); + } else { + reportUniqueWarning(ShndxTableOrErr.takeError()); + } break; + } case ELF::SHT_GNU_versym: if (!SymbolVersionSection) SymbolVersionSection = &Sec; @@ -2108,25 +1754,24 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, } } - loadDynamicTable(Obj); + loadDynamicTable(); } -template <typename ELFT> -void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) { +template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * { - auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr); + auto MappedAddrOrError = Obj.toMappedAddr(VAddr, [&](const Twine &Msg) { + this->reportUniqueWarning(Msg); + return Error::success(); + }); if (!MappedAddrOrError) { - Error Err = - createError("Unable to parse DT_" + Obj->getDynamicTagAsString(Tag) + - ": " + llvm::toString(MappedAddrOrError.takeError())); - - reportWarning(std::move(Err), ObjF->getFileName()); + this->reportUniqueWarning("unable to parse DT_" + + Obj.getDynamicTagAsString(Tag) + ": " + + llvm::toString(MappedAddrOrError.takeError())); return nullptr; } return MappedAddrOrError.get(); }; - uint64_t SONameOffset = 0; const char *StringTableBegin = nullptr; uint64_t StringTableSize = 0; Optional<DynRegionInfo> DynSymFromTable; @@ -2151,7 +1796,7 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) { // If we can't map the DT_SYMTAB value to an address (e.g. when there are // no program headers), we ignore its value. if (const uint8_t *VA = toMappedAddr(Dyn.getTag(), Dyn.getPtr())) { - DynSymFromTable.emplace(ObjF->getFileName()); + DynSymFromTable.emplace(ObjF, *this); DynSymFromTable->Addr = VA; DynSymFromTable->EntSize = sizeof(Elf_Sym); DynSymFromTable->EntSizePrintName = ""; @@ -2161,11 +1806,10 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) { case ELF::DT_SYMENT: { uint64_t Val = Dyn.getVal(); if (Val != sizeof(Elf_Sym)) - reportWarning(createError("DT_SYMENT value of 0x" + + this->reportUniqueWarning("DT_SYMENT value of 0x" + Twine::utohexstr(Val) + " is not the size of a symbol (0x" + - Twine::utohexstr(sizeof(Elf_Sym)) + ")"), - ObjF->getFileName()); + Twine::utohexstr(sizeof(Elf_Sym)) + ")"); break; } case ELF::DT_RELA: @@ -2217,10 +1861,9 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) { else if (Dyn.getVal() == DT_RELA) DynPLTRelRegion.EntSize = sizeof(Elf_Rela); else - reportError(createError(Twine("unknown DT_PLTREL value of ") + - Twine((uint64_t)Dyn.getVal())), - ObjF->getFileName()); - DynPLTRelRegion.EntSizePrintName = ""; + reportUniqueWarning(Twine("unknown DT_PLTREL value of ") + + Twine((uint64_t)Dyn.getVal())); + DynPLTRelRegion.EntSizePrintName = "PLTREL entry size"; break; case ELF::DT_JMPREL: DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); @@ -2229,24 +1872,26 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) { DynPLTRelRegion.Size = Dyn.getVal(); DynPLTRelRegion.SizePrintName = "DT_PLTRELSZ value"; break; + case ELF::DT_SYMTAB_SHNDX: + DynSymTabShndxRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); + DynSymTabShndxRegion.EntSize = sizeof(Elf_Word); + break; } } if (StringTableBegin) { - const uint64_t FileSize = ObjF->getELFFile()->getBufSize(); - const uint64_t Offset = - (const uint8_t *)StringTableBegin - ObjF->getELFFile()->base(); + const uint64_t FileSize = Obj.getBufSize(); + const uint64_t Offset = (const uint8_t *)StringTableBegin - Obj.base(); if (StringTableSize > FileSize - Offset) - reportUniqueWarning(createError( + reportUniqueWarning( "the dynamic string table at 0x" + Twine::utohexstr(Offset) + " goes past the end of the file (0x" + Twine::utohexstr(FileSize) + - ") with DT_STRSZ = 0x" + Twine::utohexstr(StringTableSize))); + ") with DT_STRSZ = 0x" + Twine::utohexstr(StringTableSize)); else DynamicStringTable = StringRef(StringTableBegin, StringTableSize); } - SOName = getDynamicString(SONameOffset); - + const bool IsHashTableSupported = getHashTableEntSize() == 4; if (DynSymRegion) { // Often we find the information about the dynamic symbol table // location in the SHT_DYNSYM section header. However, the value in @@ -2262,16 +1907,15 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) { // equal nchain". Check to see if the DT_HASH hash table nchain value // conflicts with the number of symbols in the dynamic symbol table // according to the section header. - if (HashTable) { + if (HashTable && IsHashTableSupported) { if (DynSymRegion->EntSize == 0) - reportUniqueWarning( - createError("SHT_DYNSYM section has sh_entsize == 0")); + reportUniqueWarning("SHT_DYNSYM section has sh_entsize == 0"); else if (HashTable->nchain != DynSymRegion->Size / DynSymRegion->EntSize) - reportUniqueWarning(createError( + reportUniqueWarning( "hash table nchain (" + Twine(HashTable->nchain) + ") differs from symbol count derived from SHT_DYNSYM section " "header (" + - Twine(DynSymRegion->Size / DynSymRegion->EntSize) + ")")); + Twine(DynSymRegion->Size / DynSymRegion->EntSize) + ")"); } } @@ -2290,95 +1934,31 @@ void ELFDumper<ELFT>::parseDynamicTable(const ELFFile<ELFT> *Obj) { // Derive the dynamic symbol table size from the DT_HASH hash table, if // present. - if (HashTable && DynSymRegion) - DynSymRegion->Size = HashTable->nchain * DynSymRegion->EntSize; -} - -template <typename ELFT> -typename ELFDumper<ELFT>::Elf_Rel_Range ELFDumper<ELFT>::dyn_rels() const { - return DynRelRegion.getAsArrayRef<Elf_Rel>(); -} - -template <typename ELFT> -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(ObjF->getELFFile()); -} - -template <class ELFT> void ELFDumper<ELFT>::printSectionHeaders() { - ELFDumperStyle->printSectionHeaders(ObjF->getELFFile()); -} - -template <class ELFT> void ELFDumper<ELFT>::printRelocations() { - ELFDumperStyle->printRelocations(ObjF->getELFFile()); -} - -template <class ELFT> -void ELFDumper<ELFT>::printProgramHeaders( - bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) { - ELFDumperStyle->printProgramHeaders(ObjF->getELFFile(), PrintProgramHeaders, - PrintSectionMapping); + if (HashTable && IsHashTableSupported && DynSymRegion) { + const uint64_t FileSize = Obj.getBufSize(); + const uint64_t DerivedSize = + (uint64_t)HashTable->nchain * DynSymRegion->EntSize; + const uint64_t Offset = (const uint8_t *)DynSymRegion->Addr - Obj.base(); + if (DerivedSize > FileSize - Offset) + reportUniqueWarning( + "the size (0x" + Twine::utohexstr(DerivedSize) + + ") of the dynamic symbol table at 0x" + Twine::utohexstr(Offset) + + ", derived from the hash table, goes past the end of the file (0x" + + Twine::utohexstr(FileSize) + ") and will be ignored"); + else + DynSymRegion->Size = HashTable->nchain * DynSymRegion->EntSize; + } } template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() { // Dump version symbol section. - ELFDumperStyle->printVersionSymbolSection(ObjF->getELFFile(), - SymbolVersionSection); + printVersionSymbolSection(SymbolVersionSection); // Dump version definition section. - ELFDumperStyle->printVersionDefinitionSection(ObjF->getELFFile(), - SymbolVersionDefSection); + printVersionDefinitionSection(SymbolVersionDefSection); // Dump version dependency section. - ELFDumperStyle->printVersionDependencySection(ObjF->getELFFile(), - SymbolVersionNeedSection); -} - -template <class ELFT> void ELFDumper<ELFT>::printDependentLibs() { - ELFDumperStyle->printDependentLibs(ObjF->getELFFile()); -} - -template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() { - ELFDumperStyle->printDynamicRelocations(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>::printHashSymbols() { - ELFDumperStyle->printHashSymbols(ObjF->getELFFile()); -} - -template <class ELFT> void ELFDumper<ELFT>::printHashHistograms() { - ELFDumperStyle->printHashHistograms(ObjF->getELFFile()); -} - -template <class ELFT> void ELFDumper<ELFT>::printCGProfile() { - ELFDumperStyle->printCGProfile(ObjF->getELFFile()); -} - -template <class ELFT> void ELFDumper<ELFT>::printNotes() { - ELFDumperStyle->printNotes(ObjF->getELFFile()); -} - -template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() { - ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile()); -} - -template <class ELFT> void ELFDumper<ELFT>::printStackSizes() { - ELFDumperStyle->printStackSizes(ObjF); + printVersionDependencySection(SymbolVersionNeedSection); } #define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ @@ -2445,21 +2025,28 @@ static const EnumEntry<unsigned> ElfDynamicDTMipsFlags[] = { template <typename T, typename TFlag> void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) { - using FlagEntry = EnumEntry<TFlag>; - using FlagVector = SmallVector<FlagEntry, 10>; - FlagVector SetFlags; - - for (const auto &Flag : Flags) { - if (Flag.Value == 0) - continue; - - if ((Value & Flag.Value) == Flag.Value) + SmallVector<EnumEntry<TFlag>, 10> SetFlags; + for (const EnumEntry<TFlag> &Flag : Flags) + if (Flag.Value != 0 && (Value & Flag.Value) == Flag.Value) SetFlags.push_back(Flag); - } - for (const auto &Flag : SetFlags) { + for (const EnumEntry<TFlag> &Flag : SetFlags) OS << Flag.Name << " "; +} + +template <class ELFT> +const typename ELFT::Shdr * +ELFDumper<ELFT>::findSectionByName(StringRef Name) const { + for (const Elf_Shdr &Shdr : cantFail(Obj.sections())) { + if (Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr)) { + if (*NameOrErr == Name) + return &Shdr; + } else { + reportUniqueWarning("unable to read the name of " + describe(Shdr) + + ": " + toString(NameOrErr.takeError())); + } } + return nullptr; } template <class ELFT> @@ -2483,11 +2070,12 @@ std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type, }; // Handle custom printing of architecture specific tags - switch (ObjF->getELFFile()->getHeader()->e_machine) { + switch (Obj.getHeader().e_machine) { case EM_AARCH64: switch (Type) { case DT_AARCH64_BTI_PLT: case DT_AARCH64_PAC_PLT: + case DT_AARCH64_VARIANT_PCS: return std::to_string(Value); default: break; @@ -2635,19 +2223,19 @@ std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type, template <class ELFT> StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const { if (DynamicStringTable.empty() && !DynamicStringTable.data()) { - reportUniqueWarning(createError("string table was not found")); + reportUniqueWarning("string table was not found"); return "<?>"; } auto WarnAndReturn = [this](const Twine &Msg, uint64_t Offset) { - reportUniqueWarning(createError("string table at offset 0x" + - Twine::utohexstr(Offset) + Msg)); + reportUniqueWarning("string table at offset 0x" + Twine::utohexstr(Offset) + + Msg); return "<?>"; }; - const uint64_t FileSize = ObjF->getELFFile()->getBufSize(); + const uint64_t FileSize = Obj.getBufSize(); const uint64_t Offset = - (const uint8_t *)DynamicStringTable.data() - ObjF->getELFFile()->base(); + (const uint8_t *)DynamicStringTable.data() - Obj.base(); if (DynamicStringTable.size() > FileSize - Offset) return WarnAndReturn(" with size 0x" + Twine::utohexstr(DynamicStringTable.size()) + @@ -2676,25 +2264,18 @@ template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() { Ctx.printUnwindInformation(); } +// The namespace is needed to fix the compilation with GCC older than 7.0+. namespace { - template <> void ELFDumper<ELF32LE>::printUnwindInfo() { - const ELFFile<ELF32LE> *Obj = ObjF->getELFFile(); - const unsigned Machine = Obj->getHeader()->e_machine; - if (Machine == EM_ARM) { - ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, ObjF->getFileName(), + if (Obj.getHeader().e_machine == EM_ARM) { + ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, ObjF.getFileName(), DotSymtabSec); Ctx.PrintUnwindInformation(); } DwarfCFIEH::PrinterContext<ELF32LE> Ctx(W, ObjF); Ctx.printUnwindInformation(); } - -} // end anonymous namespace - -template <class ELFT> void ELFDumper<ELFT>::printDynamicTable() { - ELFDumperStyle->printDynamic(ObjF->getELFFile()); -} +} // namespace template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() { ListScope D(W, "NeededLibraries"); @@ -2711,47 +2292,60 @@ template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() { } template <class ELFT> -static Error checkHashTable(const ELFFile<ELFT> *Obj, +static Error checkHashTable(const ELFDumper<ELFT> &Dumper, const typename ELFT::Hash *H, bool *IsHeaderValid = nullptr) { - auto MakeError = [&](uint64_t Off, const Twine &Msg = "") { - return createError("the hash table at offset 0x" + Twine::utohexstr(Off) + + const ELFFile<ELFT> &Obj = Dumper.getElfObject().getELFFile(); + const uint64_t SecOffset = (const uint8_t *)H - Obj.base(); + if (Dumper.getHashTableEntSize() == 8) { + auto It = llvm::find_if(ElfMachineType, [&](const EnumEntry<unsigned> &E) { + return E.Value == Obj.getHeader().e_machine; + }); + if (IsHeaderValid) + *IsHeaderValid = false; + return createError("the hash table at 0x" + Twine::utohexstr(SecOffset) + + " is not supported: it contains non-standard 8 " + "byte entries on " + + It->AltName + " platform"); + } + + auto MakeError = [&](const Twine &Msg = "") { + return createError("the hash table at offset 0x" + + Twine::utohexstr(SecOffset) + " goes past the end of the file (0x" + - Twine::utohexstr(Obj->getBufSize()) + ")" + Msg); + Twine::utohexstr(Obj.getBufSize()) + ")" + Msg); }; // Each SHT_HASH section starts from two 32-bit fields: nbucket and nchain. const unsigned HeaderSize = 2 * sizeof(typename ELFT::Word); - const uint64_t SecOffset = (const uint8_t *)H - Obj->base(); if (IsHeaderValid) - *IsHeaderValid = Obj->getBufSize() - SecOffset >= HeaderSize; + *IsHeaderValid = Obj.getBufSize() - SecOffset >= HeaderSize; - if (Obj->getBufSize() - SecOffset < HeaderSize) - return MakeError(SecOffset); + if (Obj.getBufSize() - SecOffset < HeaderSize) + return MakeError(); - if (Obj->getBufSize() - SecOffset - HeaderSize < + if (Obj.getBufSize() - SecOffset - HeaderSize < ((uint64_t)H->nbucket + H->nchain) * sizeof(typename ELFT::Word)) - return MakeError(SecOffset, ", nbucket = " + Twine(H->nbucket) + - ", nchain = " + Twine(H->nchain)); + return MakeError(", nbucket = " + Twine(H->nbucket) + + ", nchain = " + Twine(H->nchain)); return Error::success(); } template <class ELFT> -static Error checkGNUHashTable(const ELFFile<ELFT> *Obj, +static Error checkGNUHashTable(const ELFFile<ELFT> &Obj, const typename ELFT::GnuHash *GnuHashTable, bool *IsHeaderValid = nullptr) { const uint8_t *TableData = reinterpret_cast<const uint8_t *>(GnuHashTable); - assert(TableData >= Obj->base() && - TableData < Obj->base() + Obj->getBufSize() && + assert(TableData >= Obj.base() && TableData < Obj.base() + Obj.getBufSize() && "GnuHashTable must always point to a location inside the file"); - uint64_t TableOffset = TableData - Obj->base(); + uint64_t TableOffset = TableData - Obj.base(); if (IsHeaderValid) - *IsHeaderValid = TableOffset + /*Header size:*/ 16 < Obj->getBufSize(); + *IsHeaderValid = TableOffset + /*Header size:*/ 16 < Obj.getBufSize(); if (TableOffset + 16 + (uint64_t)GnuHashTable->nbuckets * 4 + (uint64_t)GnuHashTable->maskwords * sizeof(typename ELFT::Off) >= - Obj->getBufSize()) + Obj.getBufSize()) return createError("unable to dump the SHT_GNU_HASH " "section at 0x" + Twine::utohexstr(TableOffset) + @@ -2765,7 +2359,7 @@ template <typename ELFT> void ELFDumper<ELFT>::printHashTable() { return; bool IsHeaderValid; - Error Err = checkHashTable(ObjF->getELFFile(), HashTable, &IsHeaderValid); + Error Err = checkHashTable(*this, HashTable, &IsHeaderValid); if (IsHeaderValid) { W.printNumber("Num Buckets", HashTable->nbucket); W.printNumber("Num Chains", HashTable->nchain); @@ -2788,7 +2382,7 @@ getGnuHashTableChains(Optional<DynRegionInfo> DynSymRegion, return createError("no dynamic symbol table found"); ArrayRef<typename ELFT::Sym> DynSymTable = - DynSymRegion->getAsArrayRef<typename ELFT::Sym>(); + DynSymRegion->template getAsArrayRef<typename ELFT::Sym>(); size_t NumSyms = DynSymTable.size(); if (!NumSyms) return createError("the dynamic symbol table is empty"); @@ -2805,24 +2399,23 @@ getGnuHashTableChains(Optional<DynRegionInfo> DynSymRegion, // is irrelevant and we should not report a warning. ArrayRef<typename ELFT::Word> Buckets = GnuHashTable->buckets(); if (!llvm::all_of(Buckets, [](typename ELFT::Word V) { return V == 0; })) - return createError("the first hashed symbol index (" + - Twine(GnuHashTable->symndx) + - ") is larger than the number of dynamic symbols (" + - Twine(NumSyms) + ")"); + return createError( + "the first hashed symbol index (" + Twine(GnuHashTable->symndx) + + ") is greater than or equal to the number of dynamic symbols (" + + Twine(NumSyms) + ")"); // There is no way to represent an array of (dynamic symbols count - symndx) // length. return ArrayRef<typename ELFT::Word>(); } template <typename ELFT> -void ELFDumper<ELFT>::printGnuHashTable(const object::ObjectFile *Obj) { +void ELFDumper<ELFT>::printGnuHashTable() { DictScope D(W, "GnuHashTable"); if (!GnuHashTable) return; bool IsHeaderValid; - Error Err = - checkGNUHashTable<ELFT>(ObjF->getELFFile(), GnuHashTable, &IsHeaderValid); + Error Err = checkGNUHashTable<ELFT>(Obj, GnuHashTable, &IsHeaderValid); if (IsHeaderValid) { W.printNumber("Num Buckets", GnuHashTable->nbuckets); W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx); @@ -2844,10 +2437,9 @@ void ELFDumper<ELFT>::printGnuHashTable(const object::ObjectFile *Obj) { Expected<ArrayRef<Elf_Word>> Chains = getGnuHashTableChains<ELFT>(DynSymRegion, GnuHashTable); if (!Chains) { - reportUniqueWarning( - createError("unable to dump 'Values' for the SHT_GNU_HASH " - "section: " + - toString(Chains.takeError()))); + reportUniqueWarning("unable to dump 'Values' for the SHT_GNU_HASH " + "section: " + + toString(Chains.takeError())); return; } @@ -2855,32 +2447,32 @@ void ELFDumper<ELFT>::printGnuHashTable(const object::ObjectFile *Obj) { } template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { + StringRef SOName = "<Not found>"; + if (SONameOffset) + SOName = getDynamicString(*SONameOffset); W.printString("LoadName", SOName); } template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - switch (Obj->getHeader()->e_machine) { + switch (Obj.getHeader().e_machine) { case EM_ARM: case EM_RISCV: printAttributes(); break; case EM_MIPS: { - ELFDumperStyle->printMipsABIFlags(ObjF); + printMipsABIFlags(); printMipsOptions(); printMipsReginfo(); - - MipsGOTParser<ELFT> Parser(Obj, ObjF->getFileName(), dynamic_table(), - dynamic_symbols()); + MipsGOTParser<ELFT> Parser(*this); if (Error E = Parser.findGOT(dynamic_table(), dynamic_symbols())) - reportError(std::move(E), ObjF->getFileName()); + reportUniqueWarning(std::move(E)); else if (!Parser.isGotEmpty()) - ELFDumperStyle->printMipsGOT(Parser); + printMipsGOT(Parser); if (Error E = Parser.findPLT(dynamic_table())) - reportError(std::move(E), ObjF->getFileName()); + reportUniqueWarning(std::move(E)); else if (!Parser.isPltEmpty()) - ELFDumperStyle->printMipsPLT(Parser); + printMipsPLT(Parser); break; } default: @@ -2888,59 +2480,63 @@ template <class ELFT> void ELFDumper<ELFT>::printArchSpecificInfo() { } } -namespace { - template <class ELFT> void ELFDumper<ELFT>::printAttributes() { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - if (!Obj->isLE()) { + if (!Obj.isLE()) { W.startLine() << "Attributes not implemented.\n"; return; } - const unsigned Machine = Obj->getHeader()->e_machine; + const unsigned Machine = Obj.getHeader().e_machine; assert((Machine == EM_ARM || Machine == EM_RISCV) && "Attributes not implemented."); DictScope BA(W, "BuildAttributes"); - for (const Elf_Shdr &Sec : cantFail(Obj->sections())) { + for (const Elf_Shdr &Sec : cantFail(Obj.sections())) { if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES && Sec.sh_type != ELF::SHT_RISCV_ATTRIBUTES) continue; - ArrayRef<uint8_t> Contents = - unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(&Sec)); - if (Contents[0] != ELFAttrs::Format_Version) { - reportWarning(createError(Twine("unrecognised FormatVersion: 0x") + - Twine::utohexstr(Contents[0])), - ObjF->getFileName()); + ArrayRef<uint8_t> Contents; + if (Expected<ArrayRef<uint8_t>> ContentOrErr = + Obj.getSectionContents(Sec)) { + Contents = *ContentOrErr; + if (Contents.empty()) { + reportUniqueWarning("the " + describe(Sec) + " is empty"); + continue; + } + } else { + reportUniqueWarning("unable to read the content of the " + describe(Sec) + + ": " + toString(ContentOrErr.takeError())); continue; } + W.printHex("FormatVersion", Contents[0]); - if (Contents.size() == 1) - continue; - // TODO: Delete the redundant FormatVersion check above. - if (Machine == EM_ARM) { - if (Error E = ARMAttributeParser(&W).parse(Contents, support::little)) - reportWarning(std::move(E), ObjF->getFileName()); - } else if (Machine == EM_RISCV) { - if (Error E = RISCVAttributeParser(&W).parse(Contents, support::little)) - reportWarning(std::move(E), ObjF->getFileName()); - } + auto ParseAttrubutes = [&]() { + if (Machine == EM_ARM) + return ARMAttributeParser(&W).parse(Contents, support::little); + return RISCVAttributeParser(&W).parse(Contents, support::little); + }; + + if (Error E = ParseAttrubutes()) + reportUniqueWarning("unable to dump attributes from the " + + describe(Sec) + ": " + toString(std::move(E))); } } +namespace { + template <class ELFT> class MipsGOTParser { public: - TYPEDEF_ELF_TYPES(ELFT) - using Entry = typename ELFO::Elf_Addr; + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + using Entry = typename ELFT::Addr; using Entries = ArrayRef<Entry>; const bool IsStatic; - const ELFO * const Obj; + const ELFFile<ELFT> &Obj; + const ELFDumper<ELFT> &Dumper; - MipsGOTParser(const ELFO *Obj, StringRef FileName, Elf_Dyn_Range DynTable, - Elf_Sym_Range DynSyms); + MipsGOTParser(const ELFDumper<ELFT> &D); Error findGOT(Elf_Dyn_Range DynTable, Elf_Sym_Range DynSyms); Error findPLT(Elf_Dyn_Range DynTable); @@ -2967,6 +2563,7 @@ public: const Elf_Sym *getPltSym(const Entry *E) const; StringRef getPltStrTable() const { return PltStrTable; } + const Elf_Shdr *getPltSymTable() const { return PltSymTable; } private: const Elf_Shdr *GotSec; @@ -2988,12 +2585,11 @@ private: } // end anonymous namespace template <class ELFT> -MipsGOTParser<ELFT>::MipsGOTParser(const ELFO *Obj, StringRef FileName, - Elf_Dyn_Range DynTable, - Elf_Sym_Range DynSyms) - : IsStatic(DynTable.empty()), Obj(Obj), GotSec(nullptr), LocalNum(0), - GlobalNum(0), PltSec(nullptr), PltRelSec(nullptr), PltSymTable(nullptr), - FileName(FileName) {} +MipsGOTParser<ELFT>::MipsGOTParser(const ELFDumper<ELFT> &D) + : IsStatic(D.dynamic_table().empty()), Obj(D.getElfObject().getELFFile()), + Dumper(D), GotSec(nullptr), LocalNum(0), GlobalNum(0), PltSec(nullptr), + PltRelSec(nullptr), PltSymTable(nullptr), + FileName(D.getElfObject().getFileName()) {} template <class ELFT> Error MipsGOTParser<ELFT>::findGOT(Elf_Dyn_Range DynTable, @@ -3004,12 +2600,12 @@ Error MipsGOTParser<ELFT>::findGOT(Elf_Dyn_Range DynTable, // Find static GOT secton. if (IsStatic) { - GotSec = findSectionByName(*Obj, FileName, ".got"); + GotSec = Dumper.findSectionByName(".got"); if (!GotSec) return Error::success(); ArrayRef<uint8_t> Content = - unwrapOrError(FileName, Obj->getSectionContents(GotSec)); + unwrapOrError(FileName, Obj.getSectionContents(*GotSec)); GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()), Content.size() / sizeof(Entry)); LocalNum = GotEntries.size(); @@ -3059,7 +2655,7 @@ Error MipsGOTParser<ELFT>::findGOT(Elf_Dyn_Range DynTable, GlobalNum = DynSymTotal - *DtGotSym; ArrayRef<uint8_t> Content = - unwrapOrError(FileName, Obj->getSectionContents(GotSec)); + unwrapOrError(FileName, Obj.getSectionContents(*GotSec)); GotEntries = Entries(reinterpret_cast<const Entry *>(Content.data()), Content.size() / sizeof(Entry)); GotDynSyms = DynSyms.drop_front(*DtGotSym); @@ -3103,7 +2699,7 @@ Error MipsGOTParser<ELFT>::findPLT(Elf_Dyn_Range DynTable) { Twine::utohexstr(*DtJmpRel)); if (Expected<ArrayRef<uint8_t>> PltContentOrErr = - Obj->getSectionContents(PltSec)) + Obj.getSectionContents(*PltSec)) PltEntries = Entries(reinterpret_cast<const Entry *>(PltContentOrErr->data()), PltContentOrErr->size() / sizeof(Entry)); @@ -3112,25 +2708,20 @@ Error MipsGOTParser<ELFT>::findPLT(Elf_Dyn_Range DynTable) { toString(PltContentOrErr.takeError())); if (Expected<const Elf_Shdr *> PltSymTableOrErr = - Obj->getSection(PltRelSec->sh_link)) { + Obj.getSection(PltRelSec->sh_link)) PltSymTable = *PltSymTableOrErr; - } else { - unsigned SecNdx = PltRelSec - &cantFail(Obj->sections()).front(); - return createError("unable to get a symbol table linked to the RELPLT " - "section with index " + - Twine(SecNdx) + ": " + + else + return createError("unable to get a symbol table linked to the " + + describe(Obj, *PltRelSec) + ": " + toString(PltSymTableOrErr.takeError())); - } if (Expected<StringRef> StrTabOrErr = - Obj->getStringTableForSymtab(*PltSymTable)) { + Obj.getStringTableForSymtab(*PltSymTable)) PltStrTable = *StrTabOrErr; - } else { - unsigned SecNdx = PltSymTable - &cantFail(Obj->sections()).front(); - return createError( - "unable to get a string table for the symbol table with index " + - Twine(SecNdx) + ": " + toString(StrTabOrErr.takeError())); - } + else + return createError("unable to get a string table for the " + + describe(Obj, *PltSymTable) + ": " + + toString(StrTabOrErr.takeError())); return Error::success(); } @@ -3232,13 +2823,13 @@ const typename MipsGOTParser<ELFT>::Elf_Sym * MipsGOTParser<ELFT>::getPltSym(const Entry *E) const { int64_t Offset = std::distance(getPltEntries().data(), E); if (PltRelSec->sh_type == ELF::SHT_REL) { - Elf_Rel_Range Rels = unwrapOrError(FileName, Obj->rels(PltRelSec)); + Elf_Rel_Range Rels = unwrapOrError(FileName, Obj.rels(*PltRelSec)); return unwrapOrError(FileName, - Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); + Obj.getRelocationSymbol(Rels[Offset], PltSymTable)); } else { - Elf_Rela_Range Rels = unwrapOrError(FileName, Obj->relas(PltRelSec)); + Elf_Rela_Range Rels = unwrapOrError(FileName, Obj.relas(*PltRelSec)); return unwrapOrError(FileName, - Obj->getRelocationSymbol(&Rels[Offset], PltSymTable)); + Obj.getRelocationSymbol(Rels[Offset], PltSymTable)); } } @@ -3327,84 +2918,143 @@ static void printMipsReginfoData(ScopedPrinter &W, } template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const Elf_Shdr *Shdr = findSectionByName(*Obj, ObjF->getFileName(), ".reginfo"); - if (!Shdr) { + const Elf_Shdr *RegInfoSec = findSectionByName(".reginfo"); + if (!RegInfoSec) { W.startLine() << "There is no .reginfo section in the file.\n"; return; } - ArrayRef<uint8_t> Sec = - unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); - if (Sec.size() != sizeof(Elf_Mips_RegInfo<ELFT>)) { - W.startLine() << "The .reginfo section has a wrong size.\n"; + + Expected<ArrayRef<uint8_t>> ContentsOrErr = + Obj.getSectionContents(*RegInfoSec); + if (!ContentsOrErr) { + this->reportUniqueWarning( + "unable to read the content of the .reginfo section (" + + describe(*RegInfoSec) + "): " + toString(ContentsOrErr.takeError())); + return; + } + + if (ContentsOrErr->size() < sizeof(Elf_Mips_RegInfo<ELFT>)) { + this->reportUniqueWarning("the .reginfo section has an invalid size (0x" + + Twine::utohexstr(ContentsOrErr->size()) + ")"); return; } DictScope GS(W, "MIPS RegInfo"); - auto *Reginfo = reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>(Sec.data()); - printMipsReginfoData(W, *Reginfo); + printMipsReginfoData(W, *reinterpret_cast<const Elf_Mips_RegInfo<ELFT> *>( + ContentsOrErr->data())); +} + +template <class ELFT> +static Expected<const Elf_Mips_Options<ELFT> *> +readMipsOptions(const uint8_t *SecBegin, ArrayRef<uint8_t> &SecData, + bool &IsSupported) { + if (SecData.size() < sizeof(Elf_Mips_Options<ELFT>)) + return createError("the .MIPS.options section has an invalid size (0x" + + Twine::utohexstr(SecData.size()) + ")"); + + const Elf_Mips_Options<ELFT> *O = + reinterpret_cast<const Elf_Mips_Options<ELFT> *>(SecData.data()); + const uint8_t Size = O->size; + if (Size > SecData.size()) { + const uint64_t Offset = SecData.data() - SecBegin; + const uint64_t SecSize = Offset + SecData.size(); + return createError("a descriptor of size 0x" + Twine::utohexstr(Size) + + " at offset 0x" + Twine::utohexstr(Offset) + + " goes past the end of the .MIPS.options " + "section of size 0x" + + Twine::utohexstr(SecSize)); + } + + IsSupported = O->kind == ODK_REGINFO; + const size_t ExpectedSize = + sizeof(Elf_Mips_Options<ELFT>) + sizeof(Elf_Mips_RegInfo<ELFT>); + + if (IsSupported) + if (Size < ExpectedSize) + return createError( + "a .MIPS.options entry of kind " + + Twine(getElfMipsOptionsOdkType(O->kind)) + + " has an invalid size (0x" + Twine::utohexstr(Size) + + "), the expected size is 0x" + Twine::utohexstr(ExpectedSize)); + + SecData = SecData.drop_front(Size); + return O; } template <class ELFT> void ELFDumper<ELFT>::printMipsOptions() { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const Elf_Shdr *Shdr = - findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.options"); - if (!Shdr) { + const Elf_Shdr *MipsOpts = findSectionByName(".MIPS.options"); + if (!MipsOpts) { W.startLine() << "There is no .MIPS.options section in the file.\n"; return; } DictScope GS(W, "MIPS Options"); - ArrayRef<uint8_t> Sec = - unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); - while (!Sec.empty()) { - if (Sec.size() < sizeof(Elf_Mips_Options<ELFT>)) { - W.startLine() << "The .MIPS.options section has a wrong size.\n"; - return; - } - auto *O = reinterpret_cast<const Elf_Mips_Options<ELFT> *>(Sec.data()); - DictScope GS(W, getElfMipsOptionsOdkType(O->kind)); - switch (O->kind) { - case ODK_REGINFO: - printMipsReginfoData(W, O->getRegInfo()); - break; - default: - W.startLine() << "Unsupported MIPS options tag.\n"; + ArrayRef<uint8_t> Data = + unwrapOrError(ObjF.getFileName(), Obj.getSectionContents(*MipsOpts)); + const uint8_t *const SecBegin = Data.begin(); + while (!Data.empty()) { + bool IsSupported; + Expected<const Elf_Mips_Options<ELFT> *> OptsOrErr = + readMipsOptions<ELFT>(SecBegin, Data, IsSupported); + if (!OptsOrErr) { + reportUniqueWarning(OptsOrErr.takeError()); break; } - Sec = Sec.slice(O->size); - } -} -template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const Elf_Shdr *StackMapSection = nullptr; - for (const Elf_Shdr &Sec : cantFail(Obj->sections())) { - StringRef Name = - unwrapOrError(ObjF->getFileName(), Obj->getSectionName(&Sec)); - if (Name == ".llvm_stackmaps") { - StackMapSection = &Sec; - break; + unsigned Kind = (*OptsOrErr)->kind; + const char *Type = getElfMipsOptionsOdkType(Kind); + if (!IsSupported) { + W.startLine() << "Unsupported MIPS options tag: " << Type << " (" << Kind + << ")\n"; + continue; } + + DictScope GS(W, Type); + if (Kind == ODK_REGINFO) + printMipsReginfoData(W, (*OptsOrErr)->getRegInfo()); + else + llvm_unreachable("unexpected .MIPS.options section descriptor kind"); } +} +template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { + const Elf_Shdr *StackMapSection = findSectionByName(".llvm_stackmaps"); if (!StackMapSection) return; - ArrayRef<uint8_t> StackMapContentsArray = unwrapOrError( - ObjF->getFileName(), Obj->getSectionContents(StackMapSection)); + auto Warn = [&](Error &&E) { + this->reportUniqueWarning("unable to read the stack map from " + + describe(*StackMapSection) + ": " + + toString(std::move(E))); + }; - prettyPrintStackMap( - W, StackMapParser<ELFT::TargetEndianness>(StackMapContentsArray)); -} + Expected<ArrayRef<uint8_t>> ContentOrErr = + Obj.getSectionContents(*StackMapSection); + if (!ContentOrErr) { + Warn(ContentOrErr.takeError()); + return; + } -template <class ELFT> void ELFDumper<ELFT>::printGroupSections() { - ELFDumperStyle->printGroupSections(ObjF->getELFFile()); + if (Error E = StackMapParser<ELFT::TargetEndianness>::validateHeader( + *ContentOrErr)) { + Warn(std::move(E)); + return; + } + + prettyPrintStackMap(W, StackMapParser<ELFT::TargetEndianness>(*ContentOrErr)); } -template <class ELFT> void ELFDumper<ELFT>::printAddrsig() { - ELFDumperStyle->printAddrsig(ObjF->getELFFile()); +template <class ELFT> +void ELFDumper<ELFT>::printReloc(const Relocation<ELFT> &R, unsigned RelIndex, + const Elf_Shdr &Sec, const Elf_Shdr *SymTab) { + Expected<RelSymbol<ELFT>> Target = getRelocationTarget(R, SymTab); + if (!Target) + reportUniqueWarning("unable to print relocation " + Twine(RelIndex) + + " in " + describe(Sec) + ": " + + toString(Target.takeError())); + else + printRelRelaReloc(R, *Target); } static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, @@ -3417,155 +3067,214 @@ static inline void printFields(formatted_raw_ostream &OS, StringRef Str1, } template <class ELFT> -static std::string getSectionHeadersNumString(const ELFFile<ELFT> *Obj, +static std::string getSectionHeadersNumString(const ELFFile<ELFT> &Obj, StringRef FileName) { - const typename ELFT::Ehdr *ElfHeader = Obj->getHeader(); - if (ElfHeader->e_shnum != 0) - return to_string(ElfHeader->e_shnum); + const typename ELFT::Ehdr &ElfHeader = Obj.getHeader(); + if (ElfHeader.e_shnum != 0) + return to_string(ElfHeader.e_shnum); - ArrayRef<typename ELFT::Shdr> Arr = cantFail(Obj->sections()); - if (Arr.empty()) + Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections(); + if (!ArrOrErr) { + // In this case we can ignore an error, because we have already reported a + // warning about the broken section header table earlier. + consumeError(ArrOrErr.takeError()); + return "<?>"; + } + + if (ArrOrErr->empty()) return "0"; - return "0 (" + to_string(Arr[0].sh_size) + ")"; + return "0 (" + to_string((*ArrOrErr)[0].sh_size) + ")"; } template <class ELFT> -static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj, +static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> &Obj, StringRef FileName) { - const typename ELFT::Ehdr *ElfHeader = Obj->getHeader(); - if (ElfHeader->e_shstrndx != SHN_XINDEX) - return to_string(ElfHeader->e_shstrndx); + const typename ELFT::Ehdr &ElfHeader = Obj.getHeader(); + if (ElfHeader.e_shstrndx != SHN_XINDEX) + return to_string(ElfHeader.e_shstrndx); - ArrayRef<typename ELFT::Shdr> Arr = cantFail(Obj->sections()); - if (Arr.empty()) + Expected<ArrayRef<typename ELFT::Shdr>> ArrOrErr = Obj.sections(); + if (!ArrOrErr) { + // In this case we can ignore an error, because we have already reported a + // warning about the broken section header table earlier. + consumeError(ArrOrErr.takeError()); + return "<?>"; + } + + if (ArrOrErr->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((*ArrOrErr)[0].sh_link) + ")"; +} + +static const EnumEntry<unsigned> *getObjectFileEnumEntry(unsigned Type) { + auto It = llvm::find_if(ElfObjectFileType, [&](const EnumEntry<unsigned> &E) { + return E.Value == Type; + }); + if (It != makeArrayRef(ElfObjectFileType).end()) + return It; + return nullptr; } -template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) { - const Elf_Ehdr *e = Obj->getHeader(); +template <class ELFT> void GNUELFDumper<ELFT>::printFileHeaders() { + const Elf_Ehdr &e = this->Obj.getHeader(); OS << "ELF Header:\n"; OS << " Magic: "; std::string Str; for (int i = 0; i < ELF::EI_NIDENT; i++) - OS << format(" %02x", static_cast<int>(e->e_ident[i])); + OS << format(" %02x", static_cast<int>(e.e_ident[i])); OS << "\n"; - Str = printEnum(e->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass)); + Str = printEnum(e.e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass)); printFields(OS, "Class:", Str); - Str = printEnum(e->e_ident[ELF::EI_DATA], makeArrayRef(ElfDataEncoding)); + Str = printEnum(e.e_ident[ELF::EI_DATA], makeArrayRef(ElfDataEncoding)); printFields(OS, "Data:", Str); OS.PadToColumn(2u); OS << "Version:"; OS.PadToColumn(37u); - OS << to_hexString(e->e_ident[ELF::EI_VERSION]); - if (e->e_version == ELF::EV_CURRENT) + OS << to_hexString(e.e_ident[ELF::EI_VERSION]); + if (e.e_version == ELF::EV_CURRENT) OS << " (current)"; OS << "\n"; - Str = printEnum(e->e_ident[ELF::EI_OSABI], makeArrayRef(ElfOSABI)); + Str = printEnum(e.e_ident[ELF::EI_OSABI], makeArrayRef(ElfOSABI)); printFields(OS, "OS/ABI:", Str); printFields(OS, - "ABI Version:", std::to_string(e->e_ident[ELF::EI_ABIVERSION])); - Str = printEnum(e->e_type, makeArrayRef(ElfObjectFileType)); + "ABI Version:", std::to_string(e.e_ident[ELF::EI_ABIVERSION])); + + if (const EnumEntry<unsigned> *E = getObjectFileEnumEntry(e.e_type)) { + Str = E->AltName.str(); + } else { + if (e.e_type >= ET_LOPROC) + Str = "Processor Specific: (" + to_hexString(e.e_type, false) + ")"; + else if (e.e_type >= ET_LOOS) + Str = "OS Specific: (" + to_hexString(e.e_type, false) + ")"; + else + Str = "<unknown>: " + to_hexString(e.e_type, false); + } printFields(OS, "Type:", Str); - Str = printEnum(e->e_machine, makeArrayRef(ElfMachineType)); + + Str = printEnum(e.e_machine, makeArrayRef(ElfMachineType)); printFields(OS, "Machine:", Str); - Str = "0x" + to_hexString(e->e_version); + Str = "0x" + to_hexString(e.e_version); printFields(OS, "Version:", Str); - Str = "0x" + to_hexString(e->e_entry); + Str = "0x" + to_hexString(e.e_entry); printFields(OS, "Entry point address:", Str); - Str = to_string(e->e_phoff) + " (bytes into file)"; + Str = to_string(e.e_phoff) + " (bytes into file)"; printFields(OS, "Start of program headers:", Str); - Str = to_string(e->e_shoff) + " (bytes into file)"; + Str = to_string(e.e_shoff) + " (bytes into file)"; printFields(OS, "Start of section headers:", Str); std::string ElfFlags; - if (e->e_machine == EM_MIPS) + if (e.e_machine == EM_MIPS) ElfFlags = - printFlags(e->e_flags, makeArrayRef(ElfHeaderMipsFlags), + printFlags(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_RISCV) - ElfFlags = printFlags(e->e_flags, makeArrayRef(ElfHeaderRISCVFlags)); - Str = "0x" + to_hexString(e->e_flags); + else if (e.e_machine == EM_RISCV) + ElfFlags = printFlags(e.e_flags, makeArrayRef(ElfHeaderRISCVFlags)); + Str = "0x" + to_hexString(e.e_flags); if (!ElfFlags.empty()) Str = Str + ", " + ElfFlags; printFields(OS, "Flags:", Str); - Str = to_string(e->e_ehsize) + " (bytes)"; + Str = to_string(e.e_ehsize) + " (bytes)"; printFields(OS, "Size of this header:", Str); - Str = to_string(e->e_phentsize) + " (bytes)"; + Str = to_string(e.e_phentsize) + " (bytes)"; printFields(OS, "Size of program headers:", Str); - Str = to_string(e->e_phnum); + Str = to_string(e.e_phnum); printFields(OS, "Number of program headers:", Str); - Str = to_string(e->e_shentsize) + " (bytes)"; + Str = to_string(e.e_shentsize) + " (bytes)"; printFields(OS, "Size of section headers:", Str); - Str = getSectionHeadersNumString(Obj, this->FileName); + Str = getSectionHeadersNumString(this->Obj, this->FileName); printFields(OS, "Number of section headers:", Str); - Str = getSectionHeaderTableIndexString(Obj, this->FileName); + Str = getSectionHeaderTableIndexString(this->Obj, this->FileName); printFields(OS, "Section header string table index:", Str); } -namespace { -struct GroupMember { - StringRef Name; - uint64_t Index; -}; +template <class ELFT> std::vector<GroupSection> ELFDumper<ELFT>::getGroups() { + auto GetSignature = [&](const Elf_Sym &Sym, unsigned SymNdx, + const Elf_Shdr &Symtab) -> StringRef { + Expected<StringRef> StrTableOrErr = Obj.getStringTableForSymtab(Symtab); + if (!StrTableOrErr) { + reportUniqueWarning("unable to get the string table for " + + describe(Symtab) + ": " + + toString(StrTableOrErr.takeError())); + return "<?>"; + } -struct GroupSection { - StringRef Name; - std::string Signature; - uint64_t ShName; - uint64_t Index; - uint32_t Link; - uint32_t Info; - uint32_t Type; - std::vector<GroupMember> Members; -}; + StringRef Strings = *StrTableOrErr; + if (Sym.st_name >= Strings.size()) { + reportUniqueWarning("unable to get the name of the symbol with index " + + Twine(SymNdx) + ": st_name (0x" + + Twine::utohexstr(Sym.st_name) + + ") is past the end of the string table of size 0x" + + Twine::utohexstr(Strings.size())); + return "<?>"; + } -template <class ELFT> -std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj, - StringRef FileName) { - using Elf_Shdr = typename ELFT::Shdr; - using Elf_Sym = typename ELFT::Sym; - using Elf_Word = typename ELFT::Word; + return StrTableOrErr->data() + Sym.st_name; + }; std::vector<GroupSection> Ret; uint64_t I = 0; - for (const Elf_Shdr &Sec : cantFail(Obj->sections())) { + for (const Elf_Shdr &Sec : cantFail(Obj.sections())) { ++I; if (Sec.sh_type != ELF::SHT_GROUP) continue; - const Elf_Shdr *Symtab = - unwrapOrError(FileName, Obj->getSection(Sec.sh_link)); - StringRef StrTable = - unwrapOrError(FileName, Obj->getStringTableForSymtab(*Symtab)); - const Elf_Sym *Sym = unwrapOrError( - FileName, Obj->template getEntry<Elf_Sym>(Symtab, Sec.sh_info)); - auto Data = unwrapOrError( - FileName, Obj->template getSectionContentsAsArray<Elf_Word>(&Sec)); + StringRef Signature = "<?>"; + if (Expected<const Elf_Shdr *> SymtabOrErr = Obj.getSection(Sec.sh_link)) { + if (Expected<const Elf_Sym *> SymOrErr = + Obj.template getEntry<Elf_Sym>(**SymtabOrErr, Sec.sh_info)) + Signature = GetSignature(**SymOrErr, Sec.sh_info, **SymtabOrErr); + else + reportUniqueWarning("unable to get the signature symbol for " + + describe(Sec) + ": " + + toString(SymOrErr.takeError())); + } else { + reportUniqueWarning("unable to get the symbol table for " + + describe(Sec) + ": " + + toString(SymtabOrErr.takeError())); + } + + ArrayRef<Elf_Word> Data; + if (Expected<ArrayRef<Elf_Word>> ContentsOrErr = + Obj.template getSectionContentsAsArray<Elf_Word>(Sec)) { + if (ContentsOrErr->empty()) + reportUniqueWarning("unable to read the section group flag from the " + + describe(Sec) + ": the section is empty"); + else + Data = *ContentsOrErr; + } else { + reportUniqueWarning("unable to get the content of the " + describe(Sec) + + ": " + toString(ContentsOrErr.takeError())); + } - StringRef Name = unwrapOrError(FileName, Obj->getSectionName(&Sec)); - StringRef Signature = StrTable.data() + Sym->st_name; - Ret.push_back({Name, + Ret.push_back({getPrintableSectionName(Sec), maybeDemangle(Signature), Sec.sh_name, I - 1, Sec.sh_link, Sec.sh_info, - Data[0], + Data.empty() ? Elf_Word(0) : Data[0], {}}); + if (Data.empty()) + continue; + std::vector<GroupMember> &GM = Ret.back().Members; for (uint32_t Ndx : Data.slice(1)) { - auto Sec = unwrapOrError(FileName, Obj->getSection(Ndx)); - const StringRef Name = unwrapOrError(FileName, Obj->getSectionName(Sec)); - GM.push_back({Name, Ndx}); + if (Expected<const Elf_Shdr *> SecOrErr = Obj.getSection(Ndx)) { + GM.push_back({getPrintableSectionName(**SecOrErr), Ndx}); + } else { + reportUniqueWarning("unable to get the section with index " + + Twine(Ndx) + " when dumping the " + describe(Sec) + + ": " + toString(SecOrErr.takeError())); + GM.push_back({"<?>", Ndx}); + } } } return Ret; } -DenseMap<uint64_t, const GroupSection *> +static DenseMap<uint64_t, const GroupSection *> mapSectionsToGroups(ArrayRef<GroupSection> Groups) { DenseMap<uint64_t, const GroupSection *> Ret; for (const GroupSection &G : Groups) @@ -3574,10 +3283,8 @@ mapSectionsToGroups(ArrayRef<GroupSection> Groups) { return Ret; } -} // namespace - -template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { - std::vector<GroupSection> V = getGroups<ELFT>(Obj, this->FileName); +template <class ELFT> void GNUELFDumper<ELFT>::printGroupSections() { + std::vector<GroupSection> V = this->getGroups(); DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V); for (const GroupSection &G : V) { OS << "\n" @@ -3587,15 +3294,13 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { << " [Index] Name\n"; for (const GroupMember &GM : G.Members) { const GroupSection *MainGroup = Map[GM.Index]; - if (MainGroup != &G) { - OS.flush(); - errs() << "Error: section [" << format_decimal(GM.Index, 5) - << "] in group section [" << format_decimal(G.Index, 5) - << "] already in group section [" - << format_decimal(MainGroup->Index, 5) << "]"; - errs().flush(); - continue; - } + if (MainGroup != &G) + this->reportUniqueWarning( + "section with index " + Twine(GM.Index) + + ", included in the group section with index " + + Twine(MainGroup->Index) + + ", was also found in the group section with index " + + Twine(G.Index)); OS << " [" << format_decimal(GM.Index, 5) << "] " << GM.Name << "\n"; } } @@ -3605,60 +3310,51 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { } template <class ELFT> -void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, unsigned SecIndex, - const Elf_Shdr *SymTab, const Elf_Rela &R, - unsigned RelIndex, bool IsRela) { - Expected<std::pair<const typename ELFT::Sym *, std::string>> Target = - this->dumper()->getRelocationTarget(SymTab, R); - if (!Target) - this->reportUniqueWarning(createError( - "unable to print relocation " + Twine(RelIndex) + " in section " + - Twine(SecIndex) + ": " + toString(Target.takeError()))); - else - printRelocation(Obj, /*Sym=*/Target->first, /*Name=*/Target->second, R, - IsRela); +void GNUELFDumper<ELFT>::printRelrReloc(const Elf_Relr &R) { + OS << to_string(format_hex_no_prefix(R, ELFT::Is64Bits ? 16 : 8)) << "\n"; } template <class ELFT> -void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Sym *Sym, - StringRef SymbolName, const Elf_Rela &R, - bool IsRela) { +void GNUELFDumper<ELFT>::printRelRelaReloc(const Relocation<ELFT> &R, + const RelSymbol<ELFT> &RelSym) { // 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; - 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)); + Fields[0].Str = to_string(format_hex_no_prefix(R.Offset, Width)); + Fields[1].Str = to_string(format_hex_no_prefix(R.Info, Width)); SmallString<32> RelocName; - Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); + this->Obj.getRelocationTypeName(R.Type, RelocName); Fields[2].Str = RelocName.c_str(); - if (Sym) - Fields[3].Str = to_string(format_hex_no_prefix(Sym->getValue(), Width)); + if (RelSym.Sym) + Fields[3].Str = + to_string(format_hex_no_prefix(RelSym.Sym->getValue(), Width)); - Fields[4].Str = std::string(SymbolName); + Fields[4].Str = std::string(RelSym.Name); 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) { + if (Optional<int64_t> A = R.Addend) { + int64_t RelAddend = *A; + if (!RelSym.Name.empty()) { + if (RelAddend < 0) { Addend = " - "; RelAddend = std::abs(RelAddend); - } else + } else { Addend = " + "; + } } - Addend += to_hexString(RelAddend, false); } OS << Addend << "\n"; } -template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) { +template <class ELFT> +static void printRelocHeaderFields(formatted_raw_ostream &OS, 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) @@ -3679,75 +3375,68 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) { OS << "\n"; } -template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { - bool HasRelocSections = false; - for (const Elf_Shdr &Sec : cantFail(Obj->sections())) { - if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && - Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL && - Sec.sh_type != ELF::SHT_ANDROID_RELA && - Sec.sh_type != ELF::SHT_ANDROID_RELR) - continue; - HasRelocSections = true; - StringRef Name = unwrapOrError(this->FileName, Obj->getSectionName(&Sec)); - unsigned Entries = Sec.getEntityCount(); - std::vector<Elf_Rela> AndroidRelas; +template <class ELFT> +void GNUELFDumper<ELFT>::printDynamicRelocHeader(unsigned Type, StringRef Name, + const DynRegionInfo &Reg) { + uint64_t Offset = Reg.Addr - this->Obj.base(); + OS << "\n'" << Name.str().c_str() << "' relocation section at offset 0x" + << to_hexString(Offset, false) << " contains " << Reg.Size << " bytes:\n"; + printRelocHeaderFields<ELFT>(OS, Type); +} + +template <class ELFT> +static bool isRelocationSec(const typename ELFT::Shdr &Sec) { + return 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; +} + +template <class ELFT> void GNUELFDumper<ELFT>::printRelocations() { + auto GetEntriesNum = [&](const Elf_Shdr &Sec) -> Expected<size_t> { + // Android's packed relocation section needs to be unpacked first + // to get the actual number of entries. 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(this->FileName, Obj->android_relas(&Sec)); - Entries = AndroidRelas.size(); + Expected<std::vector<typename ELFT::Rela>> RelasOrErr = + this->Obj.android_relas(Sec); + if (!RelasOrErr) + return RelasOrErr.takeError(); + return RelasOrErr->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(this->FileName, Obj->relrs(&Sec)); - RelrRelas = unwrapOrError(this->FileName, Obj->decode_relrs(Relrs)); - Entries = RelrRelas.size(); + Expected<Elf_Relr_Range> RelrsOrErr = this->Obj.relrs(Sec); + if (!RelrsOrErr) + return RelrsOrErr.takeError(); + return this->Obj.decode_relrs(*RelrsOrErr).size(); } + + return Sec.getEntityCount(); + }; + + bool HasRelocSections = false; + for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { + if (!isRelocationSec<ELFT>(Sec)) + continue; + HasRelocSections = true; + + std::string EntriesNum = "<?>"; + if (Expected<size_t> NumOrErr = GetEntriesNum(Sec)) + EntriesNum = std::to_string(*NumOrErr); + else + this->reportUniqueWarning("unable to get the number of relocations in " + + this->describe(Sec) + ": " + + toString(NumOrErr.takeError())); + uintX_t Offset = Sec.sh_offset; + StringRef Name = this->getPrintableSectionName(Sec); OS << "\nRelocation section '" << Name << "' at offset 0x" - << to_hexString(Offset, false) << " contains " << Entries + << to_hexString(Offset, false) << " contains " << EntriesNum << " entries:\n"; - printRelocHeader(Sec.sh_type); - const Elf_Shdr *SymTab = - unwrapOrError(this->FileName, Obj->getSection(Sec.sh_link)); - unsigned SecNdx = &Sec - &cantFail(Obj->sections()).front(); - unsigned RelNdx = 0; - - switch (Sec.sh_type) { - case ELF::SHT_REL: - for (const auto &R : unwrapOrError(this->FileName, Obj->rels(&Sec))) { - Elf_Rela Rela; - Rela.r_offset = R.r_offset; - Rela.r_info = R.r_info; - Rela.r_addend = 0; - printRelocation(Obj, SecNdx, SymTab, Rela, ++RelNdx, false); - } - break; - case ELF::SHT_RELA: - for (const auto &R : unwrapOrError(this->FileName, Obj->relas(&Sec))) - printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx, true); - break; - case ELF::SHT_RELR: - case ELF::SHT_ANDROID_RELR: - if (opts::RawRelr) - for (const auto &R : unwrapOrError(this->FileName, Obj->relrs(&Sec))) - OS << to_string(format_hex_no_prefix(R, ELFT::Is64Bits ? 16 : 8)) - << "\n"; - else - for (const auto &R : RelrRelas) - printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx, false); - break; - case ELF::SHT_ANDROID_REL: - case ELF::SHT_ANDROID_RELA: - for (const auto &R : AndroidRelas) - printRelocation(Obj, SecNdx, SymTab, R, ++RelNdx, - Sec.sh_type == ELF::SHT_ANDROID_RELA); - break; - } + printRelocHeaderFields<ELFT>(OS, Sec.sh_type); + this->printRelocationsHelper(Sec); } if (!HasRelocSections) OS << "\nThere are no relocations in this file.\n"; @@ -3767,122 +3456,23 @@ static std::string getSectionTypeOffsetString(unsigned Type) { return "0x" + to_hexString(Type) + ": <unknown>"; } -static std::string getSectionTypeString(unsigned Arch, unsigned Type) { - using namespace ELF; +static std::string getSectionTypeString(unsigned Machine, unsigned Type) { + StringRef Name = getELFSectionTypeName(Machine, Type); - switch (Arch) { - case EM_ARM: - switch (Type) { - case SHT_ARM_EXIDX: - return "ARM_EXIDX"; - case SHT_ARM_PREEMPTMAP: - return "ARM_PREEMPTMAP"; - case SHT_ARM_ATTRIBUTES: - return "ARM_ATTRIBUTES"; - case SHT_ARM_DEBUGOVERLAY: - return "ARM_DEBUGOVERLAY"; - case SHT_ARM_OVERLAYSECTION: - return "ARM_OVERLAYSECTION"; - } - break; - case EM_X86_64: - switch (Type) { - case SHT_X86_64_UNWIND: - return "X86_64_UNWIND"; - } - break; - case EM_MIPS: - case EM_MIPS_RS3_LE: - switch (Type) { - case SHT_MIPS_REGINFO: - return "MIPS_REGINFO"; - case SHT_MIPS_OPTIONS: - return "MIPS_OPTIONS"; - case SHT_MIPS_DWARF: - return "MIPS_DWARF"; - case SHT_MIPS_ABIFLAGS: - return "MIPS_ABIFLAGS"; - } - break; - case EM_RISCV: - switch (Type) { - case SHT_RISCV_ATTRIBUTES: - return "RISCV_ATTRIBUTES"; - } + // Handle SHT_GNU_* type names. + if (Name.startswith("SHT_GNU_")) { + if (Name == "SHT_GNU_HASH") + return "GNU_HASH"; + // E.g. SHT_GNU_verneed -> VERNEED. + return Name.drop_front(8).upper(); } - switch (Type) { - case SHT_NULL: - return "NULL"; - case SHT_PROGBITS: - return "PROGBITS"; - case SHT_SYMTAB: - return "SYMTAB"; - case SHT_STRTAB: - return "STRTAB"; - case SHT_RELA: - return "RELA"; - case SHT_HASH: - return "HASH"; - case SHT_DYNAMIC: - return "DYNAMIC"; - case SHT_NOTE: - return "NOTE"; - case SHT_NOBITS: - return "NOBITS"; - case SHT_REL: - return "REL"; - case SHT_SHLIB: - return "SHLIB"; - case SHT_DYNSYM: - return "DYNSYM"; - case SHT_INIT_ARRAY: - return "INIT_ARRAY"; - case SHT_FINI_ARRAY: - return "FINI_ARRAY"; - case SHT_PREINIT_ARRAY: - return "PREINIT_ARRAY"; - case SHT_GROUP: - return "GROUP"; - case SHT_SYMTAB_SHNDX: + + if (Name == "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"; - 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"; - case SHT_LLVM_DEPENDENT_LIBRARIES: - return "LLVM_DEPENDENT_LIBRARIES"; - case SHT_LLVM_SYMPART: - return "LLVM_SYMPART"; - case SHT_LLVM_PART_EHDR: - return "LLVM_PART_EHDR"; - case SHT_LLVM_PART_PHDR: - return "LLVM_PART_PHDR"; - // FIXME: Parse processor specific GNU attributes - case SHT_GNU_ATTRIBUTES: - return "ATTRIBUTES"; - case SHT_GNU_HASH: - return "GNU_HASH"; - case SHT_GNU_verdef: - return "VERDEF"; - case SHT_GNU_verneed: - return "VERNEED"; - case SHT_GNU_versym: - return "VERSYM"; - default: - return getSectionTypeOffsetString(Type); - } - return ""; + + if (Name.startswith("SHT_")) + return Name.drop_front(4).str(); + return getSectionTypeOffsetString(Type); } static void printSectionDescription(formatted_raw_ostream &OS, @@ -3904,26 +3494,25 @@ static void printSectionDescription(formatted_raw_ostream &OS, OS << "p (processor specific)\n"; } -template <class ELFT> -void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { +template <class ELFT> void GNUELFDumper<ELFT>::printSectionHeaders() { unsigned Bias = ELFT::Is64Bits ? 0 : 8; - ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections()); + ArrayRef<Elf_Shdr> Sections = cantFail(this->Obj.sections()); OS << "There are " << to_string(Sections.size()) << " section headers, starting at offset " - << "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n"; + << "0x" << to_hexString(this->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) + for (const Field &F : Fields) printField(F); OS << "\n"; StringRef SecStrTable; if (Expected<StringRef> SecStrTableOrErr = - Obj->getSectionStringTable(Sections, this->dumper()->WarningHandler)) + this->Obj.getSectionStringTable(Sections, this->WarningHandler)) SecStrTable = *SecStrTableOrErr; else this->reportUniqueWarning(SecStrTableOrErr.takeError()); @@ -3935,15 +3524,15 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { Fields[1].Str = "<no-strings>"; else Fields[1].Str = std::string(unwrapOrError<StringRef>( - this->FileName, Obj->getSectionName(&Sec, SecStrTable))); + this->FileName, this->Obj.getSectionName(Sec, SecStrTable))); Fields[2].Str = - getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type); + getSectionTypeString(this->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(Obj->getHeader()->e_machine, Sec.sh_flags); + Fields[7].Str = getGNUFlags(this->Obj.getHeader().e_machine, 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); @@ -3963,13 +3552,16 @@ void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { OS << "\n"; ++SectionIndex; } - printSectionDescription(OS, Obj->getHeader()->e_machine); + printSectionDescription(OS, this->Obj.getHeader().e_machine); } template <class ELFT> -void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name, - size_t Entries, - bool NonVisibilityBitsUsed) { +void GNUELFDumper<ELFT>::printSymtabMessage(const Elf_Shdr *Symtab, + size_t Entries, + bool NonVisibilityBitsUsed) const { + StringRef Name; + if (Symtab) + Name = this->getPrintableSectionName(*Symtab); if (!Name.empty()) OS << "\nSymbol table '" << Name << "'"; else @@ -3987,10 +3579,11 @@ void GNUStyle<ELFT>::printSymtabMessage(const ELFO *Obj, StringRef Name, } template <class ELFT> -std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj, - const Elf_Sym *Symbol, - const Elf_Sym *FirstSym) { - unsigned SectionIndex = Symbol->st_shndx; +std::string +GNUELFDumper<ELFT>::getSymbolSectionNdx(const Elf_Sym &Symbol, + unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable) const { + unsigned SectionIndex = Symbol.st_shndx; switch (SectionIndex) { case ELF::SHN_UNDEF: return "UND"; @@ -3999,11 +3592,11 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj, case ELF::SHN_COMMON: return "COM"; case ELF::SHN_XINDEX: { - Expected<uint32_t> IndexOrErr = object::getExtendedSymbolTableIndex<ELFT>( - Symbol, FirstSym, this->dumper()->getShndxTable()); + Expected<uint32_t> IndexOrErr = + object::getExtendedSymbolTableIndex<ELFT>(Symbol, SymIndex, ShndxTable); if (!IndexOrErr) { - assert(Symbol->st_shndx == SHN_XINDEX && - "getSymbolSectionIndex should only fail due to an invalid " + assert(Symbol.st_shndx == SHN_XINDEX && + "getExtendedSymbolTableIndex should only fail due to an invalid " "SHT_SYMTAB_SHNDX table/reference"); this->reportUniqueWarning(IndexOrErr.takeError()); return "RSV[0xffff]"; @@ -4031,71 +3624,75 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj, } template <class ELFT> -void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, - const Elf_Sym *FirstSym, - Optional<StringRef> StrTable, bool IsDynamic, - bool NonVisibilityBitsUsed) { - static int Idx = 0; - static bool Dynamic = true; - - // If this function was called with a different value from IsDynamic - // from last call, happens when we move from dynamic to static symbol - // table, "Num" field should be reset. - if (!Dynamic != !IsDynamic) { - Idx = 0; - Dynamic = false; - } - +void GNUELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, + Optional<StringRef> StrTable, + bool IsDynamic, + bool NonVisibilityBitsUsed) const { unsigned Bias = ELFT::Is64Bits ? 8 : 0; Field Fields[8] = {0, 8, 17 + Bias, 23 + Bias, 31 + Bias, 38 + Bias, 48 + Bias, 51 + Bias}; - 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)); + Fields[0].Str = to_string(format_decimal(SymIndex, 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 && + unsigned char SymbolType = Symbol.getType(); + if (this->Obj.getHeader().e_machine == ELF::EM_AMDGPU && SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) Fields[3].Str = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes)); else Fields[3].Str = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes)); Fields[4].Str = - printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); + printEnum(Symbol.getBinding(), makeArrayRef(ElfSymbolBindings)); Fields[5].Str = - printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities)); - if (Symbol->st_other & ~0x3) - Fields[5].Str += - " [<other: " + to_string(format_hex(Symbol->st_other, 2)) + ">]"; + printEnum(Symbol.getVisibility(), makeArrayRef(ElfSymbolVisibilities)); + + if (Symbol.st_other & ~0x3) { + if (this->Obj.getHeader().e_machine == ELF::EM_AARCH64) { + uint8_t Other = Symbol.st_other & ~0x3; + if (Other & STO_AARCH64_VARIANT_PCS) { + Other &= ~STO_AARCH64_VARIANT_PCS; + Fields[5].Str += " [VARIANT_PCS"; + if (Other != 0) + Fields[5].Str.append(" | " + to_hexString(Other, false)); + Fields[5].Str.append("]"); + } + } else { + Fields[5].Str += + " [<other: " + to_string(format_hex(Symbol.st_other, 2)) + ">]"; + } + } Fields[6].Column += NonVisibilityBitsUsed ? 13 : 0; - Fields[6].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym); + Fields[6].Str = getSymbolSectionNdx(Symbol, SymIndex, ShndxTable); - Fields[7].Str = - this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); - for (auto &Entry : Fields) + Fields[7].Str = this->getFullSymbolName(Symbol, SymIndex, ShndxTable, + StrTable, IsDynamic); + for (const Field &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) { +void GNUELFDumper<ELFT>::printHashedSymbol(const Elf_Sym *Symbol, + unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, + StringRef StrTable, + uint32_t Bucket) { unsigned Bias = ELFT::Is64Bits ? 8 : 0; Field Fields[9] = {0, 6, 11, 20 + Bias, 25 + Bias, 34 + Bias, 41 + Bias, 49 + Bias, 53 + Bias}; - Fields[0].Str = to_string(format_decimal(Sym, 5)); + Fields[0].Str = to_string(format_decimal(SymIndex, 5)); Fields[1].Str = to_string(format_decimal(Bucket, 3)) + ":"; - const auto Symbol = FirstSym + Sym; Fields[2].Str = to_string( format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 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 && + if (this->Obj.getHeader().e_machine == ELF::EM_AMDGPU && SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) Fields[4].Str = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes)); else @@ -4105,30 +3702,29 @@ void GNUStyle<ELFT>::printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, 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); + Fields[7].Str = getSymbolSectionNdx(*Symbol, SymIndex, ShndxTable); + Fields[8].Str = + this->getFullSymbolName(*Symbol, SymIndex, ShndxTable, StrTable, true); - for (auto &Entry : Fields) + for (const Field &Entry : Fields) printField(Entry); OS << "\n"; } template <class ELFT> -void GNUStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols, - bool PrintDynamicSymbols) { +void GNUELFDumper<ELFT>::printSymbols(bool PrintSymbols, + bool PrintDynamicSymbols) { if (!PrintSymbols && !PrintDynamicSymbols) return; // GNU readelf prints both the .dynsym and .symtab with --symbols. - this->dumper()->printSymbolsHelper(true); + this->printSymbolsHelper(true); if (PrintSymbols) - this->dumper()->printSymbolsHelper(false); + this->printSymbolsHelper(false); } template <class ELFT> -void GNUStyle<ELFT>::printHashTableSymbols(const ELFO *Obj, - const Elf_Hash &SysVHash) { - StringRef StringTable = this->dumper()->getDynamicStringTable(); - if (StringTable.empty()) +void GNUELFDumper<ELFT>::printHashTableSymbols(const Elf_Hash &SysVHash) { + if (this->DynamicStringTable.empty()) return; if (ELFT::Is64Bits) @@ -4137,17 +3733,18 @@ void GNUStyle<ELFT>::printHashTableSymbols(const ELFO *Obj, OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; OS << "\n"; - Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols(); + Elf_Sym_Range DynSyms = this->dynamic_symbols(); const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0]; if (!FirstSym) { - Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion(); this->reportUniqueWarning( - createError(Twine("unable to print symbols for the .hash table: the " - "dynamic symbol table ") + - (DynSymRegion ? "is empty" : "was not found"))); + Twine("unable to print symbols for the .hash table: the " + "dynamic symbol table ") + + (this->DynSymRegion ? "is empty" : "was not found")); return; } + DataRegion<Elf_Word> ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); auto Buckets = SysVHash.buckets(); auto Chains = SysVHash.chains(); for (uint32_t Buc = 0; Buc < SysVHash.nbucket; Buc++) { @@ -4159,64 +3756,100 @@ void GNUStyle<ELFT>::printHashTableSymbols(const ELFO *Obj, break; if (Visited[Ch]) { - reportWarning(createError(".hash section is invalid: bucket " + + this->reportUniqueWarning(".hash section is invalid: bucket " + Twine(Ch) + - ": a cycle was detected in the linked chain"), - this->FileName); + ": a cycle was detected in the linked chain"); break; } - printHashedSymbol(Obj, FirstSym, Ch, StringTable, Buc); + printHashedSymbol(FirstSym + Ch, Ch, ShndxTable, this->DynamicStringTable, + Buc); Visited[Ch] = true; } } } template <class ELFT> -void GNUStyle<ELFT>::printGnuHashTableSymbols(const ELFO *Obj, - const Elf_GnuHash &GnuHash) { - StringRef StringTable = this->dumper()->getDynamicStringTable(); - if (StringTable.empty()) +void GNUELFDumper<ELFT>::printGnuHashTableSymbols(const Elf_GnuHash &GnuHash) { + if (this->DynamicStringTable.empty()) return; - Elf_Sym_Range DynSyms = this->dumper()->dynamic_symbols(); + Elf_Sym_Range DynSyms = this->dynamic_symbols(); const Elf_Sym *FirstSym = DynSyms.empty() ? nullptr : &DynSyms[0]; if (!FirstSym) { - Optional<DynRegionInfo> DynSymRegion = this->dumper()->getDynSymRegion(); - this->reportUniqueWarning(createError( + this->reportUniqueWarning( Twine("unable to print symbols for the .gnu.hash table: the " "dynamic symbol table ") + - (DynSymRegion ? "is empty" : "was not found"))); + (this->DynSymRegion ? "is empty" : "was not found")); return; } + auto GetSymbol = [&](uint64_t SymIndex, + uint64_t SymsTotal) -> const Elf_Sym * { + if (SymIndex >= SymsTotal) { + this->reportUniqueWarning( + "unable to print hashed symbol with index " + Twine(SymIndex) + + ", which is greater than or equal to the number of dynamic symbols " + "(" + + Twine::utohexstr(SymsTotal) + ")"); + return nullptr; + } + return FirstSym + SymIndex; + }; + + Expected<ArrayRef<Elf_Word>> ValuesOrErr = + getGnuHashTableChains<ELFT>(this->DynSymRegion, &GnuHash); + ArrayRef<Elf_Word> Values; + if (!ValuesOrErr) + this->reportUniqueWarning("unable to get hash values for the SHT_GNU_HASH " + "section: " + + toString(ValuesOrErr.takeError())); + else + Values = *ValuesOrErr; + + DataRegion<Elf_Word> ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); ArrayRef<Elf_Word> Buckets = GnuHash.buckets(); for (uint32_t Buc = 0; Buc < GnuHash.nbuckets; Buc++) { if (Buckets[Buc] == ELF::STN_UNDEF) continue; uint32_t Index = Buckets[Buc]; - uint32_t GnuHashable = Index - GnuHash.symndx; - // Print whole chain + // Print whole chain. while (true) { - printHashedSymbol(Obj, FirstSym, Index++, StringTable, Buc); - // Chain ends at symbol with stopper bit - if ((GnuHash.values(DynSyms.size())[GnuHashable++] & 1) == 1) + uint32_t SymIndex = Index++; + if (const Elf_Sym *Sym = GetSymbol(SymIndex, DynSyms.size())) + printHashedSymbol(Sym, SymIndex, ShndxTable, this->DynamicStringTable, + Buc); + else + break; + + if (SymIndex < GnuHash.symndx) { + this->reportUniqueWarning( + "unable to read the hash value for symbol with index " + + Twine(SymIndex) + + ", which is less than the index of the first hashed symbol (" + + Twine(GnuHash.symndx) + ")"); + break; + } + + // Chain ends at symbol with stopper bit. + if ((Values[SymIndex - GnuHash.symndx] & 1) == 1) break; } } } -template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { - if (const Elf_Hash *SysVHash = this->dumper()->getHashTable()) { +template <class ELFT> void GNUELFDumper<ELFT>::printHashSymbols() { + if (this->HashTable) { OS << "\n Symbol table of .hash for image:\n"; - if (Error E = checkHashTable<ELFT>(Obj, SysVHash)) + if (Error E = checkHashTable<ELFT>(*this, this->HashTable)) this->reportUniqueWarning(std::move(E)); else - printHashTableSymbols(Obj, *SysVHash); + printHashTableSymbols(*this->HashTable); } // Try printing the .gnu.hash table. - if (const Elf_GnuHash *GnuHash = this->dumper()->getGnuHashTable()) { + if (this->GnuHashTable) { OS << "\n Symbol table of .gnu.hash for image:\n"; if (ELFT::Is64Bits) OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; @@ -4224,10 +3857,119 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; OS << "\n"; - if (Error E = checkGNUHashTable<ELFT>(Obj, GnuHash)) + if (Error E = checkGNUHashTable<ELFT>(this->Obj, this->GnuHashTable)) this->reportUniqueWarning(std::move(E)); else - printGnuHashTableSymbols(Obj, *GnuHash); + printGnuHashTableSymbols(*this->GnuHashTable); + } +} + +template <class ELFT> void GNUELFDumper<ELFT>::printSectionDetails() { + ArrayRef<Elf_Shdr> Sections = cantFail(this->Obj.sections()); + OS << "There are " << to_string(Sections.size()) + << " section headers, starting at offset " + << "0x" << to_hexString(this->Obj.getHeader().e_shoff, false) << ":\n\n"; + + OS << "Section Headers:\n"; + + auto PrintFields = [&](ArrayRef<Field> V) { + for (const Field &F : V) + printField(F); + OS << "\n"; + }; + + PrintFields({{"[Nr]", 2}, {"Name", 7}}); + + constexpr bool Is64 = ELFT::Is64Bits; + PrintFields({{"Type", 7}, + {Is64 ? "Address" : "Addr", 23}, + {"Off", Is64 ? 40 : 32}, + {"Size", Is64 ? 47 : 39}, + {"ES", Is64 ? 54 : 46}, + {"Lk", Is64 ? 59 : 51}, + {"Inf", Is64 ? 62 : 54}, + {"Al", Is64 ? 66 : 57}}); + PrintFields({{"Flags", 7}}); + + StringRef SecStrTable; + if (Expected<StringRef> SecStrTableOrErr = + this->Obj.getSectionStringTable(Sections, this->WarningHandler)) + SecStrTable = *SecStrTableOrErr; + else + this->reportUniqueWarning(SecStrTableOrErr.takeError()); + + size_t SectionIndex = 0; + const unsigned AddrSize = Is64 ? 16 : 8; + for (const Elf_Shdr &S : Sections) { + StringRef Name = "<?>"; + if (Expected<StringRef> NameOrErr = + this->Obj.getSectionName(S, SecStrTable)) + Name = *NameOrErr; + else + this->reportUniqueWarning(NameOrErr.takeError()); + + OS.PadToColumn(2); + OS << "[" << right_justify(to_string(SectionIndex), 2) << "]"; + PrintFields({{Name, 7}}); + PrintFields( + {{getSectionTypeString(this->Obj.getHeader().e_machine, S.sh_type), 7}, + {to_string(format_hex_no_prefix(S.sh_addr, AddrSize)), 23}, + {to_string(format_hex_no_prefix(S.sh_offset, 6)), Is64 ? 39 : 32}, + {to_string(format_hex_no_prefix(S.sh_size, 6)), Is64 ? 47 : 39}, + {to_string(format_hex_no_prefix(S.sh_entsize, 2)), Is64 ? 54 : 46}, + {to_string(S.sh_link), Is64 ? 59 : 51}, + {to_string(S.sh_info), Is64 ? 63 : 55}, + {to_string(S.sh_addralign), Is64 ? 66 : 58}}); + + OS.PadToColumn(7); + OS << "[" << to_string(format_hex_no_prefix(S.sh_flags, AddrSize)) << "]: "; + + DenseMap<unsigned, StringRef> FlagToName = { + {SHF_WRITE, "WRITE"}, {SHF_ALLOC, "ALLOC"}, + {SHF_EXECINSTR, "EXEC"}, {SHF_MERGE, "MERGE"}, + {SHF_STRINGS, "STRINGS"}, {SHF_INFO_LINK, "INFO LINK"}, + {SHF_LINK_ORDER, "LINK ORDER"}, {SHF_OS_NONCONFORMING, "OS NONCONF"}, + {SHF_GROUP, "GROUP"}, {SHF_TLS, "TLS"}, + {SHF_COMPRESSED, "COMPRESSED"}, {SHF_EXCLUDE, "EXCLUDE"}}; + + uint64_t Flags = S.sh_flags; + uint64_t UnknownFlags = 0; + bool NeedsComma = false; + while (Flags) { + // Take the least significant bit as a flag. + uint64_t Flag = Flags & -Flags; + Flags -= Flag; + + auto It = FlagToName.find(Flag); + if (It != FlagToName.end()) { + if (NeedsComma) + OS << ", "; + NeedsComma = true; + OS << It->second; + } else { + UnknownFlags |= Flag; + } + } + + auto PrintUnknownFlags = [&](uint64_t Mask, StringRef Name) { + uint64_t FlagsToPrint = UnknownFlags & Mask; + if (!FlagsToPrint) + return; + + if (NeedsComma) + OS << ", "; + OS << Name << " (" + << to_string(format_hex_no_prefix(FlagsToPrint, AddrSize)) << ")"; + UnknownFlags &= ~Mask; + NeedsComma = true; + }; + + PrintUnknownFlags(SHF_MASKOS, "OS"); + PrintUnknownFlags(SHF_MASKPROC, "PROC"); + PrintUnknownFlags(uint64_t(-1), "UNKNOWN"); + + OS << "\n"; + ++SectionIndex; } } @@ -4312,29 +4054,27 @@ static bool checkPTDynamic(const typename ELFT::Phdr &Phdr, } template <class ELFT> -void GNUStyle<ELFT>::printProgramHeaders( - const ELFO *Obj, bool PrintProgramHeaders, - cl::boolOrDefault PrintSectionMapping) { +void GNUELFDumper<ELFT>::printProgramHeaders( + bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) { if (PrintProgramHeaders) - printProgramHeaders(Obj); + printProgramHeaders(); // Display the section mapping along with the program headers, unless // -section-mapping is explicitly set to false. if (PrintSectionMapping != cl::BOU_FALSE) - printSectionMapping(Obj); + printSectionMapping(); } -template <class ELFT> -void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { +template <class ELFT> void GNUELFDumper<ELFT>::printProgramHeaders() { unsigned Bias = ELFT::Is64Bits ? 8 : 0; - const Elf_Ehdr *Header = Obj->getHeader(); + const Elf_Ehdr &Header = this->Obj.getHeader(); Field Fields[8] = {2, 17, 26, 37 + Bias, 48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias}; OS << "\nElf file type is " - << printEnum(Header->e_type, makeArrayRef(ElfObjectFileType)) << "\n" - << "Entry point " << format_hex(Header->e_entry, 3) << "\n" - << "There are " << Header->e_phnum << " program headers," - << " starting at offset " << Header->e_phoff << "\n\n" + << printEnum(Header.e_type, makeArrayRef(ElfObjectFileType)) << "\n" + << "Entry point " << format_hex(Header.e_entry, 3) << "\n" + << "There are " << Header.e_phnum << " program headers," + << " starting at offset " << Header.e_phoff << "\n\n" << "Program Headers:\n"; if (ELFT::Is64Bits) OS << " Type Offset VirtAddr PhysAddr " @@ -4346,15 +4086,15 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { unsigned Width = ELFT::Is64Bits ? 18 : 10; unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7; - Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers(); + Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = this->Obj.program_headers(); if (!PhdrsOrErr) { - this->reportUniqueWarning(createError("unable to dump program headers: " + - toString(PhdrsOrErr.takeError()))); + this->reportUniqueWarning("unable to dump program headers: " + + toString(PhdrsOrErr.takeError())); return; } for (const Elf_Phdr &Phdr : *PhdrsOrErr) { - Fields[0].Str = getElfPtType(Header->e_machine, Phdr.p_type); + Fields[0].Str = getGNUPtType(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)); @@ -4362,26 +4102,25 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { 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); + for (const Field &F : Fields) + printField(F); if (Phdr.p_type == ELF::PT_INTERP) { OS << "\n"; auto ReportBadInterp = [&](const Twine &Msg) { - reportWarning( - createError("unable to read program interpreter name at offset 0x" + - Twine::utohexstr(Phdr.p_offset) + ": " + Msg), - this->FileName); + this->reportUniqueWarning( + "unable to read program interpreter name at offset 0x" + + Twine::utohexstr(Phdr.p_offset) + ": " + Msg); }; - if (Phdr.p_offset >= Obj->getBufSize()) { + if (Phdr.p_offset >= this->Obj.getBufSize()) { ReportBadInterp("it goes past the end of the file (0x" + - Twine::utohexstr(Obj->getBufSize()) + ")"); + Twine::utohexstr(this->Obj.getBufSize()) + ")"); continue; } const char *Data = - reinterpret_cast<const char *>(Obj->base()) + Phdr.p_offset; - size_t MaxSize = Obj->getBufSize() - Phdr.p_offset; + reinterpret_cast<const char *>(this->Obj.base()) + Phdr.p_offset; + size_t MaxSize = this->Obj.getBufSize() - Phdr.p_offset; size_t Len = strnlen(Data, MaxSize); if (Len == MaxSize) { ReportBadInterp("it is not null-terminated"); @@ -4395,17 +4134,16 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { } } -template <class ELFT> -void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { +template <class ELFT> void GNUELFDumper<ELFT>::printSectionMapping() { OS << "\n Section to Segment mapping:\n Segment Sections...\n"; DenseSet<const Elf_Shdr *> BelongsToSegment; int Phnum = 0; - Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers(); + Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = this->Obj.program_headers(); if (!PhdrsOrErr) { - this->reportUniqueWarning(createError( + this->reportUniqueWarning( "can't read program headers to build section to segment mapping: " + - toString(PhdrsOrErr.takeError()))); + toString(PhdrsOrErr.takeError())); return; } @@ -4413,7 +4151,7 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { std::string Sections; OS << format(" %2.2d ", Phnum++); // Check if each section is in a segment and then print mapping. - for (const Elf_Shdr &Sec : cantFail(Obj->sections())) { + for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { if (Sec.sh_type == ELF::SHT_NULL) continue; @@ -4423,7 +4161,7 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { if (checkTLSSections<ELFT>(Phdr, Sec) && checkOffsets<ELFT>(Phdr, Sec) && checkVMA<ELFT>(Phdr, Sec) && checkPTDynamic<ELFT>(Phdr, Sec)) { Sections += - unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() + + unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() + " "; BelongsToSegment.insert(&Sec); } @@ -4434,10 +4172,11 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { // Display sections that do not belong to a segment. std::string Sections; - for (const Elf_Shdr &Sec : cantFail(Obj->sections())) { + for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { if (BelongsToSegment.find(&Sec) == BelongsToSegment.end()) Sections += - unwrapOrError(this->FileName, Obj->getSectionName(&Sec)).str() + ' '; + unwrapOrError(this->FileName, this->Obj.getSectionName(Sec)).str() + + ' '; } if (!Sections.empty()) { OS << " None " << Sections << '\n'; @@ -4446,41 +4185,44 @@ void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { } namespace { -template <class ELFT> struct RelSymbol { - const typename ELFT::Sym *Sym; - std::string Name; -}; template <class ELFT> -RelSymbol<ELFT> getSymbolForReloc(const ELFFile<ELFT> *Obj, StringRef FileName, - const ELFDumper<ELFT> *Dumper, - const typename ELFT::Rela &Reloc) { - uint32_t SymIndex = Reloc.getSymbol(Obj->isMips64EL()); - auto WarnAndReturn = [&](const typename ELFT::Sym *Sym, +RelSymbol<ELFT> getSymbolForReloc(const ELFDumper<ELFT> &Dumper, + const Relocation<ELFT> &Reloc) { + using Elf_Sym = typename ELFT::Sym; + auto WarnAndReturn = [&](const Elf_Sym *Sym, const Twine &Reason) -> RelSymbol<ELFT> { - reportWarning( - createError("unable to get name of the dynamic symbol with index " + - Twine(SymIndex) + ": " + Reason), - FileName); + Dumper.reportUniqueWarning( + "unable to get name of the dynamic symbol with index " + + Twine(Reloc.Symbol) + ": " + Reason); return {Sym, "<corrupt>"}; }; - ArrayRef<typename ELFT::Sym> Symbols = Dumper->dynamic_symbols(); - const typename ELFT::Sym *FirstSym = Symbols.begin(); + ArrayRef<Elf_Sym> Symbols = Dumper.dynamic_symbols(); + const Elf_Sym *FirstSym = Symbols.begin(); if (!FirstSym) return WarnAndReturn(nullptr, "no dynamic symbol table found"); // We might have an object without a section header. In this case the size of // Symbols is zero, because there is no way to know the size of the dynamic // table. We should allow this case and not print a warning. - if (!Symbols.empty() && SymIndex >= Symbols.size()) + if (!Symbols.empty() && Reloc.Symbol >= Symbols.size()) return WarnAndReturn( nullptr, "index is greater than or equal to the number of dynamic symbols (" + Twine(Symbols.size()) + ")"); - const typename ELFT::Sym *Sym = FirstSym + SymIndex; - Expected<StringRef> ErrOrName = Sym->getName(Dumper->getDynamicStringTable()); + const ELFFile<ELFT> &Obj = Dumper.getElfObject().getELFFile(); + const uint64_t FileSize = Obj.getBufSize(); + const uint64_t SymOffset = ((const uint8_t *)FirstSym - Obj.base()) + + (uint64_t)Reloc.Symbol * sizeof(Elf_Sym); + if (SymOffset + sizeof(Elf_Sym) > FileSize) + return WarnAndReturn(nullptr, "symbol at 0x" + Twine::utohexstr(SymOffset) + + " goes past the end of the file (0x" + + Twine::utohexstr(FileSize) + ")"); + + const Elf_Sym *Sym = FirstSym + Reloc.Symbol; + Expected<StringRef> ErrOrName = Sym->getName(Dumper.getDynamicStringTable()); if (!ErrOrName) return WarnAndReturn(Sym, toString(ErrOrName.takeError())); @@ -4489,37 +4231,27 @@ RelSymbol<ELFT> getSymbolForReloc(const ELFFile<ELFT> *Obj, StringRef FileName, } // namespace template <class ELFT> -void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R, - bool IsRela) { - RelSymbol<ELFT> S = getSymbolForReloc(Obj, this->FileName, this->dumper(), R); - printRelocation(Obj, S.Sym, S.Name, R, IsRela); -} - -template <class ELFT> -static size_t getMaxDynamicTagSize(const ELFFile<ELFT> *Obj, +static size_t getMaxDynamicTagSize(const ELFFile<ELFT> &Obj, typename ELFT::DynRange Tags) { size_t Max = 0; for (const typename ELFT::Dyn &Dyn : Tags) - Max = std::max(Max, Obj->getDynamicTagAsString(Dyn.d_tag).size()); + Max = std::max(Max, Obj.getDynamicTagAsString(Dyn.d_tag).size()); return Max; } -template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) { - Elf_Dyn_Range Table = this->dumper()->dynamic_table(); +template <class ELFT> void GNUELFDumper<ELFT>::printDynamicTable() { + Elf_Dyn_Range Table = this->dynamic_table(); if (Table.empty()) return; - const DynRegionInfo &DynamicTableRegion = - this->dumper()->getDynamicTableRegion(); - OS << "Dynamic section at offset " - << format_hex(reinterpret_cast<const uint8_t *>(DynamicTableRegion.Addr) - - Obj->base(), + << format_hex(reinterpret_cast<const uint8_t *>(this->DynamicTable.Addr) - + this->Obj.base(), 1) << " contains " << Table.size() << " entries:\n"; // The type name is surrounded with round brackets, hence add 2. - size_t MaxTagSize = getMaxDynamicTagSize(Obj, Table) + 2; + size_t MaxTagSize = getMaxDynamicTagSize(this->Obj, Table) + 2; // The "Name/Value" column should be indented from the "Type" column by N // spaces, where N = MaxTagSize - length of "Type" (4) + trailing // space (1) = 3. @@ -4530,127 +4262,115 @@ template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) { for (auto Entry : Table) { uintX_t Tag = Entry.getTag(); std::string Type = - std::string("(") + Obj->getDynamicTagAsString(Tag).c_str() + ")"; - std::string Value = this->dumper()->getDynamicEntry(Tag, Entry.getVal()); + std::string("(") + this->Obj.getDynamicTagAsString(Tag).c_str() + ")"; + std::string Value = this->getDynamicEntry(Tag, Entry.getVal()); OS << " " << format_hex(Tag, ELFT::Is64Bits ? 18 : 10) << format(ValueFmt.c_str(), Type.c_str()) << Value << "\n"; } } +template <class ELFT> void GNUELFDumper<ELFT>::printDynamicRelocations() { + this->printDynamicRelocationsHelper(); +} + 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(ELF::SHT_RELA); - for (const Elf_Rela &Rela : this->dumper()->dyn_relas()) - printDynamicRelocation(Obj, Rela, true); +void ELFDumper<ELFT>::printDynamicReloc(const Relocation<ELFT> &R) { + printRelRelaReloc(R, getSymbolForReloc(*this, R)); +} + +template <class ELFT> +void ELFDumper<ELFT>::printRelocationsHelper(const Elf_Shdr &Sec) { + this->forEachRelocationDo( + Sec, opts::RawRelr, + [&](const Relocation<ELFT> &R, unsigned Ndx, const Elf_Shdr &Sec, + const Elf_Shdr *SymTab) { printReloc(R, Ndx, Sec, SymTab); }, + [&](const Elf_Relr &R) { printRelrReloc(R); }); +} + +template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocationsHelper() { + const bool IsMips64EL = this->Obj.isMips64EL(); + if (this->DynRelaRegion.Size > 0) { + printDynamicRelocHeader(ELF::SHT_RELA, "RELA", this->DynRelaRegion); + for (const Elf_Rela &Rela : + this->DynRelaRegion.template getAsArrayRef<Elf_Rela>()) + printDynamicReloc(Relocation<ELFT>(Rela, IsMips64EL)); } - if (DynRelRegion.Size > 0) { - OS << "\n'REL' relocation section at offset " - << format_hex(reinterpret_cast<const uint8_t *>(DynRelRegion.Addr) - - Obj->base(), - 1) - << " contains " << DynRelRegion.Size << " bytes:\n"; - printRelocHeader(ELF::SHT_REL); - for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) { - Elf_Rela Rela; - Rela.r_offset = Rel.r_offset; - Rela.r_info = Rel.r_info; - Rela.r_addend = 0; - printDynamicRelocation(Obj, Rela, false); - } + + if (this->DynRelRegion.Size > 0) { + printDynamicRelocHeader(ELF::SHT_REL, "REL", this->DynRelRegion); + for (const Elf_Rel &Rel : + this->DynRelRegion.template getAsArrayRef<Elf_Rel>()) + printDynamicReloc(Relocation<ELFT>(Rel, IsMips64EL)); } - 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(this->FileName, Obj->decode_relrs(Relrs)); - for (const Elf_Rela &Rela : RelrRelas) { - printDynamicRelocation(Obj, Rela, false); - } + + if (this->DynRelrRegion.Size > 0) { + printDynamicRelocHeader(ELF::SHT_REL, "RELR", this->DynRelrRegion); + Elf_Relr_Range Relrs = + this->DynRelrRegion.template getAsArrayRef<Elf_Relr>(); + for (const Elf_Rel &Rel : Obj.decode_relrs(Relrs)) + printDynamicReloc(Relocation<ELFT>(Rel, IsMips64EL)); } - if (DynPLTRelRegion.Size) { - OS << "\n'PLT' relocation section at offset " - << format_hex(reinterpret_cast<const uint8_t *>(DynPLTRelRegion.Addr) - - Obj->base(), - 1) - << " contains " << DynPLTRelRegion.Size << " bytes:\n"; - if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) { - printRelocHeader(ELF::SHT_RELA); - for (const Elf_Rela &Rela : DynPLTRelRegion.getAsArrayRef<Elf_Rela>()) - printDynamicRelocation(Obj, Rela, true); + if (this->DynPLTRelRegion.Size) { + if (this->DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) { + printDynamicRelocHeader(ELF::SHT_RELA, "PLT", this->DynPLTRelRegion); + for (const Elf_Rela &Rela : + this->DynPLTRelRegion.template getAsArrayRef<Elf_Rela>()) + printDynamicReloc(Relocation<ELFT>(Rela, IsMips64EL)); } else { - printRelocHeader(ELF::SHT_REL); - for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef<Elf_Rel>()) { - Elf_Rela Rela; - Rela.r_offset = Rel.r_offset; - Rela.r_info = Rel.r_info; - Rela.r_addend = 0; - printDynamicRelocation(Obj, Rela, false); - } + printDynamicRelocHeader(ELF::SHT_REL, "PLT", this->DynPLTRelRegion); + for (const Elf_Rel &Rel : + this->DynPLTRelRegion.template getAsArrayRef<Elf_Rel>()) + printDynamicReloc(Relocation<ELFT>(Rel, IsMips64EL)); } } } template <class ELFT> -void GNUStyle<ELFT>::printGNUVersionSectionProlog( - const ELFFile<ELFT> *Obj, const typename ELFT::Shdr *Sec, - const Twine &Label, unsigned EntriesNum) { - StringRef SecName = unwrapOrError(this->FileName, Obj->getSectionName(Sec)); +void GNUELFDumper<ELFT>::printGNUVersionSectionProlog( + const typename ELFT::Shdr &Sec, const Twine &Label, unsigned EntriesNum) { + // Don't inline the SecName, because it might report a warning to stderr and + // corrupt the output. + StringRef SecName = this->getPrintableSectionName(Sec); OS << Label << " section '" << SecName << "' " << "contains " << EntriesNum << " entries:\n"; - unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); - StringRef SymTabName = "<corrupt>"; - - Expected<const typename ELFT::Shdr *> SymTabOrErr = - Obj->getSection(Sec->sh_link); - if (SymTabOrErr) - SymTabName = - unwrapOrError(this->FileName, Obj->getSectionName(*SymTabOrErr)); + StringRef LinkedSecName = "<corrupt>"; + if (Expected<const typename ELFT::Shdr *> LinkedSecOrErr = + this->Obj.getSection(Sec.sh_link)) + LinkedSecName = this->getPrintableSectionName(**LinkedSecOrErr); else - this->reportUniqueWarning( - createError("invalid section linked to " + - object::getELFSectionTypeName(Obj->getHeader()->e_machine, - Sec->sh_type) + - " section with index " + Twine(SecNdx) + ": " + - toString(SymTabOrErr.takeError()))); + this->reportUniqueWarning("invalid section linked to " + + this->describe(Sec) + ": " + + toString(LinkedSecOrErr.takeError())); - OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16) - << " Offset: " << format_hex(Sec->sh_offset, 8) - << " Link: " << Sec->sh_link << " (" << SymTabName << ")\n"; + OS << " Addr: " << format_hex_no_prefix(Sec.sh_addr, 16) + << " Offset: " << format_hex(Sec.sh_offset, 8) + << " Link: " << Sec.sh_link << " (" << LinkedSecName << ")\n"; } template <class ELFT> -void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, - const Elf_Shdr *Sec) { +void GNUELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) { if (!Sec) return; - printGNUVersionSectionProlog(Obj, Sec, "Version symbols", + printGNUVersionSectionProlog(*Sec, "Version symbols", Sec->sh_size / sizeof(Elf_Versym)); Expected<ArrayRef<Elf_Versym>> VerTableOrErr = - this->dumper()->getVersionTable(Sec, /*SymTab=*/nullptr, - /*StrTab=*/nullptr); + this->getVersionTable(*Sec, /*SymTab=*/nullptr, + /*StrTab=*/nullptr, /*SymTabSec=*/nullptr); if (!VerTableOrErr) { this->reportUniqueWarning(VerTableOrErr.takeError()); return; } + SmallVector<Optional<VersionEntry>, 0> *VersionMap = nullptr; + if (Expected<SmallVector<Optional<VersionEntry>, 0> *> MapOrErr = + this->getVersionMap()) + VersionMap = *MapOrErr; + else + this->reportUniqueWarning(MapOrErr.takeError()); + ArrayRef<Elf_Versym> VerTable = *VerTableOrErr; std::vector<StringRef> Versions; for (size_t I = 0, E = VerTable.size(); I < E; ++I) { @@ -4660,17 +4380,18 @@ void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, continue; } + if (!VersionMap) { + Versions.emplace_back("<corrupt>"); + continue; + } + bool IsDefault; - Expected<StringRef> NameOrErr = - this->dumper()->getSymbolVersionByIndex(Ndx, IsDefault); + Expected<StringRef> NameOrErr = this->Obj.getSymbolVersionByIndex( + Ndx, IsDefault, *VersionMap, /*IsSymHidden=*/None); if (!NameOrErr) { - if (!NameOrErr) { - unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); - this->reportUniqueWarning(createError( - "unable to get a version for entry " + Twine(I) + - " of SHT_GNU_versym section with index " + Twine(SecNdx) + ": " + - toString(NameOrErr.takeError()))); - } + this->reportUniqueWarning("unable to get a version for entry " + + Twine(I) + " of " + this->describe(*Sec) + + ": " + toString(NameOrErr.takeError())); Versions.emplace_back("<corrupt>"); continue; } @@ -4714,14 +4435,13 @@ static std::string versionFlagToString(unsigned Flags) { } template <class ELFT> -void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, - const Elf_Shdr *Sec) { +void GNUELFDumper<ELFT>::printVersionDefinitionSection(const Elf_Shdr *Sec) { if (!Sec) return; - printGNUVersionSectionProlog(Obj, Sec, "Version definition", Sec->sh_info); + printGNUVersionSectionProlog(*Sec, "Version definition", Sec->sh_info); - Expected<std::vector<VerDef>> V = this->dumper()->getVersionDefinitions(Sec); + Expected<std::vector<VerDef>> V = this->Obj.getVersionDefinitions(*Sec); if (!V) { this->reportUniqueWarning(V.takeError()); return; @@ -4742,16 +4462,15 @@ void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, } template <class ELFT> -void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, - const Elf_Shdr *Sec) { +void GNUELFDumper<ELFT>::printVersionDependencySection(const Elf_Shdr *Sec) { if (!Sec) return; unsigned VerneedNum = Sec->sh_info; - printGNUVersionSectionProlog(Obj, Sec, "Version needs", VerneedNum); + printGNUVersionSectionProlog(*Sec, "Version needs", VerneedNum); Expected<std::vector<VerNeed>> V = - this->dumper()->getVersionDependencies(Sec); + this->Obj.getVersionDependencies(*Sec, this->WarningHandler); if (!V) { this->reportUniqueWarning(V.takeError()); return; @@ -4769,7 +4488,7 @@ void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, } template <class ELFT> -void GNUStyle<ELFT>::printHashHistogram(const Elf_Hash &HashTable) { +void GNUELFDumper<ELFT>::printHashHistogram(const Elf_Hash &HashTable) { size_t NBucket = HashTable.nbucket; size_t NChain = HashTable.nchain; ArrayRef<Elf_Word> Buckets = HashTable.buckets(); @@ -4791,10 +4510,9 @@ void GNUStyle<ELFT>::printHashHistogram(const Elf_Hash &HashTable) { if (C == ELF::STN_UNDEF) break; if (Visited[C]) { - reportWarning(createError(".hash section is invalid: bucket " + + this->reportUniqueWarning(".hash section is invalid: bucket " + Twine(C) + - ": a cycle was detected in the linked chain"), - this->FileName); + ": a cycle was detected in the linked chain"); break; } Visited[C] = true; @@ -4825,13 +4543,13 @@ void GNUStyle<ELFT>::printHashHistogram(const Elf_Hash &HashTable) { } template <class ELFT> -void GNUStyle<ELFT>::printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) { - Expected<ArrayRef<Elf_Word>> ChainsOrErr = getGnuHashTableChains<ELFT>( - this->dumper()->getDynSymRegion(), &GnuHashTable); +void GNUELFDumper<ELFT>::printGnuHashHistogram( + const Elf_GnuHash &GnuHashTable) { + Expected<ArrayRef<Elf_Word>> ChainsOrErr = + getGnuHashTableChains<ELFT>(this->DynSymRegion, &GnuHashTable); if (!ChainsOrErr) { - this->reportUniqueWarning( - createError("unable to print the GNU hash table histogram: " + - toString(ChainsOrErr.takeError()))); + this->reportUniqueWarning("unable to print the GNU hash table histogram: " + + toString(ChainsOrErr.takeError())); return; } @@ -4883,211 +4601,83 @@ void GNUStyle<ELFT>::printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) { // dynamic symbol table. The table shows the number of hash buckets for // different lengths of chains as an absolute number and percentage of the total // buckets, and the cumulative coverage of symbols for each set of buckets. -template <class ELFT> -void GNUStyle<ELFT>::printHashHistograms(const ELFFile<ELFT> *Obj) { +template <class ELFT> void GNUELFDumper<ELFT>::printHashHistograms() { // Print histogram for the .hash section. - if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) { - if (Error E = checkHashTable<ELFT>(Obj, HashTable)) + if (this->HashTable) { + if (Error E = checkHashTable<ELFT>(*this, this->HashTable)) this->reportUniqueWarning(std::move(E)); else - printHashHistogram(*HashTable); + printHashHistogram(*this->HashTable); } // Print histogram for the .gnu.hash section. - if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) { - if (Error E = checkGNUHashTable<ELFT>(Obj, GnuHashTable)) + if (this->GnuHashTable) { + if (Error E = checkGNUHashTable<ELFT>(this->Obj, this->GnuHashTable)) this->reportUniqueWarning(std::move(E)); else - printGnuHashHistogram(*GnuHashTable); + printGnuHashHistogram(*this->GnuHashTable); } } -template <class ELFT> -void GNUStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) { +template <class ELFT> void GNUELFDumper<ELFT>::printCGProfile() { OS << "GNUStyle::printCGProfile not implemented\n"; } -template <class ELFT> -void GNUStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { - reportError(createError("--addrsig: not implemented"), this->FileName); -} - -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 StringRef getCoreNoteTypeName(const uint32_t NT) { - static const struct { - uint32_t ID; - const char *Name; - } Notes[] = { - {ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"}, - {ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"}, - {ELF::NT_PRPSINFO, "NT_PRPSINFO (prpsinfo structure)"}, - {ELF::NT_TASKSTRUCT, "NT_TASKSTRUCT (task structure)"}, - {ELF::NT_AUXV, "NT_AUXV (auxiliary vector)"}, - {ELF::NT_PSTATUS, "NT_PSTATUS (pstatus structure)"}, - {ELF::NT_FPREGS, "NT_FPREGS (floating point registers)"}, - {ELF::NT_PSINFO, "NT_PSINFO (psinfo structure)"}, - {ELF::NT_LWPSTATUS, "NT_LWPSTATUS (lwpstatus_t structure)"}, - {ELF::NT_LWPSINFO, "NT_LWPSINFO (lwpsinfo_t structure)"}, - {ELF::NT_WIN32PSTATUS, "NT_WIN32PSTATUS (win32_pstatus structure)"}, - - {ELF::NT_PPC_VMX, "NT_PPC_VMX (ppc Altivec registers)"}, - {ELF::NT_PPC_VSX, "NT_PPC_VSX (ppc VSX registers)"}, - {ELF::NT_PPC_TAR, "NT_PPC_TAR (ppc TAR register)"}, - {ELF::NT_PPC_PPR, "NT_PPC_PPR (ppc PPR register)"}, - {ELF::NT_PPC_DSCR, "NT_PPC_DSCR (ppc DSCR register)"}, - {ELF::NT_PPC_EBB, "NT_PPC_EBB (ppc EBB registers)"}, - {ELF::NT_PPC_PMU, "NT_PPC_PMU (ppc PMU registers)"}, - {ELF::NT_PPC_TM_CGPR, "NT_PPC_TM_CGPR (ppc checkpointed GPR registers)"}, - {ELF::NT_PPC_TM_CFPR, - "NT_PPC_TM_CFPR (ppc checkpointed floating point registers)"}, - {ELF::NT_PPC_TM_CVMX, - "NT_PPC_TM_CVMX (ppc checkpointed Altivec registers)"}, - {ELF::NT_PPC_TM_CVSX, "NT_PPC_TM_CVSX (ppc checkpointed VSX registers)"}, - {ELF::NT_PPC_TM_SPR, "NT_PPC_TM_SPR (ppc TM special purpose registers)"}, - {ELF::NT_PPC_TM_CTAR, "NT_PPC_TM_CTAR (ppc checkpointed TAR register)"}, - {ELF::NT_PPC_TM_CPPR, "NT_PPC_TM_CPPR (ppc checkpointed PPR register)"}, - {ELF::NT_PPC_TM_CDSCR, - "NT_PPC_TM_CDSCR (ppc checkpointed DSCR register)"}, - - {ELF::NT_386_TLS, "NT_386_TLS (x86 TLS information)"}, - {ELF::NT_386_IOPERM, "NT_386_IOPERM (x86 I/O permissions)"}, - {ELF::NT_X86_XSTATE, "NT_X86_XSTATE (x86 XSAVE extended state)"}, - - {ELF::NT_S390_HIGH_GPRS, - "NT_S390_HIGH_GPRS (s390 upper register halves)"}, - {ELF::NT_S390_TIMER, "NT_S390_TIMER (s390 timer register)"}, - {ELF::NT_S390_TODCMP, "NT_S390_TODCMP (s390 TOD comparator register)"}, - {ELF::NT_S390_TODPREG, - "NT_S390_TODPREG (s390 TOD programmable register)"}, - {ELF::NT_S390_CTRS, "NT_S390_CTRS (s390 control registers)"}, - {ELF::NT_S390_PREFIX, "NT_S390_PREFIX (s390 prefix register)"}, - {ELF::NT_S390_LAST_BREAK, - "NT_S390_LAST_BREAK (s390 last breaking event address)"}, - {ELF::NT_S390_SYSTEM_CALL, - "NT_S390_SYSTEM_CALL (s390 system call restart data)"}, - {ELF::NT_S390_TDB, "NT_S390_TDB (s390 transaction diagnostic block)"}, - {ELF::NT_S390_VXRS_LOW, - "NT_S390_VXRS_LOW (s390 vector registers 0-15 upper half)"}, - {ELF::NT_S390_VXRS_HIGH, - "NT_S390_VXRS_HIGH (s390 vector registers 16-31)"}, - {ELF::NT_S390_GS_CB, "NT_S390_GS_CB (s390 guarded-storage registers)"}, - {ELF::NT_S390_GS_BC, - "NT_S390_GS_BC (s390 guarded-storage broadcast control)"}, - - {ELF::NT_ARM_VFP, "NT_ARM_VFP (arm VFP registers)"}, - {ELF::NT_ARM_TLS, "NT_ARM_TLS (AArch TLS registers)"}, - {ELF::NT_ARM_HW_BREAK, - "NT_ARM_HW_BREAK (AArch hardware breakpoint registers)"}, - {ELF::NT_ARM_HW_WATCH, - "NT_ARM_HW_WATCH (AArch hardware watchpoint registers)"}, - - {ELF::NT_FILE, "NT_FILE (mapped files)"}, - {ELF::NT_PRXFPREG, "NT_PRXFPREG (user_xfpregs structure)"}, - {ELF::NT_SIGINFO, "NT_SIGINFO (siginfo_t data)"}, - }; - - 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; - const char *Name; - } Notes[] = { - {ELF::NT_GNU_ABI_TAG, "NT_GNU_ABI_TAG (ABI version tag)"}, - {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) - if (Note.ID == NT) - return std::string(Note.Name); - - std::string string; - raw_string_ostream OS(string); - OS << format("Unknown note type (0x%08x)", NT); - return OS.str(); +static Expected<std::vector<uint64_t>> toULEB128Array(ArrayRef<uint8_t> Data) { + std::vector<uint64_t> Ret; + const uint8_t *Cur = Data.begin(); + const uint8_t *End = Data.end(); + while (Cur != End) { + unsigned Size; + const char *Err; + Ret.push_back(decodeULEB128(Cur, &Size, End, &Err)); + if (Err) + return createError(Err); + Cur += Size; + } + return Ret; } -static std::string getFreeBSDNoteTypeName(const uint32_t NT) { - static const struct { - uint32_t ID; - const char *Name; - } Notes[] = { - {ELF::NT_FREEBSD_THRMISC, "NT_THRMISC (thrmisc structure)"}, - {ELF::NT_FREEBSD_PROCSTAT_PROC, "NT_PROCSTAT_PROC (proc data)"}, - {ELF::NT_FREEBSD_PROCSTAT_FILES, "NT_PROCSTAT_FILES (files data)"}, - {ELF::NT_FREEBSD_PROCSTAT_VMMAP, "NT_PROCSTAT_VMMAP (vmmap data)"}, - {ELF::NT_FREEBSD_PROCSTAT_GROUPS, "NT_PROCSTAT_GROUPS (groups data)"}, - {ELF::NT_FREEBSD_PROCSTAT_UMASK, "NT_PROCSTAT_UMASK (umask data)"}, - {ELF::NT_FREEBSD_PROCSTAT_RLIMIT, "NT_PROCSTAT_RLIMIT (rlimit data)"}, - {ELF::NT_FREEBSD_PROCSTAT_OSREL, "NT_PROCSTAT_OSREL (osreldate data)"}, - {ELF::NT_FREEBSD_PROCSTAT_PSSTRINGS, - "NT_PROCSTAT_PSSTRINGS (ps_strings data)"}, - {ELF::NT_FREEBSD_PROCSTAT_AUXV, "NT_PROCSTAT_AUXV (auxv data)"}, - }; - - for (const auto &Note : Notes) - if (Note.ID == NT) - return std::string(Note.Name); +template <class ELFT> +static Expected<std::vector<uint64_t>> +decodeAddrsigSection(const ELFFile<ELFT> &Obj, const typename ELFT::Shdr &Sec) { + Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj.getSectionContents(Sec); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); - std::string string; - raw_string_ostream OS(string); - OS << format("Unknown note type (0x%08x)", NT); - return OS.str(); + if (Expected<std::vector<uint64_t>> SymsOrErr = + toULEB128Array(*ContentsOrErr)) + return *SymsOrErr; + else + return createError("unable to decode " + describe(Obj, Sec) + ": " + + toString(SymsOrErr.takeError())); } -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)"}}; - - for (const auto &Note : Notes) - if (Note.ID == NT) - return std::string(Note.Name); +template <class ELFT> void GNUELFDumper<ELFT>::printAddrsig() { + if (!this->DotAddrsigSec) + return; - std::string string; - raw_string_ostream OS(string); - OS << format("Unknown note type (0x%08x)", NT); - return OS.str(); -} + Expected<std::vector<uint64_t>> SymsOrErr = + decodeAddrsigSection(this->Obj, *this->DotAddrsigSec); + if (!SymsOrErr) { + this->reportUniqueWarning(SymsOrErr.takeError()); + return; + } -static std::string getAMDGPUNoteTypeName(const uint32_t NT) { - if (NT == ELF::NT_AMDGPU_METADATA) - return std::string("NT_AMDGPU_METADATA (AMDGPU Metadata)"); + StringRef Name = this->getPrintableSectionName(*this->DotAddrsigSec); + OS << "\nAddress-significant symbols section '" << Name << "'" + << " contains " << SymsOrErr->size() << " entries:\n"; + OS << " Num: Name\n"; - std::string string; - raw_string_ostream OS(string); - OS << format("Unknown note type (0x%08x)", NT); - return OS.str(); + Field Fields[2] = {0, 8}; + size_t SymIndex = 0; + for (uint64_t Sym : *SymsOrErr) { + Fields[0].Str = to_string(format_decimal(++SymIndex, 6)) + ":"; + Fields[1].Str = this->getStaticSymbolName(Sym); + for (const Field &Entry : Fields) + printField(Entry); + OS << "\n"; + } } template <typename ELFT> @@ -5277,7 +4867,7 @@ template <typename ELFT> static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) { static std::string getGNUBuildId(ArrayRef<uint8_t> Desc) { std::string str; raw_string_ostream OS(str); - for (const auto &B : Desc) + for (uint8_t B : Desc) OS << format_hex_no_prefix(B, 2); return OS.str(); } @@ -5309,7 +4899,7 @@ static void printGNUNote(raw_ostream &OS, uint32_t NoteType, break; case ELF::NT_GNU_PROPERTY_TYPE_0: OS << " Properties:"; - for (const auto &Property : getGNUPropertyList<ELFT>(Desc)) + for (const std::string &Property : getGNUPropertyList<ELFT>(Desc)) OS << " " << Property << "\n"; break; } @@ -5348,17 +4938,17 @@ static AMDGPUNote getAMDGPUNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) { default: return {"", ""}; case ELF::NT_AMDGPU_METADATA: { - auto MsgPackString = + StringRef MsgPackString = StringRef(reinterpret_cast<const char *>(Desc.data()), Desc.size()); msgpack::Document MsgPackDoc; if (!MsgPackDoc.readFromBlob(MsgPackString, /*Multi=*/false)) return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"}; AMDGPU::HSAMD::V3::MetadataVerifier Verifier(true); + std::string HSAMetadataString; if (!Verifier.verify(MsgPackDoc.getRoot())) - return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"}; + HSAMetadataString = "Invalid AMDGPU Metadata\n"; - std::string HSAMetadataString; raw_string_ostream StrOS(HSAMetadataString); MsgPackDoc.toYAML(StrOS); @@ -5389,19 +4979,20 @@ static Expected<CoreNote> readCoreNote(DataExtractor Desc) { const int Bytes = Desc.getAddressSize(); if (!Desc.isValidOffsetForAddress(2)) - return createStringError(object_error::parse_failed, - "malformed note: header too short"); + return createError("the note of size 0x" + Twine::utohexstr(Desc.size()) + + " is too short, expected at least 0x" + + Twine::utohexstr(Bytes * 2)); if (Desc.getData().back() != 0) - return createStringError(object_error::parse_failed, - "malformed note: not NUL terminated"); + return createError("the note is not NUL terminated"); uint64_t DescOffset = 0; uint64_t FileCount = Desc.getAddress(&DescOffset); Ret.PageSize = Desc.getAddress(&DescOffset); if (!Desc.isValidOffsetForAddress(3 * FileCount * Bytes)) - return createStringError(object_error::parse_failed, - "malformed note: too short for number of files"); + return createError("unable to read file mappings (found " + + Twine(FileCount) + "): the note of size 0x" + + Twine::utohexstr(Desc.size()) + " is too short"); uint64_t FilenamesOffset = 0; DataExtractor Filenames( @@ -5409,10 +5000,14 @@ static Expected<CoreNote> readCoreNote(DataExtractor Desc) { Desc.isLittleEndian(), Desc.getAddressSize()); Ret.Mappings.resize(FileCount); + size_t I = 0; for (CoreFileMapping &Mapping : Ret.Mappings) { + ++I; if (!Filenames.isValidOffsetForDataOfSize(FilenamesOffset, 1)) - return createStringError(object_error::parse_failed, - "malformed note: too few filenames"); + return createError( + "unable to read the file name for the mapping with index " + + Twine(I) + ": the note of size 0x" + Twine::utohexstr(Desc.size()) + + " is truncated"); Mapping.Start = Desc.getAddress(&DescOffset); Mapping.End = Desc.getAddress(&DescOffset); Mapping.Offset = Desc.getAddress(&DescOffset); @@ -5439,8 +5034,205 @@ static void printCoreNote(raw_ostream &OS, const CoreNote &Note) { } } +static const NoteType GenericNoteTypes[] = { + {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"}, +}; + +static const NoteType GNUNoteTypes[] = { + {ELF::NT_GNU_ABI_TAG, "NT_GNU_ABI_TAG (ABI version tag)"}, + {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)"}, +}; + +static const NoteType FreeBSDNoteTypes[] = { + {ELF::NT_FREEBSD_THRMISC, "NT_THRMISC (thrmisc structure)"}, + {ELF::NT_FREEBSD_PROCSTAT_PROC, "NT_PROCSTAT_PROC (proc data)"}, + {ELF::NT_FREEBSD_PROCSTAT_FILES, "NT_PROCSTAT_FILES (files data)"}, + {ELF::NT_FREEBSD_PROCSTAT_VMMAP, "NT_PROCSTAT_VMMAP (vmmap data)"}, + {ELF::NT_FREEBSD_PROCSTAT_GROUPS, "NT_PROCSTAT_GROUPS (groups data)"}, + {ELF::NT_FREEBSD_PROCSTAT_UMASK, "NT_PROCSTAT_UMASK (umask data)"}, + {ELF::NT_FREEBSD_PROCSTAT_RLIMIT, "NT_PROCSTAT_RLIMIT (rlimit data)"}, + {ELF::NT_FREEBSD_PROCSTAT_OSREL, "NT_PROCSTAT_OSREL (osreldate data)"}, + {ELF::NT_FREEBSD_PROCSTAT_PSSTRINGS, + "NT_PROCSTAT_PSSTRINGS (ps_strings data)"}, + {ELF::NT_FREEBSD_PROCSTAT_AUXV, "NT_PROCSTAT_AUXV (auxv data)"}, +}; + +static const NoteType AMDNoteTypes[] = { + {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)"}, +}; + +static const NoteType AMDGPUNoteTypes[] = { + {ELF::NT_AMDGPU_METADATA, "NT_AMDGPU_METADATA (AMDGPU Metadata)"}, +}; + +static const NoteType CoreNoteTypes[] = { + {ELF::NT_PRSTATUS, "NT_PRSTATUS (prstatus structure)"}, + {ELF::NT_FPREGSET, "NT_FPREGSET (floating point registers)"}, + {ELF::NT_PRPSINFO, "NT_PRPSINFO (prpsinfo structure)"}, + {ELF::NT_TASKSTRUCT, "NT_TASKSTRUCT (task structure)"}, + {ELF::NT_AUXV, "NT_AUXV (auxiliary vector)"}, + {ELF::NT_PSTATUS, "NT_PSTATUS (pstatus structure)"}, + {ELF::NT_FPREGS, "NT_FPREGS (floating point registers)"}, + {ELF::NT_PSINFO, "NT_PSINFO (psinfo structure)"}, + {ELF::NT_LWPSTATUS, "NT_LWPSTATUS (lwpstatus_t structure)"}, + {ELF::NT_LWPSINFO, "NT_LWPSINFO (lwpsinfo_t structure)"}, + {ELF::NT_WIN32PSTATUS, "NT_WIN32PSTATUS (win32_pstatus structure)"}, + + {ELF::NT_PPC_VMX, "NT_PPC_VMX (ppc Altivec registers)"}, + {ELF::NT_PPC_VSX, "NT_PPC_VSX (ppc VSX registers)"}, + {ELF::NT_PPC_TAR, "NT_PPC_TAR (ppc TAR register)"}, + {ELF::NT_PPC_PPR, "NT_PPC_PPR (ppc PPR register)"}, + {ELF::NT_PPC_DSCR, "NT_PPC_DSCR (ppc DSCR register)"}, + {ELF::NT_PPC_EBB, "NT_PPC_EBB (ppc EBB registers)"}, + {ELF::NT_PPC_PMU, "NT_PPC_PMU (ppc PMU registers)"}, + {ELF::NT_PPC_TM_CGPR, "NT_PPC_TM_CGPR (ppc checkpointed GPR registers)"}, + {ELF::NT_PPC_TM_CFPR, + "NT_PPC_TM_CFPR (ppc checkpointed floating point registers)"}, + {ELF::NT_PPC_TM_CVMX, + "NT_PPC_TM_CVMX (ppc checkpointed Altivec registers)"}, + {ELF::NT_PPC_TM_CVSX, "NT_PPC_TM_CVSX (ppc checkpointed VSX registers)"}, + {ELF::NT_PPC_TM_SPR, "NT_PPC_TM_SPR (ppc TM special purpose registers)"}, + {ELF::NT_PPC_TM_CTAR, "NT_PPC_TM_CTAR (ppc checkpointed TAR register)"}, + {ELF::NT_PPC_TM_CPPR, "NT_PPC_TM_CPPR (ppc checkpointed PPR register)"}, + {ELF::NT_PPC_TM_CDSCR, "NT_PPC_TM_CDSCR (ppc checkpointed DSCR register)"}, + + {ELF::NT_386_TLS, "NT_386_TLS (x86 TLS information)"}, + {ELF::NT_386_IOPERM, "NT_386_IOPERM (x86 I/O permissions)"}, + {ELF::NT_X86_XSTATE, "NT_X86_XSTATE (x86 XSAVE extended state)"}, + + {ELF::NT_S390_HIGH_GPRS, "NT_S390_HIGH_GPRS (s390 upper register halves)"}, + {ELF::NT_S390_TIMER, "NT_S390_TIMER (s390 timer register)"}, + {ELF::NT_S390_TODCMP, "NT_S390_TODCMP (s390 TOD comparator register)"}, + {ELF::NT_S390_TODPREG, "NT_S390_TODPREG (s390 TOD programmable register)"}, + {ELF::NT_S390_CTRS, "NT_S390_CTRS (s390 control registers)"}, + {ELF::NT_S390_PREFIX, "NT_S390_PREFIX (s390 prefix register)"}, + {ELF::NT_S390_LAST_BREAK, + "NT_S390_LAST_BREAK (s390 last breaking event address)"}, + {ELF::NT_S390_SYSTEM_CALL, + "NT_S390_SYSTEM_CALL (s390 system call restart data)"}, + {ELF::NT_S390_TDB, "NT_S390_TDB (s390 transaction diagnostic block)"}, + {ELF::NT_S390_VXRS_LOW, + "NT_S390_VXRS_LOW (s390 vector registers 0-15 upper half)"}, + {ELF::NT_S390_VXRS_HIGH, "NT_S390_VXRS_HIGH (s390 vector registers 16-31)"}, + {ELF::NT_S390_GS_CB, "NT_S390_GS_CB (s390 guarded-storage registers)"}, + {ELF::NT_S390_GS_BC, + "NT_S390_GS_BC (s390 guarded-storage broadcast control)"}, + + {ELF::NT_ARM_VFP, "NT_ARM_VFP (arm VFP registers)"}, + {ELF::NT_ARM_TLS, "NT_ARM_TLS (AArch TLS registers)"}, + {ELF::NT_ARM_HW_BREAK, + "NT_ARM_HW_BREAK (AArch hardware breakpoint registers)"}, + {ELF::NT_ARM_HW_WATCH, + "NT_ARM_HW_WATCH (AArch hardware watchpoint registers)"}, + + {ELF::NT_FILE, "NT_FILE (mapped files)"}, + {ELF::NT_PRXFPREG, "NT_PRXFPREG (user_xfpregs structure)"}, + {ELF::NT_SIGINFO, "NT_SIGINFO (siginfo_t data)"}, +}; + +template <class ELFT> +const StringRef getNoteTypeName(const typename ELFT::Note &Note, + unsigned ELFType) { + uint32_t Type = Note.getType(); + auto FindNote = [&](ArrayRef<NoteType> V) -> StringRef { + for (const NoteType &N : V) + if (N.ID == Type) + return N.Name; + return ""; + }; + + StringRef Name = Note.getName(); + if (Name == "GNU") + return FindNote(GNUNoteTypes); + if (Name == "FreeBSD") + return FindNote(FreeBSDNoteTypes); + if (Name == "AMD") + return FindNote(AMDNoteTypes); + if (Name == "AMDGPU") + return FindNote(AMDGPUNoteTypes); + + if (ELFType == ELF::ET_CORE) + return FindNote(CoreNoteTypes); + return FindNote(GenericNoteTypes); +} + template <class ELFT> -void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { +static void printNotesHelper( + const ELFDumper<ELFT> &Dumper, + llvm::function_ref<void(Optional<StringRef>, typename ELFT::Off, + typename ELFT::Addr)> + StartNotesFn, + llvm::function_ref<Error(const typename ELFT::Note &)> ProcessNoteFn, + llvm::function_ref<void()> FinishNotesFn) { + const ELFFile<ELFT> &Obj = Dumper.getElfObject().getELFFile(); + + ArrayRef<typename ELFT::Shdr> Sections = cantFail(Obj.sections()); + if (Obj.getHeader().e_type != ELF::ET_CORE && !Sections.empty()) { + for (const typename ELFT::Shdr &S : Sections) { + if (S.sh_type != SHT_NOTE) + continue; + StartNotesFn(expectedToOptional(Obj.getSectionName(S)), S.sh_offset, + S.sh_size); + Error Err = Error::success(); + size_t I = 0; + for (const typename ELFT::Note Note : Obj.notes(S, Err)) { + if (Error E = ProcessNoteFn(Note)) + Dumper.reportUniqueWarning( + "unable to read note with index " + Twine(I) + " from the " + + describe(Obj, S) + ": " + toString(std::move(E))); + ++I; + } + if (Err) + Dumper.reportUniqueWarning("unable to read notes from the " + + describe(Obj, S) + ": " + + toString(std::move(Err))); + FinishNotesFn(); + } + return; + } + + Expected<ArrayRef<typename ELFT::Phdr>> PhdrsOrErr = Obj.program_headers(); + if (!PhdrsOrErr) { + Dumper.reportUniqueWarning( + "unable to read program headers to locate the PT_NOTE segment: " + + toString(PhdrsOrErr.takeError())); + return; + } + + for (size_t I = 0, E = (*PhdrsOrErr).size(); I != E; ++I) { + const typename ELFT::Phdr &P = (*PhdrsOrErr)[I]; + if (P.p_type != PT_NOTE) + continue; + StartNotesFn(/*SecName=*/None, P.p_offset, P.p_filesz); + Error Err = Error::success(); + size_t Index = 0; + for (const typename ELFT::Note Note : Obj.notes(P, Err)) { + if (Error E = ProcessNoteFn(Note)) + Dumper.reportUniqueWarning("unable to read note with index " + + Twine(Index) + + " from the PT_NOTE segment with index " + + Twine(I) + ": " + toString(std::move(E))); + ++Index; + } + if (Err) + Dumper.reportUniqueWarning( + "unable to read notes from the PT_NOTE segment with index " + + Twine(I) + ": " + toString(std::move(Err))); + FinishNotesFn(); + } +} + +template <class ELFT> void GNUELFDumper<ELFT>::printNotes() { auto PrintHeader = [&](Optional<StringRef> SecName, const typename ELFT::Off Offset, const typename ELFT::Addr Size) { @@ -5455,7 +5247,7 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { OS << " Owner Data size \tDescription\n"; }; - auto ProcessNote = [&](const Elf_Note &Note) { + auto ProcessNote = [&](const Elf_Note &Note) -> Error { StringRef Name = Note.getName(); ArrayRef<uint8_t> Descriptor = Note.getDesc(); Elf_Word Type = Note.getType(); @@ -5463,23 +5255,13 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { // Print the note owner/type. OS << " " << left_justify(Name, 20) << ' ' << format_hex(Descriptor.size(), 10) << '\t'; - if (Name == "GNU") { - OS << getGNUNoteTypeName(Type) << '\n'; - } else if (Name == "FreeBSD") { - OS << getFreeBSDNoteTypeName(Type) << '\n'; - } else if (Name == "AMD") { - OS << getAMDNoteTypeName(Type) << '\n'; - } else if (Name == "AMDGPU") { - OS << getAMDGPUNoteTypeName(Type) << '\n'; - } else { - StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE - ? getCoreNoteTypeName(Type) - : getGenericNoteTypeName(Type); - if (!NoteType.empty()) - OS << NoteType << '\n'; - else - OS << "Unknown note type: (" << format_hex(Type, 10) << ")\n"; - } + + StringRef NoteType = + getNoteTypeName<ELFT>(Note, this->Obj.getHeader().e_type); + if (!NoteType.empty()) + OS << NoteType << '\n'; + else + OS << "Unknown note type: (" << format_hex(Type, 10) << ")\n"; // Print the description, or fallback to printing raw bytes for unknown // owners. @@ -5498,11 +5280,10 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { DataExtractor DescExtractor(Descriptor, ELFT::TargetEndianness == support::little, sizeof(Elf_Addr)); - Expected<CoreNote> Note = readCoreNote(DescExtractor); - if (Note) - printCoreNote<ELFT>(OS, *Note); + if (Expected<CoreNote> NoteOrErr = readCoreNote(DescExtractor)) + printCoreNote<ELFT>(OS, *NoteOrErr); else - reportWarning(Note.takeError(), this->FileName); + return NoteOrErr.takeError(); } } else if (!Descriptor.empty()) { OS << " description data:"; @@ -5510,68 +5291,34 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { OS << " " << format("%02x", B); OS << '\n'; } + return Error::success(); }; - ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections()); - if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) { - for (const auto &S : Sections) { - if (S.sh_type != SHT_NOTE) - continue; - PrintHeader(expectedToOptional(Obj->getSectionName(&S)), S.sh_offset, - S.sh_size); - Error Err = Error::success(); - for (auto Note : Obj->notes(S, Err)) - ProcessNote(Note); - if (Err) - reportError(std::move(Err), this->FileName); - } - } else { - Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers(); - if (!PhdrsOrErr) { - this->reportUniqueWarning(createError( - "unable to read program headers to locate the PT_NOTE segment: " + - toString(PhdrsOrErr.takeError()))); - return; - } - - for (const Elf_Phdr &P : *PhdrsOrErr) { - if (P.p_type != PT_NOTE) - continue; - PrintHeader(/*SecName=*/None, P.p_offset, P.p_filesz); - Error Err = Error::success(); - for (auto Note : Obj->notes(P, Err)) - ProcessNote(Note); - if (Err) - reportError(std::move(Err), this->FileName); - } - } + printNotesHelper(*this, PrintHeader, ProcessNote, []() {}); } -template <class ELFT> -void GNUStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { +template <class ELFT> void GNUELFDumper<ELFT>::printELFLinkerOptions() { OS << "printELFLinkerOptions not implemented!\n"; } template <class ELFT> -void DumpStyle<ELFT>::printDependentLibsHelper( - const ELFFile<ELFT> *Obj, +void ELFDumper<ELFT>::printDependentLibsHelper( function_ref<void(const Elf_Shdr &)> OnSectionStart, function_ref<void(StringRef, uint64_t)> OnLibEntry) { auto Warn = [this](unsigned SecNdx, StringRef Msg) { - this->reportUniqueWarning( - createError("SHT_LLVM_DEPENDENT_LIBRARIES section at index " + - Twine(SecNdx) + " is broken: " + Msg)); + this->reportUniqueWarning("SHT_LLVM_DEPENDENT_LIBRARIES section at index " + + Twine(SecNdx) + " is broken: " + Msg); }; unsigned I = -1; - for (const Elf_Shdr &Shdr : cantFail(Obj->sections())) { + for (const Elf_Shdr &Shdr : cantFail(Obj.sections())) { ++I; if (Shdr.sh_type != ELF::SHT_LLVM_DEPENDENT_LIBRARIES) continue; OnSectionStart(Shdr); - Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr); + Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj.getSectionContents(Shdr); if (!ContentsOrErr) { Warn(I, toString(ContentsOrErr.takeError())); continue; @@ -5592,7 +5339,93 @@ void DumpStyle<ELFT>::printDependentLibsHelper( } template <class ELFT> -void GNUStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) { +void ELFDumper<ELFT>::forEachRelocationDo( + const Elf_Shdr &Sec, bool RawRelr, + llvm::function_ref<void(const Relocation<ELFT> &, unsigned, + const Elf_Shdr &, const Elf_Shdr *)> + RelRelaFn, + llvm::function_ref<void(const Elf_Relr &)> RelrFn) { + auto Warn = [&](Error &&E, + const Twine &Prefix = "unable to read relocations from") { + this->reportUniqueWarning(Prefix + " " + describe(Sec) + ": " + + toString(std::move(E))); + }; + + // SHT_RELR/SHT_ANDROID_RELR sections do not have an associated symbol table. + // For them we should not treat the value of the sh_link field as an index of + // a symbol table. + const Elf_Shdr *SymTab; + if (Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_RELR) { + Expected<const Elf_Shdr *> SymTabOrErr = Obj.getSection(Sec.sh_link); + if (!SymTabOrErr) { + Warn(SymTabOrErr.takeError(), "unable to locate a symbol table for"); + return; + } + SymTab = *SymTabOrErr; + } + + unsigned RelNdx = 0; + const bool IsMips64EL = this->Obj.isMips64EL(); + switch (Sec.sh_type) { + case ELF::SHT_REL: + if (Expected<Elf_Rel_Range> RangeOrErr = Obj.rels(Sec)) { + for (const Elf_Rel &R : *RangeOrErr) + RelRelaFn(Relocation<ELFT>(R, IsMips64EL), RelNdx++, Sec, SymTab); + } else { + Warn(RangeOrErr.takeError()); + } + break; + case ELF::SHT_RELA: + if (Expected<Elf_Rela_Range> RangeOrErr = Obj.relas(Sec)) { + for (const Elf_Rela &R : *RangeOrErr) + RelRelaFn(Relocation<ELFT>(R, IsMips64EL), RelNdx++, Sec, SymTab); + } else { + Warn(RangeOrErr.takeError()); + } + break; + case ELF::SHT_RELR: + case ELF::SHT_ANDROID_RELR: { + Expected<Elf_Relr_Range> RangeOrErr = Obj.relrs(Sec); + if (!RangeOrErr) { + Warn(RangeOrErr.takeError()); + break; + } + if (RawRelr) { + for (const Elf_Relr &R : *RangeOrErr) + RelrFn(R); + break; + } + + for (const Elf_Rel &R : Obj.decode_relrs(*RangeOrErr)) + RelRelaFn(Relocation<ELFT>(R, IsMips64EL), RelNdx++, Sec, + /*SymTab=*/nullptr); + break; + } + case ELF::SHT_ANDROID_REL: + case ELF::SHT_ANDROID_RELA: + if (Expected<std::vector<Elf_Rela>> RelasOrErr = Obj.android_relas(Sec)) { + for (const Elf_Rela &R : *RelasOrErr) + RelRelaFn(Relocation<ELFT>(R, IsMips64EL), RelNdx++, Sec, SymTab); + } else { + Warn(RelasOrErr.takeError()); + } + break; + } +} + +template <class ELFT> +StringRef ELFDumper<ELFT>::getPrintableSectionName(const Elf_Shdr &Sec) const { + StringRef Name = "<?>"; + if (Expected<StringRef> SecNameOrErr = + Obj.getSectionName(Sec, this->WarningHandler)) + Name = *SecNameOrErr; + else + this->reportUniqueWarning("unable to get the name of " + describe(Sec) + + ": " + toString(SecNameOrErr.takeError())); + return Name; +} + +template <class ELFT> void GNUELFDumper<ELFT>::printDependentLibs() { bool SectionStarted = false; struct NameOffset { StringRef Name; @@ -5605,7 +5438,7 @@ void GNUStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) { << format_hex(Current.Offset, 1) << " contains " << SecEntries.size() << " entries:\n"; for (NameOffset Entry : SecEntries) - OS << " [" << format("%6tx", Entry.Offset) << "] " << Entry.Name + OS << " [" << format("%6" PRIx64, Entry.Offset) << "] " << Entry.Name << "\n"; OS << "\n"; SecEntries.clear(); @@ -5616,104 +5449,94 @@ void GNUStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) { PrintSection(); SectionStarted = true; Current.Offset = Shdr.sh_offset; - Expected<StringRef> Name = Obj->getSectionName(&Shdr); - if (!Name) { - Current.Name = "<?>"; - this->reportUniqueWarning( - createError("cannot get section name of " - "SHT_LLVM_DEPENDENT_LIBRARIES section: " + - toString(Name.takeError()))); - } else { - Current.Name = *Name; - } + Current.Name = this->getPrintableSectionName(Shdr); }; auto OnLibEntry = [&](StringRef Lib, uint64_t Offset) { SecEntries.push_back(NameOffset{Lib, Offset}); }; - this->printDependentLibsHelper(Obj, OnSectionStart, OnLibEntry); + this->printDependentLibsHelper(OnSectionStart, OnLibEntry); if (SectionStarted) PrintSection(); } -// Used for printing section names in places where possible errors can be -// ignored. -static StringRef getSectionName(const SectionRef &Sec) { - Expected<StringRef> NameOrErr = Sec.getName(); - if (NameOrErr) - return *NameOrErr; - consumeError(NameOrErr.takeError()); - return "<?>"; -} +template <class ELFT> +bool ELFDumper<ELFT>::printFunctionStackSize( + uint64_t SymValue, Optional<const Elf_Shdr *> FunctionSec, + const Elf_Shdr &StackSizeSec, DataExtractor Data, uint64_t *Offset) { + uint32_t FuncSymIndex = 0; + if (this->DotSymtabSec) { + if (Expected<Elf_Sym_Range> SymsOrError = Obj.symbols(this->DotSymtabSec)) { + uint32_t Index = (uint32_t)-1; + for (const Elf_Sym &Sym : *SymsOrError) { + ++Index; -// Used for printing symbol names in places where possible errors can be -// ignored. -static std::string getSymbolName(const ELFSymbolRef &Sym) { - Expected<StringRef> NameOrErr = Sym.getName(); - if (NameOrErr) - return maybeDemangle(*NameOrErr); - consumeError(NameOrErr.takeError()); - return "<?>"; -} + if (Sym.st_shndx == ELF::SHN_UNDEF || Sym.getType() != ELF::STT_FUNC) + continue; -template <class ELFT> -void DumpStyle<ELFT>::printFunctionStackSize(const ELFObjectFile<ELFT> *Obj, - uint64_t SymValue, - Optional<SectionRef> FunctionSec, - const StringRef SectionName, - DataExtractor Data, - uint64_t *Offset) { - // This function ignores potentially erroneous input, unless it is directly - // related to stack size reporting. - SymbolRef FuncSym; - for (const ELFSymbolRef &Symbol : Obj->symbols()) { - Expected<uint64_t> SymAddrOrErr = Symbol.getAddress(); - if (!SymAddrOrErr) { - consumeError(SymAddrOrErr.takeError()); - continue; - } - if (Expected<uint32_t> SymFlags = Symbol.getFlags()) { - if (*SymFlags & SymbolRef::SF_Undefined) - continue; - } else - consumeError(SymFlags.takeError()); - if (Symbol.getELFType() == ELF::STT_FUNC && *SymAddrOrErr == SymValue) { - // Check if the symbol is in the right section. FunctionSec == None means - // "any section". - if (!FunctionSec || FunctionSec->containsSymbol(Symbol)) { - FuncSym = Symbol; + if (Expected<uint64_t> SymAddrOrErr = + ObjF.toSymbolRef(this->DotSymtabSec, Index).getAddress()) { + if (SymValue != *SymAddrOrErr) + continue; + } else { + std::string Name = this->getStaticSymbolName(Index); + reportUniqueWarning("unable to get address of symbol '" + Name + + "': " + toString(SymAddrOrErr.takeError())); + break; + } + + // Check if the symbol is in the right section. FunctionSec == None + // means "any section". + if (FunctionSec) { + if (Expected<const Elf_Shdr *> SecOrErr = + Obj.getSection(Sym, this->DotSymtabSec, + this->getShndxTable(this->DotSymtabSec))) { + if (*FunctionSec != *SecOrErr) + continue; + } else { + std::string Name = this->getStaticSymbolName(Index); + // Note: it is impossible to trigger this error currently, it is + // untested. + reportUniqueWarning("unable to get section of symbol '" + Name + + "': " + toString(SecOrErr.takeError())); + break; + } + } + + FuncSymIndex = Index; break; } + } else { + reportUniqueWarning("unable to read the symbol table: " + + toString(SymsOrError.takeError())); } } std::string FuncName = "?"; - // A valid SymbolRef has a non-null object file pointer. - if (FuncSym.BasicSymbolRef::getObject()) - FuncName = getSymbolName(FuncSym); + if (!FuncSymIndex) + reportUniqueWarning( + "could not identify function symbol for stack size entry in " + + describe(StackSizeSec)); else - reportWarning( - createError("could not identify function symbol for stack size entry"), - Obj->getFileName()); + FuncName = this->getStaticSymbolName(FuncSymIndex); // Extract the size. The expectation is that Offset is pointing to the right // place, i.e. past the function address. - uint64_t PrevOffset = *Offset; - uint64_t StackSize = Data.getULEB128(Offset); - // getULEB128() does not advance Offset if it is not able to extract a valid - // integer. - if (*Offset == PrevOffset) - reportError( - createStringError(object_error::parse_failed, - "could not extract a valid stack size in section %s", - SectionName.data()), - Obj->getFileName()); - + Error Err = Error::success(); + uint64_t StackSize = Data.getULEB128(Offset, &Err); + if (Err) { + reportUniqueWarning("could not extract a valid stack size from " + + describe(StackSizeSec) + ": " + + toString(std::move(Err))); + return false; + } printStackSizeEntry(StackSize, FuncName); + return true; } template <class ELFT> -void GNUStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) { +void GNUELFDumper<ELFT>::printStackSizeEntry(uint64_t Size, + StringRef FuncName) { OS.PadToColumn(2); OS << format_decimal(Size, 11); OS.PadToColumn(18); @@ -5721,108 +5544,98 @@ void GNUStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) { } template <class ELFT> -void DumpStyle<ELFT>::printStackSize(const ELFObjectFile<ELFT> *Obj, - RelocationRef Reloc, - SectionRef FunctionSec, - const StringRef &StackSizeSectionName, +void ELFDumper<ELFT>::printStackSize(const Relocation<ELFT> &R, + const Elf_Shdr &RelocSec, unsigned Ndx, + const Elf_Shdr *SymTab, + const Elf_Shdr *FunctionSec, + const Elf_Shdr &StackSizeSec, const RelocationResolver &Resolver, DataExtractor Data) { // This function ignores potentially erroneous input, unless it is directly // related to stack size reporting. - object::symbol_iterator RelocSym = Reloc.getSymbol(); + const Elf_Sym *Sym = nullptr; + Expected<RelSymbol<ELFT>> TargetOrErr = this->getRelocationTarget(R, SymTab); + if (!TargetOrErr) + reportUniqueWarning("unable to get the target of relocation with index " + + Twine(Ndx) + " in " + describe(RelocSec) + ": " + + toString(TargetOrErr.takeError())); + else + Sym = TargetOrErr->Sym; + uint64_t RelocSymValue = 0; - StringRef FileStr = Obj->getFileName(); - if (RelocSym != Obj->symbol_end()) { - // Ensure that the relocation symbol is in the function section, i.e. the - // section where the functions whose stack sizes we are reporting are - // located. - auto SectionOrErr = RelocSym->getSection(); + if (Sym) { + Expected<const Elf_Shdr *> SectionOrErr = + this->Obj.getSection(*Sym, SymTab, this->getShndxTable(SymTab)); if (!SectionOrErr) { - reportWarning( - createError("cannot identify the section for relocation symbol '" + - getSymbolName(*RelocSym) + "'"), - FileStr); - consumeError(SectionOrErr.takeError()); + reportUniqueWarning( + "cannot identify the section for relocation symbol '" + + (*TargetOrErr).Name + "': " + toString(SectionOrErr.takeError())); } else if (*SectionOrErr != FunctionSec) { - reportWarning(createError("relocation symbol '" + - getSymbolName(*RelocSym) + - "' is not in the expected section"), - FileStr); + reportUniqueWarning("relocation symbol '" + (*TargetOrErr).Name + + "' is not in the expected section"); // Pretend that the symbol is in the correct section and report its // stack size anyway. - FunctionSec = **SectionOrErr; + FunctionSec = *SectionOrErr; } - Expected<uint64_t> RelocSymValueOrErr = RelocSym->getValue(); - if (RelocSymValueOrErr) - RelocSymValue = *RelocSymValueOrErr; - else - consumeError(RelocSymValueOrErr.takeError()); + RelocSymValue = Sym->st_value; } - uint64_t Offset = Reloc.getOffset(); - if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) - reportError( - createStringError(object_error::parse_failed, - "found invalid relocation offset into section %s " - "while trying to extract a stack size entry", - StackSizeSectionName.data()), - FileStr); + uint64_t Offset = R.Offset; + if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) { + reportUniqueWarning("found invalid relocation offset (0x" + + Twine::utohexstr(Offset) + ") into " + + describe(StackSizeSec) + + " while trying to extract a stack size entry"); + return; + } - uint64_t Addend = Data.getAddress(&Offset); - uint64_t SymValue = Resolver(Reloc, RelocSymValue, Addend); - this->printFunctionStackSize(Obj, SymValue, FunctionSec, StackSizeSectionName, - Data, &Offset); + uint64_t SymValue = + Resolver(R.Type, Offset, RelocSymValue, Data.getAddress(&Offset), + R.Addend.getValueOr(0)); + this->printFunctionStackSize(SymValue, FunctionSec, StackSizeSec, Data, + &Offset); } template <class ELFT> -void DumpStyle<ELFT>::printNonRelocatableStackSizes( - const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) { +void ELFDumper<ELFT>::printNonRelocatableStackSizes( + std::function<void()> PrintHeader) { // This function ignores potentially erroneous input, unless it is directly // related to stack size reporting. - const ELFFile<ELFT> *EF = Obj->getELFFile(); - StringRef FileStr = Obj->getFileName(); - for (const SectionRef &Sec : Obj->sections()) { - StringRef SectionName = getSectionName(Sec); - if (SectionName != ".stack_sizes") + for (const Elf_Shdr &Sec : cantFail(Obj.sections())) { + if (this->getPrintableSectionName(Sec) != ".stack_sizes") continue; PrintHeader(); - const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl()); ArrayRef<uint8_t> Contents = - unwrapOrError(this->FileName, EF->getSectionContents(ElfSec)); - DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr)); + unwrapOrError(this->FileName, Obj.getSectionContents(Sec)); + DataExtractor Data(Contents, Obj.isLE(), sizeof(Elf_Addr)); uint64_t Offset = 0; while (Offset < Contents.size()) { // The function address is followed by a ULEB representing the stack // size. Check for an extra byte before we try to process the entry. if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Elf_Addr) + 1)) { - reportError( - createStringError( - object_error::parse_failed, - "section %s ended while trying to extract a stack size entry", - SectionName.data()), - FileStr); + reportUniqueWarning( + describe(Sec) + + " ended while trying to extract a stack size entry"); + break; } uint64_t SymValue = Data.getAddress(&Offset); - printFunctionStackSize(Obj, SymValue, /*FunctionSec=*/None, SectionName, - Data, &Offset); + if (!printFunctionStackSize(SymValue, /*FunctionSec=*/None, Sec, Data, + &Offset)) + break; } } } template <class ELFT> -void DumpStyle<ELFT>::printRelocatableStackSizes( - const ELFObjectFile<ELFT> *Obj, std::function<void()> PrintHeader) { - const ELFFile<ELFT> *EF = Obj->getELFFile(); - +void ELFDumper<ELFT>::printRelocatableStackSizes( + std::function<void()> PrintHeader) { // Build a map between stack size sections and their corresponding relocation // sections. - llvm::MapVector<SectionRef, SectionRef> StackSizeRelocMap; - const SectionRef NullSection{}; - - for (const SectionRef &Sec : Obj->sections()) { + llvm::MapVector<const Elf_Shdr *, const Elf_Shdr *> StackSizeRelocMap; + for (const Elf_Shdr &Sec : cantFail(Obj.sections())) { StringRef SectionName; - if (Expected<StringRef> NameOrErr = Sec.getName()) + if (Expected<StringRef> NameOrErr = Obj.getSectionName(Sec)) SectionName = *NameOrErr; else consumeError(NameOrErr.takeError()); @@ -5830,84 +5643,83 @@ void DumpStyle<ELFT>::printRelocatableStackSizes( // A stack size section that we haven't encountered yet is mapped to the // null section until we find its corresponding relocation section. if (SectionName == ".stack_sizes") - if (StackSizeRelocMap.count(Sec) == 0) { - StackSizeRelocMap[Sec] = NullSection; + if (StackSizeRelocMap + .insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr)) + .second) continue; - } // Check relocation sections if they are relocating contents of a // stack sizes section. - const Elf_Shdr *ElfSec = Obj->getSection(Sec.getRawDataRefImpl()); - uint32_t SectionType = ElfSec->sh_type; - if (SectionType != ELF::SHT_RELA && SectionType != ELF::SHT_REL) + if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL) continue; - Expected<section_iterator> RelSecOrErr = Sec.getRelocatedSection(); - if (!RelSecOrErr) - reportError(createStringError(object_error::parse_failed, - "%s: failed to get a relocated section: %s", - SectionName.data(), - toString(RelSecOrErr.takeError()).c_str()), - Obj->getFileName()); - - const Elf_Shdr *ContentsSec = - Obj->getSection((*RelSecOrErr)->getRawDataRefImpl()); - Expected<StringRef> ContentsSectionNameOrErr = - EF->getSectionName(ContentsSec); - if (!ContentsSectionNameOrErr) { - consumeError(ContentsSectionNameOrErr.takeError()); + Expected<const Elf_Shdr *> RelSecOrErr = Obj.getSection(Sec.sh_info); + if (!RelSecOrErr) { + reportUniqueWarning(describe(Sec) + + ": failed to get a relocated section: " + + toString(RelSecOrErr.takeError())); continue; } - if (*ContentsSectionNameOrErr != ".stack_sizes") + + const Elf_Shdr *ContentsSec = *RelSecOrErr; + if (this->getPrintableSectionName(**RelSecOrErr) != ".stack_sizes") continue; + // Insert a mapping from the stack sizes section to its relocation section. - StackSizeRelocMap[Obj->toSectionRef(ContentsSec)] = Sec; + StackSizeRelocMap[ContentsSec] = &Sec; } for (const auto &StackSizeMapEntry : StackSizeRelocMap) { PrintHeader(); - const SectionRef &StackSizesSec = StackSizeMapEntry.first; - const SectionRef &RelocSec = StackSizeMapEntry.second; + const Elf_Shdr *StackSizesELFSec = StackSizeMapEntry.first; + const Elf_Shdr *RelocSec = StackSizeMapEntry.second; // Warn about stack size sections without a relocation section. - StringRef StackSizeSectionName = getSectionName(StackSizesSec); - if (RelocSec == NullSection) { - reportWarning(createError("section " + StackSizeSectionName + - " does not have a corresponding " + if (!RelocSec) { + reportWarning(createError(".stack_sizes (" + describe(*StackSizesELFSec) + + ") does not have a corresponding " "relocation section"), - Obj->getFileName()); + FileName); continue; } // A .stack_sizes section header's sh_link field is supposed to point // to the section that contains the functions whose stack sizes are // described in it. - const Elf_Shdr *StackSizesELFSec = - Obj->getSection(StackSizesSec.getRawDataRefImpl()); - const SectionRef FunctionSec = Obj->toSectionRef(unwrapOrError( - this->FileName, EF->getSection(StackSizesELFSec->sh_link))); + const Elf_Shdr *FunctionSec = unwrapOrError( + this->FileName, Obj.getSection(StackSizesELFSec->sh_link)); - bool (*IsSupportedFn)(uint64_t); + SupportsRelocation IsSupportedFn; RelocationResolver Resolver; - std::tie(IsSupportedFn, Resolver) = getRelocationResolver(*Obj); - auto Contents = unwrapOrError(this->FileName, StackSizesSec.getContents()); - DataExtractor Data(Contents, Obj->isLittleEndian(), sizeof(Elf_Addr)); - for (const RelocationRef &Reloc : RelocSec.relocations()) { - if (!IsSupportedFn || !IsSupportedFn(Reloc.getType())) - reportError(createStringError( - object_error::parse_failed, - "unsupported relocation type in section %s: %s", - getSectionName(RelocSec).data(), - EF->getRelocationTypeName(Reloc.getType()).data()), - Obj->getFileName()); - this->printStackSize(Obj, Reloc, FunctionSec, StackSizeSectionName, - Resolver, Data); - } + std::tie(IsSupportedFn, Resolver) = getRelocationResolver(this->ObjF); + ArrayRef<uint8_t> Contents = + unwrapOrError(this->FileName, Obj.getSectionContents(*StackSizesELFSec)); + DataExtractor Data(Contents, Obj.isLE(), sizeof(Elf_Addr)); + + forEachRelocationDo( + *RelocSec, /*RawRelr=*/false, + [&](const Relocation<ELFT> &R, unsigned Ndx, const Elf_Shdr &Sec, + const Elf_Shdr *SymTab) { + if (!IsSupportedFn || !IsSupportedFn(R.Type)) { + reportUniqueWarning( + describe(*RelocSec) + + " contains an unsupported relocation with index " + Twine(Ndx) + + ": " + Obj.getRelocationTypeName(R.Type)); + return; + } + + this->printStackSize(R, *RelocSec, Ndx, SymTab, FunctionSec, + *StackSizesELFSec, Resolver, Data); + }, + [](const Elf_Relr &) { + llvm_unreachable("can't get here, because we only support " + "SHT_REL/SHT_RELA sections"); + }); } } template <class ELFT> -void GNUStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) { +void GNUELFDumper<ELFT>::printStackSizes() { bool HeaderHasBeenPrinted = false; auto PrintHeader = [&]() { if (HeaderHasBeenPrinted) @@ -5922,14 +5734,14 @@ void GNUStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) { // For non-relocatable objects, look directly for sections whose name starts // with .stack_sizes and process the contents. - if (Obj->isRelocatableObject()) - this->printRelocatableStackSizes(Obj, PrintHeader); + if (this->Obj.getHeader().e_type == ELF::ET_REL) + this->printRelocatableStackSizes(PrintHeader); else - this->printNonRelocatableStackSizes(Obj, PrintHeader); + this->printNonRelocatableStackSizes(PrintHeader); } template <class ELFT> -void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { +void GNUELFDumper<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { size_t Bias = ELFT::Is64Bits ? 8 : 0; auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) { OS.PadToColumn(2); @@ -5977,10 +5789,14 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { << " Type Ndx Name\n"; else OS << " Address Access Initial Sym.Val. Type Ndx Name\n"; + + DataRegion<Elf_Word> ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); for (auto &E : Parser.getGlobalEntries()) { - const Elf_Sym *Sym = Parser.getGotSym(&E); - std::string SymName = this->dumper()->getFullSymbolName( - Sym, this->dumper()->getDynamicStringTable(), false); + const Elf_Sym &Sym = *Parser.getGotSym(&E); + const Elf_Sym &FirstSym = this->dynamic_symbols()[0]; + std::string SymName = this->getFullSymbolName( + Sym, &Sym - &FirstSym, ShndxTable, this->DynamicStringTable, false); OS.PadToColumn(2); OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias)); @@ -5989,12 +5805,12 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { OS.PadToColumn(22 + Bias); OS << to_string(format_hex_no_prefix(E, 8 + Bias)); OS.PadToColumn(31 + 2 * Bias); - OS << to_string(format_hex_no_prefix(Sym->st_value, 8 + Bias)); + OS << to_string(format_hex_no_prefix(Sym.st_value, 8 + Bias)); OS.PadToColumn(40 + 3 * Bias); - OS << printEnum(Sym->getType(), makeArrayRef(ElfSymbolTypes)); + OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes)); OS.PadToColumn(48 + 3 * Bias); - OS << getSymbolSectionNdx(Parser.Obj, Sym, - this->dumper()->dynamic_symbols().begin()); + OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(), + ShndxTable); OS.PadToColumn(52 + 3 * Bias); OS << SymName << "\n"; } @@ -6006,7 +5822,7 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { } template <class ELFT> -void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { +void GNUELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { size_t Bias = ELFT::Is64Bits ? 8 : 0; auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) { OS.PadToColumn(2); @@ -6029,22 +5845,26 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { OS << "\n"; OS << " Entries:\n"; OS << " Address Initial Sym.Val. Type Ndx Name\n"; + DataRegion<Elf_Word> ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); for (auto &E : Parser.getPltEntries()) { - const Elf_Sym *Sym = Parser.getPltSym(&E); - std::string SymName = this->dumper()->getFullSymbolName( - Sym, this->dumper()->getDynamicStringTable(), false); + const Elf_Sym &Sym = *Parser.getPltSym(&E); + const Elf_Sym &FirstSym = *cantFail( + this->Obj.template getEntry<Elf_Sym>(*Parser.getPltSymTable(), 0)); + std::string SymName = this->getFullSymbolName( + Sym, &Sym - &FirstSym, ShndxTable, this->DynamicStringTable, false); OS.PadToColumn(2); 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); - OS << to_string(format_hex_no_prefix(Sym->st_value, 8 + Bias)); + OS << to_string(format_hex_no_prefix(Sym.st_value, 8 + Bias)); OS.PadToColumn(29 + 3 * Bias); - OS << printEnum(Sym->getType(), makeArrayRef(ElfSymbolTypes)); + OS << printEnum(Sym.getType(), makeArrayRef(ElfSymbolTypes)); OS.PadToColumn(37 + 3 * Bias); - OS << getSymbolSectionNdx(Parser.Obj, Sym, - this->dumper()->dynamic_symbols().begin()); + OS << getSymbolSectionNdx(Sym, &Sym - this->dynamic_symbols().begin(), + ShndxTable); OS.PadToColumn(41 + 3 * Bias); OS << SymName << "\n"; } @@ -6052,20 +5872,33 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { } template <class ELFT> -void GNUStyle<ELFT>::printMipsABIFlags(const ELFObjectFile<ELFT> *ObjF) { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const Elf_Shdr *Shdr = - findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.abiflags"); - if (!Shdr) - return; +Expected<const Elf_Mips_ABIFlags<ELFT> *> +getMipsAbiFlagsSection(const ELFDumper<ELFT> &Dumper) { + const typename ELFT::Shdr *Sec = Dumper.findSectionByName(".MIPS.abiflags"); + if (Sec == nullptr) + return nullptr; - ArrayRef<uint8_t> Sec = - unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); - if (Sec.size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) - reportError(createError(".MIPS.abiflags section has a wrong size"), - ObjF->getFileName()); + constexpr StringRef ErrPrefix = "unable to read the .MIPS.abiflags section: "; + Expected<ArrayRef<uint8_t>> DataOrErr = + Dumper.getElfObject().getELFFile().getSectionContents(*Sec); + if (!DataOrErr) + return createError(ErrPrefix + toString(DataOrErr.takeError())); + + if (DataOrErr->size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) + return createError(ErrPrefix + "it has a wrong size (" + + Twine(DataOrErr->size()) + ")"); + return reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(DataOrErr->data()); +} - auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec.data()); +template <class ELFT> void GNUELFDumper<ELFT>::printMipsABIFlags() { + const Elf_Mips_ABIFlags<ELFT> *Flags = nullptr; + if (Expected<const Elf_Mips_ABIFlags<ELFT> *> SecOrErr = + getMipsAbiFlagsSection(*this)) + Flags = *SecOrErr; + else + this->reportUniqueWarning(SecOrErr.takeError()); + if (!Flags) + return; OS << "MIPS ABI Flags Version: " << Flags->version << "\n\n"; OS << "ISA: MIPS" << int(Flags->isa_level); @@ -6090,22 +5923,22 @@ void GNUStyle<ELFT>::printMipsABIFlags(const ELFObjectFile<ELFT> *ObjF) { OS << "\n"; } -template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { - const Elf_Ehdr *E = Obj->getHeader(); +template <class ELFT> void LLVMELFDumper<ELFT>::printFileHeaders() { + const Elf_Ehdr &E = this->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; @@ -6117,43 +5950,54 @@ 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), + std::string TypeStr; + if (const EnumEntry<unsigned> *Ent = getObjectFileEnumEntry(E.e_type)) { + TypeStr = Ent->Name.str(); + } else { + if (E.e_type >= ET_LOPROC) + TypeStr = "Processor Specific"; + else if (E.e_type >= ET_LOOS) + TypeStr = "OS Specific"; + else + TypeStr = "Unknown"; + } + W.printString("Type", TypeStr + " (0x" + to_hexString(E.e_type) + ")"); + + 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, this->FileName)); + getSectionHeadersNumString(this->Obj, this->FileName)); W.printString("StringTableSectionIndex", - getSectionHeaderTableIndexString(Obj, this->FileName)); + getSectionHeaderTableIndexString(this->Obj, this->FileName)); } } -template <class ELFT> -void LLVMStyle<ELFT>::printGroupSections(const ELFO *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printGroupSections() { DictScope Lists(W, "Groups"); - std::vector<GroupSection> V = getGroups<ELFT>(Obj, this->FileName); + std::vector<GroupSection> V = this->getGroups(); DenseMap<uint64_t, const GroupSection *> Map = mapSectionsToGroups(V); for (const GroupSection &G : V) { DictScope D(W, "Group"); @@ -6167,15 +6011,13 @@ void LLVMStyle<ELFT>::printGroupSections(const ELFO *Obj) { ListScope L(W, "Section(s) in group"); for (const GroupMember &GM : G.Members) { const GroupSection *MainGroup = Map[GM.Index]; - if (MainGroup != &G) { - W.flush(); - errs() << "Error: " << GM.Name << " (" << GM.Index - << ") in a group " + G.Name + " (" << G.Index - << ") is already in a group " + MainGroup->Name + " (" - << MainGroup->Index << ")\n"; - errs().flush(); - continue; - } + if (MainGroup != &G) + this->reportUniqueWarning( + "section with index " + Twine(GM.Index) + + ", included in the group section with index " + + Twine(MainGroup->Index) + + ", was also found in the group section with index " + + Twine(G.Index)); W.startLine() << GM.Name << " (" << GM.Index << ")\n"; } } @@ -6184,129 +6026,66 @@ void LLVMStyle<ELFT>::printGroupSections(const ELFO *Obj) { W.startLine() << "There are no group sections in the file.\n"; } -template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printRelocations() { ListScope D(W, "Relocations"); - int SectionNumber = -1; - for (const Elf_Shdr &Sec : cantFail(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 && - Sec.sh_type != ELF::SHT_ANDROID_RELA && - Sec.sh_type != ELF::SHT_ANDROID_RELR) + for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { + if (!isRelocationSec<ELFT>(Sec)) continue; - StringRef Name = unwrapOrError(this->FileName, Obj->getSectionName(&Sec)); - - W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + StringRef Name = this->getPrintableSectionName(Sec); + unsigned SecNdx = &Sec - &cantFail(this->Obj.sections()).front(); + W.startLine() << "Section (" << SecNdx << ") " << Name << " {\n"; W.indent(); - - printRelocations(&Sec, Obj); - + this->printRelocationsHelper(Sec); W.unindent(); W.startLine() << "}\n"; } } template <class ELFT> -void LLVMStyle<ELFT>::printRelocations(const Elf_Shdr *Sec, const ELFO *Obj) { - const Elf_Shdr *SymTab = - unwrapOrError(this->FileName, Obj->getSection(Sec->sh_link)); - unsigned SecNdx = Sec - &cantFail(Obj->sections()).front(); - unsigned RelNdx = 0; - - switch (Sec->sh_type) { - case ELF::SHT_REL: - for (const Elf_Rel &R : unwrapOrError(this->FileName, Obj->rels(Sec))) { - Elf_Rela Rela; - Rela.r_offset = R.r_offset; - Rela.r_info = R.r_info; - Rela.r_addend = 0; - printRelocation(Obj, SecNdx, Rela, ++RelNdx, SymTab); - } - break; - case ELF::SHT_RELA: - for (const Elf_Rela &R : unwrapOrError(this->FileName, Obj->relas(Sec))) - printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab); - break; - case ELF::SHT_RELR: - case ELF::SHT_ANDROID_RELR: { - Elf_Relr_Range Relrs = unwrapOrError(this->FileName, 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(this->FileName, Obj->decode_relrs(Relrs)); - for (const Elf_Rela &R : RelrRelas) - printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab); - } - break; - } - case ELF::SHT_ANDROID_REL: - case ELF::SHT_ANDROID_RELA: - for (const Elf_Rela &R : - unwrapOrError(this->FileName, Obj->android_relas(Sec))) - printRelocation(Obj, SecNdx, R, ++RelNdx, SymTab); - break; - } +void LLVMELFDumper<ELFT>::printRelrReloc(const Elf_Relr &R) { + W.startLine() << W.hex(R) << "\n"; } template <class ELFT> -void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, unsigned SecIndex, - Elf_Rela Rel, unsigned RelIndex, - const Elf_Shdr *SymTab) { - Expected<std::pair<const typename ELFT::Sym *, std::string>> Target = - this->dumper()->getRelocationTarget(SymTab, Rel); - if (!Target) { - this->reportUniqueWarning(createError( - "unable to print relocation " + Twine(RelIndex) + " in section " + - Twine(SecIndex) + ": " + toString(Target.takeError()))); - return; - } - - std::string TargetName = Target->second; +void LLVMELFDumper<ELFT>::printRelRelaReloc(const Relocation<ELFT> &R, + const RelSymbol<ELFT> &RelSym) { + StringRef SymbolName = RelSym.Name; SmallString<32> RelocName; - Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); + this->Obj.getRelocationTypeName(R.Type, RelocName); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); - W.printHex("Offset", Rel.r_offset); - W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); - W.printNumber("Symbol", !TargetName.empty() ? TargetName : "-", - Rel.getSymbol(Obj->isMips64EL())); - W.printHex("Addend", Rel.r_addend); + W.printHex("Offset", R.Offset); + W.printNumber("Type", RelocName, R.Type); + W.printNumber("Symbol", !SymbolName.empty() ? SymbolName : "-", R.Symbol); + if (R.Addend) + W.printHex("Addend", (uintX_t)*R.Addend); } else { raw_ostream &OS = W.startLine(); - OS << W.hex(Rel.r_offset) << " " << RelocName << " " - << (!TargetName.empty() ? TargetName : "-") << " " << W.hex(Rel.r_addend) - << "\n"; + OS << W.hex(R.Offset) << " " << RelocName << " " + << (!SymbolName.empty() ? SymbolName : "-"); + if (R.Addend) + OS << " " << W.hex((uintX_t)*R.Addend); + OS << "\n"; } } -template <class ELFT> -void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printSectionHeaders() { ListScope SectionsD(W, "Sections"); int SectionIndex = -1; std::vector<EnumEntry<unsigned>> FlagsList = - getSectionFlagsForTarget(Obj->getHeader()->e_machine); - for (const Elf_Shdr &Sec : cantFail(Obj->sections())) { - StringRef Name = "<?>"; - if (Expected<StringRef> SecNameOrErr = - Obj->getSectionName(&Sec, this->dumper()->WarningHandler)) - Name = *SecNameOrErr; - else - this->reportUniqueWarning(SecNameOrErr.takeError()); - + getSectionFlagsForTarget(this->Obj.getHeader().e_machine); + for (const Elf_Shdr &Sec : cantFail(this->Obj.sections())) { DictScope SectionD(W, "Section"); W.printNumber("Index", ++SectionIndex); - W.printNumber("Name", Name, Sec.sh_name); - W.printHex( - "Type", - object::getELFSectionTypeName(Obj->getHeader()->e_machine, Sec.sh_type), - Sec.sh_type); + W.printNumber("Name", this->getPrintableSectionName(Sec), Sec.sh_name); + W.printHex("Type", + object::getELFSectionTypeName(this->Obj.getHeader().e_machine, + Sec.sh_type), + Sec.sh_type); W.printFlags("Flags", Sec.sh_flags, makeArrayRef(FlagsList)); W.printHex("Address", Sec.sh_addr); W.printHex("Offset", Sec.sh_offset); @@ -6318,31 +6097,33 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { if (opts::SectionRelocations) { ListScope D(W, "Relocations"); - printRelocations(&Sec, Obj); + this->printRelocationsHelper(Sec); } if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - const Elf_Shdr *Symtab = this->dumper()->getDotSymtabSec(); - StringRef StrTable = - unwrapOrError(this->FileName, Obj->getStringTableForSymtab(*Symtab)); - - for (const Elf_Sym &Sym : - unwrapOrError(this->FileName, Obj->symbols(Symtab))) { - const Elf_Shdr *SymSec = unwrapOrError( + if (this->DotSymtabSec) { + StringRef StrTable = unwrapOrError( this->FileName, - Obj->getSection(&Sym, Symtab, this->dumper()->getShndxTable())); - if (SymSec == &Sec) - printSymbol( - Obj, &Sym, - unwrapOrError(this->FileName, Obj->symbols(Symtab)).begin(), - StrTable, false, false); + this->Obj.getStringTableForSymtab(*this->DotSymtabSec)); + ArrayRef<Elf_Word> ShndxTable = this->getShndxTable(this->DotSymtabSec); + + typename ELFT::SymRange Symbols = unwrapOrError( + this->FileName, this->Obj.symbols(this->DotSymtabSec)); + for (const Elf_Sym &Sym : Symbols) { + const Elf_Shdr *SymSec = unwrapOrError( + this->FileName, + this->Obj.getSection(Sym, this->DotSymtabSec, ShndxTable)); + if (SymSec == &Sec) + printSymbol(Sym, &Sym - &Symbols[0], ShndxTable, StrTable, false, + false); + } } } if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) { ArrayRef<uint8_t> Data = - unwrapOrError(this->FileName, Obj->getSectionContents(&Sec)); + unwrapOrError(this->FileName, this->Obj.getSectionContents(Sec)); W.printBinaryBlock( "SectionData", StringRef(reinterpret_cast<const char *>(Data.data()), Data.size())); @@ -6351,12 +6132,34 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { } template <class ELFT> -void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol, - const Elf_Sym *First) { +void LLVMELFDumper<ELFT>::printSymbolSection( + const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable) const { + auto GetSectionSpecialType = [&]() -> Optional<StringRef> { + if (Symbol.isUndefined()) + return StringRef("Undefined"); + if (Symbol.isProcessorSpecific()) + return StringRef("Processor Specific"); + if (Symbol.isOSSpecific()) + return StringRef("Operating System Specific"); + if (Symbol.isAbsolute()) + return StringRef("Absolute"); + if (Symbol.isCommon()) + return StringRef("Common"); + if (Symbol.isReserved() && Symbol.st_shndx != SHN_XINDEX) + return StringRef("Reserved"); + return None; + }; + + if (Optional<StringRef> Type = GetSectionSpecialType()) { + W.printHex("Section", *Type, Symbol.st_shndx); + return; + } + Expected<unsigned> SectionIndex = - this->dumper()->getSymbolSectionIndex(Symbol, First); + this->getSymbolSectionIndex(Symbol, SymIndex, ShndxTable); if (!SectionIndex) { - assert(Symbol->st_shndx == SHN_XINDEX && + assert(Symbol.st_shndx == SHN_XINDEX && "getSymbolSectionIndex should only fail due to an invalid " "SHT_SYMTAB_SHNDX table/reference"); this->reportUniqueWarning(SectionIndex.takeError()); @@ -6365,11 +6168,11 @@ void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol, } Expected<StringRef> SectionName = - this->dumper()->getSymbolSectionName(Symbol, *SectionIndex); + this->getSymbolSectionName(Symbol, *SectionIndex); if (!SectionName) { // Don't report an invalid section name if the section headers are missing. // In such situations, all sections will be "invalid". - if (!this->dumper()->getElfObject()->sections().empty()) + if (!this->ObjF.sections().empty()) this->reportUniqueWarning(SectionName.takeError()); else consumeError(SectionName.takeError()); @@ -6380,36 +6183,37 @@ void LLVMStyle<ELFT>::printSymbolSection(const Elf_Sym *Symbol, } template <class ELFT> -void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, - const Elf_Sym *First, - Optional<StringRef> StrTable, bool IsDynamic, - bool /*NonVisibilityBitsUsed*/) { - std::string FullSymbolName = - this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); - unsigned char SymbolType = Symbol->getType(); +void LLVMELFDumper<ELFT>::printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, + DataRegion<Elf_Word> ShndxTable, + Optional<StringRef> StrTable, + bool IsDynamic, + bool /*NonVisibilityBitsUsed*/) const { + std::string FullSymbolName = this->getFullSymbolName( + Symbol, SymIndex, ShndxTable, StrTable, IsDynamic); + unsigned char SymbolType = Symbol.getType(); DictScope D(W, "Symbol"); - W.printNumber("Name", FullSymbolName, Symbol->st_name); - W.printHex("Value", Symbol->st_value); - W.printNumber("Size", Symbol->st_size); - W.printEnum("Binding", Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); - if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU && + W.printNumber("Name", FullSymbolName, Symbol.st_name); + W.printHex("Value", Symbol.st_value); + W.printNumber("Size", Symbol.st_size); + W.printEnum("Binding", Symbol.getBinding(), makeArrayRef(ElfSymbolBindings)); + if (this->Obj.getHeader().e_machine == ELF::EM_AMDGPU && SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) W.printEnum("Type", SymbolType, makeArrayRef(AMDGPUSymbolTypes)); else W.printEnum("Type", SymbolType, makeArrayRef(ElfSymbolTypes)); - if (Symbol->st_other == 0) + if (Symbol.st_other == 0) // Usually st_other flag is zero. Do not pollute the output // by flags enumeration in that case. W.printNumber("Other", 0); else { std::vector<EnumEntry<unsigned>> SymOtherFlags(std::begin(ElfSymOtherFlags), std::end(ElfSymOtherFlags)); - if (Obj->getHeader()->e_machine == EM_MIPS) { + if (this->Obj.getHeader().e_machine == EM_MIPS) { // Someones in their infinite wisdom decided to make STO_MIPS_MIPS16 // flag overlapped with other ST_MIPS_xxx flags. So consider both // cases separately. - if ((Symbol->st_other & STO_MIPS_MIPS16) == STO_MIPS_MIPS16) + if ((Symbol.st_other & STO_MIPS_MIPS16) == STO_MIPS_MIPS16) SymOtherFlags.insert(SymOtherFlags.end(), std::begin(ElfMips16SymOtherFlags), std::end(ElfMips16SymOtherFlags)); @@ -6417,40 +6221,37 @@ void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, SymOtherFlags.insert(SymOtherFlags.end(), std::begin(ElfMipsSymOtherFlags), std::end(ElfMipsSymOtherFlags)); + } else if (this->Obj.getHeader().e_machine == EM_AARCH64) { + SymOtherFlags.insert(SymOtherFlags.end(), + std::begin(ElfAArch64SymOtherFlags), + std::end(ElfAArch64SymOtherFlags)); } - W.printFlags("Other", Symbol->st_other, makeArrayRef(SymOtherFlags), 0x3u); + W.printFlags("Other", Symbol.st_other, makeArrayRef(SymOtherFlags), 0x3u); } - printSymbolSection(Symbol, First); -} - -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); + printSymbolSection(Symbol, SymIndex, ShndxTable); } template <class ELFT> -void LLVMStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) { - ListScope Group(W, "DynamicSymbols"); - this->dumper()->printSymbolsHelper(true); +void LLVMELFDumper<ELFT>::printSymbols(bool PrintSymbols, + bool PrintDynamicSymbols) { + if (PrintSymbols) { + ListScope Group(W, "Symbols"); + this->printSymbolsHelper(false); + } + if (PrintDynamicSymbols) { + ListScope Group(W, "DynamicSymbols"); + this->printSymbolsHelper(true); + } } -template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Obj) { - Elf_Dyn_Range Table = this->dumper()->dynamic_table(); +template <class ELFT> void LLVMELFDumper<ELFT>::printDynamicTable() { + Elf_Dyn_Range Table = this->dynamic_table(); if (Table.empty()) return; W.startLine() << "DynamicSection [ (" << Table.size() << " entries)\n"; - size_t MaxTagSize = getMaxDynamicTagSize(Obj, Table); + size_t MaxTagSize = getMaxDynamicTagSize(this->Obj, Table); // The "Name/Value" column should be indented from the "Type" column by N // spaces, where N = MaxTagSize - length of "Type" (4) + trailing // space (1) = -3. @@ -6460,108 +6261,49 @@ template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Ob std::string ValueFmt = "%-" + std::to_string(MaxTagSize) + "s "; for (auto Entry : Table) { uintX_t Tag = Entry.getTag(); - std::string Value = this->dumper()->getDynamicEntry(Tag, Entry.getVal()); + std::string Value = this->getDynamicEntry(Tag, Entry.getVal()); W.startLine() << " " << format_hex(Tag, ELFT::Is64Bits ? 18 : 10, true) << " " << format(ValueFmt.c_str(), - Obj->getDynamicTagAsString(Tag).c_str()) + this->Obj.getDynamicTagAsString(Tag).c_str()) << Value << "\n"; } W.startLine() << "]\n"; } -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(); - +template <class ELFT> void LLVMELFDumper<ELFT>::printDynamicRelocations() { W.startLine() << "Dynamic Relocations {\n"; W.indent(); - if (DynRelaRegion.Size > 0) { - for (const Elf_Rela &Rela : this->dumper()->dyn_relas()) - printDynamicRelocation(Obj, Rela); - } - if (DynRelRegion.Size > 0) { - for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) { - Elf_Rela Rela; - Rela.r_offset = Rel.r_offset; - Rela.r_info = Rel.r_info; - 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(this->FileName, 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); - else - for (const Elf_Rel &Rel : DynPLTRelRegion.getAsArrayRef<Elf_Rel>()) { - Elf_Rela Rela; - Rela.r_offset = Rel.r_offset; - Rela.r_info = Rel.r_info; - Rela.r_addend = 0; - printDynamicRelocation(Obj, Rela); - } + this->printDynamicRelocationsHelper(); W.unindent(); W.startLine() << "}\n"; } template <class ELFT> -void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) { - SmallString<32> RelocName; - Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); - std::string SymbolName = - getSymbolForReloc(Obj, this->FileName, this->dumper(), Rel).Name; - - if (opts::ExpandRelocs) { - DictScope Group(W, "Relocation"); - W.printHex("Offset", Rel.r_offset); - W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); - W.printString("Symbol", !SymbolName.empty() ? SymbolName : "-"); - W.printHex("Addend", Rel.r_addend); - } else { - raw_ostream &OS = W.startLine(); - OS << W.hex(Rel.r_offset) << " " << RelocName << " " - << (!SymbolName.empty() ? SymbolName : "-") << " " << W.hex(Rel.r_addend) - << "\n"; - } -} - -template <class ELFT> -void LLVMStyle<ELFT>::printProgramHeaders( - const ELFO *Obj, bool PrintProgramHeaders, - cl::boolOrDefault PrintSectionMapping) { +void LLVMELFDumper<ELFT>::printProgramHeaders( + bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) { if (PrintProgramHeaders) - printProgramHeaders(Obj); + printProgramHeaders(); if (PrintSectionMapping == cl::BOU_TRUE) - printSectionMapping(Obj); + printSectionMapping(); } -template <class ELFT> -void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printProgramHeaders() { ListScope L(W, "ProgramHeaders"); - Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers(); + Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = this->Obj.program_headers(); if (!PhdrsOrErr) { - this->reportUniqueWarning(createError("unable to dump program headers: " + - toString(PhdrsOrErr.takeError()))); + this->reportUniqueWarning("unable to dump program headers: " + + toString(PhdrsOrErr.takeError())); return; } for (const Elf_Phdr &Phdr : *PhdrsOrErr) { DictScope P(W, "ProgramHeader"); - W.printHex("Type", - getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type), - Phdr.p_type); + StringRef Type = + segmentTypeToString(this->Obj.getHeader().e_machine, Phdr.p_type); + + W.printHex("Type", Type.empty() ? "Unknown" : Type, Phdr.p_type); W.printHex("Offset", Phdr.p_offset); W.printHex("VirtualAddress", Phdr.p_vaddr); W.printHex("PhysicalAddress", Phdr.p_paddr); @@ -6573,16 +6315,16 @@ void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { } template <class ELFT> -void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, - const Elf_Shdr *Sec) { +void LLVMELFDumper<ELFT>::printVersionSymbolSection(const Elf_Shdr *Sec) { ListScope SS(W, "VersionSymbols"); if (!Sec) return; StringRef StrTable; ArrayRef<Elf_Sym> Syms; + const Elf_Shdr *SymTabSec; Expected<ArrayRef<Elf_Versym>> VerTableOrErr = - this->dumper()->getVersionTable(Sec, &Syms, &StrTable); + this->getVersionTable(*Sec, &Syms, &StrTable, &SymTabSec); if (!VerTableOrErr) { this->reportUniqueWarning(VerTableOrErr.takeError()); return; @@ -6591,22 +6333,28 @@ void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, if (StrTable.empty() || Syms.empty() || Syms.size() != VerTableOrErr->size()) return; + ArrayRef<Elf_Word> ShNdxTable = this->getShndxTable(SymTabSec); for (size_t I = 0, E = Syms.size(); I < E; ++I) { DictScope S(W, "Symbol"); W.printNumber("Version", (*VerTableOrErr)[I].vs_index & VERSYM_VERSION); - W.printString("Name", this->dumper()->getFullSymbolName( - &Syms[I], StrTable, /*IsDynamic=*/true)); + W.printString("Name", + this->getFullSymbolName(Syms[I], I, ShNdxTable, StrTable, + /*IsDynamic=*/true)); } } +static const EnumEntry<unsigned> SymVersionFlags[] = { + {"Base", "BASE", VER_FLG_BASE}, + {"Weak", "WEAK", VER_FLG_WEAK}, + {"Info", "INFO", VER_FLG_INFO}}; + template <class ELFT> -void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, - const Elf_Shdr *Sec) { +void LLVMELFDumper<ELFT>::printVersionDefinitionSection(const Elf_Shdr *Sec) { ListScope SD(W, "VersionDefinitions"); if (!Sec) return; - Expected<std::vector<VerDef>> V = this->dumper()->getVersionDefinitions(Sec); + Expected<std::vector<VerDef>> V = this->Obj.getVersionDefinitions(*Sec); if (!V) { this->reportUniqueWarning(V.takeError()); return; @@ -6626,14 +6374,13 @@ void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, } template <class ELFT> -void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, - const Elf_Shdr *Sec) { +void LLVMELFDumper<ELFT>::printVersionDependencySection(const Elf_Shdr *Sec) { ListScope SD(W, "VersionRequirements"); if (!Sec) return; Expected<std::vector<VerNeed>> V = - this->dumper()->getVersionDependencies(Sec); + this->Obj.getVersionDependencies(*Sec, this->WarningHandler); if (!V) { this->reportUniqueWarning(V.takeError()); return; @@ -6656,75 +6403,49 @@ void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, } } -template <class ELFT> -void LLVMStyle<ELFT>::printHashHistograms(const ELFFile<ELFT> *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printHashHistograms() { W.startLine() << "Hash Histogram not implemented!\n"; } -template <class ELFT> -void LLVMStyle<ELFT>::printCGProfile(const ELFFile<ELFT> *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printCGProfile() { ListScope L(W, "CGProfile"); - if (!this->dumper()->getDotCGProfileSec()) + if (!this->DotCGProfileSec) return; Expected<ArrayRef<Elf_CGProfile>> CGProfileOrErr = - Obj->template getSectionContentsAsArray<Elf_CGProfile>( - this->dumper()->getDotCGProfileSec()); + this->Obj.template getSectionContentsAsArray<Elf_CGProfile>( + *this->DotCGProfileSec); if (!CGProfileOrErr) { this->reportUniqueWarning( - createError("unable to dump the SHT_LLVM_CALL_GRAPH_PROFILE section: " + - toString(CGProfileOrErr.takeError()))); + "unable to dump the SHT_LLVM_CALL_GRAPH_PROFILE section: " + + toString(CGProfileOrErr.takeError())); return; } for (const Elf_CGProfile &CGPE : *CGProfileOrErr) { DictScope D(W, "CGProfileEntry"); - W.printNumber("From", this->dumper()->getStaticSymbolName(CGPE.cgp_from), + W.printNumber("From", this->getStaticSymbolName(CGPE.cgp_from), CGPE.cgp_from); - W.printNumber("To", this->dumper()->getStaticSymbolName(CGPE.cgp_to), + W.printNumber("To", this->getStaticSymbolName(CGPE.cgp_to), CGPE.cgp_to); W.printNumber("Weight", CGPE.cgp_weight); } } -static Expected<std::vector<uint64_t>> toULEB128Array(ArrayRef<uint8_t> Data) { - std::vector<uint64_t> Ret; - const uint8_t *Cur = Data.begin(); - const uint8_t *End = Data.end(); - while (Cur != End) { - unsigned Size; - const char *Err; - Ret.push_back(decodeULEB128(Cur, &Size, End, &Err)); - if (Err) - return createError(Err); - Cur += Size; - } - return Ret; -} - -template <class ELFT> -void LLVMStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printAddrsig() { ListScope L(W, "Addrsig"); - if (!this->dumper()->getDotAddrsigSec()) + if (!this->DotAddrsigSec) return; - ArrayRef<uint8_t> Contents = unwrapOrError( - this->FileName, - Obj->getSectionContents(this->dumper()->getDotAddrsigSec())); - Expected<std::vector<uint64_t>> V = toULEB128Array(Contents); - if (!V) { - reportWarning(V.takeError(), this->FileName); + + Expected<std::vector<uint64_t>> SymsOrErr = + decodeAddrsigSection(this->Obj, *this->DotAddrsigSec); + if (!SymsOrErr) { + this->reportUniqueWarning(SymsOrErr.takeError()); return; } - for (uint64_t Sym : *V) { - Expected<std::string> NameOrErr = this->dumper()->getStaticSymbolName(Sym); - if (NameOrErr) { - W.printNumber("Sym", *NameOrErr, Sym); - continue; - } - reportWarning(NameOrErr.takeError(), this->FileName); - W.printNumber("Sym", "<?>", Sym); - } + for (uint64_t Sym : *SymsOrErr) + W.printNumber("Sym", this->getStaticSymbolName(Sym), Sym); } template <typename ELFT> @@ -6752,7 +6473,7 @@ static void printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc, break; case ELF::NT_GNU_PROPERTY_TYPE_0: ListScope D(W, "Property"); - for (const auto &Property : getGNUPropertyList<ELFT>(Desc)) + for (const std::string &Property : getGNUPropertyList<ELFT>(Desc)) W.printString(Property); break; } @@ -6769,19 +6490,22 @@ static void printCoreNoteLLVMStyle(const CoreNote &Note, ScopedPrinter &W) { } } -template <class ELFT> -void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printNotes() { ListScope L(W, "Notes"); - auto PrintHeader = [&](Optional<StringRef> SecName, - const typename ELFT::Off Offset, - const typename ELFT::Addr Size) { + std::unique_ptr<DictScope> NoteScope; + auto StartNotes = [&](Optional<StringRef> SecName, + const typename ELFT::Off Offset, + const typename ELFT::Addr Size) { + NoteScope = std::make_unique<DictScope>(W, "NoteSection"); W.printString("Name", SecName ? *SecName : "<?>"); W.printHex("Offset", Offset); W.printHex("Size", Size); }; - auto ProcessNote = [&](const Elf_Note &Note) { + auto EndNotes = [&] { NoteScope.reset(); }; + + auto ProcessNote = [&](const Elf_Note &Note) -> Error { DictScope D2(W, "Note"); StringRef Name = Note.getName(); ArrayRef<uint8_t> Descriptor = Note.getDesc(); @@ -6790,24 +6514,14 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { // Print the note owner/type. W.printString("Owner", Name); W.printHex("Data size", Descriptor.size()); - if (Name == "GNU") { - W.printString("Type", getGNUNoteTypeName(Type)); - } else if (Name == "FreeBSD") { - W.printString("Type", getFreeBSDNoteTypeName(Type)); - } else if (Name == "AMD") { - W.printString("Type", getAMDNoteTypeName(Type)); - } else if (Name == "AMDGPU") { - W.printString("Type", getAMDGPUNoteTypeName(Type)); - } else { - StringRef NoteType = Obj->getHeader()->e_type == ELF::ET_CORE - ? getCoreNoteTypeName(Type) - : getGenericNoteTypeName(Type); - if (!NoteType.empty()) - W.printString("Type", NoteType); - else - W.printString("Type", - "Unknown (" + to_string(format_hex(Type, 10)) + ")"); - } + + StringRef NoteType = + getNoteTypeName<ELFT>(Note, this->Obj.getHeader().e_type); + if (!NoteType.empty()) + W.printString("Type", NoteType); + else + W.printString("Type", + "Unknown (" + to_string(format_hex(Type, 10)) + ")"); // Print the description, or fallback to printing raw bytes for unknown // owners. @@ -6826,91 +6540,56 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { DataExtractor DescExtractor(Descriptor, ELFT::TargetEndianness == support::little, sizeof(Elf_Addr)); - Expected<CoreNote> Note = readCoreNote(DescExtractor); - if (Note) + if (Expected<CoreNote> Note = readCoreNote(DescExtractor)) printCoreNoteLLVMStyle(*Note, W); else - reportWarning(Note.takeError(), this->FileName); + return Note.takeError(); } } else if (!Descriptor.empty()) { W.printBinaryBlock("Description data", Descriptor); } + return Error::success(); }; - ArrayRef<Elf_Shdr> Sections = cantFail(Obj->sections()); - if (Obj->getHeader()->e_type != ELF::ET_CORE && !Sections.empty()) { - for (const auto &S : Sections) { - if (S.sh_type != SHT_NOTE) - continue; - DictScope D(W, "NoteSection"); - PrintHeader(expectedToOptional(Obj->getSectionName(&S)), S.sh_offset, - S.sh_size); - Error Err = Error::success(); - for (auto Note : Obj->notes(S, Err)) - ProcessNote(Note); - if (Err) - reportError(std::move(Err), this->FileName); - } - } else { - Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj->program_headers(); - if (!PhdrsOrErr) { - this->reportUniqueWarning(createError( - "unable to read program headers to locate the PT_NOTE segment: " + - toString(PhdrsOrErr.takeError()))); - return; - } - - for (const Elf_Phdr &P : *PhdrsOrErr) { - if (P.p_type != PT_NOTE) - continue; - DictScope D(W, "NoteSection"); - PrintHeader(/*SecName=*/None, P.p_offset, P.p_filesz); - Error Err = Error::success(); - for (auto Note : Obj->notes(P, Err)) - ProcessNote(Note); - if (Err) - reportError(std::move(Err), this->FileName); - } - } + printNotesHelper(*this, StartNotes, ProcessNote, EndNotes); } -template <class ELFT> -void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printELFLinkerOptions() { ListScope L(W, "LinkerOptions"); unsigned I = -1; - for (const Elf_Shdr &Shdr : cantFail(Obj->sections())) { + for (const Elf_Shdr &Shdr : cantFail(this->Obj.sections())) { ++I; if (Shdr.sh_type != ELF::SHT_LLVM_LINKER_OPTIONS) continue; - Expected<ArrayRef<uint8_t>> ContentsOrErr = Obj->getSectionContents(&Shdr); + Expected<ArrayRef<uint8_t>> ContentsOrErr = + this->Obj.getSectionContents(Shdr); if (!ContentsOrErr) { - this->reportUniqueWarning( - createError("unable to read the content of the " - "SHT_LLVM_LINKER_OPTIONS section: " + - toString(ContentsOrErr.takeError()))); + this->reportUniqueWarning("unable to read the content of the " + "SHT_LLVM_LINKER_OPTIONS section: " + + toString(ContentsOrErr.takeError())); continue; } if (ContentsOrErr->empty()) continue; if (ContentsOrErr->back() != 0) { - this->reportUniqueWarning( - createError("SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) + - " is broken: the " - "content is not null-terminated")); + this->reportUniqueWarning("SHT_LLVM_LINKER_OPTIONS section at index " + + Twine(I) + + " is broken: the " + "content is not null-terminated"); continue; } SmallVector<StringRef, 16> Strings; toStringRef(ContentsOrErr->drop_back()).split(Strings, '\0'); if (Strings.size() % 2 != 0) { - this->reportUniqueWarning(createError( + this->reportUniqueWarning( "SHT_LLVM_LINKER_OPTIONS section at index " + Twine(I) + " is broken: an incomplete " "key-value pair was found. The last possible key was: \"" + - Strings.back() + "\"")); + Strings.back() + "\""); continue; } @@ -6919,32 +6598,30 @@ void LLVMStyle<ELFT>::printELFLinkerOptions(const ELFFile<ELFT> *Obj) { } } -template <class ELFT> -void LLVMStyle<ELFT>::printDependentLibs(const ELFFile<ELFT> *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printDependentLibs() { ListScope L(W, "DependentLibs"); this->printDependentLibsHelper( - Obj, [](const Elf_Shdr &) {}, + [](const Elf_Shdr &) {}, [this](StringRef Lib, uint64_t) { W.printString(Lib); }); } -template <class ELFT> -void LLVMStyle<ELFT>::printStackSizes(const ELFObjectFile<ELFT> *Obj) { +template <class ELFT> void LLVMELFDumper<ELFT>::printStackSizes() { ListScope L(W, "StackSizes"); - if (Obj->isRelocatableObject()) - this->printRelocatableStackSizes(Obj, []() {}); + if (this->Obj.getHeader().e_type == ELF::ET_REL) + this->printRelocatableStackSizes([]() {}); else - this->printNonRelocatableStackSizes(Obj, []() {}); + this->printNonRelocatableStackSizes([]() {}); } template <class ELFT> -void LLVMStyle<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) { +void LLVMELFDumper<ELFT>::printStackSizeEntry(uint64_t Size, StringRef FuncName) { DictScope D(W, "Entry"); W.printString("Function", FuncName); W.printHex("Size", Size); } template <class ELFT> -void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { +void LLVMELFDumper<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { auto PrintEntry = [&](const Elf_Addr *E) { W.printHex("Address", Parser.getGotAddress(E)); W.printNumber("Access", Parser.getGotOffset(E)); @@ -6986,14 +6663,18 @@ void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { PrintEntry(&E); - const Elf_Sym *Sym = Parser.getGotSym(&E); - W.printHex("Value", Sym->st_value); - W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); - printSymbolSection(Sym, this->dumper()->dynamic_symbols().begin()); + const Elf_Sym &Sym = *Parser.getGotSym(&E); + W.printHex("Value", Sym.st_value); + W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes)); - std::string SymName = this->dumper()->getFullSymbolName( - Sym, this->dumper()->getDynamicStringTable(), true); - W.printNumber("Name", SymName, Sym->st_name); + const unsigned SymIndex = &Sym - this->dynamic_symbols().begin(); + DataRegion<Elf_Word> ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); + printSymbolSection(Sym, SymIndex, ShndxTable); + + std::string SymName = this->getFullSymbolName( + Sym, SymIndex, ShndxTable, this->DynamicStringTable, true); + W.printNumber("Name", SymName, Sym.st_name); } } @@ -7002,7 +6683,7 @@ void LLVMStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { } template <class ELFT> -void LLVMStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { +void LLVMELFDumper<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { auto PrintEntry = [&](const Elf_Addr *E) { W.printHex("Address", Parser.getPltAddress(E)); W.printHex("Initial", *E); @@ -7026,40 +6707,41 @@ void LLVMStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { } { ListScope LS(W, "Entries"); + DataRegion<Elf_Word> ShndxTable( + (const Elf_Word *)this->DynSymTabShndxRegion.Addr, this->Obj.end()); for (auto &E : Parser.getPltEntries()) { DictScope D(W, "Entry"); PrintEntry(&E); - const Elf_Sym *Sym = Parser.getPltSym(&E); - W.printHex("Value", Sym->st_value); - W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); - printSymbolSection(Sym, this->dumper()->dynamic_symbols().begin()); + const Elf_Sym &Sym = *Parser.getPltSym(&E); + W.printHex("Value", Sym.st_value); + W.printEnum("Type", Sym.getType(), makeArrayRef(ElfSymbolTypes)); + printSymbolSection(Sym, &Sym - this->dynamic_symbols().begin(), + ShndxTable); - std::string SymName = - this->dumper()->getFullSymbolName(Sym, Parser.getPltStrTable(), true); - W.printNumber("Name", SymName, Sym->st_name); + const Elf_Sym *FirstSym = cantFail( + this->Obj.template getEntry<Elf_Sym>(*Parser.getPltSymTable(), 0)); + std::string SymName = this->getFullSymbolName( + Sym, &Sym - FirstSym, ShndxTable, Parser.getPltStrTable(), true); + W.printNumber("Name", SymName, Sym.st_name); } } } -template <class ELFT> -void LLVMStyle<ELFT>::printMipsABIFlags(const ELFObjectFile<ELFT> *ObjF) { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - const Elf_Shdr *Shdr = - findSectionByName(*Obj, ObjF->getFileName(), ".MIPS.abiflags"); - if (!Shdr) { - W.startLine() << "There is no .MIPS.abiflags section in the file.\n"; - return; - } - ArrayRef<uint8_t> Sec = - unwrapOrError(ObjF->getFileName(), Obj->getSectionContents(Shdr)); - if (Sec.size() != sizeof(Elf_Mips_ABIFlags<ELFT>)) { - W.startLine() << "The .MIPS.abiflags section has a wrong size.\n"; +template <class ELFT> void LLVMELFDumper<ELFT>::printMipsABIFlags() { + const Elf_Mips_ABIFlags<ELFT> *Flags; + if (Expected<const Elf_Mips_ABIFlags<ELFT> *> SecOrErr = + getMipsAbiFlagsSection(*this)) { + Flags = *SecOrErr; + if (!Flags) { + W.startLine() << "There is no .MIPS.abiflags section in the file.\n"; + return; + } + } else { + this->reportUniqueWarning(SecOrErr.takeError()); return; } - auto *Flags = reinterpret_cast<const Elf_Mips_ABIFlags<ELFT> *>(Sec.data()); - raw_ostream &OS = W.getOStream(); DictScope GS(W, "MIPS ABI Flags"); diff --git a/llvm/tools/llvm-readobj/Error.cpp b/llvm/tools/llvm-readobj/Error.cpp deleted file mode 100644 index 1010f18a58c8..000000000000 --- a/llvm/tools/llvm-readobj/Error.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===- Error.cpp - system_error extensions for llvm-readobj -----*- 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 defines a new error_category for the llvm-readobj tool. -// -//===----------------------------------------------------------------------===// - -#include "Error.h" -#include "llvm/Support/ErrorHandling.h" - -using namespace llvm; - -namespace { -// FIXME: This class is only here to support the transition to llvm::Error. It -// will be removed once this transition is complete. Clients should prefer to -// deal with the Error value directly, rather than converting to error_code. -class _readobj_error_category : public std::error_category { -public: - const char* name() const noexcept override; - std::string message(int ev) const override; -}; -} // namespace - -const char *_readobj_error_category::name() const noexcept { - return "llvm.readobj"; -} - -std::string _readobj_error_category::message(int EV) const { - switch (static_cast<readobj_error>(EV)) { - case readobj_error::success: return "Success"; - case readobj_error::file_not_found: - return "No such file."; - case readobj_error::unsupported_file_format: - return "The file was not recognized as a valid object file."; - case readobj_error::unrecognized_file_format: - return "Unrecognized file type."; - case readobj_error::unsupported_obj_file_format: - return "Unsupported object file format."; - case readobj_error::unknown_symbol: - return "Unknown symbol."; - } - llvm_unreachable("An enumerator of readobj_error does not have a message " - "defined."); -} - -namespace llvm { -const std::error_category &readobj_category() { - static _readobj_error_category o; - return o; -} -} // namespace llvm diff --git a/llvm/tools/llvm-readobj/Error.h b/llvm/tools/llvm-readobj/Error.h deleted file mode 100644 index f390e1b96f8a..000000000000 --- a/llvm/tools/llvm-readobj/Error.h +++ /dev/null @@ -1,40 +0,0 @@ -//===- Error.h - system_error extensions for llvm-readobj -------*- 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 declares a new error_category for the llvm-readobj tool. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TOOLS_LLVM_READOBJ_ERROR_H -#define LLVM_TOOLS_LLVM_READOBJ_ERROR_H - -#include <system_error> - -namespace llvm { -const std::error_category &readobj_category(); - -enum class readobj_error { - success = 0, - file_not_found, - unsupported_file_format, - unrecognized_file_format, - unsupported_obj_file_format, - unknown_symbol -}; - -inline std::error_code make_error_code(readobj_error e) { - return std::error_code(static_cast<int>(e), readobj_category()); -} - -} // namespace llvm - -namespace std { -template <> struct is_error_code_enum<llvm::readobj_error> : std::true_type {}; -} - -#endif diff --git a/llvm/tools/llvm-readobj/MachODumper.cpp b/llvm/tools/llvm-readobj/MachODumper.cpp index 20a60b3df699..c13b1f3bf2a0 100644 --- a/llvm/tools/llvm-readobj/MachODumper.cpp +++ b/llvm/tools/llvm-readobj/MachODumper.cpp @@ -10,7 +10,6 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "ObjDumper.h" #include "StackMapPrinter.h" #include "llvm-readobj.h" @@ -28,7 +27,7 @@ namespace { class MachODumper : public ObjDumper { public: MachODumper(const MachOObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer), Obj(Obj) {} + : ObjDumper(Writer, Obj->getFileName()), Obj(Obj) {} void printFileHeaders() override; void printSectionHeaders() override; @@ -68,15 +67,9 @@ private: namespace llvm { -std::error_code createMachODumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result) { - const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); - if (!MachOObj) - return readobj_error::unsupported_obj_file_format; - - Result.reset(new MachODumper(MachOObj, Writer)); - return readobj_error::success; +std::unique_ptr<ObjDumper> createMachODumper(const object::MachOObjectFile &Obj, + ScopedPrinter &Writer) { + return std::make_unique<MachODumper>(&Obj, Writer); } } // namespace llvm @@ -161,8 +154,9 @@ 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), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_ALL), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64_V8), + LLVM_READOBJ_ENUM_ENT(MachO, CPU_SUBTYPE_ARM64E), }; static const EnumEntry<uint32_t> MachOHeaderCpuSubtypesSPARC[] = { @@ -629,13 +623,20 @@ void MachODumper::printSymbol(const SymbolRef &Symbol) { getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); StringRef SectionName = ""; - Expected<section_iterator> SecIOrErr = Symbol.getSection(); - if (!SecIOrErr) - reportError(SecIOrErr.takeError(), Obj->getFileName()); + // Don't ask a Mach-O STABS symbol for its section unless we know that + // STAB symbol's section field refers to a valid section index. Otherwise + // the symbol may error trying to load a section that does not exist. + // TODO: Add a whitelist of STABS symbol types that contain valid section + // indices. + if (!(MOSymbol.Type & MachO::N_STAB)) { + Expected<section_iterator> SecIOrErr = Symbol.getSection(); + if (!SecIOrErr) + reportError(SecIOrErr.takeError(), Obj->getFileName()); - section_iterator SecI = *SecIOrErr; - if (SecI != Obj->section_end()) - SectionName = unwrapOrError(Obj->getFileName(), SecI->getName()); + section_iterator SecI = *SecIOrErr; + if (SecI != Obj->section_end()) + SectionName = unwrapOrError(Obj->getFileName(), SecI->getName()); + } DictScope D(W, "Symbol"); W.printNumber("Name", SymbolName, MOSymbol.StringIndex); diff --git a/llvm/tools/llvm-readobj/ObjDumper.cpp b/llvm/tools/llvm-readobj/ObjDumper.cpp index ce61f1c53a4d..fc91d81f0784 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.cpp +++ b/llvm/tools/llvm-readobj/ObjDumper.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "ObjDumper.h" -#include "Error.h" #include "llvm-readobj.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Error.h" @@ -27,9 +26,25 @@ static inline Error createError(const Twine &Msg) { return createStringError(object::object_error::parse_failed, Msg); } -ObjDumper::ObjDumper(ScopedPrinter &Writer) : W(Writer) {} +ObjDumper::ObjDumper(ScopedPrinter &Writer, StringRef ObjName) : W(Writer) { + // Dumper reports all non-critical errors as warnings. + // It does not print the same warning more than once. + WarningHandler = [=](const Twine &Msg) { + if (Warnings.insert(Msg.str()).second) + reportWarning(createError(Msg), ObjName); + return Error::success(); + }; +} + +ObjDumper::~ObjDumper() {} + +void ObjDumper::reportUniqueWarning(Error Err) const { + reportUniqueWarning(toString(std::move(Err))); +} -ObjDumper::~ObjDumper() { +void ObjDumper::reportUniqueWarning(const Twine &Msg) const { + cantFail(WarningHandler(Msg), + "WarningHandler should always return ErrorSuccess"); } static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) { @@ -38,7 +53,7 @@ static void printAsPrintable(raw_ostream &W, const uint8_t *Start, size_t Len) { } static std::vector<object::SectionRef> -getSectionRefsByNameOrIndex(const object::ObjectFile *Obj, +getSectionRefsByNameOrIndex(const object::ObjectFile &Obj, ArrayRef<std::string> Sections) { std::vector<object::SectionRef> Ret; std::map<std::string, bool> SecNames; @@ -51,9 +66,9 @@ getSectionRefsByNameOrIndex(const object::ObjectFile *Obj, SecNames.emplace(std::string(Section), false); } - SecIndex = Obj->isELF() ? 0 : 1; - for (object::SectionRef SecRef : Obj->sections()) { - StringRef SecName = unwrapOrError(Obj->getFileName(), SecRef.getName()); + SecIndex = Obj.isELF() ? 0 : 1; + for (object::SectionRef SecRef : Obj.sections()) { + StringRef SecName = unwrapOrError(Obj.getFileName(), SecRef.getName()); auto NameIt = SecNames.find(std::string(SecName)); if (NameIt != SecNames.end()) NameIt->second = true; @@ -69,24 +84,23 @@ getSectionRefsByNameOrIndex(const object::ObjectFile *Obj, if (!S.second) reportWarning( createError(formatv("could not find section '{0}'", S.first).str()), - Obj->getFileName()); + Obj.getFileName()); for (std::pair<unsigned, bool> S : SecIndices) if (!S.second) reportWarning( createError(formatv("could not find section {0}", S.first).str()), - Obj->getFileName()); + Obj.getFileName()); return Ret; } -void ObjDumper::printSectionsAsString(const object::ObjectFile *Obj, +void ObjDumper::printSectionsAsString(const object::ObjectFile &Obj, ArrayRef<std::string> Sections) { bool First = true; for (object::SectionRef Section : getSectionRefsByNameOrIndex(Obj, Sections)) { - StringRef SectionName = - unwrapOrError(Obj->getFileName(), Section.getName()); + StringRef SectionName = unwrapOrError(Obj.getFileName(), Section.getName()); if (!First) W.startLine() << '\n'; @@ -94,7 +108,7 @@ void ObjDumper::printSectionsAsString(const object::ObjectFile *Obj, W.startLine() << "String dump of section '" << SectionName << "':\n"; StringRef SectionContent = - unwrapOrError(Obj->getFileName(), Section.getContents()); + unwrapOrError(Obj.getFileName(), Section.getContents()); const uint8_t *SecContent = SectionContent.bytes_begin(); const uint8_t *CurrentWord = SecContent; @@ -115,13 +129,12 @@ void ObjDumper::printSectionsAsString(const object::ObjectFile *Obj, } } -void ObjDumper::printSectionsAsHex(const object::ObjectFile *Obj, +void ObjDumper::printSectionsAsHex(const object::ObjectFile &Obj, ArrayRef<std::string> Sections) { bool First = true; for (object::SectionRef Section : getSectionRefsByNameOrIndex(Obj, Sections)) { - StringRef SectionName = - unwrapOrError(Obj->getFileName(), Section.getName()); + StringRef SectionName = unwrapOrError(Obj.getFileName(), Section.getName()); if (!First) W.startLine() << '\n'; @@ -129,7 +142,7 @@ void ObjDumper::printSectionsAsHex(const object::ObjectFile *Obj, W.startLine() << "Hex dump of section '" << SectionName << "':\n"; StringRef SectionContent = - unwrapOrError(Obj->getFileName(), Section.getContents()); + unwrapOrError(Obj.getFileName(), Section.getContents()); const uint8_t *SecContent = SectionContent.bytes_begin(); const uint8_t *SecEnd = SecContent + SectionContent.size(); @@ -155,8 +168,9 @@ void ObjDumper::printSectionsAsHex(const object::ObjectFile *Obj, // 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)), - ' '); + W.startLine() << format("%*c", (4 - i) * 8 + (4 - i), ' '); + if (k < 4) + W.startLine() << format("%*c", 8 - k * 2, ' '); TmpSecPtr = SecPtr; for (i = 0; TmpSecPtr + i < SecEnd && i < 16; ++i) diff --git a/llvm/tools/llvm-readobj/ObjDumper.h b/llvm/tools/llvm-readobj/ObjDumper.h index 57477606d6e8..d4e166b504cf 100644 --- a/llvm/tools/llvm-readobj/ObjDumper.h +++ b/llvm/tools/llvm-readobj/ObjDumper.h @@ -16,10 +16,14 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/CommandLine.h" +#include <unordered_set> + namespace llvm { namespace object { class COFFImportFile; class ObjectFile; +class XCOFFObjectFile; +class ELFObjectFileBase; } namespace codeview { class GlobalTypeTableBuilder; @@ -30,9 +34,11 @@ class ScopedPrinter; class ObjDumper { public: - ObjDumper(ScopedPrinter &Writer); + ObjDumper(ScopedPrinter &Writer, StringRef ObjName); virtual ~ObjDumper(); + virtual bool canDumpContent() { return true; } + virtual void printFileHeaders() = 0; virtual void printSectionHeaders() = 0; virtual void printRelocations() = 0; @@ -59,7 +65,7 @@ public: virtual void printNeededLibraries() { } virtual void printSectionAsHex(StringRef SectionName) {} virtual void printHashTable() { } - virtual void printGnuHashTable(const object::ObjectFile *Obj) {} + virtual void printGnuHashTable() {} virtual void printHashSymbols() {} virtual void printLoadName() {} virtual void printVersionInfo() {} @@ -70,7 +76,8 @@ public: virtual void printNotes() {} virtual void printELFLinkerOptions() {} virtual void printStackSizes() {} - virtual void printArchSpecificInfo() { } + virtual void printSectionDetails() {} + virtual void printArchSpecificInfo() {} // Only implemented for PE/COFF. virtual void printCOFFImports() { } @@ -78,6 +85,7 @@ public: virtual void printCOFFDirectives() { } virtual void printCOFFBaseReloc() { } virtual void printCOFFDebugDirectory() { } + virtual void printCOFFTLSDirectory() {} virtual void printCOFFResources() {} virtual void printCOFFLoadConfig() { } virtual void printCodeViewDebugInfo() { } @@ -98,11 +106,15 @@ public: virtual void printStackMap() const = 0; - void printSectionsAsString(const object::ObjectFile *Obj, + void printSectionsAsString(const object::ObjectFile &Obj, ArrayRef<std::string> Sections); - void printSectionsAsHex(const object::ObjectFile *Obj, + void printSectionsAsHex(const object::ObjectFile &Obj, ArrayRef<std::string> Sections); + std::function<Error(const Twine &Msg)> WarningHandler; + void reportUniqueWarning(Error Err) const; + void reportUniqueWarning(const Twine &Msg) const; + protected: ScopedPrinter &W; @@ -111,27 +123,24 @@ private: virtual void printDynamicSymbols() {} virtual void printProgramHeaders() {} virtual void printSectionMapping() {} + + std::unordered_set<std::string> Warnings; }; -std::error_code createCOFFDumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result); +std::unique_ptr<ObjDumper> createCOFFDumper(const object::COFFObjectFile &Obj, + ScopedPrinter &Writer); -std::error_code createELFDumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result); +std::unique_ptr<ObjDumper> createELFDumper(const object::ELFObjectFileBase &Obj, + ScopedPrinter &Writer); -std::error_code createMachODumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result); +std::unique_ptr<ObjDumper> createMachODumper(const object::MachOObjectFile &Obj, + ScopedPrinter &Writer); -std::error_code createWasmDumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result); +std::unique_ptr<ObjDumper> createWasmDumper(const object::WasmObjectFile &Obj, + ScopedPrinter &Writer); -std::error_code createXCOFFDumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result); +std::unique_ptr<ObjDumper> createXCOFFDumper(const object::XCOFFObjectFile &Obj, + ScopedPrinter &Writer); void dumpCOFFImportFile(const object::COFFImportFile *File, ScopedPrinter &Writer); diff --git a/llvm/tools/llvm-readobj/WasmDumper.cpp b/llvm/tools/llvm-readobj/WasmDumper.cpp index a02dbb999826..fb7134d20a85 100644 --- a/llvm/tools/llvm-readobj/WasmDumper.cpp +++ b/llvm/tools/llvm-readobj/WasmDumper.cpp @@ -10,7 +10,6 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "ObjDumper.h" #include "llvm-readobj.h" #include "llvm/Object/Wasm.h" @@ -25,7 +24,7 @@ static const EnumEntry<unsigned> WasmSymbolTypes[] = { #define ENUM_ENTRY(X) \ { #X, wasm::WASM_SYMBOL_TYPE_##X } ENUM_ENTRY(FUNCTION), ENUM_ENTRY(DATA), ENUM_ENTRY(GLOBAL), - ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT), + ENUM_ENTRY(SECTION), ENUM_ENTRY(EVENT), ENUM_ENTRY(TABLE), #undef ENUM_ENTRY }; @@ -58,7 +57,7 @@ static const EnumEntry<unsigned> WasmSymbolFlags[] = { class WasmDumper : public ObjDumper { public: WasmDumper(const WasmObjectFile *Obj, ScopedPrinter &Writer) - : ObjDumper(Writer), Obj(Obj) {} + : ObjDumper(Writer, Obj->getFileName()), Obj(Obj) {} void printFileHeaders() override; void printSectionHeaders() override; @@ -241,14 +240,9 @@ void WasmDumper::printSymbol(const SymbolRef &Sym) { namespace llvm { -std::error_code createWasmDumper(const object::ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result) { - const auto *WasmObj = dyn_cast<WasmObjectFile>(Obj); - assert(WasmObj && "createWasmDumper called with non-wasm object"); - - Result.reset(new WasmDumper(WasmObj, Writer)); - return readobj_error::success; +std::unique_ptr<ObjDumper> createWasmDumper(const object::WasmObjectFile &Obj, + ScopedPrinter &Writer) { + return std::make_unique<WasmDumper>(&Obj, Writer); } } // namespace llvm diff --git a/llvm/tools/llvm-readobj/Win64EHDumper.cpp b/llvm/tools/llvm-readobj/Win64EHDumper.cpp index 380baae2eeb4..7e84c1bca35d 100644 --- a/llvm/tools/llvm-readobj/Win64EHDumper.cpp +++ b/llvm/tools/llvm-readobj/Win64EHDumper.cpp @@ -7,7 +7,6 @@ //===----------------------------------------------------------------------===// #include "Win64EHDumper.h" -#include "Error.h" #include "llvm-readobj.h" #include "llvm/Object/COFF.h" #include "llvm/Support/ErrorHandling.h" @@ -120,10 +119,10 @@ static std::error_code getSymbol(const COFFObjectFile &COFF, uint64_t VA, return errorToErrorCode(Address.takeError()); if (*Address == VA) { Sym = Symbol; - return readobj_error::success; + return std::error_code(); } } - return readobj_error::unknown_symbol; + return inconvertibleErrorCode(); } static std::string formatSymbol(const Dumper::Context &Ctx, diff --git a/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp b/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp index a2fb6aac3f93..fb085ecaa76e 100644 --- a/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp +++ b/llvm/tools/llvm-readobj/WindowsResourceDumper.cpp @@ -11,7 +11,6 @@ //===----------------------------------------------------------------------===// #include "WindowsResourceDumper.h" -#include "Error.h" #include "llvm/Object/WindowsResource.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ScopedPrinter.h" diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp index dd62f98d9595..8f0f18cedceb 100644 --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -10,7 +10,6 @@ // //===----------------------------------------------------------------------===// -#include "Error.h" #include "ObjDumper.h" #include "llvm-readobj.h" #include "llvm/Object/XCOFFObjectFile.h" @@ -25,7 +24,7 @@ class XCOFFDumper : public ObjDumper { public: XCOFFDumper(const XCOFFObjectFile &Obj, ScopedPrinter &Writer) - : ObjDumper(Writer), Obj(Obj) {} + : ObjDumper(Writer, Obj.getFileName()), Obj(Obj) {} void printFileHeaders() override; void printSectionHeaders() override; @@ -515,14 +514,8 @@ void XCOFFDumper::printSectionHeaders(ArrayRef<T> Sections) { } 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; +std::unique_ptr<ObjDumper> +createXCOFFDumper(const object::XCOFFObjectFile &XObj, ScopedPrinter &Writer) { + return std::make_unique<XCOFFDumper>(XObj, Writer); } } // namespace llvm diff --git a/llvm/tools/llvm-readobj/llvm-readobj.cpp b/llvm/tools/llvm-readobj/llvm-readobj.cpp index b9c6ad2256ae..41cd4414d051 100644 --- a/llvm/tools/llvm-readobj/llvm-readobj.cpp +++ b/llvm/tools/llvm-readobj/llvm-readobj.cpp @@ -19,20 +19,23 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" -#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" +#include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" #include "llvm/Object/WindowsResource.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Debug.h" +#include "llvm/Support/Errc.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/InitLLVM.h" @@ -63,7 +66,7 @@ namespace opts { DependentLibraries("dependent-libraries", cl::desc("Display the dependent libraries section")); - // --headers -e + // --headers, -e cl::opt<bool> Headers("headers", cl::desc("Equivalent to setting: --file-headers, --program-headers, " @@ -134,6 +137,11 @@ namespace opts { cl::opt<bool> DynRelocs("dyn-relocations", cl::desc("Display the dynamic relocation entries in the file")); + // --section-details + // Also -t in llvm-readelf mode. + cl::opt<bool> SectionDetails("section-details", + cl::desc("Display the section details")); + // --symbols // Also -s in llvm-readelf mode, or -t in llvm-readobj mode. cl::opt<bool> @@ -183,14 +191,18 @@ namespace opts { cl::aliasopt(ProgramHeaders)); // --string-dump, -p - cl::list<std::string> StringDump("string-dump", cl::desc("<number|name>"), - cl::ZeroOrMore); + cl::list<std::string> StringDump( + "string-dump", cl::value_desc("number|name"), + cl::desc("Display the specified section(s) as a list of strings"), + cl::ZeroOrMore); cl::alias StringDumpShort("p", cl::desc("Alias for --string-dump"), cl::aliasopt(StringDump), cl::Prefix); // --hex-dump, -x - cl::list<std::string> HexDump("hex-dump", cl::desc("<number|name>"), - cl::ZeroOrMore); + cl::list<std::string> + HexDump("hex-dump", cl::value_desc("number|name"), + cl::desc("Display the specified section(s) as hexadecimal bytes"), + cl::ZeroOrMore); cl::alias HexDumpShort("x", cl::desc("Alias for --hex-dump"), cl::aliasopt(HexDump), cl::Prefix); @@ -265,6 +277,10 @@ namespace opts { COFFDebugDirectory("coff-debug-directory", cl::desc("Display the PE/COFF debug directory")); + // --coff-tls-directory + cl::opt<bool> COFFTLSDirectory("coff-tls-directory", + cl::desc("Display the PE/COFF TLS directory")); + // --coff-resources cl::opt<bool> COFFResources("coff-resources", cl::desc("Display the PE/COFF .rsrc section")); @@ -420,55 +436,73 @@ struct ReadObjTypeTableBuilder { static ReadObjTypeTableBuilder CVTypes; /// Creates an format-specific object file dumper. -static std::error_code createDumper(const ObjectFile *Obj, - ScopedPrinter &Writer, - std::unique_ptr<ObjDumper> &Result) { - if (!Obj) - return readobj_error::unsupported_file_format; +static Expected<std::unique_ptr<ObjDumper>> +createDumper(const ObjectFile &Obj, ScopedPrinter &Writer) { + if (const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(&Obj)) + return createCOFFDumper(*COFFObj, Writer); + + if (const ELFObjectFileBase *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj)) + return createELFDumper(*ELFObj, Writer); + + if (const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(&Obj)) + return createMachODumper(*MachOObj, Writer); - if (Obj->isCOFF()) - return createCOFFDumper(Obj, Writer, Result); - if (Obj->isELF()) - return createELFDumper(Obj, Writer, Result); - if (Obj->isMachO()) - return createMachODumper(Obj, Writer, Result); - if (Obj->isWasm()) - return createWasmDumper(Obj, Writer, Result); - if (Obj->isXCOFF()) - return createXCOFFDumper(Obj, Writer, Result); + if (const WasmObjectFile *WasmObj = dyn_cast<WasmObjectFile>(&Obj)) + return createWasmDumper(*WasmObj, Writer); - return readobj_error::unsupported_obj_file_format; + if (const XCOFFObjectFile *XObj = dyn_cast<XCOFFObjectFile>(&Obj)) + return createXCOFFDumper(*XObj, Writer); + + return createStringError(errc::invalid_argument, + "unsupported object file format"); } /// Dumps the specified object file. -static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, +static void dumpObject(ObjectFile &Obj, ScopedPrinter &Writer, const Archive *A = nullptr) { std::string FileStr = - A ? Twine(A->getFileName() + "(" + Obj->getFileName() + ")").str() - : Obj->getFileName().str(); + A ? Twine(A->getFileName() + "(" + Obj.getFileName() + ")").str() + : Obj.getFileName().str(); + + std::string ContentErrString; + if (Error ContentErr = Obj.initContent()) + ContentErrString = "unable to continue dumping, the file is corrupt: " + + toString(std::move(ContentErr)); - std::unique_ptr<ObjDumper> Dumper; - if (std::error_code EC = createDumper(Obj, Writer, Dumper)) - reportError(errorCodeToError(EC), FileStr); + ObjDumper *Dumper; + Expected<std::unique_ptr<ObjDumper>> DumperOrErr = createDumper(Obj, Writer); + if (!DumperOrErr) + reportError(DumperOrErr.takeError(), FileStr); + Dumper = (*DumperOrErr).get(); if (opts::Output == opts::LLVM || opts::InputFilenames.size() > 1 || A) { Writer.startLine() << "\n"; Writer.printString("File", FileStr); } if (opts::Output == opts::LLVM) { - Writer.printString("Format", Obj->getFileFormatName()); - Writer.printString("Arch", Triple::getArchTypeName( - (llvm::Triple::ArchType)Obj->getArch())); + Writer.printString("Format", Obj.getFileFormatName()); + Writer.printString("Arch", Triple::getArchTypeName(Obj.getArch())); Writer.printString( "AddressSize", - std::string(formatv("{0}bit", 8 * Obj->getBytesInAddress()))); + std::string(formatv("{0}bit", 8 * Obj.getBytesInAddress()))); Dumper->printLoadName(); } if (opts::FileHeaders) Dumper->printFileHeaders(); - if (opts::SectionHeaders) - Dumper->printSectionHeaders(); + + // This is only used for ELF currently. In some cases, when an object is + // corrupt (e.g. truncated), we can't dump anything except the file header. + if (!ContentErrString.empty()) + reportError(createError(ContentErrString), FileStr); + + if (opts::SectionDetails || opts::SectionHeaders) { + if (opts::Output == opts::GNU && opts::SectionDetails) + Dumper->printSectionDetails(); + else + Dumper->printSectionHeaders(); + } + if (opts::HashSymbols) Dumper->printHashSymbols(); if (opts::ProgramHeaders || opts::SectionMapping == cl::BOU_TRUE) @@ -492,10 +526,10 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, if (opts::HashTable) Dumper->printHashTable(); if (opts::GnuHashTable) - Dumper->printGnuHashTable(Obj); + Dumper->printGnuHashTable(); if (opts::VersionInfo) Dumper->printVersionInfo(); - if (Obj->isELF()) { + if (Obj.isELF()) { if (opts::DependentLibraries) Dumper->printDependentLibs(); if (opts::ELFLinkerOptions) @@ -513,7 +547,7 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, if (opts::Notes) Dumper->printNotes(); } - if (Obj->isCOFF()) { + if (Obj.isCOFF()) { if (opts::COFFImports) Dumper->printCOFFImports(); if (opts::COFFExports) @@ -524,6 +558,8 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, Dumper->printCOFFBaseReloc(); if (opts::COFFDebugDirectory) Dumper->printCOFFDebugDirectory(); + if (opts::COFFTLSDirectory) + Dumper->printCOFFTLSDirectory(); if (opts::COFFResources) Dumper->printCOFFResources(); if (opts::COFFLoadConfig) @@ -539,7 +575,7 @@ static void dumpObject(const ObjectFile *Obj, ScopedPrinter &Writer, CVTypes.GlobalIDTable, CVTypes.GlobalTypeTable, opts::CodeViewEnableGHash); } - if (Obj->isMachO()) { + if (Obj.isMachO()) { if (opts::MachODataInCode) Dumper->printMachODataInCode(); if (opts::MachOIndirectSymbols) @@ -569,13 +605,17 @@ static void dumpArchive(const Archive *Arc, ScopedPrinter &Writer) { reportError(std::move(E), Arc->getFileName()); continue; } - if (ObjectFile *Obj = dyn_cast<ObjectFile>(&*ChildOrErr.get())) - dumpObject(Obj, Writer, Arc); - else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(&*ChildOrErr.get())) + + Binary *Bin = ChildOrErr->get(); + if (ObjectFile *Obj = dyn_cast<ObjectFile>(Bin)) + dumpObject(*Obj, Writer, Arc); + else if (COFFImportFile *Imp = dyn_cast<COFFImportFile>(Bin)) dumpCOFFImportFile(Imp, Writer); else - reportError(errorCodeToError(readobj_error::unrecognized_file_format), - Arc->getFileName()); + reportWarning(createStringError(errc::invalid_argument, + Bin->getFileName() + + " has an unsupported file type"), + Arc->getFileName()); } if (Err) reportError(std::move(Err), Arc->getFileName()); @@ -587,7 +627,7 @@ static void dumpMachOUniversalBinary(const MachOUniversalBinary *UBinary, for (const MachOUniversalBinary::ObjectForArch &Obj : UBinary->objects()) { Expected<std::unique_ptr<MachOObjectFile>> ObjOrErr = Obj.getAsObjectFile(); if (ObjOrErr) - dumpObject(&*ObjOrErr.get(), Writer); + dumpObject(*ObjOrErr.get(), Writer); else if (auto E = isNotObjectErrorInvalidFileType(ObjOrErr.takeError())) reportError(ObjOrErr.takeError(), UBinary->getFileName()); else if (Expected<std::unique_ptr<Archive>> AOrErr = Obj.getAsArchive()) @@ -607,7 +647,8 @@ static void dumpWindowsResourceFile(WindowsResource *WinRes, /// Opens \a File and dumps it. static void dumpInput(StringRef File, ScopedPrinter &Writer) { // Attempt to open the binary. - Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(File); + Expected<OwningBinary<Binary>> BinaryOrErr = + createBinary(File, /*Context=*/nullptr, /*InitContent=*/false); if (!BinaryOrErr) reportError(BinaryOrErr.takeError(), File); Binary &Binary = *BinaryOrErr.get().getBinary(); @@ -618,14 +659,13 @@ static void dumpInput(StringRef File, ScopedPrinter &Writer) { dyn_cast<MachOUniversalBinary>(&Binary)) dumpMachOUniversalBinary(UBinary, Writer); else if (ObjectFile *Obj = dyn_cast<ObjectFile>(&Binary)) - dumpObject(Obj, Writer); + dumpObject(*Obj, Writer); else if (COFFImportFile *Import = dyn_cast<COFFImportFile>(&Binary)) dumpCOFFImportFile(Import, Writer); else if (WindowsResource *WinRes = dyn_cast<WindowsResource>(&Binary)) dumpWindowsResourceFile(WinRes, Writer); else - reportError(errorCodeToError(readobj_error::unrecognized_file_format), - File); + llvm_unreachable("unrecognized file type"); CVTypes.Binaries.push_back(std::move(*BinaryOrErr)); } @@ -638,8 +678,7 @@ static void registerReadobjAliases() { cl::aliasopt(opts::SectionHeaders), cl::NotHidden); - // Only register -t in llvm-readobj, as readelf reserves it for - // --section-details (not implemented yet). + // llvm-readelf reserves it for --section-details. static cl::alias SymbolsShort("t", cl::desc("Alias for --symbols"), cl::aliasopt(opts::Symbols), cl::NotHidden); @@ -665,6 +704,11 @@ static void registerReadelfAliases() { cl::aliasopt(opts::Symbols), cl::NotHidden, cl::Grouping); + // -t is here because for readobj it is an alias for --symbols. + static cl::alias SectionDetailsShort( + "t", cl::desc("Alias for --section-details"), + cl::aliasopt(opts::SectionDetails), cl::NotHidden); + // Allow all single letter flags to be grouped together. for (auto &OptEntry : cl::getRegisteredOptions()) { StringRef ArgName = OptEntry.getKey(); @@ -690,6 +734,11 @@ int main(int argc, const char *argv[]) { cl::ParseCommandLineOptions(argc, argv, "LLVM Object Reader\n"); + // Default to print error if no filename is specified. + if (opts::InputFilenames.empty()) { + error("no input files specified"); + } + if (opts::All) { opts::FileHeaders = true; opts::ProgramHeaders = true; @@ -714,10 +763,6 @@ int main(int argc, const char *argv[]) { opts::SectionHeaders = true; } - // Default to stdin if no filename is specified. - if (opts::InputFilenames.empty()) - opts::InputFilenames.push_back("-"); - ScopedPrinter Writer(fouts()); for (const std::string &I : opts::InputFilenames) dumpInput(I, Writer); |
