X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-readobj%2FELFDumper.cpp;h=8074a35ed464190032df45352dd8615091f476a5;hb=3f1d2f9e7863ced5221b1c5afef80ac7aa6bd479;hp=b0e2734ac937344dd5309c32b4801fcb65afa1da;hpb=1c8dfa5e90fa7ba5d351d2e2511dc1495c83f6fd;p=oota-llvm.git diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index b0e2734ac93..8074a35ed46 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -13,22 +13,27 @@ //===----------------------------------------------------------------------===// #include "llvm-readobj.h" +#include "ARMAttributeParser.h" +#include "ARMEHABIPrinter.h" #include "Error.h" #include "ObjDumper.h" +#include "StackMapPrinter.h" #include "StreamWriter.h" - +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" -#include "llvm/Object/ELF.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Format.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/MipsABIFlags.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace llvm::object; using namespace ELF; - #define LLVM_READOBJ_ENUM_CASE(ns, enum) \ case ns::enum: return #enum; @@ -37,78 +42,185 @@ namespace { template class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFObjectFile *Obj, StreamWriter& Writer) - : ObjDumper(Writer) - , Obj(Obj) { } + ELFDumper(const ELFFile *Obj, StreamWriter &Writer); - virtual void printFileHeaders() LLVM_OVERRIDE; - virtual void printSections() LLVM_OVERRIDE; - virtual void printRelocations() LLVM_OVERRIDE; - virtual void printSymbols() LLVM_OVERRIDE; - virtual void printDynamicSymbols() LLVM_OVERRIDE; - virtual void printUnwindInfo() LLVM_OVERRIDE; + void printFileHeaders() override; + void printSections() override; + void printRelocations() override; + void printDynamicRelocations() override; + void printSymbols() override; + void printDynamicSymbols() override; + void printUnwindInfo() override; - virtual void printDynamicTable() LLVM_OVERRIDE; - virtual void printNeededLibraries() LLVM_OVERRIDE; + void printDynamicTable() override; + void printNeededLibraries() override; + void printProgramHeaders() override; + void printHashTable() override; + void printLoadName() override; -private: - typedef typename ELFObjectFile::Elf_Shdr Elf_Shdr; - typedef typename ELFObjectFile::Elf_Sym Elf_Sym; + void printAttributes() override; + void printMipsPLTGOT() override; + void printMipsABIFlags() override; + void printMipsReginfo() override; - void printSymbol(symbol_iterator SymI, bool IsDynamic = false); + void printStackMap() const override; - void printRelocation(section_iterator SecI, relocation_iterator RelI); +private: + typedef ELFFile ELFO; + typedef typename ELFO::Elf_Shdr Elf_Shdr; + typedef typename ELFO::Elf_Sym Elf_Sym; + typedef typename ELFO::Elf_Dyn Elf_Dyn; + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; + typedef typename ELFO::Elf_Rela Elf_Rela; + typedef typename ELFO::Elf_Rela_Range Elf_Rela_Range; + typedef typename ELFO::Elf_Phdr Elf_Phdr; + typedef typename ELFO::Elf_Hash Elf_Hash; + typedef typename ELFO::uintX_t uintX_t; + + /// \brief Represents a region described by entries in the .dynamic table. + struct DynRegionInfo { + DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} + /// \brief Address in current address space. + const void *Addr; + /// \brief Size in bytes of the region. + uintX_t Size; + /// \brief Size of each entity in the region. + uintX_t EntSize; + }; + + void printSymbol(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic); + + void printRelocations(const Elf_Shdr *Sec); + void printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel); + void printValue(uint64_t Type, uint64_t Value); + + const Elf_Rela *dyn_rela_begin() const; + const Elf_Rela *dyn_rela_end() const; + Elf_Rela_Range dyn_relas() const; + StringRef getDynamicString(uint64_t Offset) const; + const Elf_Dyn *dynamic_table_begin() const; + const Elf_Dyn *dynamic_table_end() const; + Elf_Dyn_Range dynamic_table() const { + return make_range(dynamic_table_begin(), dynamic_table_end()); + } - const ELFObjectFile *Obj; + const ELFO *Obj; + DynRegionInfo DynRelaRegion; + DynRegionInfo DynamicRegion; + StringRef DynamicStringTable; + StringRef SOName; + const Elf_Hash *HashTable = nullptr; }; -} // namespace +template T errorOrDefault(ErrorOr Val, T Default = T()) { + if (!Val) { + error(Val.getError()); + return Default; + } + return *Val; +} +} // namespace namespace llvm { -error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr &Result) { - typedef ELFType Little32ELF; - typedef ELFType Big32ELF; - typedef ELFType Little64ELF; - typedef ELFType Big64ELF; - - typedef ELFObjectFile LittleELF32Obj; - typedef ELFObjectFile BigELF32Obj; - typedef ELFObjectFile LittleELF64Obj; - typedef ELFObjectFile BigELF64Obj; +template +static std::error_code createELFDumper(const ELFFile *Obj, + StreamWriter &Writer, + std::unique_ptr &Result) { + Result.reset(new ELFDumper(Obj, Writer)); + return readobj_error::success; +} +std::error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr &Result) { // Little-endian 32-bit - if (const LittleELF32Obj *ELFObj = dyn_cast(Obj)) { - Result.reset(new ELFDumper(ELFObj, Writer)); - return readobj_error::success; - } + if (const ELF32LEObjectFile *ELFObj = dyn_cast(Obj)) + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Big-endian 32-bit - if (const BigELF32Obj *ELFObj = dyn_cast(Obj)) { - Result.reset(new ELFDumper(ELFObj, Writer)); - return readobj_error::success; - } + if (const ELF32BEObjectFile *ELFObj = dyn_cast(Obj)) + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Little-endian 64-bit - if (const LittleELF64Obj *ELFObj = dyn_cast(Obj)) { - Result.reset(new ELFDumper(ELFObj, Writer)); - return readobj_error::success; - } + if (const ELF64LEObjectFile *ELFObj = dyn_cast(Obj)) + return createELFDumper(ELFObj->getELFFile(), Writer, Result); // Big-endian 64-bit - if (const BigELF64Obj *ELFObj = dyn_cast(Obj)) { - Result.reset(new ELFDumper(ELFObj, Writer)); - return readobj_error::success; - } + if (const ELF64BEObjectFile *ELFObj = dyn_cast(Obj)) + return createELFDumper(ELFObj->getELFFile(), Writer, Result); return readobj_error::unsupported_obj_file_format; } } // namespace llvm +template +static std::string getFullSymbolName(const ELFO &Obj, + const typename ELFO::Elf_Sym *Symbol, + StringRef StrTable, bool IsDynamic) { + StringRef SymbolName = errorOrDefault(Symbol->getName(StrTable)); + if (!IsDynamic) + return SymbolName; + + std::string FullSymbolName(SymbolName); + + bool IsDefault; + ErrorOr Version = + Obj.getSymbolVersion(StrTable, &*Symbol, IsDefault); + if (Version) { + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += *Version; + } else + error(Version.getError()); + return FullSymbolName; +} + +template +static void +getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, + StringRef &SectionName, unsigned &SectionIndex) { + SectionIndex = Symbol->st_shndx; + if (Symbol->isUndefined()) + SectionName = "Undefined"; + else if (Symbol->isProcessorSpecific()) + SectionName = "Processor Specific"; + else if (Symbol->isOSSpecific()) + SectionName = "Operating System Specific"; + else if (Symbol->isAbsolute()) + SectionName = "Absolute"; + else if (Symbol->isCommon()) + SectionName = "Common"; + else if (Symbol->isReserved() && SectionIndex != SHN_XINDEX) + SectionName = "Reserved"; + else { + if (SectionIndex == SHN_XINDEX) + SectionIndex = Obj.getExtendedSymbolTableIndex(&*Symbol); + ErrorOr Sec = Obj.getSection(SectionIndex); + error(Sec.getError()); + SectionName = errorOrDefault(Obj.getSectionName(*Sec)); + } +} + +template +static const typename ELFFile::Elf_Shdr * +findSectionByAddress(const ELFFile *Obj, uint64_t Addr) { + for (const auto &Shdr : Obj->sections()) + if (Shdr.sh_addr == Addr) + return &Shdr; + return nullptr; +} + +template +static const typename ELFFile::Elf_Shdr * +findSectionByName(const ELFFile &Obj, StringRef Name) { + for (const auto &Shdr : Obj.sections()) { + if (Name == errorOrDefault(Obj.getSectionName(&Shdr))) + return &Shdr; + } + return nullptr; +} static const EnumEntry ElfClass[] = { { "None", ELF::ELFCLASSNONE }, @@ -147,6 +259,7 @@ static const EnumEntry ElfOSABI[] = { { "NSK", ELF::ELFOSABI_NSK }, { "AROS", ELF::ELFOSABI_AROS }, { "FenixOS", ELF::ELFOSABI_FENIXOS }, + { "CloudABI", ELF::ELFOSABI_CLOUDABI }, { "C6000_ELFABI", ELF::ELFOSABI_C6000_ELFABI }, { "C6000_LINUX" , ELF::ELFOSABI_C6000_LINUX }, { "ARM", ELF::ELFOSABI_ARM }, @@ -160,7 +273,7 @@ static const EnumEntry ElfMachineType[] = { LLVM_READOBJ_ENUM_ENT(ELF, EM_386 ), LLVM_READOBJ_ENUM_ENT(ELF, EM_68K ), LLVM_READOBJ_ENUM_ENT(ELF, EM_88K ), - LLVM_READOBJ_ENUM_ENT(ELF, EM_486 ), + LLVM_READOBJ_ENUM_ENT(ELF, EM_IAMCU ), LLVM_READOBJ_ENUM_ENT(ELF, EM_860 ), LLVM_READOBJ_ENUM_ENT(ELF, EM_MIPS ), LLVM_READOBJ_ENUM_ENT(ELF, EM_S370 ), @@ -298,7 +411,6 @@ static const EnumEntry ElfMachineType[] = { LLVM_READOBJ_ENUM_ENT(ELF, EM_STM8 ), LLVM_READOBJ_ENUM_ENT(ELF, EM_TILE64 ), LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEPRO ), - LLVM_READOBJ_ENUM_ENT(ELF, EM_MICROBLAZE ), LLVM_READOBJ_ENUM_ENT(ELF, EM_CUDA ), LLVM_READOBJ_ENUM_ENT(ELF, EM_TILEGX ), LLVM_READOBJ_ENUM_ENT(ELF, EM_CLOUDSHIELD ), @@ -310,13 +422,14 @@ static const EnumEntry ElfMachineType[] = { LLVM_READOBJ_ENUM_ENT(ELF, EM_VIDEOCORE5 ), LLVM_READOBJ_ENUM_ENT(ELF, EM_78KOR ), LLVM_READOBJ_ENUM_ENT(ELF, EM_56800EX ), - LLVM_READOBJ_ENUM_ENT(ELF, EM_MBLAZE ) + LLVM_READOBJ_ENUM_ENT(ELF, EM_AMDGPU ) }; static const EnumEntry ElfSymbolBindings[] = { - { "Local", ELF::STB_LOCAL }, - { "Global", ELF::STB_GLOBAL }, - { "Weak", ELF::STB_WEAK } + { "Local", ELF::STB_LOCAL }, + { "Global", ELF::STB_GLOBAL }, + { "Weak", ELF::STB_WEAK }, + { "Unique", ELF::STB_GNU_UNIQUE } }; static const EnumEntry ElfSymbolTypes[] = { @@ -332,7 +445,7 @@ static const EnumEntry ElfSymbolTypes[] = { static const char *getElfSectionType(unsigned Arch, unsigned Type) { switch (Arch) { - case Triple::arm: + case ELF::EM_ARM: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_EXIDX); LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP); @@ -340,19 +453,16 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY); LLVM_READOBJ_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION); } - case Triple::hexagon: - switch (Type) { - LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); - } - case Triple::x86_64: - switch (Type) { - LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); - } - case Triple::mips: - case Triple::mipsel: + case ELF::EM_HEXAGON: + switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_HEX_ORDERED); } + case ELF::EM_X86_64: + switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_X86_64_UNWIND); } + case ELF::EM_MIPS: + case ELF::EM_MIPS_RS3_LE: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_REGINFO); LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); + LLVM_READOBJ_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS); } } @@ -386,6 +496,7 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) { static const EnumEntry ElfSectionFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, SHF_WRITE ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_ALLOC ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXCLUDE ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_EXECINSTR ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_MERGE ), LLVM_READOBJ_ENUM_ENT(ELF, SHF_STRINGS ), @@ -399,13 +510,200 @@ static const EnumEntry ElfSectionFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) }; +static const char *getElfSegmentType(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); + } + case ELF::EM_MIPS: + case ELF::EM_MIPS_RS3_LE: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_REGINFO); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_RTPROC); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS); + LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_ABIFLAGS); + } + } + + 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_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); + default: return ""; + } +} + +static const EnumEntry ElfSegmentFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, PF_X), + LLVM_READOBJ_ENUM_ENT(ELF, PF_W), + LLVM_READOBJ_ENUM_ENT(ELF, PF_R) +}; + +static const EnumEntry ElfHeaderMipsFlags[] = { + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_NOREORDER), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_PIC), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_CPIC), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_32BITMODE), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_FP64), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_NAN2008), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_O32), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_O64), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_EABI32), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ABI_EABI64), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_3900), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4010), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4100), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4650), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4120), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_4111), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_SB1), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_XLR), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_OCTEON3), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5400), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5900), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_5500), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_9000), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS2E), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS2F), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MACH_LS3A), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_MICROMIPS), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_ASE_M16), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_ASE_MDMX), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_1), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_3), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_4), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_5), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32R2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R2), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_32R6), + LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6) +}; + +template +ELFDumper::ELFDumper(const ELFFile *Obj, StreamWriter &Writer) + : ObjDumper(Writer), Obj(Obj) { + + SmallVector LoadSegments; + for (const Elf_Phdr &Phdr : Obj->program_headers()) { + if (Phdr.p_type == ELF::PT_DYNAMIC) { + DynamicRegion.Addr = Obj->base() + Phdr.p_offset; + uint64_t Size = Phdr.p_filesz; + if (Size % sizeof(Elf_Dyn)) + report_fatal_error("Invalid dynamic table size"); + DynamicRegion.Size = Phdr.p_filesz; + continue; + } + if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) + continue; + LoadSegments.push_back(&Phdr); + } + + auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { + const Elf_Phdr **I = std::upper_bound( + LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr); + if (I == LoadSegments.begin()) + report_fatal_error("Virtual address is not in any segment"); + --I; + const Elf_Phdr &Phdr = **I; + uint64_t Delta = VAddr - Phdr.p_vaddr; + if (Delta >= Phdr.p_filesz) + report_fatal_error("Virtual address is not in any segment"); + return Obj->base() + Phdr.p_offset + Delta; + }; + + uint64_t SONameOffset = 0; + const char *StringTableBegin = nullptr; + uint64_t StringTableSize = 0; + for (const Elf_Dyn &Dyn : dynamic_table()) { + switch (Dyn.d_tag) { + case ELF::DT_HASH: + HashTable = + reinterpret_cast(toMappedAddr(Dyn.getPtr())); + break; + case ELF::DT_RELA: + DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_RELASZ: + DynRelaRegion.Size = Dyn.getVal(); + break; + case ELF::DT_RELAENT: + DynRelaRegion.EntSize = Dyn.getVal(); + break; + case ELF::DT_SONAME: + SONameOffset = Dyn.getVal(); + break; + case ELF::DT_STRTAB: + StringTableBegin = (const char *)toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_STRSZ: + StringTableSize = Dyn.getVal(); + break; + } + } + if (StringTableBegin) + DynamicStringTable = StringRef(StringTableBegin, StringTableSize); + if (SONameOffset) + SOName = getDynamicString(SONameOffset); +} + +template +const typename ELFDumper::Elf_Rela * +ELFDumper::dyn_rela_begin() const { + if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast(DynRelaRegion.Addr); +} + +template +const typename ELFDumper::Elf_Rela * +ELFDumper::dyn_rela_end() const { + uint64_t Size = DynRelaRegion.Size; + if (Size % sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation table size"); + return dyn_rela_begin() + Size / sizeof(Elf_Rela); +} + +template +typename ELFDumper::Elf_Rela_Range ELFDumper::dyn_relas() const { + return make_range(dyn_rela_begin(), dyn_rela_end()); +} + +template +const typename ELFDumper::Elf_Dyn * +ELFDumper::dynamic_table_begin() const { + return reinterpret_cast(DynamicRegion.Addr); +} + +template +const typename ELFDumper::Elf_Dyn * +ELFDumper::dynamic_table_end() const { + uint64_t Size = DynamicRegion.Size; + return dynamic_table_begin() + Size / sizeof(Elf_Dyn); +} template void ELFDumper::printFileHeaders() { - error_code EC; - typedef ELFObjectFile ELFO; - - const typename ELFO::Elf_Ehdr *Header = Obj->getElfHeader(); + const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); { DictScope D(W, "ElfHeader"); @@ -418,7 +716,13 @@ void ELFDumper::printFileHeaders() { W.printEnum ("DataEncoding", Header->e_ident[ELF::EI_DATA], makeArrayRef(ElfDataEncoding)); W.printNumber("FileVersion", Header->e_ident[ELF::EI_VERSION]); - W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI], + + // Handle architecture specific OS/ABI values. + if (Header->e_machine == ELF::EM_AMDGPU && + Header->e_ident[ELF::EI_OSABI] == ELF::ELFOSABI_AMDGPU_HSA) + W.printHex("OS/ABI", "AMDGPU_HSA", ELF::ELFOSABI_AMDGPU_HSA); + else + W.printEnum ("OS/ABI", Header->e_ident[ELF::EI_OSABI], makeArrayRef(ElfOSABI)); W.printNumber("ABIVersion", Header->e_ident[ELF::EI_ABIVERSION]); W.printBinary("Unused", makeArrayRef(Header->e_ident).slice(ELF::EI_PAD)); @@ -430,7 +734,12 @@ void ELFDumper::printFileHeaders() { W.printHex ("Entry", Header->e_entry); W.printHex ("ProgramHeaderOffset", Header->e_phoff); W.printHex ("SectionHeaderOffset", Header->e_shoff); - W.printFlags ("Flags", Header->e_flags); + if (Header->e_machine == EM_MIPS) + W.printFlags("Flags", Header->e_flags, makeArrayRef(ElfHeaderMipsFlags), + unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI), + unsigned(ELF::EF_MIPS_MACH)); + else + W.printFlags("Flags", Header->e_flags); W.printNumber("HeaderSize", Header->e_ehsize); W.printNumber("ProgramHeaderEntrySize", Header->e_phentsize); W.printNumber("ProgramHeaderCount", Header->e_phnum); @@ -445,64 +754,51 @@ void ELFDumper::printSections() { ListScope SectionsD(W, "Sections"); int SectionIndex = -1; - error_code EC; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; - + for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { ++SectionIndex; - const Elf_Shdr *Section = Obj->getElfSection(SecI); - StringRef Name; - if (error(SecI->getName(Name))) - Name = ""; + StringRef Name = errorOrDefault(Obj->getSectionName(&Sec)); DictScope SectionD(W, "Section"); W.printNumber("Index", SectionIndex); - W.printNumber("Name", Name, Section->sh_name); - W.printHex ("Type", getElfSectionType(Obj->getArch(), Section->sh_type), - Section->sh_type); - W.printFlags ("Flags", Section->sh_flags, makeArrayRef(ElfSectionFlags)); - W.printHex ("Address", Section->sh_addr); - W.printHex ("Offset", Section->sh_offset); - W.printNumber("Size", Section->sh_size); - W.printNumber("Link", Section->sh_link); - W.printNumber("Info", Section->sh_info); - W.printNumber("AddressAlignment", Section->sh_addralign); - W.printNumber("EntrySize", Section->sh_entsize); + W.printNumber("Name", Name, Sec.sh_name); + W.printHex("Type", + getElfSectionType(Obj->getHeader()->e_machine, Sec.sh_type), + Sec.sh_type); + W.printFlags("Flags", Sec.sh_flags, makeArrayRef(ElfSectionFlags)); + W.printHex("Address", Sec.sh_addr); + W.printHex("Offset", Sec.sh_offset); + W.printNumber("Size", Sec.sh_size); + W.printNumber("Link", Sec.sh_link); + W.printNumber("Info", Sec.sh_info); + W.printNumber("AddressAlignment", Sec.sh_addralign); + W.printNumber("EntrySize", Sec.sh_entsize); if (opts::SectionRelocations) { ListScope D(W, "Relocations"); - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; - - printRelocation(SecI, RelI); - } + printRelocations(&Sec); } if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (symbol_iterator SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - bool Contained = false; - if (SecI->containsSymbol(*SymI, Contained) || !Contained) + const Elf_Shdr *Symtab = Obj->getDotSymtabSec(); + ErrorOr StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + + for (const typename ELFO::Elf_Sym &Sym : Obj->symbols()) { + ErrorOr SymSec = Obj->getSection(&Sym); + if (!SymSec) continue; - - printSymbol(SymI); + if (*SymSec == &Sec) + printSymbol(&Sym, StrTable, false); } } - if (opts::SectionData) { - StringRef Data; - if (error(SecI->getContents(Data))) break; - - W.printBinaryBlock("SectionData", Data); + if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) { + ArrayRef Data = errorOrDefault(Obj->getSectionContents(&Sec)); + W.printBinaryBlock("SectionData", + StringRef((const char *)Data.data(), Data.size())); } } } @@ -511,69 +807,106 @@ template void ELFDumper::printRelocations() { ListScope D(W, "Relocations"); - error_code EC; int SectionNumber = -1; - for (section_iterator SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; SecI.increment(EC)) { - if (error(EC)) break; - + for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { ++SectionNumber; - StringRef Name; - if (error(SecI->getName(Name))) + + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) continue; - bool PrintedGroup = false; - for (relocation_iterator RelI = SecI->begin_relocations(), - RelE = SecI->end_relocations(); - RelI != RelE; RelI.increment(EC)) { - if (error(EC)) break; + StringRef Name = errorOrDefault(Obj->getSectionName(&Sec)); - if (!PrintedGroup) { - W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; - W.indent(); - PrintedGroup = true; - } + W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; + W.indent(); + + printRelocations(&Sec); + + W.unindent(); + W.startLine() << "}\n"; + } +} - printRelocation(SecI, RelI); +template +void ELFDumper::printDynamicRelocations() { + W.startLine() << "Dynamic Relocations {\n"; + W.indent(); + for (const typename ELFO::Elf_Rela &Rel : dyn_relas()) { + SmallString<32> RelocName; + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); + StringRef SymbolName; + uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); + const typename ELFO::Elf_Sym *Sym = Obj->dynamic_symbol_begin() + SymIndex; + SymbolName = errorOrDefault(Sym->getName(DynamicStringTable)); + 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.size() > 0 ? SymbolName : "-"); + W.printHex("Addend", Rel.r_addend); + } + else { + raw_ostream& OS = W.startLine(); + OS << W.hex(Rel.r_offset) << " " << RelocName << " " + << (SymbolName.size() > 0 ? SymbolName : "-") << " " + << W.hex(Rel.r_addend) << "\n"; } + } + W.unindent(); + W.startLine() << "}\n"; +} - if (PrintedGroup) { - W.unindent(); - W.startLine() << "}\n"; +template +void ELFDumper::printRelocations(const Elf_Shdr *Sec) { + switch (Sec->sh_type) { + case ELF::SHT_REL: + for (const typename ELFO::Elf_Rel &R : Obj->rels(Sec)) { + typename ELFO::Elf_Rela Rela; + Rela.r_offset = R.r_offset; + Rela.r_info = R.r_info; + Rela.r_addend = 0; + printRelocation(Sec, Rela); } + break; + case ELF::SHT_RELA: + for (const typename ELFO::Elf_Rela &R : Obj->relas(Sec)) + printRelocation(Sec, R); + break; } } -template -void ELFDumper::printRelocation(section_iterator Sec, - relocation_iterator RelI) { - uint64_t Offset; - uint64_t RelocType; +template +void ELFDumper::printRelocation(const Elf_Shdr *Sec, + typename ELFO::Elf_Rela Rel) { SmallString<32> RelocName; - int64_t Info; - StringRef SymbolName; - SymbolRef Symbol; - if (error(RelI->getOffset(Offset))) return; - if (error(RelI->getType(RelocType))) return; - if (error(RelI->getTypeName(RelocName))) return; - if (error(RelI->getAdditionalInfo(Info))) return; - if (error(RelI->getSymbol(Symbol))) return; - if (error(Symbol.getName(SymbolName))) return; + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); + StringRef TargetName; + std::pair Sym = + Obj->getRelocationSymbol(Sec, &Rel); + if (Sym.second && Sym.second->getType() == ELF::STT_SECTION) { + ErrorOr Sec = Obj->getSection(Sym.second); + error(Sec.getError()); + ErrorOr SecName = Obj->getSectionName(*Sec); + if (SecName) + TargetName = SecName.get(); + } else if (Sym.first) { + const Elf_Shdr *SymTable = Sym.first; + ErrorOr StrTableOrErr = Obj->getStringTableForSymtab(*SymTable); + error(StrTableOrErr.getError()); + TargetName = errorOrDefault(Sym.second->getName(*StrTableOrErr)); + } if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); - W.printHex("Offset", Offset); - W.printNumber("Type", RelocName, RelocType); - W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); - W.printHex("Info", Info); + W.printHex("Offset", Rel.r_offset); + W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); + W.printNumber("Symbol", TargetName.size() > 0 ? TargetName : "-", + Rel.getSymbol(Obj->isMips64EL())); + W.printHex("Addend", Rel.r_addend); } else { raw_ostream& OS = W.startLine(); - OS << W.hex(Offset) - << " " << RelocName - << " " << (SymbolName.size() > 0 ? SymbolName : "-") - << " " << W.hex(Info) - << "\n"; + OS << W.hex(Rel.r_offset) << " " << RelocName << " " + << (TargetName.size() > 0 ? TargetName : "-") << " " + << W.hex(Rel.r_addend) << "\n"; } } @@ -581,55 +914,34 @@ template void ELFDumper::printSymbols() { ListScope Group(W, "Symbols"); - error_code EC; - for (symbol_iterator SymI = Obj->begin_symbols(), SymE = Obj->end_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - printSymbol(SymI); - } + const Elf_Shdr *Symtab = Obj->getDotSymtabSec(); + ErrorOr StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + for (const typename ELFO::Elf_Sym &Sym : Obj->symbols()) + printSymbol(&Sym, StrTable, false); } template void ELFDumper::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); - error_code EC; - for (symbol_iterator SymI = Obj->begin_dynamic_symbols(), - SymE = Obj->end_dynamic_symbols(); - SymI != SymE; SymI.increment(EC)) { - if (error(EC)) break; - - printSymbol(SymI, true); - } + const Elf_Shdr *Symtab = Obj->getDotDynSymSec(); + ErrorOr StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + for (const typename ELFO::Elf_Sym &Sym : Obj->dynamic_symbols()) + printSymbol(&Sym, StrTable, true); } -template -void ELFDumper::printSymbol(symbol_iterator SymI, bool IsDynamic) { - error_code EC; - - const Elf_Sym *Symbol = Obj->getElfSymbol(SymI); - const Elf_Shdr *Section = Obj->getSection(Symbol); - - StringRef SymbolName; - if (SymI->getName(SymbolName)) - SymbolName = ""; - +template +void ELFDumper::printSymbol(const typename ELFO::Elf_Sym *Symbol, + StringRef StrTable, bool IsDynamic) { + unsigned SectionIndex = 0; StringRef SectionName; - if (Section && Obj->getSectionName(Section, SectionName)) - SectionName = ""; - - std::string FullSymbolName(SymbolName); - if (IsDynamic) { - StringRef Version; - bool IsDefault; - if (error(Obj->getSymbolVersion(*SymI, Version, IsDefault))) - return; - if (!Version.empty()) { - FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += Version; - } - } + getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex); + std::string FullSymbolName = + getFullSymbolName(*Obj, Symbol, StrTable, IsDynamic); DictScope D(W, "Symbol"); W.printNumber("Name", FullSymbolName, Symbol->st_name); @@ -639,7 +951,7 @@ void ELFDumper::printSymbol(symbol_iterator SymI, bool IsDynamic) { makeArrayRef(ElfSymbolBindings)); W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); W.printNumber("Other", Symbol->st_other); - W.printHex ("Section", SectionName, Symbol->st_shndx); + W.printHex("Section", SectionName, SectionIndex); } #define LLVM_READOBJ_TYPE_CASE(name) \ @@ -653,6 +965,7 @@ static const char *getTypeString(uint64_t Type) { LLVM_READOBJ_TYPE_CASE(FINI_ARRAY); LLVM_READOBJ_TYPE_CASE(FINI_ARRAYSZ); LLVM_READOBJ_TYPE_CASE(FLAGS); + LLVM_READOBJ_TYPE_CASE(FLAGS_1); LLVM_READOBJ_TYPE_CASE(HASH); LLVM_READOBJ_TYPE_CASE(INIT); LLVM_READOBJ_TYPE_CASE(INIT_ARRAY); @@ -680,15 +993,116 @@ static const char *getTypeString(uint64_t Type) { LLVM_READOBJ_TYPE_CASE(SYMENT); LLVM_READOBJ_TYPE_CASE(SYMTAB); LLVM_READOBJ_TYPE_CASE(TEXTREL); + LLVM_READOBJ_TYPE_CASE(VERNEED); + LLVM_READOBJ_TYPE_CASE(VERNEEDNUM); + LLVM_READOBJ_TYPE_CASE(VERSYM); + LLVM_READOBJ_TYPE_CASE(RELCOUNT); + LLVM_READOBJ_TYPE_CASE(GNU_HASH); + LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION); + LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS); + LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS); + LLVM_READOBJ_TYPE_CASE(MIPS_LOCAL_GOTNO); + LLVM_READOBJ_TYPE_CASE(MIPS_SYMTABNO); + LLVM_READOBJ_TYPE_CASE(MIPS_UNREFEXTNO); + LLVM_READOBJ_TYPE_CASE(MIPS_GOTSYM); + LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP); + LLVM_READOBJ_TYPE_CASE(MIPS_PLTGOT); + LLVM_READOBJ_TYPE_CASE(MIPS_OPTIONS); default: return "unknown"; } } #undef LLVM_READOBJ_TYPE_CASE -template -static void printValue(const ELFObjectFile *O, uint64_t Type, - uint64_t Value, bool Is64, raw_ostream &OS) { +#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ + { #enum, prefix##_##enum } + +static const EnumEntry ElfDynamicDTFlags[] = { + LLVM_READOBJ_DT_FLAG_ENT(DF, ORIGIN), + LLVM_READOBJ_DT_FLAG_ENT(DF, SYMBOLIC), + LLVM_READOBJ_DT_FLAG_ENT(DF, TEXTREL), + LLVM_READOBJ_DT_FLAG_ENT(DF, BIND_NOW), + LLVM_READOBJ_DT_FLAG_ENT(DF, STATIC_TLS) +}; + +static const EnumEntry ElfDynamicDTFlags1[] = { + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOW), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAL), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, GROUP), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODELETE), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, LOADFLTR), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, INITFIRST), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOOPEN), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, ORIGIN), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, DIRECT), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, TRANS), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, INTERPOSE), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODEFLIB), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODUMP), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, CONFALT), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, ENDFILTEE), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, DISPRELDNE), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODIRECT), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, IGNMULDEF), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOKSYMS), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOHDR), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, EDITED), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, NORELOC), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, SYMINTPOSE), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAUDIT), + LLVM_READOBJ_DT_FLAG_ENT(DF_1, SINGLETON) +}; + +static const EnumEntry ElfDynamicDTMipsFlags[] = { + LLVM_READOBJ_DT_FLAG_ENT(RHF, NONE), + LLVM_READOBJ_DT_FLAG_ENT(RHF, QUICKSTART), + LLVM_READOBJ_DT_FLAG_ENT(RHF, NOTPOT), + LLVM_READOBJ_DT_FLAG_ENT(RHS, NO_LIBRARY_REPLACEMENT), + LLVM_READOBJ_DT_FLAG_ENT(RHF, NO_MOVE), + LLVM_READOBJ_DT_FLAG_ENT(RHF, SGI_ONLY), + LLVM_READOBJ_DT_FLAG_ENT(RHF, GUARANTEE_INIT), + LLVM_READOBJ_DT_FLAG_ENT(RHF, DELTA_C_PLUS_PLUS), + LLVM_READOBJ_DT_FLAG_ENT(RHF, GUARANTEE_START_INIT), + LLVM_READOBJ_DT_FLAG_ENT(RHF, PIXIE), + LLVM_READOBJ_DT_FLAG_ENT(RHF, DEFAULT_DELAY_LOAD), + LLVM_READOBJ_DT_FLAG_ENT(RHF, REQUICKSTART), + LLVM_READOBJ_DT_FLAG_ENT(RHF, REQUICKSTARTED), + LLVM_READOBJ_DT_FLAG_ENT(RHF, CORD), + LLVM_READOBJ_DT_FLAG_ENT(RHF, NO_UNRES_UNDEF), + LLVM_READOBJ_DT_FLAG_ENT(RHF, RLD_ORDER_SAFE) +}; + +#undef LLVM_READOBJ_DT_FLAG_ENT + +template +void printFlags(T Value, ArrayRef> Flags, raw_ostream &OS) { + typedef EnumEntry FlagEntry; + typedef SmallVector FlagVector; + FlagVector SetFlags; + + for (const auto &Flag : Flags) { + if (Flag.Value == 0) + continue; + + if ((Value & Flag.Value) == Flag.Value) + SetFlags.push_back(Flag); + } + + for (const auto &Flag : SetFlags) { + OS << Flag.Name << " "; + } +} + +template +StringRef ELFDumper::getDynamicString(uint64_t Value) const { + if (Value >= DynamicStringTable.size()) + reportError("Invalid dynamic string table reference"); + return StringRef(DynamicStringTable.data() + Value); +} + +template +void ELFDumper::printValue(uint64_t Type, uint64_t Value) { + raw_ostream &OS = W.getOStream(); switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -712,9 +1126,25 @@ static void printValue(const ELFObjectFile *O, uint64_t Type, case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: case DT_DEBUG: + case DT_VERNEED: + case DT_VERSYM: + case DT_GNU_HASH: case DT_NULL: + case DT_MIPS_BASE_ADDRESS: + case DT_MIPS_GOTSYM: + case DT_MIPS_RLD_MAP: + case DT_MIPS_PLTGOT: + case DT_MIPS_OPTIONS: OS << format("0x%" PRIX64, Value); break; + case DT_RELCOUNT: + case DT_VERNEEDNUM: + case DT_MIPS_RLD_VERSION: + case DT_MIPS_LOCAL_GOTNO: + case DT_MIPS_SYMTABNO: + case DT_MIPS_UNREFEXTNO: + OS << Value; + break; case DT_PLTRELSZ: case DT_RELASZ: case DT_RELAENT: @@ -728,12 +1158,26 @@ static void printValue(const ELFObjectFile *O, uint64_t Type, OS << Value << " (bytes)"; break; case DT_NEEDED: - OS << "SharedLibrary (" - << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + OS << "SharedLibrary (" << getDynamicString(Value) << ")"; break; case DT_SONAME: - OS << "LibrarySoname (" - << O->getString(O->getDynamicStringTableSectionHeader(), Value) << ")"; + OS << "LibrarySoname (" << getDynamicString(Value) << ")"; + break; + case DT_RPATH: + case DT_RUNPATH: + OS << getDynamicString(Value); + break; + case DT_MIPS_FLAGS: + printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); + break; + case DT_FLAGS: + printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS); + break; + case DT_FLAGS_1: + printFlags(Value, makeArrayRef(ElfDynamicDTFlags1), OS); + break; + default: + OS << format("0x%" PRIX64, Value); break; } } @@ -743,68 +1187,615 @@ void ELFDumper::printUnwindInfo() { W.startLine() << "UnwindInfo not implemented.\n"; } +namespace { +template <> void ELFDumper>::printUnwindInfo() { + const unsigned Machine = Obj->getHeader()->e_machine; + if (Machine == EM_ARM) { + ARM::EHABI::PrinterContext> Ctx(W, Obj); + return Ctx.PrintUnwindInformation(); + } + W.startLine() << "UnwindInfo not implemented.\n"; +} +} + template void ELFDumper::printDynamicTable() { - typedef ELFObjectFile ELFO; - typedef typename ELFO::Elf_Dyn_iterator EDI; - EDI Start = Obj->begin_dynamic_table(), - End = Obj->end_dynamic_table(true); + auto I = dynamic_table_begin(); + auto E = dynamic_table_end(); + + if (I == E) + return; + + --E; + while (I != E && E->getTag() == ELF::DT_NULL) + --E; + if (E->getTag() != ELF::DT_NULL) + ++E; + ++E; - if (Start == End) + ptrdiff_t Total = std::distance(I, E); + if (Total == 0) return; - ptrdiff_t Total = std::distance(Start, End); raw_ostream &OS = W.getOStream(); W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; - bool Is64 = Obj->getBytesInAddress() == 8; + bool Is64 = ELFT::Is64Bits; W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" << " " << "Name/Value\n"; - for (; Start != End; ++Start) { + while (I != E) { + const typename ELFO::Elf_Dyn &Entry = *I; + ++I; W.startLine() << " " - << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Start->getTag()) - << " " << format("%-21s", getTypeString(Start->getTag())); - printValue(Obj, Start->getTag(), Start->getVal(), Is64, OS); + << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag()) + << " " << format("%-21s", getTypeString(Entry.getTag())); + printValue(Entry.getTag(), Entry.getVal()); OS << "\n"; } W.startLine() << "]\n"; } -static bool compareLibraryName(const LibraryRef &L, const LibraryRef &R) { - StringRef LPath, RPath; - L.getPath(LPath); - R.getPath(RPath); - return LPath < RPath; -} - template void ELFDumper::printNeededLibraries() { ListScope D(W, "NeededLibraries"); - error_code EC; - - typedef std::vector LibsTy; + typedef std::vector LibsTy; LibsTy Libs; - for (library_iterator I = Obj->begin_libraries_needed(), - E = Obj->end_libraries_needed(); - I != E; I.increment(EC)) { - if (EC) - report_fatal_error("Needed libraries iteration failed"); + for (const auto &Entry : dynamic_table()) + if (Entry.d_tag == ELF::DT_NEEDED) + Libs.push_back(getDynamicString(Entry.d_un.d_val)); - Libs.push_back(*I); + std::stable_sort(Libs.begin(), Libs.end()); + + for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); I != E; ++I) { + outs() << " " << *I << "\n"; + } +} + +template +void ELFDumper::printProgramHeaders() { + ListScope L(W, "ProgramHeaders"); + + for (const typename ELFO::Elf_Phdr &Phdr : Obj->program_headers()) { + DictScope P(W, "ProgramHeader"); + W.printHex("Type", + getElfSegmentType(Obj->getHeader()->e_machine, Phdr.p_type), + Phdr.p_type); + W.printHex("Offset", Phdr.p_offset); + W.printHex("VirtualAddress", Phdr.p_vaddr); + W.printHex("PhysicalAddress", Phdr.p_paddr); + W.printNumber("FileSize", Phdr.p_filesz); + W.printNumber("MemSize", Phdr.p_memsz); + W.printFlags("Flags", Phdr.p_flags, makeArrayRef(ElfSegmentFlags)); + W.printNumber("Alignment", Phdr.p_align); } +} + +template +void ELFDumper::printHashTable() { + DictScope D(W, "HashTable"); + if (!HashTable) + return; + W.printNumber("Num Buckets", HashTable->nbucket); + W.printNumber("Num Chains", HashTable->nchain); + W.printList("Buckets", HashTable->buckets()); + W.printList("Chains", HashTable->chains()); +} + +template void ELFDumper::printLoadName() { + outs() << "LoadName: " << SOName << '\n'; +} - std::sort(Libs.begin(), Libs.end(), &compareLibraryName); +template +void ELFDumper::printAttributes() { + W.startLine() << "Attributes not implemented.\n"; +} - for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); - I != E; ++I) { - StringRef Path; - I->getPath(Path); - outs() << " " << Path << "\n"; +namespace { +template <> void ELFDumper>::printAttributes() { + if (Obj->getHeader()->e_machine != EM_ARM) { + W.startLine() << "Attributes not implemented.\n"; + return; } + + DictScope BA(W, "BuildAttributes"); + for (const ELFO::Elf_Shdr &Sec : Obj->sections()) { + if (Sec.sh_type != ELF::SHT_ARM_ATTRIBUTES) + continue; + + ErrorOr> Contents = Obj->getSectionContents(&Sec); + if (!Contents) + continue; + + if ((*Contents)[0] != ARMBuildAttrs::Format_Version) { + errs() << "unrecognised FormatVersion: 0x" << utohexstr((*Contents)[0]) + << '\n'; + continue; + } + + W.printHex("FormatVersion", (*Contents)[0]); + if (Contents->size() == 1) + continue; + + ARMAttributeParser(W).Parse(*Contents); + } +} +} + +namespace { +template class MipsGOTParser { +public: + typedef object::ELFFile ObjectFile; + typedef typename ObjectFile::Elf_Shdr Elf_Shdr; + typedef typename ObjectFile::Elf_Sym Elf_Sym; + typedef typename ObjectFile::Elf_Dyn_Range Elf_Dyn_Range; + + MipsGOTParser(const ObjectFile *Obj, Elf_Dyn_Range DynTable, StreamWriter &W); + + void parseGOT(); + void parsePLT(); + +private: + typedef typename ObjectFile::Elf_Addr GOTEntry; + typedef typename ObjectFile::template ELFEntityIterator + GOTIter; + + const ObjectFile *Obj; + StreamWriter &W; + llvm::Optional DtPltGot; + llvm::Optional DtLocalGotNum; + llvm::Optional DtGotSym; + llvm::Optional DtMipsPltGot; + llvm::Optional DtJmpRel; + + std::size_t getGOTTotal(ArrayRef GOT) const; + GOTIter makeGOTIter(ArrayRef GOT, std::size_t EntryNum); + + void printGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It); + void printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, GOTIter It, + const Elf_Sym *Sym, StringRef StrTable, + bool IsDynamic); + void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It, + StringRef Purpose); + void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It, + StringRef StrTable, const Elf_Sym *Sym); +}; +} + +template +MipsGOTParser::MipsGOTParser(const ObjectFile *Obj, + Elf_Dyn_Range DynTable, StreamWriter &W) + : Obj(Obj), W(W) { + for (const auto &Entry : DynTable) { + switch (Entry.getTag()) { + case ELF::DT_PLTGOT: + DtPltGot = Entry.getVal(); + break; + case ELF::DT_MIPS_LOCAL_GOTNO: + DtLocalGotNum = Entry.getVal(); + break; + case ELF::DT_MIPS_GOTSYM: + DtGotSym = Entry.getVal(); + break; + case ELF::DT_MIPS_PLTGOT: + DtMipsPltGot = Entry.getVal(); + break; + case ELF::DT_JMPREL: + DtJmpRel = Entry.getVal(); + break; + } + } +} + +template void MipsGOTParser::parseGOT() { + // See "Global Offset Table" in Chapter 5 in the following document + // for detailed GOT description. + // ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf + if (!DtPltGot) { + W.startLine() << "Cannot find PLTGOT dynamic table tag.\n"; + return; + } + if (!DtLocalGotNum) { + W.startLine() << "Cannot find MIPS_LOCAL_GOTNO dynamic table tag.\n"; + return; + } + if (!DtGotSym) { + W.startLine() << "Cannot find MIPS_GOTSYM dynamic table tag.\n"; + return; + } + + const Elf_Shdr *GOTShdr = findSectionByAddress(Obj, *DtPltGot); + if (!GOTShdr) { + W.startLine() << "There is no .got section in the file.\n"; + return; + } + + ErrorOr> GOT = Obj->getSectionContents(GOTShdr); + if (!GOT) { + W.startLine() << "The .got section is empty.\n"; + return; + } + + if (*DtLocalGotNum > getGOTTotal(*GOT)) { + W.startLine() << "MIPS_LOCAL_GOTNO exceeds a number of GOT entries.\n"; + return; + } + + const Elf_Shdr *DynSymSec = Obj->getDotDynSymSec(); + ErrorOr StrTable = Obj->getStringTableForSymtab(*DynSymSec); + error(StrTable.getError()); + const Elf_Sym *DynSymBegin = Obj->dynamic_symbol_begin(); + const Elf_Sym *DynSymEnd = Obj->dynamic_symbol_end(); + std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); + + if (*DtGotSym > DynSymTotal) { + W.startLine() << "MIPS_GOTSYM exceeds a number of dynamic symbols.\n"; + return; + } + + std::size_t GlobalGotNum = DynSymTotal - *DtGotSym; + + if (*DtLocalGotNum + GlobalGotNum > getGOTTotal(*GOT)) { + W.startLine() << "Number of global GOT entries exceeds the size of GOT.\n"; + return; + } + + GOTIter GotBegin = makeGOTIter(*GOT, 0); + GOTIter GotLocalEnd = makeGOTIter(*GOT, *DtLocalGotNum); + GOTIter It = GotBegin; + + DictScope GS(W, "Primary GOT"); + + W.printHex("Canonical gp value", GOTShdr->sh_addr + 0x7ff0); + { + ListScope RS(W, "Reserved entries"); + + { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Lazy resolver")); + } + + if (It != GotLocalEnd && (*It >> (sizeof(GOTEntry) * 8 - 1)) != 0) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It++); + W.printString("Purpose", StringRef("Module pointer (GNU extension)")); + } + } + { + ListScope LS(W, "Local entries"); + for (; It != GotLocalEnd; ++It) { + DictScope D(W, "Entry"); + printGotEntry(GOTShdr->sh_addr, GotBegin, It); + } + } + { + ListScope GS(W, "Global entries"); + + GOTIter GotGlobalEnd = makeGOTIter(*GOT, *DtLocalGotNum + GlobalGotNum); + const Elf_Sym *GotDynSym = DynSymBegin + *DtGotSym; + for (; It != GotGlobalEnd; ++It) { + DictScope D(W, "Entry"); + printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, + *StrTable, true); + } + } + + std::size_t SpecGotNum = getGOTTotal(*GOT) - *DtLocalGotNum - GlobalGotNum; + W.printNumber("Number of TLS and multi-GOT entries", uint64_t(SpecGotNum)); +} + +template void MipsGOTParser::parsePLT() { + if (!DtMipsPltGot) { + W.startLine() << "Cannot find MIPS_PLTGOT dynamic table tag.\n"; + return; + } + if (!DtJmpRel) { + W.startLine() << "Cannot find JMPREL dynamic table tag.\n"; + return; + } + + const Elf_Shdr *PLTShdr = findSectionByAddress(Obj, *DtMipsPltGot); + if (!PLTShdr) { + W.startLine() << "There is no .got.plt section in the file.\n"; + return; + } + ErrorOr> PLT = Obj->getSectionContents(PLTShdr); + if (!PLT) { + W.startLine() << "The .got.plt section is empty.\n"; + return; + } + + const Elf_Shdr *PLTRelShdr = findSectionByAddress(Obj, *DtJmpRel); + if (!PLTShdr) { + W.startLine() << "There is no .rel.plt section in the file.\n"; + return; + } + ErrorOr SymTableOrErr = + Obj->getSection(PLTRelShdr->sh_link); + error(SymTableOrErr.getError()); + ErrorOr StrTable = Obj->getStringTableForSymtab(**SymTableOrErr); + error(StrTable.getError()); + + GOTIter PLTBegin = makeGOTIter(*PLT, 0); + GOTIter PLTEnd = makeGOTIter(*PLT, getGOTTotal(*PLT)); + GOTIter It = PLTBegin; + + DictScope GS(W, "PLT GOT"); + { + ListScope RS(W, "Reserved entries"); + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It++, "PLT lazy resolver"); + if (It != PLTEnd) + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It++, "Module pointer"); + } + { + ListScope GS(W, "Entries"); + + switch (PLTRelShdr->sh_type) { + case ELF::SHT_REL: + for (const typename ObjectFile::Elf_Rel *RI = Obj->rel_begin(PLTRelShdr), + *RE = Obj->rel_end(PLTRelShdr); + RI != RE && It != PLTEnd; ++RI, ++It) { + const Elf_Sym *Sym = + Obj->getRelocationSymbol(&*PLTRelShdr, &*RI).second; + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, *StrTable, Sym); + } + break; + case ELF::SHT_RELA: + for (const typename ObjectFile::Elf_Rela + *RI = Obj->rela_begin(PLTRelShdr), + *RE = Obj->rela_end(PLTRelShdr); + RI != RE && It != PLTEnd; ++RI, ++It) { + const Elf_Sym *Sym = + Obj->getRelocationSymbol(&*PLTRelShdr, &*RI).second; + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, *StrTable, Sym); + } + break; + } + } +} + +template +std::size_t MipsGOTParser::getGOTTotal(ArrayRef GOT) const { + return GOT.size() / sizeof(GOTEntry); +} + +template +typename MipsGOTParser::GOTIter +MipsGOTParser::makeGOTIter(ArrayRef GOT, std::size_t EntryNum) { + const char *Data = reinterpret_cast(GOT.data()); + return GOTIter(sizeof(GOTEntry), Data + EntryNum * sizeof(GOTEntry)); +} + +template +void MipsGOTParser::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, + GOTIter It) { + int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); + W.printHex("Address", GotAddr + Offset); + W.printNumber("Access", Offset - 0x7ff0); + W.printHex("Initial", *It); +} + +template +void MipsGOTParser::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, + GOTIter It, const Elf_Sym *Sym, + StringRef StrTable, + bool IsDynamic) { + printGotEntry(GotAddr, BeginIt, It); + + W.printHex("Value", Sym->st_value); + W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); + + unsigned SectionIndex = 0; + StringRef SectionName; + getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + W.printHex("Section", SectionName, SectionIndex); + + std::string FullSymbolName = + getFullSymbolName(*Obj, Sym, StrTable, IsDynamic); + W.printNumber("Name", FullSymbolName, Sym->st_name); +} + +template +void MipsGOTParser::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, + GOTIter It, StringRef Purpose) { + DictScope D(W, "Entry"); + int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); + W.printHex("Address", PLTAddr + Offset); + W.printHex("Initial", *It); + W.printString("Purpose", Purpose); +} + +template +void MipsGOTParser::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, + GOTIter It, StringRef StrTable, + const Elf_Sym *Sym) { + DictScope D(W, "Entry"); + int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); + W.printHex("Address", PLTAddr + Offset); + W.printHex("Initial", *It); + W.printHex("Value", Sym->st_value); + W.printEnum("Type", Sym->getType(), makeArrayRef(ElfSymbolTypes)); + + unsigned SectionIndex = 0; + StringRef SectionName; + getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + W.printHex("Section", SectionName, SectionIndex); + + std::string FullSymbolName = getFullSymbolName(*Obj, Sym, StrTable, true); + W.printNumber("Name", FullSymbolName, Sym->st_name); +} + +template void ELFDumper::printMipsPLTGOT() { + if (Obj->getHeader()->e_machine != EM_MIPS) { + W.startLine() << "MIPS PLT GOT is available for MIPS targets only.\n"; + return; + } + + MipsGOTParser GOTParser(Obj, dynamic_table(), W); + GOTParser.parseGOT(); + GOTParser.parsePLT(); +} + +static const EnumEntry ElfMipsISAExtType[] = { + {"None", Mips::AFL_EXT_NONE}, + {"Broadcom SB-1", Mips::AFL_EXT_SB1}, + {"Cavium Networks Octeon", Mips::AFL_EXT_OCTEON}, + {"Cavium Networks Octeon2", Mips::AFL_EXT_OCTEON2}, + {"Cavium Networks OcteonP", Mips::AFL_EXT_OCTEONP}, + {"Cavium Networks Octeon3", Mips::AFL_EXT_OCTEON3}, + {"LSI R4010", Mips::AFL_EXT_4010}, + {"Loongson 2E", Mips::AFL_EXT_LOONGSON_2E}, + {"Loongson 2F", Mips::AFL_EXT_LOONGSON_2F}, + {"Loongson 3A", Mips::AFL_EXT_LOONGSON_3A}, + {"MIPS R4650", Mips::AFL_EXT_4650}, + {"MIPS R5900", Mips::AFL_EXT_5900}, + {"MIPS R10000", Mips::AFL_EXT_10000}, + {"NEC VR4100", Mips::AFL_EXT_4100}, + {"NEC VR4111/VR4181", Mips::AFL_EXT_4111}, + {"NEC VR4120", Mips::AFL_EXT_4120}, + {"NEC VR5400", Mips::AFL_EXT_5400}, + {"NEC VR5500", Mips::AFL_EXT_5500}, + {"RMI Xlr", Mips::AFL_EXT_XLR}, + {"Toshiba R3900", Mips::AFL_EXT_3900} +}; + +static const EnumEntry ElfMipsASEFlags[] = { + {"DSP", Mips::AFL_ASE_DSP}, + {"DSPR2", Mips::AFL_ASE_DSPR2}, + {"Enhanced VA Scheme", Mips::AFL_ASE_EVA}, + {"MCU", Mips::AFL_ASE_MCU}, + {"MDMX", Mips::AFL_ASE_MDMX}, + {"MIPS-3D", Mips::AFL_ASE_MIPS3D}, + {"MT", Mips::AFL_ASE_MT}, + {"SmartMIPS", Mips::AFL_ASE_SMARTMIPS}, + {"VZ", Mips::AFL_ASE_VIRT}, + {"MSA", Mips::AFL_ASE_MSA}, + {"MIPS16", Mips::AFL_ASE_MIPS16}, + {"microMIPS", Mips::AFL_ASE_MICROMIPS}, + {"XPA", Mips::AFL_ASE_XPA} +}; + +static const EnumEntry ElfMipsFpABIType[] = { + {"Hard or soft float", Mips::Val_GNU_MIPS_ABI_FP_ANY}, + {"Hard float (double precision)", Mips::Val_GNU_MIPS_ABI_FP_DOUBLE}, + {"Hard float (single precision)", Mips::Val_GNU_MIPS_ABI_FP_SINGLE}, + {"Soft float", Mips::Val_GNU_MIPS_ABI_FP_SOFT}, + {"Hard float (MIPS32r2 64-bit FPU 12 callee-saved)", + Mips::Val_GNU_MIPS_ABI_FP_OLD_64}, + {"Hard float (32-bit CPU, Any FPU)", Mips::Val_GNU_MIPS_ABI_FP_XX}, + {"Hard float (32-bit CPU, 64-bit FPU)", Mips::Val_GNU_MIPS_ABI_FP_64}, + {"Hard float compat (32-bit CPU, 64-bit FPU)", + Mips::Val_GNU_MIPS_ABI_FP_64A} +}; + +static const EnumEntry ElfMipsFlags1[] { + {"ODDSPREG", Mips::AFL_FLAGS1_ODDSPREG}, +}; + +static int getMipsRegisterSize(uint8_t Flag) { + switch (Flag) { + case Mips::AFL_REG_NONE: + return 0; + case Mips::AFL_REG_32: + return 32; + case Mips::AFL_REG_64: + return 64; + case Mips::AFL_REG_128: + return 128; + default: + return -1; + } +} + +template void ELFDumper::printMipsABIFlags() { + const Elf_Shdr *Shdr = findSectionByName(*Obj, ".MIPS.abiflags"); + if (!Shdr) { + W.startLine() << "There is no .MIPS.abiflags section in the file.\n"; + return; + } + ErrorOr> Sec = Obj->getSectionContents(Shdr); + if (!Sec) { + W.startLine() << "The .MIPS.abiflags section is empty.\n"; + return; + } + if (Sec->size() != sizeof(Elf_Mips_ABIFlags)) { + W.startLine() << "The .MIPS.abiflags section has a wrong size.\n"; + return; + } + + auto *Flags = reinterpret_cast *>(Sec->data()); + + raw_ostream &OS = W.getOStream(); + DictScope GS(W, "MIPS ABI Flags"); + + W.printNumber("Version", Flags->version); + W.startLine() << "ISA: "; + if (Flags->isa_rev <= 1) + OS << format("MIPS%u", Flags->isa_level); + else + OS << format("MIPS%ur%u", Flags->isa_level, Flags->isa_rev); + OS << "\n"; + W.printEnum("ISA Extension", Flags->isa_ext, makeArrayRef(ElfMipsISAExtType)); + W.printFlags("ASEs", Flags->ases, makeArrayRef(ElfMipsASEFlags)); + W.printEnum("FP ABI", Flags->fp_abi, makeArrayRef(ElfMipsFpABIType)); + W.printNumber("GPR size", getMipsRegisterSize(Flags->gpr_size)); + W.printNumber("CPR1 size", getMipsRegisterSize(Flags->cpr1_size)); + W.printNumber("CPR2 size", getMipsRegisterSize(Flags->cpr2_size)); + W.printFlags("Flags 1", Flags->flags1, makeArrayRef(ElfMipsFlags1)); + W.printHex("Flags 2", Flags->flags2); +} + +template void ELFDumper::printMipsReginfo() { + const Elf_Shdr *Shdr = findSectionByName(*Obj, ".reginfo"); + if (!Shdr) { + W.startLine() << "There is no .reginfo section in the file.\n"; + return; + } + ErrorOr> Sec = Obj->getSectionContents(Shdr); + if (!Sec) { + W.startLine() << "The .reginfo section is empty.\n"; + return; + } + if (Sec->size() != sizeof(Elf_Mips_RegInfo)) { + W.startLine() << "The .reginfo section has a wrong size.\n"; + return; + } + + auto *Reginfo = reinterpret_cast *>(Sec->data()); + + DictScope GS(W, "MIPS RegInfo"); + W.printHex("GP", Reginfo->ri_gp_value); + W.printHex("General Mask", Reginfo->ri_gprmask); + W.printHex("Co-Proc Mask0", Reginfo->ri_cprmask[0]); + W.printHex("Co-Proc Mask1", Reginfo->ri_cprmask[1]); + W.printHex("Co-Proc Mask2", Reginfo->ri_cprmask[2]); + W.printHex("Co-Proc Mask3", Reginfo->ri_cprmask[3]); +} + +template void ELFDumper::printStackMap() const { + const typename ELFFile::Elf_Shdr *StackMapSection = nullptr; + for (const auto &Sec : Obj->sections()) { + ErrorOr Name = Obj->getSectionName(&Sec); + if (*Name == ".llvm_stackmaps") { + StackMapSection = &Sec; + break; + } + } + + if (!StackMapSection) + return; + + StringRef StackMapContents; + ErrorOr> StackMapContentsArray = + Obj->getSectionContents(StackMapSection); + + prettyPrintStackMap( + llvm::outs(), + StackMapV1Parser(*StackMapContentsArray)); }