X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=tools%2Fllvm-readobj%2FELFDumper.cpp;h=8074a35ed464190032df45352dd8615091f476a5;hb=3f1d2f9e7863ced5221b1c5afef80ac7aa6bd479;hp=71f03bc3d0690ddadb9add5e0838bc80a41d4156;hpb=766f25306af343fb2784350cb4d8cd9ca180f0d3;p=oota-llvm.git diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 71f03bc3d06..8074a35ed46 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -13,15 +13,21 @@ //===----------------------------------------------------------------------===// #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/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; @@ -36,36 +42,79 @@ namespace { template class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFFile *Obj, StreamWriter &Writer) - : ObjDumper(Writer), Obj(Obj) {} + ELFDumper(const ELFFile *Obj, StreamWriter &Writer); + + void printFileHeaders() override; + void printSections() override; + void printRelocations() override; + void printDynamicRelocations() override; + void printSymbols() override; + void printDynamicSymbols() override; + void printUnwindInfo() override; + + void printDynamicTable() override; + void printNeededLibraries() override; + void printProgramHeaders() override; + void printHashTable() override; + void printLoadName() override; - 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 printAttributes() override; + void printMipsPLTGOT() override; + void printMipsABIFlags() override; + void printMipsReginfo() override; - virtual void printDynamicTable() LLVM_OVERRIDE; - virtual void printNeededLibraries() LLVM_OVERRIDE; - virtual void printProgramHeaders() LLVM_OVERRIDE; + void printStackMap() const override; private: typedef ELFFile ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; - - void printSymbol(typename ELFO::Elf_Sym_Iter Symbol); + 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 ELFO *Obj; + DynRegionInfo DynRelaRegion; + DynRegionInfo DynamicRegion; + StringRef DynamicStringTable; + StringRef SOName; + const Elf_Hash *HashTable = nullptr; }; template T errorOrDefault(ErrorOr Val, T Default = T()) { if (!Val) { - error(Val); + error(Val.getError()); return Default; } @@ -76,16 +125,16 @@ template T errorOrDefault(ErrorOr Val, T Default = T()) { namespace llvm { template -static error_code createELFDumper(const ELFFile *Obj, - StreamWriter &Writer, - OwningPtr &Result) { +static std::error_code createELFDumper(const ELFFile *Obj, + StreamWriter &Writer, + std::unique_ptr &Result) { Result.reset(new ELFDumper(Obj, Writer)); return readobj_error::success; } -error_code createELFDumper(const object::ObjectFile *Obj, - StreamWriter& Writer, - OwningPtr &Result) { +std::error_code createELFDumper(const object::ObjectFile *Obj, + StreamWriter &Writer, + std::unique_ptr &Result) { // Little-endian 32-bit if (const ELF32LEObjectFile *ELFObj = dyn_cast(Obj)) return createELFDumper(ELFObj->getELFFile(), Writer, Result); @@ -107,6 +156,72 @@ error_code createELFDumper(const object::ObjectFile *Obj, } // 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 }, { "32-bit", ELF::ELFCLASS32 }, @@ -144,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 }, @@ -157,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 ), @@ -305,13 +421,15 @@ static const EnumEntry ElfMachineType[] = { LLVM_READOBJ_ENUM_ENT(ELF, EM_RL78 ), 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_56800EX ), + 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[] = { @@ -344,6 +462,7 @@ static const char *getElfSectionType(unsigned Arch, unsigned Type) { 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); } } @@ -391,26 +510,42 @@ static const EnumEntry ElfSectionFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) }; -static const EnumEntry ElfSegmentTypes[] = { - LLVM_READOBJ_ENUM_ENT(ELF, PT_NULL ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_LOAD ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_DYNAMIC), - LLVM_READOBJ_ENUM_ENT(ELF, PT_INTERP ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_NOTE ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_SHLIB ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_PHDR ), - LLVM_READOBJ_ENUM_ENT(ELF, PT_TLS ), - - LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_EH_FRAME), - LLVM_READOBJ_ENUM_ENT(ELF, PT_SUNW_EH_FRAME), - LLVM_READOBJ_ENUM_ENT(ELF, PT_SUNW_UNWIND), - - LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_STACK), - LLVM_READOBJ_ENUM_ENT(ELF, PT_GNU_RELRO), - - LLVM_READOBJ_ENUM_ENT(ELF, PT_ARM_EXIDX), - LLVM_READOBJ_ENUM_ENT(ELF, PT_ARM_UNWIND) -}; +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), @@ -418,10 +553,156 @@ static const EnumEntry ElfSegmentFlags[] = { 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; - const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); { @@ -435,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)); @@ -447,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); @@ -462,46 +754,49 @@ void ELFDumper::printSections() { ListScope SectionsD(W, "Sections"); int SectionIndex = -1; - for (typename ELFO::Elf_Shdr_Iter SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; ++SecI) { + for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { ++SectionIndex; - const Elf_Shdr *Section = &*SecI; - StringRef Name = errorOrDefault(Obj->getSectionName(Section)); + StringRef Name = errorOrDefault(Obj->getSectionName(&Sec)); DictScope SectionD(W, "Section"); W.printNumber("Index", SectionIndex); - W.printNumber("Name", Name, Section->sh_name); + W.printNumber("Name", Name, Sec.sh_name); W.printHex("Type", - getElfSectionType(Obj->getHeader()->e_machine, 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); + 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"); - printRelocations(Section); + printRelocations(&Sec); } if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; ++SymI) { - if (Obj->getSection(&*SymI) == Section) - 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()) { + ErrorOr SymSec = Obj->getSection(&Sym); + if (!SymSec) + continue; + if (*SymSec == &Sec) + printSymbol(&Sym, StrTable, false); } } - if (opts::SectionData) { - ArrayRef Data = errorOrDefault(Obj->getSectionContents(Section)); + 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())); } @@ -512,48 +807,69 @@ template void ELFDumper::printRelocations() { ListScope D(W, "Relocations"); - error_code EC; int SectionNumber = -1; - for (typename ELFO::Elf_Shdr_Iter SecI = Obj->begin_sections(), - SecE = Obj->end_sections(); - SecI != SecE; ++SecI) { + for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { ++SectionNumber; - if (SecI->sh_type != ELF::SHT_REL && SecI->sh_type != ELF::SHT_RELA) + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) continue; - StringRef Name = errorOrDefault(Obj->getSectionName(&*SecI)); + StringRef Name = errorOrDefault(Obj->getSectionName(&Sec)); W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; W.indent(); - printRelocations(&*SecI); + printRelocations(&Sec); W.unindent(); W.startLine() << "}\n"; } } +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"; +} + template void ELFDumper::printRelocations(const Elf_Shdr *Sec) { switch (Sec->sh_type) { case ELF::SHT_REL: - for (typename ELFO::Elf_Rel_Iter RI = Obj->begin_rel(Sec), - RE = Obj->end_rel(Sec); - RI != RE; ++RI) { + for (const typename ELFO::Elf_Rel &R : Obj->rels(Sec)) { typename ELFO::Elf_Rela Rela; - Rela.r_offset = RI->r_offset; - Rela.r_info = RI->r_info; + 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 (typename ELFO::Elf_Rela_Iter RI = Obj->begin_rela(Sec), - RE = Obj->end_rela(Sec); - RI != RE; ++RI) { - printRelocation(Sec, *RI); - } + for (const typename ELFO::Elf_Rela &R : Obj->relas(Sec)) + printRelocation(Sec, R); break; } } @@ -563,64 +879,69 @@ void ELFDumper::printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel) { SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); - StringRef SymbolName; + StringRef TargetName; std::pair Sym = Obj->getRelocationSymbol(Sec, &Rel); - if (Sym.first) - SymbolName = errorOrDefault(Obj->getSymbolName(Sym.first, Sym.second)); + 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", Rel.r_offset); W.printNumber("Type", RelocName, (int)Rel.getType(Obj->isMips64EL())); - W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); + 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(Rel.r_offset) - << " " << RelocName - << " " << (SymbolName.size() > 0 ? SymbolName : "-") - << " " << W.hex(Rel.r_addend) - << "\n"; + OS << W.hex(Rel.r_offset) << " " << RelocName << " " + << (TargetName.size() > 0 ? TargetName : "-") << " " + << W.hex(Rel.r_addend) << "\n"; } } template void ELFDumper::printSymbols() { ListScope Group(W, "Symbols"); - for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_symbols(), - SymE = Obj->end_symbols(); - SymI != SymE; ++SymI) { - 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"); - for (typename ELFO::Elf_Sym_Iter SymI = Obj->begin_dynamic_symbols(), - SymE = Obj->end_dynamic_symbols(); - SymI != SymE; ++SymI) { - printSymbol(SymI); - } + 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(typename ELFO::Elf_Sym_Iter Symbol) { - StringRef SymbolName = errorOrDefault(Obj->getSymbolName(Symbol)); - const Elf_Shdr *Sec = Obj->getSection(&*Symbol); - StringRef SectionName = Sec ? errorOrDefault(Obj->getSectionName(Sec)) : ""; - std::string FullSymbolName(SymbolName); - if (Symbol.isDynamic()) { - bool IsDefault; - ErrorOr Version = Obj->getSymbolVersion(0, &*Symbol, IsDefault); - if (Version) { - FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += *Version; - } else - error(Version); - } +void ELFDumper::printSymbol(const typename ELFO::Elf_Sym *Symbol, + StringRef StrTable, bool IsDynamic) { + unsigned SectionIndex = 0; + StringRef SectionName; + getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex); + std::string FullSymbolName = + getFullSymbolName(*Obj, Symbol, StrTable, IsDynamic); DictScope D(W, "Symbol"); W.printNumber("Name", FullSymbolName, Symbol->st_name); @@ -630,7 +951,7 @@ void ELFDumper::printSymbol(typename ELFO::Elf_Sym_Iter Symbol) { 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) \ @@ -644,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); @@ -671,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 +#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 -static void printValue(const ELFFile *O, uint64_t Type, uint64_t Value, - bool Is64, raw_ostream &OS) { +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) { @@ -703,9 +1126,25 @@ static void printValue(const ELFFile *O, uint64_t Type, uint64_t Value, 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: @@ -719,14 +1158,26 @@ static void printValue(const ELFFile *O, uint64_t Type, uint64_t Value, OS << Value << " (bytes)"; break; case DT_NEEDED: - OS << "SharedLibrary (" << O->getDynamicString(Value) << ")"; + OS << "SharedLibrary (" << getDynamicString(Value) << ")"; break; case DT_SONAME: - OS << "LibrarySoname (" << O->getDynamicString(Value) << ")"; + OS << "LibrarySoname (" << getDynamicString(Value) << ")"; break; case DT_RPATH: case DT_RUNPATH: - OS << O->getDynamicString(Value); + 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; } } @@ -736,15 +1187,36 @@ 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 typename ELFO::Elf_Dyn_Iter EDI; - EDI Start = Obj->begin_dynamic_table(), End = Obj->end_dynamic_table(true); + auto I = dynamic_table_begin(); + auto E = dynamic_table_end(); - if (Start == End) + if (I == E) + return; + + --E; + while (I != E && E->getTag() == ELF::DT_NULL) + --E; + if (E->getTag() != ELF::DT_NULL) + ++E; + ++E; + + ptrdiff_t Total = std::distance(I, E); + if (Total == 0) return; - ptrdiff_t Total = std::distance(Start, End); raw_ostream &OS = W.getOStream(); W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; @@ -753,12 +1225,14 @@ void ELFDumper::printDynamicTable() { 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"; } @@ -769,16 +1243,12 @@ template void ELFDumper::printNeededLibraries() { ListScope D(W, "NeededLibraries"); - error_code EC; - typedef std::vector LibsTy; LibsTy Libs; - for (typename ELFO::Elf_Dyn_Iter DynI = Obj->begin_dynamic_table(), - DynE = Obj->end_dynamic_table(); - DynI != DynE; ++DynI) - if (DynI->d_tag == ELF::DT_NEEDED) - Libs.push_back(Obj->getDynamicString(DynI->d_un.d_val)); + for (const auto &Entry : dynamic_table()) + if (Entry.d_tag == ELF::DT_NEEDED) + Libs.push_back(getDynamicString(Entry.d_un.d_val)); std::stable_sort(Libs.begin(), Libs.end()); @@ -791,17 +1261,541 @@ template void ELFDumper::printProgramHeaders() { ListScope L(W, "ProgramHeaders"); - for (typename ELFO::Elf_Phdr_Iter PI = Obj->begin_program_headers(), - PE = Obj->end_program_headers(); - PI != PE; ++PI) { + for (const typename ELFO::Elf_Phdr &Phdr : Obj->program_headers()) { DictScope P(W, "ProgramHeader"); - W.printEnum ("Type", PI->p_type, makeArrayRef(ElfSegmentTypes)); - W.printHex ("Offset", PI->p_offset); - W.printHex ("VirtualAddress", PI->p_vaddr); - W.printHex ("PhysicalAddress", PI->p_paddr); - W.printNumber("FileSize", PI->p_filesz); - W.printNumber("MemSize", PI->p_memsz); - W.printFlags ("Flags", PI->p_flags, makeArrayRef(ElfSegmentFlags)); - W.printNumber("Alignment", PI->p_align); + 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'; +} + +template +void ELFDumper::printAttributes() { + W.startLine() << "Attributes not implemented.\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)); +}