diff options
Diffstat (limited to 'contrib/llvm/tools/llvm-readobj/ELFDumper.cpp')
-rw-r--r-- | contrib/llvm/tools/llvm-readobj/ELFDumper.cpp | 907 |
1 files changed, 724 insertions, 183 deletions
diff --git a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp index 1cdf5529c080..02397f382848 100644 --- a/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/contrib/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -42,8 +42,7 @@ namespace { template<typename ELFT> class ELFDumper : public ObjDumper { public: - ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) - : ObjDumper(Writer), Obj(Obj) {} + ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer); void printFileHeaders() override; void printSections() override; @@ -57,6 +56,9 @@ public: void printNeededLibraries() override; void printProgramHeaders() override; void printHashTable() override; + void printGnuHashTable() override; + void printLoadName() override; + void printVersionInfo() override; void printAttributes() override; void printMipsPLTGOT() override; @@ -69,13 +71,114 @@ private: typedef ELFFile<ELFT> ELFO; typedef typename ELFO::Elf_Shdr Elf_Shdr; typedef typename ELFO::Elf_Sym Elf_Sym; - - void printSymbol(const Elf_Sym *Symbol, bool IsDynamic); + typedef typename ELFO::Elf_Dyn Elf_Dyn; + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; + typedef typename ELFO::Elf_Rel Elf_Rel; + 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_Half Elf_Half; + typedef typename ELFO::Elf_Hash Elf_Hash; + typedef typename ELFO::Elf_GnuHash Elf_GnuHash; + typedef typename ELFO::Elf_Ehdr Elf_Ehdr; + typedef typename ELFO::Elf_Word Elf_Word; + typedef typename ELFO::uintX_t uintX_t; + typedef typename ELFO::Elf_Versym Elf_Versym; + typedef typename ELFO::Elf_Verneed Elf_Verneed; + typedef typename ELFO::Elf_Vernaux Elf_Vernaux; + typedef typename ELFO::Elf_Verdef Elf_Verdef; + typedef typename ELFO::Elf_Verdaux Elf_Verdaux; + + /// \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 printSymbolsHelper(bool IsDynamic); + void printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, + StringRef StrTable, bool IsDynamic); void printRelocations(const Elf_Shdr *Sec); - void printRelocation(const Elf_Shdr *Sec, typename ELFO::Elf_Rela Rel); + void printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab); + 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 { + ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_begin(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + const Elf_Dyn *dynamic_table_end() const { + ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_end(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, + bool &IsDefault); + void LoadVersionMap(); + void LoadVersionNeeds(const Elf_Shdr *ec) const; + void LoadVersionDefs(const Elf_Shdr *sec) const; const ELFO *Obj; + DynRegionInfo DynRelaRegion; + const Elf_Phdr *DynamicProgHeader = nullptr; + StringRef DynamicStringTable; + const Elf_Sym *DynSymStart = nullptr; + StringRef SOName; + const Elf_Hash *HashTable = nullptr; + const Elf_GnuHash *GnuHashTable = nullptr; + const Elf_Shdr *DotDynSymSec = nullptr; + const Elf_Shdr *DotSymtabSec = nullptr; + ArrayRef<Elf_Word> ShndxTable; + + const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version + const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r + const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d + + // Records for each version index the corresponding Verdef or Vernaux entry. + // This is filled the first time LoadVersionMap() is called. + class VersionMapEntry : public PointerIntPair<const void *, 1> { + public: + // If the integer is 0, this is an Elf_Verdef*. + // If the integer is 1, this is an Elf_Vernaux*. + VersionMapEntry() : PointerIntPair<const void *, 1>(nullptr, 0) {} + VersionMapEntry(const Elf_Verdef *verdef) + : PointerIntPair<const void *, 1>(verdef, 0) {} + VersionMapEntry(const Elf_Vernaux *vernaux) + : PointerIntPair<const void *, 1>(vernaux, 1) {} + bool isNull() const { return getPointer() == nullptr; } + bool isVerdef() const { return !isNull() && getInt() == 0; } + bool isVernaux() const { return !isNull() && getInt() == 1; } + const Elf_Verdef *getVerdef() const { + return isVerdef() ? (const Elf_Verdef *)getPointer() : nullptr; + } + const Elf_Vernaux *getVernaux() const { + return isVernaux() ? (const Elf_Vernaux *)getPointer() : nullptr; + } + }; + mutable SmallVector<VersionMapEntry, 16> VersionMap; + +public: + Elf_Dyn_Range dynamic_table() const { + ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + + std::string getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, + bool IsDynamic); + const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } + const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } + ArrayRef<Elf_Word> getShndxTable() { return ShndxTable; } }; template <class T> T errorOrDefault(ErrorOr<T> Val, T Default = T()) { @@ -122,30 +225,246 @@ std::error_code createELFDumper(const object::ObjectFile *Obj, } // namespace llvm -template <typename ELFO> -static std::string getFullSymbolName(const ELFO &Obj, - const typename ELFO::Elf_Sym *Symbol, - bool IsDynamic) { - StringRef SymbolName = errorOrDefault(Obj.getSymbolName(Symbol, IsDynamic)); +// Iterate through the versions needed section, and place each Elf_Vernaux +// in the VersionMap according to its index. +template <class ELFT> +void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *sec) const { + unsigned vn_size = sec->sh_size; // Size of section in bytes + unsigned vn_count = sec->sh_info; // Number of Verneed entries + const char *sec_start = (const char *)Obj->base() + sec->sh_offset; + const char *sec_end = sec_start + vn_size; + // The first Verneed entry is at the start of the section. + const char *p = sec_start; + for (unsigned i = 0; i < vn_count; i++) { + if (p + sizeof(Elf_Verneed) > sec_end) + report_fatal_error("Section ended unexpectedly while scanning " + "version needed records."); + const Elf_Verneed *vn = reinterpret_cast<const Elf_Verneed *>(p); + if (vn->vn_version != ELF::VER_NEED_CURRENT) + report_fatal_error("Unexpected verneed version"); + // Iterate through the Vernaux entries + const char *paux = p + vn->vn_aux; + for (unsigned j = 0; j < vn->vn_cnt; j++) { + if (paux + sizeof(Elf_Vernaux) > sec_end) + report_fatal_error("Section ended unexpected while scanning auxiliary " + "version needed records."); + const Elf_Vernaux *vna = reinterpret_cast<const Elf_Vernaux *>(paux); + size_t index = vna->vna_other & ELF::VERSYM_VERSION; + if (index >= VersionMap.size()) + VersionMap.resize(index + 1); + VersionMap[index] = VersionMapEntry(vna); + paux += vna->vna_next; + } + p += vn->vn_next; + } +} + +// Iterate through the version definitions, and place each Elf_Verdef +// in the VersionMap according to its index. +template <class ELFT> +void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *sec) const { + unsigned vd_size = sec->sh_size; // Size of section in bytes + unsigned vd_count = sec->sh_info; // Number of Verdef entries + const char *sec_start = (const char *)Obj->base() + sec->sh_offset; + const char *sec_end = sec_start + vd_size; + // The first Verdef entry is at the start of the section. + const char *p = sec_start; + for (unsigned i = 0; i < vd_count; i++) { + if (p + sizeof(Elf_Verdef) > sec_end) + report_fatal_error("Section ended unexpectedly while scanning " + "version definitions."); + const Elf_Verdef *vd = reinterpret_cast<const Elf_Verdef *>(p); + if (vd->vd_version != ELF::VER_DEF_CURRENT) + report_fatal_error("Unexpected verdef version"); + size_t index = vd->vd_ndx & ELF::VERSYM_VERSION; + if (index >= VersionMap.size()) + VersionMap.resize(index + 1); + VersionMap[index] = VersionMapEntry(vd); + p += vd->vd_next; + } +} + +template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() { + // If there is no dynamic symtab or version table, there is nothing to do. + if (!DynSymStart || !dot_gnu_version_sec) + return; + + // Has the VersionMap already been loaded? + if (VersionMap.size() > 0) + return; + + // The first two version indexes are reserved. + // Index 0 is LOCAL, index 1 is GLOBAL. + VersionMap.push_back(VersionMapEntry()); + VersionMap.push_back(VersionMapEntry()); + + if (dot_gnu_version_d_sec) + LoadVersionDefs(dot_gnu_version_d_sec); + + if (dot_gnu_version_r_sec) + LoadVersionNeeds(dot_gnu_version_r_sec); +} + + +template <typename ELFO, class ELFT> +static void printVersionSymbolSection(ELFDumper<ELFT> *Dumper, + const ELFO *Obj, + const typename ELFO::Elf_Shdr *Sec, + StreamWriter &W) { + DictScope SS(W, "Version symbols"); + if (!Sec) + return; + StringRef Name = errorOrDefault(Obj->getSectionName(Sec)); + W.printNumber("Section Name", Name, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + const typename ELFO::Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); + const uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset; + ErrorOr<StringRef> StrTableOrErr = + Obj->getStringTableForSymtab(*DynSymSec); + error(StrTableOrErr.getError()); + + // Same number of entries in the dynamic symbol table (DT_SYMTAB). + ListScope Syms(W, "Symbols"); + for (const typename ELFO::Elf_Sym &Sym : Obj->symbols(DynSymSec)) { + DictScope S(W, "Symbol"); + std::string FullSymbolName = + Dumper->getFullSymbolName(&Sym, *StrTableOrErr, true /* IsDynamic */); + W.printNumber("Version", *P); + W.printString("Name", FullSymbolName); + P += sizeof(typename ELFO::Elf_Half); + } +} + +template <typename ELFO, class ELFT> +static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper, + const ELFO *Obj, + const typename ELFO::Elf_Shdr *Sec, + StreamWriter &W) { + DictScope SD(W, "Version definition"); + if (!Sec) + return; + StringRef Name = errorOrDefault(Obj->getSectionName(Sec)); + W.printNumber("Section Name", Name, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + unsigned verdef_entries = 0; + // The number of entries in the section SHT_GNU_verdef + // is determined by DT_VERDEFNUM tag. + for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) { + if (Dyn.d_tag == DT_VERDEFNUM) + verdef_entries = Dyn.d_un.d_val; + } + const uint8_t *SecStartAddress = + (const uint8_t *)Obj->base() + Sec->sh_offset; + const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; + const uint8_t *P = SecStartAddress; + ErrorOr<const typename ELFO::Elf_Shdr *> StrTabOrErr = + Obj->getSection(Sec->sh_link); + error(StrTabOrErr.getError()); + + ListScope Entries(W, "Entries"); + for (unsigned i = 0; i < verdef_entries; ++i) { + if (P + sizeof(typename ELFO::Elf_Verdef) > SecEndAddress) + report_fatal_error("invalid offset in the section"); + auto *VD = reinterpret_cast<const typename ELFO::Elf_Verdef *>(P); + DictScope Entry(W, "Entry"); + W.printHex("Offset", (uintptr_t)P - (uintptr_t)SecStartAddress); + W.printNumber("Rev", VD->vd_version); + // FIXME: print something more readable. + W.printNumber("Flags", VD->vd_flags); + W.printNumber("Index", VD->vd_ndx); + W.printNumber("Cnt", VD->vd_cnt); + W.printString("Name", StringRef((const char *)(Obj->base() + + (*StrTabOrErr)->sh_offset + + VD->getAux()->vda_name))); + P += VD->vd_next; + } +} + +template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() { + // Dump version symbol section. + printVersionSymbolSection(this, Obj, dot_gnu_version_sec, W); + + // Dump version definition section. + printVersionDefinitionSection(this, Obj, dot_gnu_version_d_sec, W); +} + +template <typename ELFT> +StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, + const Elf_Sym *symb, + bool &IsDefault) { + // This is a dynamic symbol. Look in the GNU symbol version table. + if (!dot_gnu_version_sec) { + // No version table. + IsDefault = false; + return StringRef(""); + } + + // Determine the position in the symbol table of this entry. + size_t entry_index = (reinterpret_cast<uintptr_t>(symb) - + reinterpret_cast<uintptr_t>(DynSymStart)) / + sizeof(Elf_Sym); + + // Get the corresponding version index entry + const Elf_Versym *vs = + Obj->template getEntry<Elf_Versym>(dot_gnu_version_sec, entry_index); + size_t version_index = vs->vs_index & ELF::VERSYM_VERSION; + + // Special markers for unversioned symbols. + if (version_index == ELF::VER_NDX_LOCAL || + version_index == ELF::VER_NDX_GLOBAL) { + IsDefault = false; + return StringRef(""); + } + + // Lookup this symbol in the version table + LoadVersionMap(); + if (version_index >= VersionMap.size() || VersionMap[version_index].isNull()) + reportError("Invalid version entry"); + const VersionMapEntry &entry = VersionMap[version_index]; + + // Get the version name string + size_t name_offset; + if (entry.isVerdef()) { + // The first Verdaux entry holds the name. + name_offset = entry.getVerdef()->getAux()->vda_name; + IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN); + } else { + name_offset = entry.getVernaux()->vna_name; + IsDefault = false; + } + if (name_offset >= StrTab.size()) + reportError("Invalid string offset"); + return StringRef(StrTab.data() + name_offset); +} + +template <typename ELFT> +std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, + StringRef StrTable, + bool IsDynamic) { + StringRef SymbolName = errorOrDefault(Symbol->getName(StrTable)); if (!IsDynamic) return SymbolName; std::string FullSymbolName(SymbolName); bool IsDefault; - ErrorOr<StringRef> Version = - Obj.getSymbolVersion(nullptr, &*Symbol, IsDefault); - if (Version) { - FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += *Version; - } else - error(Version.getError()); + StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault); + FullSymbolName += (IsDefault ? "@@" : "@"); + FullSymbolName += Version; return FullSymbolName; } template <typename ELFO> static void getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, + const typename ELFO::Elf_Shdr *SymTab, + ArrayRef<typename ELFO::Elf_Word> ShndxTable, StringRef &SectionName, unsigned &SectionIndex) { SectionIndex = Symbol->st_shndx; if (Symbol->isUndefined()) @@ -162,25 +481,26 @@ getSectionNameIndex(const ELFO &Obj, const typename ELFO::Elf_Sym *Symbol, SectionName = "Reserved"; else { if (SectionIndex == SHN_XINDEX) - SectionIndex = Obj.getExtendedSymbolTableIndex(&*Symbol); + SectionIndex = + Obj.getExtendedSymbolTableIndex(Symbol, SymTab, ShndxTable); ErrorOr<const typename ELFO::Elf_Shdr *> Sec = Obj.getSection(SectionIndex); - if (!error(Sec.getError())) - SectionName = errorOrDefault(Obj.getSectionName(*Sec)); + error(Sec.getError()); + SectionName = errorOrDefault(Obj.getSectionName(*Sec)); } } -template <class ELFT> -static const typename ELFFile<ELFT>::Elf_Shdr * -findSectionByAddress(const ELFFile<ELFT> *Obj, uint64_t Addr) { +template <class ELFO> +static const typename ELFO::Elf_Shdr *findSectionByAddress(const ELFO *Obj, + uint64_t Addr) { for (const auto &Shdr : Obj->sections()) if (Shdr.sh_addr == Addr) return &Shdr; return nullptr; } -template <class ELFT> -static const typename ELFFile<ELFT>::Elf_Shdr * -findSectionByName(const ELFFile<ELFT> &Obj, StringRef Name) { +template <class ELFO> +static const typename ELFO::Elf_Shdr *findSectionByName(const ELFO &Obj, + StringRef Name) { for (const auto &Shdr : Obj.sections()) { if (Name == errorOrDefault(Obj.getSectionName(&Shdr))) return &Shdr; @@ -409,6 +729,12 @@ static const EnumEntry<unsigned> ElfSymbolTypes[] = { { "GNU_IFunc", ELF::STT_GNU_IFUNC } }; +static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = { + { "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL }, + { "AMDGPU_HSA_INDIRECT_FUNCTION", ELF::STT_AMDGPU_HSA_INDIRECT_FUNCTION }, + { "AMDGPU_HSA_METADATA", ELF::STT_AMDGPU_HSA_METADATA } +}; + static const char *getElfSectionType(unsigned Arch, unsigned Type) { switch (Arch) { case ELF::EM_ARM: @@ -473,13 +799,24 @@ static const EnumEntry<unsigned> ElfSectionFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, SHF_TLS ), LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_CP_SECTION), LLVM_READOBJ_ENUM_ENT(ELF, XCORE_SHF_DP_SECTION), - LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ) + LLVM_READOBJ_ENUM_ENT(ELF, SHF_MIPS_NOSTRIP ), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_GLOBAL), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_READONLY), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_CODE), + LLVM_READOBJ_ENUM_ENT(ELF, SHF_AMDGPU_HSA_AGENT) }; static const char *getElfSegmentType(unsigned Arch, unsigned Type) { // Check potentially overlapped processor-specific // program header type. switch (Arch) { + case ELF::EM_AMDGPU: + switch (Type) { + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_PROGRAM); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_GLOBAL_AGENT); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_READONLY_AGENT); + LLVM_READOBJ_ENUM_CASE(ELF, PT_AMDGPU_HSA_LOAD_CODE_AGENT); + } case ELF::EM_ARM: switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); @@ -565,9 +902,138 @@ static const EnumEntry<unsigned> ElfHeaderMipsFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_MIPS_ARCH_64R6) }; +template <typename ELFT> +ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) + : ObjDumper(Writer), Obj(Obj) { + + SmallVector<const Elf_Phdr *, 4> LoadSegments; + for (const Elf_Phdr &Phdr : Obj->program_headers()) { + if (Phdr.p_type == ELF::PT_DYNAMIC) { + DynamicProgHeader = &Phdr; + 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<ELFT>); + 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<const Elf_Hash *>(toMappedAddr(Dyn.getPtr())); + break; + case ELF::DT_GNU_HASH: + GnuHashTable = + reinterpret_cast<const Elf_GnuHash *>(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; + case ELF::DT_SYMTAB: + DynSymStart = + reinterpret_cast<const Elf_Sym *>(toMappedAddr(Dyn.getPtr())); + break; + } + } + if (StringTableBegin) + DynamicStringTable = StringRef(StringTableBegin, StringTableSize); + if (SONameOffset) + SOName = getDynamicString(SONameOffset); + + for (const Elf_Shdr &Sec : Obj->sections()) { + switch (Sec.sh_type) { + case ELF::SHT_GNU_versym: + if (dot_gnu_version_sec != nullptr) + reportError("Multiple SHT_GNU_versym"); + dot_gnu_version_sec = &Sec; + break; + case ELF::SHT_GNU_verdef: + if (dot_gnu_version_d_sec != nullptr) + reportError("Multiple SHT_GNU_verdef"); + dot_gnu_version_d_sec = &Sec; + break; + case ELF::SHT_GNU_verneed: + if (dot_gnu_version_r_sec != nullptr) + reportError("Multilpe SHT_GNU_verneed"); + dot_gnu_version_r_sec = &Sec; + break; + case ELF::SHT_DYNSYM: + if (DotDynSymSec != nullptr) + reportError("Multilpe SHT_DYNSYM"); + DotDynSymSec = &Sec; + break; + case ELF::SHT_SYMTAB: + if (DotSymtabSec != nullptr) + reportError("Multilpe SHT_SYMTAB"); + DotSymtabSec = &Sec; + break; + case ELF::SHT_SYMTAB_SHNDX: { + ErrorOr<ArrayRef<Elf_Word>> TableOrErr = Obj->getSHNDXTable(Sec); + error(TableOrErr.getError()); + ShndxTable = *TableOrErr; + break; + } + } + } +} + +template <typename ELFT> +const typename ELFDumper<ELFT>::Elf_Rela * +ELFDumper<ELFT>::dyn_rela_begin() const { + if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast<const Elf_Rela *>(DynRelaRegion.Addr); +} + +template <typename ELFT> +const typename ELFDumper<ELFT>::Elf_Rela * +ELFDumper<ELFT>::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 ELFT> +typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const { + return make_range(dyn_rela_begin(), dyn_rela_end()); +} + template<class ELFT> void ELFDumper<ELFT>::printFileHeaders() { - const typename ELFO::Elf_Ehdr *Header = Obj->getHeader(); + const Elf_Ehdr *Header = Obj->getHeader(); { DictScope D(W, "ElfHeader"); @@ -618,7 +1084,7 @@ void ELFDumper<ELFT>::printSections() { ListScope SectionsD(W, "Sections"); int SectionIndex = -1; - for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { + for (const Elf_Shdr &Sec : Obj->sections()) { ++SectionIndex; StringRef Name = errorOrDefault(Obj->getSectionName(&Sec)); @@ -645,12 +1111,18 @@ void ELFDumper<ELFT>::printSections() { if (opts::SectionSymbols) { ListScope D(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Obj->symbols()) { - ErrorOr<const Elf_Shdr *> SymSec = Obj->getSection(&Sym); + const Elf_Shdr *Symtab = DotSymtabSec; + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + + for (const Elf_Sym &Sym : Obj->symbols(Symtab)) { + ErrorOr<const Elf_Shdr *> SymSec = + Obj->getSection(&Sym, Symtab, ShndxTable); if (!SymSec) continue; if (*SymSec == &Sec) - printSymbol(&Sym, false); + printSymbol(&Sym, Symtab, StrTable, false); } } @@ -667,7 +1139,7 @@ void ELFDumper<ELFT>::printRelocations() { ListScope D(W, "Relocations"); int SectionNumber = -1; - for (const typename ELFO::Elf_Shdr &Sec : Obj->sections()) { + for (const Elf_Shdr &Sec : Obj->sections()) { ++SectionNumber; if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA) @@ -689,29 +1161,25 @@ template<class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() { W.startLine() << "Dynamic Relocations {\n"; W.indent(); - for (typename ELFO::Elf_Rela_Iter RelI = Obj->dyn_rela_begin(), - RelE = Obj->dyn_rela_end(); - RelI != RelE; ++RelI) { + for (const Elf_Rela &Rel : dyn_relas()) { SmallString<32> RelocName; - Obj->getRelocationTypeName(RelI->getType(Obj->isMips64EL()), RelocName); + Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef SymbolName; - uint32_t SymIndex = RelI->getSymbol(Obj->isMips64EL()); - const typename ELFO::Elf_Sym *Sym = Obj->dynamic_symbol_begin() + SymIndex; - SymbolName = errorOrDefault(Obj->getSymbolName(Sym, true)); + uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); + const Elf_Sym *Sym = DynSymStart + SymIndex; + SymbolName = errorOrDefault(Sym->getName(DynamicStringTable)); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); - W.printHex("Offset", RelI->r_offset); - W.printNumber("Type", RelocName, (int)RelI->getType(Obj->isMips64EL())); + 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", RelI->r_addend); + W.printHex("Addend", Rel.r_addend); } else { raw_ostream& OS = W.startLine(); - OS << W.hex(RelI->r_offset) - << " " << RelocName - << " " << (SymbolName.size() > 0 ? SymbolName : "-") - << " " << W.hex(RelI->r_addend) - << "\n"; + OS << W.hex(Rel.r_offset) << " " << RelocName << " " + << (SymbolName.size() > 0 ? SymbolName : "-") << " " + << W.hex(Rel.r_addend) << "\n"; } } W.unindent(); @@ -720,51 +1188,43 @@ void ELFDumper<ELFT>::printDynamicRelocations() { template <class ELFT> void ELFDumper<ELFT>::printRelocations(const Elf_Shdr *Sec) { + ErrorOr<const Elf_Shdr *> SymTabOrErr = Obj->getSection(Sec->sh_link); + error(SymTabOrErr.getError()); + const Elf_Shdr *SymTab = *SymTabOrErr; + switch (Sec->sh_type) { case ELF::SHT_REL: - for (typename ELFO::Elf_Rel_Iter RI = Obj->rel_begin(Sec), - RE = Obj->rel_end(Sec); - RI != RE; ++RI) { - typename ELFO::Elf_Rela Rela; - Rela.r_offset = RI->r_offset; - Rela.r_info = RI->r_info; + for (const Elf_Rel &R : Obj->rels(Sec)) { + Elf_Rela Rela; + Rela.r_offset = R.r_offset; + Rela.r_info = R.r_info; Rela.r_addend = 0; - printRelocation(Sec, Rela); + printRelocation(Rela, SymTab); } break; case ELF::SHT_RELA: - for (typename ELFO::Elf_Rela_Iter RI = Obj->rela_begin(Sec), - RE = Obj->rela_end(Sec); - RI != RE; ++RI) { - printRelocation(Sec, *RI); - } + for (const Elf_Rela &R : Obj->relas(Sec)) + printRelocation(R, SymTab); break; } } template <class ELFT> -void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec, - typename ELFO::Elf_Rela Rel) { +void ELFDumper<ELFT>::printRelocation(Elf_Rela Rel, const Elf_Shdr *SymTab) { SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); StringRef TargetName; - std::pair<const Elf_Shdr *, const Elf_Sym *> Sym = - Obj->getRelocationSymbol(Sec, &Rel); - if (Sym.second && Sym.second->getType() == ELF::STT_SECTION) { - ErrorOr<const Elf_Shdr *> Sec = Obj->getSection(Sym.second); - if (!error(Sec.getError())) { - ErrorOr<StringRef> SecName = Obj->getSectionName(*Sec); - if (SecName) - TargetName = SecName.get(); - } - } else if (Sym.first) { - const Elf_Shdr *SymTable = Sym.first; - ErrorOr<const Elf_Shdr *> StrTableSec = Obj->getSection(SymTable->sh_link); - if (!error(StrTableSec.getError())) { - ErrorOr<StringRef> StrTableOrErr = Obj->getStringTable(*StrTableSec); - if (!error(StrTableOrErr.getError())) - TargetName = errorOrDefault(Sym.second->getName(*StrTableOrErr)); - } + const Elf_Sym *Sym = Obj->getRelocationSymbol(&Rel, SymTab); + if (Sym && Sym->getType() == ELF::STT_SECTION) { + ErrorOr<const Elf_Shdr *> Sec = Obj->getSection(Sym, SymTab, ShndxTable); + error(Sec.getError()); + ErrorOr<StringRef> SecName = Obj->getSectionName(*Sec); + if (SecName) + TargetName = SecName.get(); + } else if (Sym) { + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*SymTab); + error(StrTableOrErr.getError()); + TargetName = errorOrDefault(Sym->getName(*StrTableOrErr)); } if (opts::ExpandRelocs) { @@ -783,27 +1243,38 @@ void ELFDumper<ELFT>::printRelocation(const Elf_Shdr *Sec, } template<class ELFT> +void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic) { + const Elf_Shdr *Symtab = (IsDynamic) ? DotDynSymSec : DotSymtabSec; + if (!Symtab) + return; + ErrorOr<StringRef> StrTableOrErr = Obj->getStringTableForSymtab(*Symtab); + error(StrTableOrErr.getError()); + StringRef StrTable = *StrTableOrErr; + for (const Elf_Sym &Sym : Obj->symbols(Symtab)) + printSymbol(&Sym, Symtab, StrTable, IsDynamic); +} + +template<class ELFT> void ELFDumper<ELFT>::printSymbols() { ListScope Group(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Obj->symbols()) - printSymbol(&Sym, false); + printSymbolsHelper(false); } template<class ELFT> void ELFDumper<ELFT>::printDynamicSymbols() { ListScope Group(W, "DynamicSymbols"); - - for (const typename ELFO::Elf_Sym &Sym : Obj->dynamic_symbols()) - printSymbol(&Sym, true); + printSymbolsHelper(true); } template <class ELFT> -void ELFDumper<ELFT>::printSymbol(const typename ELFO::Elf_Sym *Symbol, - bool IsDynamic) { +void ELFDumper<ELFT>::printSymbol(const Elf_Sym *Symbol, const Elf_Shdr *SymTab, + StringRef StrTable, bool IsDynamic) { unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Symbol, SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Symbol, IsDynamic); + getSectionNameIndex(*Obj, Symbol, SymTab, ShndxTable, SectionName, + SectionIndex); + std::string FullSymbolName = getFullSymbolName(Symbol, StrTable, IsDynamic); + unsigned char SymbolType = Symbol->getType(); DictScope D(W, "Symbol"); W.printNumber("Name", FullSymbolName, Symbol->st_name); @@ -811,7 +1282,11 @@ void ELFDumper<ELFT>::printSymbol(const typename ELFO::Elf_Sym *Symbol, W.printNumber("Size", Symbol->st_size); W.printEnum ("Binding", Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); - W.printEnum ("Type", Symbol->getType(), makeArrayRef(ElfSymbolTypes)); + if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU && + SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) + W.printEnum ("Type", SymbolType, makeArrayRef(AMDGPUSymbolTypes)); + else + W.printEnum ("Type", SymbolType, makeArrayRef(ElfSymbolTypes)); W.printNumber("Other", Symbol->st_other); W.printHex("Section", SectionName, SectionIndex); } @@ -855,12 +1330,15 @@ 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(VERDEF); + LLVM_READOBJ_TYPE_CASE(VERDEFNUM); LLVM_READOBJ_TYPE_CASE(VERNEED); LLVM_READOBJ_TYPE_CASE(VERNEEDNUM); LLVM_READOBJ_TYPE_CASE(VERSYM); LLVM_READOBJ_TYPE_CASE(RELCOUNT); LLVM_READOBJ_TYPE_CASE(GNU_HASH); LLVM_READOBJ_TYPE_CASE(MIPS_RLD_VERSION); + LLVM_READOBJ_TYPE_CASE(MIPS_RLD_MAP_REL); LLVM_READOBJ_TYPE_CASE(MIPS_FLAGS); LLVM_READOBJ_TYPE_CASE(MIPS_BASE_ADDRESS); LLVM_READOBJ_TYPE_CASE(MIPS_LOCAL_GOTNO); @@ -956,8 +1434,15 @@ void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) { } template <class ELFT> -static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, - bool Is64, raw_ostream &OS) { +StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const { + if (Value >= DynamicStringTable.size()) + reportError("Invalid dynamic string table reference"); + return StringRef(DynamicStringTable.data() + Value); +} + +template <class ELFT> +void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { + raw_ostream &OS = W.getOStream(); switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -981,6 +1466,7 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_FINI_ARRAY: case DT_PREINIT_ARRAY: case DT_DEBUG: + case DT_VERDEF: case DT_VERNEED: case DT_VERSYM: case DT_GNU_HASH: @@ -988,11 +1474,13 @@ static void printValue(const ELFFile<ELFT> *O, uint64_t Type, uint64_t Value, case DT_MIPS_BASE_ADDRESS: case DT_MIPS_GOTSYM: case DT_MIPS_RLD_MAP: + case DT_MIPS_RLD_MAP_REL: case DT_MIPS_PLTGOT: case DT_MIPS_OPTIONS: OS << format("0x%" PRIX64, Value); break; case DT_RELCOUNT: + case DT_VERDEFNUM: case DT_VERNEEDNUM: case DT_MIPS_RLD_VERSION: case DT_MIPS_LOCAL_GOTNO: @@ -1013,14 +1501,14 @@ static void printValue(const ELFFile<ELFT> *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); @@ -1046,7 +1534,8 @@ namespace { template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() { const unsigned Machine = Obj->getHeader()->e_machine; if (Machine == EM_ARM) { - ARM::EHABI::PrinterContext<ELFType<support::little, false>> Ctx(W, Obj); + ARM::EHABI::PrinterContext<ELFType<support::little, false>> Ctx( + W, Obj, DotSymtabSec); return Ctx.PrintUnwindInformation(); } W.startLine() << "UnwindInfo not implemented.\n"; @@ -1055,9 +1544,20 @@ template <> void ELFDumper<ELFType<support::little, false>>::printUnwindInfo() { template<class ELFT> void ELFDumper<ELFT>::printDynamicTable() { - auto DynTable = Obj->dynamic_table(true); + auto I = dynamic_table_begin(); + auto E = dynamic_table_end(); - ptrdiff_t Total = std::distance(DynTable.begin(), DynTable.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; @@ -1069,12 +1569,13 @@ void ELFDumper<ELFT>::printDynamicTable() { W.startLine() << " Tag" << (Is64 ? " " : " ") << "Type" << " " << "Name/Value\n"; - for (const auto &Entry : DynTable) { - W.startLine() - << " " - << format(Is64 ? "0x%016" PRIX64 : "0x%08" PRIX64, Entry.getTag()) - << " " << format("%-21s", getTypeString(Entry.getTag())); - printValue(Obj, Entry.getTag(), Entry.getVal(), Is64, OS); + while (I != E) { + const Elf_Dyn &Entry = *I; + uintX_t Tag = Entry.getTag(); + ++I; + W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " " + << format("%-21s", getTypeString(Tag)); + printValue(Tag, Entry.getVal()); OS << "\n"; } @@ -1088,14 +1589,14 @@ void ELFDumper<ELFT>::printNeededLibraries() { typedef std::vector<StringRef> LibsTy; LibsTy Libs; - for (const auto &Entry : Obj->dynamic_table()) + for (const auto &Entry : dynamic_table()) if (Entry.d_tag == ELF::DT_NEEDED) - Libs.push_back(Obj->getDynamicString(Entry.d_un.d_val)); + Libs.push_back(getDynamicString(Entry.d_un.d_val)); std::stable_sort(Libs.begin(), Libs.end()); - for (LibsTy::const_iterator I = Libs.begin(), E = Libs.end(); I != E; ++I) { - outs() << " " << *I << "\n"; + for (const auto &L : Libs) { + outs() << " " << L << "\n"; } } @@ -1103,33 +1604,51 @@ template<class ELFT> void ELFDumper<ELFT>::printProgramHeaders() { ListScope L(W, "ProgramHeaders"); - for (typename ELFO::Elf_Phdr_Iter PI = Obj->program_header_begin(), - PE = Obj->program_header_end(); - PI != PE; ++PI) { + for (const Elf_Phdr &Phdr : Obj->program_headers()) { DictScope P(W, "ProgramHeader"); - W.printHex ("Type", - getElfSegmentType(Obj->getHeader()->e_machine, PI->p_type), - PI->p_type); - 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 <typename ELFT> void ELFDumper<ELFT>::printHashTable() { DictScope D(W, "HashTable"); - auto HT = Obj->getHashTable(); - if (!HT) + 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 <typename ELFT> +void ELFDumper<ELFT>::printGnuHashTable() { + DictScope D(W, "GnuHashTable"); + if (!GnuHashTable) return; - W.printNumber("Num Buckets", HT->nbucket); - W.printNumber("Num Chains", HT->nchain); - W.printList("Buckets", HT->buckets()); - W.printList("Chains", HT->chains()); + W.printNumber("Num Buckets", GnuHashTable->nbuckets); + W.printNumber("First Hashed Symbol Index", GnuHashTable->symndx); + W.printNumber("Num Mask Words", GnuHashTable->maskwords); + W.printNumber("Shift Count", GnuHashTable->shift2); + W.printHexList("Bloom Filter", GnuHashTable->filter()); + W.printList("Buckets", GnuHashTable->buckets()); + if (!DotDynSymSec) + reportError("No dynamic symbol section"); + W.printHexList("Values", + GnuHashTable->values(DotDynSymSec->getEntityCount())); +} + +template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { + outs() << "LoadName: " << SOName << '\n'; } template <class ELFT> @@ -1171,21 +1690,23 @@ template <> void ELFDumper<ELFType<support::little, false>>::printAttributes() { namespace { template <class ELFT> class MipsGOTParser { public: - typedef object::ELFFile<ELFT> ObjectFile; - typedef typename ObjectFile::Elf_Shdr Elf_Shdr; - typedef typename ObjectFile::Elf_Sym Elf_Sym; + typedef object::ELFFile<ELFT> ELFO; + typedef typename ELFO::Elf_Shdr Elf_Shdr; + typedef typename ELFO::Elf_Sym Elf_Sym; + typedef typename ELFO::Elf_Dyn_Range Elf_Dyn_Range; + typedef typename ELFO::Elf_Addr GOTEntry; + typedef typename ELFO::Elf_Rel Elf_Rel; + typedef typename ELFO::Elf_Rela Elf_Rela; - MipsGOTParser(const ObjectFile *Obj, StreamWriter &W); + MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, + Elf_Dyn_Range DynTable, StreamWriter &W); void parseGOT(); void parsePLT(); private: - typedef typename ObjectFile::Elf_Addr GOTEntry; - typedef typename ObjectFile::template ELFEntityIterator<const GOTEntry> - GOTIter; - - const ObjectFile *Obj; + ELFDumper<ELFT> *Dumper; + const ELFO *Obj; StreamWriter &W; llvm::Optional<uint64_t> DtPltGot; llvm::Optional<uint64_t> DtLocalGotNum; @@ -1194,22 +1715,26 @@ private: llvm::Optional<uint64_t> DtJmpRel; std::size_t getGOTTotal(ArrayRef<uint8_t> GOT) const; - GOTIter makeGOTIter(ArrayRef<uint8_t> 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, bool IsDynamic); - void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It, - StringRef Purpose); - void printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, GOTIter It, + const GOTEntry *makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum); + + void printGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, + const GOTEntry *It); + void printGlobalGotEntry(uint64_t GotAddr, const GOTEntry *BeginIt, + const GOTEntry *It, const Elf_Sym *Sym, + StringRef StrTable, bool IsDynamic); + void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, + const GOTEntry *It, StringRef Purpose); + void printPLTEntry(uint64_t PLTAddr, const GOTEntry *BeginIt, + const GOTEntry *It, StringRef StrTable, const Elf_Sym *Sym); }; } template <class ELFT> -MipsGOTParser<ELFT>::MipsGOTParser(const ObjectFile *Obj, StreamWriter &W) - : Obj(Obj), W(W) { - for (const auto &Entry : Obj->dynamic_table()) { +MipsGOTParser<ELFT>::MipsGOTParser(ELFDumper<ELFT> *Dumper, const ELFO *Obj, + Elf_Dyn_Range DynTable, StreamWriter &W) + : Dumper(Dumper), Obj(Obj), W(W) { + for (const auto &Entry : DynTable) { switch (Entry.getTag()) { case ELF::DT_PLTGOT: DtPltGot = Entry.getVal(); @@ -1264,8 +1789,11 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - const Elf_Sym *DynSymBegin = Obj->dynamic_symbol_begin(); - const Elf_Sym *DynSymEnd = Obj->dynamic_symbol_end(); + const Elf_Shdr *DynSymSec = Dumper->getDotDynSymSec(); + ErrorOr<StringRef> StrTable = Obj->getStringTableForSymtab(*DynSymSec); + error(StrTable.getError()); + const Elf_Sym *DynSymBegin = Obj->symbol_begin(DynSymSec); + const Elf_Sym *DynSymEnd = Obj->symbol_end(DynSymSec); std::size_t DynSymTotal = std::size_t(std::distance(DynSymBegin, DynSymEnd)); if (*DtGotSym > DynSymTotal) { @@ -1280,9 +1808,9 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { return; } - GOTIter GotBegin = makeGOTIter(*GOT, 0); - GOTIter GotLocalEnd = makeGOTIter(*GOT, *DtLocalGotNum); - GOTIter It = GotBegin; + const GOTEntry *GotBegin = makeGOTIter(*GOT, 0); + const GOTEntry *GotLocalEnd = makeGOTIter(*GOT, *DtLocalGotNum); + const GOTEntry *It = GotBegin; DictScope GS(W, "Primary GOT"); @@ -1312,11 +1840,13 @@ template <class ELFT> void MipsGOTParser<ELFT>::parseGOT() { { ListScope GS(W, "Global entries"); - GOTIter GotGlobalEnd = makeGOTIter(*GOT, *DtLocalGotNum + GlobalGotNum); + const GOTEntry *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++, true); + printGlobalGotEntry(GOTShdr->sh_addr, GotBegin, It, GotDynSym++, + *StrTable, true); } } @@ -1350,10 +1880,16 @@ template <class ELFT> void MipsGOTParser<ELFT>::parsePLT() { W.startLine() << "There is no .rel.plt section in the file.\n"; return; } + ErrorOr<const Elf_Shdr *> SymTableOrErr = + Obj->getSection(PLTRelShdr->sh_link); + error(SymTableOrErr.getError()); + const Elf_Shdr *SymTable = *SymTableOrErr; + ErrorOr<StringRef> StrTable = Obj->getStringTableForSymtab(*SymTable); + error(StrTable.getError()); - GOTIter PLTBegin = makeGOTIter(*PLT, 0); - GOTIter PLTEnd = makeGOTIter(*PLT, getGOTTotal(*PLT)); - GOTIter It = PLTBegin; + const GOTEntry *PLTBegin = makeGOTIter(*PLT, 0); + const GOTEntry *PLTEnd = makeGOTIter(*PLT, getGOTTotal(*PLT)); + const GOTEntry *It = PLTBegin; DictScope GS(W, "PLT GOT"); { @@ -1367,21 +1903,19 @@ template <class ELFT> void MipsGOTParser<ELFT>::parsePLT() { switch (PLTRelShdr->sh_type) { case ELF::SHT_REL: - for (typename ObjectFile::Elf_Rel_Iter RI = Obj->rel_begin(PLTRelShdr), - RE = Obj->rel_end(PLTRelShdr); + for (const 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, Sym); + const Elf_Sym *Sym = Obj->getRelocationSymbol(&*RI, SymTable); + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, *StrTable, Sym); } break; case ELF::SHT_RELA: - for (typename ObjectFile::Elf_Rela_Iter RI = Obj->rela_begin(PLTRelShdr), - RE = Obj->rela_end(PLTRelShdr); + for (const 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, Sym); + const Elf_Sym *Sym = Obj->getRelocationSymbol(&*RI, SymTable); + printPLTEntry(PLTShdr->sh_addr, PLTBegin, It, *StrTable, Sym); } break; } @@ -1394,15 +1928,16 @@ std::size_t MipsGOTParser<ELFT>::getGOTTotal(ArrayRef<uint8_t> GOT) const { } template <class ELFT> -typename MipsGOTParser<ELFT>::GOTIter +const typename MipsGOTParser<ELFT>::GOTEntry * MipsGOTParser<ELFT>::makeGOTIter(ArrayRef<uint8_t> GOT, std::size_t EntryNum) { const char *Data = reinterpret_cast<const char *>(GOT.data()); - return GOTIter(sizeof(GOTEntry), Data + EntryNum * sizeof(GOTEntry)); + return reinterpret_cast<const GOTEntry *>(Data + EntryNum * sizeof(GOTEntry)); } template <class ELFT> -void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, - GOTIter It) { +void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, + const GOTEntry *BeginIt, + const GOTEntry *It) { int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); W.printHex("Address", GotAddr + Offset); W.printNumber("Access", Offset - 0x7ff0); @@ -1410,9 +1945,9 @@ void MipsGOTParser<ELFT>::printGotEntry(uint64_t GotAddr, GOTIter BeginIt, } template <class ELFT> -void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, - GOTIter It, const Elf_Sym *Sym, - bool IsDynamic) { +void MipsGOTParser<ELFT>::printGlobalGotEntry( + uint64_t GotAddr, const GOTEntry *BeginIt, const GOTEntry *It, + const Elf_Sym *Sym, StringRef StrTable, bool IsDynamic) { printGotEntry(GotAddr, BeginIt, It); W.printHex("Value", Sym->st_value); @@ -1420,16 +1955,19 @@ void MipsGOTParser<ELFT>::printGlobalGotEntry(uint64_t GotAddr, GOTIter BeginIt, unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Sym, IsDynamic); + std::string FullSymbolName = + Dumper->getFullSymbolName(Sym, StrTable, IsDynamic); W.printNumber("Name", FullSymbolName, Sym->st_name); } template <class ELFT> -void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, - GOTIter It, StringRef Purpose) { +void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, + const GOTEntry *BeginIt, + const GOTEntry *It, StringRef Purpose) { DictScope D(W, "Entry"); int64_t Offset = std::distance(BeginIt, It) * sizeof(GOTEntry); W.printHex("Address", PLTAddr + Offset); @@ -1438,8 +1976,10 @@ void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, } template <class ELFT> -void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, - GOTIter It, const Elf_Sym *Sym) { +void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, + const GOTEntry *BeginIt, + const GOTEntry *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); @@ -1449,10 +1989,11 @@ void MipsGOTParser<ELFT>::printPLTEntry(uint64_t PLTAddr, GOTIter BeginIt, unsigned SectionIndex = 0; StringRef SectionName; - getSectionNameIndex(*Obj, Sym, SectionName, SectionIndex); + getSectionNameIndex(*Obj, Sym, Dumper->getDotDynSymSec(), + Dumper->getShndxTable(), SectionName, SectionIndex); W.printHex("Section", SectionName, SectionIndex); - std::string FullSymbolName = getFullSymbolName(*Obj, Sym, true); + std::string FullSymbolName = Dumper->getFullSymbolName(Sym, StrTable, true); W.printNumber("Name", FullSymbolName, Sym->st_name); } @@ -1462,7 +2003,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsPLTGOT() { return; } - MipsGOTParser<ELFT> GOTParser(Obj, W); + MipsGOTParser<ELFT> GOTParser(this, Obj, dynamic_table(), W); GOTParser.parseGOT(); GOTParser.parsePLT(); } @@ -1604,7 +2145,7 @@ template <class ELFT> void ELFDumper<ELFT>::printMipsReginfo() { } template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { - const typename ELFFile<ELFT>::Elf_Shdr *StackMapSection = nullptr; + const Elf_Shdr *StackMapSection = nullptr; for (const auto &Sec : Obj->sections()) { ErrorOr<StringRef> Name = Obj->getSectionName(&Sec); if (*Name == ".llvm_stackmaps") { |