diff options
Diffstat (limited to 'tools/llvm-readobj/ELFDumper.cpp')
-rw-r--r-- | tools/llvm-readobj/ELFDumper.cpp | 2259 |
1 files changed, 1370 insertions, 889 deletions
diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 93254717e921..4e1cb7d544e7 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -1,9 +1,8 @@ //===- ELFDumper.cpp - ELF-specific dumper --------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// @@ -20,6 +19,7 @@ #include "llvm-readobj.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/DenseSet.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" @@ -30,6 +30,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/Demangle/Demangle.h" #include "llvm/Object/ELF.h" #include "llvm/Object/ELFObjectFile.h" #include "llvm/Object/ELFTypes.h" @@ -66,13 +67,14 @@ using namespace llvm; using namespace llvm::object; using namespace ELF; -#define LLVM_READOBJ_ENUM_CASE(ns, enum) \ - case ns::enum: return #enum; +#define LLVM_READOBJ_ENUM_CASE(ns, enum) \ + case ns::enum: \ + return #enum; -#define ENUM_ENT(enum, altName) \ +#define ENUM_ENT(enum, altName) \ { #enum, altName, ELF::enum } -#define ENUM_ENT_1(enum) \ +#define ENUM_ENT_1(enum) \ { #enum, #enum, ELF::enum } #define LLVM_READOBJ_PHDR_ENUM(ns, enum) \ @@ -132,14 +134,17 @@ struct DynRegionInfo { const Type *Start = reinterpret_cast<const Type *>(Addr); if (!Start) return {Start, Start}; - if (EntSize != sizeof(Type) || Size % EntSize) - reportError("Invalid entity size"); + if (EntSize != sizeof(Type) || Size % EntSize) { + // TODO: Add a section index to this warning. + reportWarning("invalid section size (" + Twine(Size) + + ") or entity size (" + Twine(EntSize) + ")"); + return {Start, Start}; + } return {Start, Start + (Size / EntSize)}; } }; -template<typename ELFT> -class ELFDumper : public ObjDumper { +template <typename ELFT> class ELFDumper : public ObjDumper { public: ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ScopedPrinter &Writer); @@ -147,13 +152,14 @@ public: void printSectionHeaders() override; void printRelocations() override; void printDynamicRelocations() override; - void printSymbols() override; - void printDynamicSymbols() override; + void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols) override; + void printHashSymbols() override; void printUnwindInfo() override; void printDynamicTable() override; void printNeededLibraries() override; - void printProgramHeaders() override; + void printProgramHeaders(bool PrintProgramHeaders, + cl::boolOrDefault PrintSectionMapping) override; void printHashTable() override; void printGnuHashTable() override; void printLoadName() override; @@ -177,6 +183,8 @@ public: void printELFLinkerOptions() override; + const object::ELFObjectFile<ELFT> *getElfObject() const { return ObjF; }; + private: std::unique_ptr<DumpStyle<ELFT>> ELFDumperStyle; @@ -185,24 +193,25 @@ private: DynRegionInfo checkDRI(DynRegionInfo DRI) { const ELFFile<ELFT> *Obj = ObjF->getELFFile(); if (DRI.Addr < Obj->base() || - (const uint8_t *)DRI.Addr + DRI.Size > Obj->base() + Obj->getBufSize()) + reinterpret_cast<const uint8_t *>(DRI.Addr) + DRI.Size > + Obj->base() + Obj->getBufSize()) error(llvm::object::object_error::parse_failed); return DRI; } DynRegionInfo createDRIFrom(const Elf_Phdr *P, uintX_t EntSize) { - return checkDRI({ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize}); + return checkDRI( + {ObjF->getELFFile()->base() + P->p_offset, P->p_filesz, EntSize}); } DynRegionInfo createDRIFrom(const Elf_Shdr *S) { - return checkDRI({ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize}); + return checkDRI( + {ObjF->getELFFile()->base() + S->sh_offset, S->sh_size, S->sh_entsize}); } - void parseDynamicTable(ArrayRef<const Elf_Phdr *> LoadSegments); + void loadDynamicTable(const ELFFile<ELFT> *Obj); + void parseDynamicTable(); - void printValue(uint64_t Type, uint64_t Value); - - StringRef getDynamicString(uint64_t Offset) const; StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, bool &IsDefault) const; void LoadVersionMap() const; @@ -217,7 +226,7 @@ private: DynRegionInfo DynSymRegion; DynRegionInfo DynamicTable; StringRef DynamicStringTable; - StringRef SOName; + StringRef SOName = "<Not found>"; const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; @@ -226,9 +235,9 @@ private: StringRef DynSymtabName; 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 + const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version + const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r + const Elf_Shdr *SymbolVersionDefSection = nullptr; // .gnu.version_d // Records for each version index the corresponding Verdef or Vernaux entry. // This is filled the first time LoadVersionMap() is called. @@ -256,7 +265,18 @@ private: public: Elf_Dyn_Range dynamic_table() const { - return DynamicTable.getAsArrayRef<Elf_Dyn>(); + // A valid .dynamic section contains an array of entries terminated + // with a DT_NULL entry. However, sometimes the section content may + // continue past the DT_NULL entry, so to dump the section correctly, + // we first find the end of the entries by iterating over them. + Elf_Dyn_Range Table = DynamicTable.getAsArrayRef<Elf_Dyn>(); + + size_t Size = 0; + while (Size < Table.size()) + if (Table[Size++].getTag() == DT_NULL) + break; + + return Table.slice(0, Size); } Elf_Sym_Range dynamic_symbols() const { @@ -271,9 +291,14 @@ public: void getSectionNameIndex(const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef &SectionName, unsigned &SectionIndex) const; - StringRef getStaticSymbolName(uint32_t Index) const; + std::string getStaticSymbolName(uint32_t Index) const; + StringRef getSymbolVersionByIndex(StringRef StrTab, + uint32_t VersionSymbolIndex, + bool &IsDefault) const; void printSymbolsHelper(bool IsDynamic) const; + void printDynamicEntry(raw_ostream &OS, uint64_t Type, uint64_t Value) const; + const Elf_Shdr *getDotSymtabSec() const { return DotSymtabSec; } const Elf_Shdr *getDotCGProfileSec() const { return DotCGProfileSec; } const Elf_Shdr *getDotAddrsigSec() const { return DotAddrsigSec; } @@ -283,6 +308,7 @@ public: const DynRegionInfo &getDynRelaRegion() const { return DynRelaRegion; } const DynRegionInfo &getDynRelrRegion() const { return DynRelrRegion; } const DynRegionInfo &getDynPLTRelRegion() const { return DynPLTRelRegion; } + const DynRegionInfo &getDynamicTableRegion() const { return DynamicTable; } const Elf_Hash *getHashTable() const { return HashTable; } const Elf_GnuHash *getGnuHashTable() const { return GnuHashTable; } }; @@ -328,15 +354,25 @@ public: virtual void printGroupSections(const ELFFile<ELFT> *Obj) = 0; virtual void printRelocations(const ELFFile<ELFT> *Obj) = 0; virtual void printSectionHeaders(const ELFFile<ELFT> *Obj) = 0; - virtual void printSymbols(const ELFFile<ELFT> *Obj) = 0; - virtual void printDynamicSymbols(const ELFFile<ELFT> *Obj) = 0; + virtual void printSymbols(const ELFFile<ELFT> *Obj, bool PrintSymbols, + bool PrintDynamicSymbols) = 0; + virtual void printHashSymbols(const ELFFile<ELFT> *Obj) {} + virtual void printDynamic(const ELFFile<ELFT> *Obj) {} virtual void printDynamicRelocations(const ELFFile<ELFT> *Obj) = 0; - virtual void printSymtabMessage(const ELFFile<ELFT> *obj, StringRef Name, + virtual void printSymtabMessage(const ELFFile<ELFT> *Obj, StringRef Name, size_t Offset) {} virtual void printSymbol(const ELFFile<ELFT> *Obj, const Elf_Sym *Symbol, const Elf_Sym *FirstSym, StringRef StrTable, bool IsDynamic) = 0; - virtual void printProgramHeaders(const ELFFile<ELFT> *Obj) = 0; + virtual void printProgramHeaders(const ELFFile<ELFT> *Obj, + bool PrintProgramHeaders, + cl::boolOrDefault PrintSectionMapping) = 0; + virtual void printVersionSymbolSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) = 0; + virtual void printVersionDefinitionSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) = 0; + virtual void printVersionDependencySection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) = 0; virtual void printHashHistogram(const ELFFile<ELFT> *Obj) = 0; virtual void printCGProfile(const ELFFile<ELFT> *Obj) = 0; virtual void printAddrsig(const ELFFile<ELFT> *Obj) = 0; @@ -351,24 +387,36 @@ private: }; template <typename ELFT> class GNUStyle : public DumpStyle<ELFT> { - formatted_raw_ostream OS; + formatted_raw_ostream &OS; public: TYPEDEF_ELF_TYPES(ELFT) GNUStyle(ScopedPrinter &W, ELFDumper<ELFT> *Dumper) - : DumpStyle<ELFT>(Dumper), OS(W.getOStream()) {} + : DumpStyle<ELFT>(Dumper), + OS(static_cast<formatted_raw_ostream&>(W.getOStream())) { + assert (&W.getOStream() == &llvm::fouts()); + } void printFileHeaders(const ELFO *Obj) override; void printGroupSections(const ELFFile<ELFT> *Obj) override; void printRelocations(const ELFO *Obj) override; void printSectionHeaders(const ELFO *Obj) override; - void printSymbols(const ELFO *Obj) override; - void printDynamicSymbols(const ELFO *Obj) override; + void printSymbols(const ELFO *Obj, bool PrintSymbols, + bool PrintDynamicSymbols) override; + void printHashSymbols(const ELFO *Obj) override; + void printDynamic(const ELFFile<ELFT> *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; void printSymtabMessage(const ELFO *Obj, StringRef Name, size_t Offset) override; - void printProgramHeaders(const ELFO *Obj) override; + void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, + cl::boolOrDefault PrintSectionMapping) override; + void printVersionSymbolSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) override; + void printVersionDefinitionSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) override; + void printVersionDependencySection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) override; void printHashHistogram(const ELFFile<ELFT> *Obj) override; void printCGProfile(const ELFFile<ELFT> *Obj) override; void printAddrsig(const ELFFile<ELFT> *Obj) override; @@ -379,11 +427,11 @@ public: private: struct Field { - StringRef Str; + std::string Str; unsigned Column; Field(StringRef S, unsigned Col) : Str(S), Column(Col) {} - Field(unsigned Col) : Str(""), Column(Col) {} + Field(unsigned Col) : Column(Col) {} }; template <typename T, typename TEnum> @@ -433,6 +481,8 @@ private: void printRelocHeader(unsigned SType); void printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, const Elf_Rela &R, bool IsRela); + void printRelocation(const ELFO *Obj, const Elf_Sym *Sym, + StringRef SymbolName, const Elf_Rela &R, bool IsRela); void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, StringRef StrTable, bool IsDynamic) override; std::string getSymbolSectionNdx(const ELFO *Obj, const Elf_Sym *Symbol, @@ -442,6 +492,8 @@ private: bool checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); bool checkVMA(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); bool checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec); + void printProgramHeaders(const ELFO *Obj); + void printSectionMapping(const ELFO *Obj); }; template <typename ELFT> class LLVMStyle : public DumpStyle<ELFT> { @@ -456,10 +508,18 @@ public: void printRelocations(const ELFO *Obj) override; void printRelocations(const Elf_Shdr *Sec, const ELFO *Obj); void printSectionHeaders(const ELFO *Obj) override; - void printSymbols(const ELFO *Obj) override; - void printDynamicSymbols(const ELFO *Obj) override; + void printSymbols(const ELFO *Obj, bool PrintSymbols, + bool PrintDynamicSymbols) override; + void printDynamic(const ELFFile<ELFT> *Obj) override; void printDynamicRelocations(const ELFO *Obj) override; - void printProgramHeaders(const ELFO *Obj) override; + void printProgramHeaders(const ELFO *Obj, bool PrintProgramHeaders, + cl::boolOrDefault PrintSectionMapping) override; + void printVersionSymbolSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) override; + void printVersionDefinitionSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) override; + void printVersionDependencySection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) override; void printHashHistogram(const ELFFile<ELFT> *Obj) override; void printCGProfile(const ELFFile<ELFT> *Obj) override; void printAddrsig(const ELFFile<ELFT> *Obj) override; @@ -471,8 +531,12 @@ public: private: void printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab); void printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel); + void printSymbols(const ELFO *Obj); + void printDynamicSymbols(const ELFO *Obj); void printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, const Elf_Sym *First, StringRef StrTable, bool IsDynamic) override; + void printProgramHeaders(const ELFO *Obj); + void printSectionMapping(const ELFO *Obj) {} ScopedPrinter &W; }; @@ -516,65 +580,71 @@ std::error_code createELFDumper(const object::ObjectFile *Obj, // 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 *)ObjF->getELFFile()->base() + sec->sh_offset; - const char *sec_end = sec_start + vn_size; +void ELFDumper<ELFT>::LoadVersionNeeds(const Elf_Shdr *Sec) const { + unsigned VerneedSize = Sec->sh_size; // Size of section in bytes + unsigned VerneedEntries = Sec->sh_info; // Number of Verneed entries + const uint8_t *VerneedStart = reinterpret_cast<const uint8_t *>( + ObjF->getELFFile()->base() + Sec->sh_offset); + const uint8_t *VerneedEnd = VerneedStart + VerneedSize; // 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) + const uint8_t *VerneedBuf = VerneedStart; + for (unsigned VerneedIndex = 0; VerneedIndex < VerneedEntries; + ++VerneedIndex) { + if (VerneedBuf + sizeof(Elf_Verneed) > VerneedEnd) 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) + const Elf_Verneed *Verneed = + reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + if (Verneed->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) + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + for (unsigned VernauxIndex = 0; VernauxIndex < Verneed->vn_cnt; + ++VernauxIndex) { + if (VernauxBuf + sizeof(Elf_Vernaux) > VerneedEnd) 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; + const Elf_Vernaux *Vernaux = + reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + size_t Index = Vernaux->vna_other & ELF::VERSYM_VERSION; + if (Index >= VersionMap.size()) + VersionMap.resize(Index + 1); + VersionMap[Index] = VersionMapEntry(Vernaux); + VernauxBuf += Vernaux->vna_next; } - p += vn->vn_next; + VerneedBuf += Verneed->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 *)ObjF->getELFFile()->base() + sec->sh_offset; - const char *sec_end = sec_start + vd_size; +void ELFDumper<ELFT>::LoadVersionDefs(const Elf_Shdr *Sec) const { + unsigned VerdefSize = Sec->sh_size; // Size of section in bytes + unsigned VerdefEntries = Sec->sh_info; // Number of Verdef entries + const uint8_t *VerdefStart = reinterpret_cast<const uint8_t *>( + ObjF->getELFFile()->base() + Sec->sh_offset); + const uint8_t *VerdefEnd = VerdefStart + VerdefSize; // 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) + const uint8_t *VerdefBuf = VerdefStart; + for (unsigned VerdefIndex = 0; VerdefIndex < VerdefEntries; ++VerdefIndex) { + if (VerdefBuf + sizeof(Elf_Verdef) > VerdefEnd) 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) + const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); + if (Verdef->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; + size_t Index = Verdef->vd_ndx & ELF::VERSYM_VERSION; + if (Index >= VersionMap.size()) + VersionMap.resize(Index + 1); + VersionMap[Index] = VersionMapEntry(Verdef); + VerdefBuf += Verdef->vd_next; } } template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const { // If there is no dynamic symtab or version table, there is nothing to do. - if (!DynSymRegion.Addr || !dot_gnu_version_sec) + if (!DynSymRegion.Addr || !SymbolVersionSection) return; // Has the VersionMap already been loaded? @@ -586,243 +656,111 @@ template <class ELFT> void ELFDumper<ELFT>::LoadVersionMap() const { 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, - ScopedPrinter &W) { - DictScope SS(W, "Version symbols"); - if (!Sec) - return; - StringRef Name = unwrapOrError(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 uint8_t *P = (const uint8_t *)Obj->base() + Sec->sh_offset; - StringRef StrTable = Dumper->getDynamicStringTable(); - - // Same number of entries in the dynamic symbol table (DT_SYMTAB). - ListScope Syms(W, "Symbols"); - for (const typename ELFO::Elf_Sym &Sym : Dumper->dynamic_symbols()) { - DictScope S(W, "Symbol"); - std::string FullSymbolName = - Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */); - W.printNumber("Version", *P); - W.printString("Name", FullSymbolName); - P += sizeof(typename ELFO::Elf_Half); - } -} - -static const EnumEntry<unsigned> SymVersionFlags[] = { - {"Base", "BASE", VER_FLG_BASE}, - {"Weak", "WEAK", VER_FLG_WEAK}, - {"Info", "INFO", VER_FLG_INFO}}; - -template <typename ELFO, class ELFT> -static void printVersionDefinitionSection(ELFDumper<ELFT> *Dumper, - const ELFO *Obj, - const typename ELFO::Elf_Shdr *Sec, - ScopedPrinter &W) { - using VerDef = typename ELFO::Elf_Verdef; - using VerdAux = typename ELFO::Elf_Verdaux; - - DictScope SD(W, "SHT_GNU_verdef"); - if (!Sec) - return; - - // The number of entries in the section SHT_GNU_verdef - // is determined by DT_VERDEFNUM tag. - unsigned VerDefsNum = 0; - for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) { - if (Dyn.d_tag == DT_VERDEFNUM) { - VerDefsNum = Dyn.d_un.d_val; - break; - } - } - - 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; - const typename ELFO::Elf_Shdr *StrTab = - unwrapOrError(Obj->getSection(Sec->sh_link)); - - while (VerDefsNum--) { - if (P + sizeof(VerDef) > SecEndAddress) - report_fatal_error("invalid offset in the section"); - - auto *VD = reinterpret_cast<const VerDef *>(P); - DictScope Def(W, "Definition"); - W.printNumber("Version", VD->vd_version); - W.printEnum("Flags", VD->vd_flags, makeArrayRef(SymVersionFlags)); - W.printNumber("Index", VD->vd_ndx); - W.printNumber("Hash", VD->vd_hash); - W.printString("Name", - StringRef((const char *)(Obj->base() + StrTab->sh_offset + - VD->getAux()->vda_name))); - if (!VD->vd_cnt) - report_fatal_error("at least one definition string must exist"); - if (VD->vd_cnt > 2) - report_fatal_error("more than one predecessor is not expected"); - - if (VD->vd_cnt == 2) { - const uint8_t *PAux = P + VD->vd_aux + VD->getAux()->vda_next; - const VerdAux *Aux = reinterpret_cast<const VerdAux *>(PAux); - W.printString("Predecessor", - StringRef((const char *)(Obj->base() + StrTab->sh_offset + - Aux->vda_name))); - } - - P += VD->vd_next; - } -} - -template <typename ELFO, class ELFT> -static void printVersionDependencySection(ELFDumper<ELFT> *Dumper, - const ELFO *Obj, - const typename ELFO::Elf_Shdr *Sec, - ScopedPrinter &W) { - using VerNeed = typename ELFO::Elf_Verneed; - using VernAux = typename ELFO::Elf_Vernaux; - - DictScope SD(W, "SHT_GNU_verneed"); - if (!Sec) - return; - - unsigned VerNeedNum = 0; - for (const typename ELFO::Elf_Dyn &Dyn : Dumper->dynamic_table()) { - if (Dyn.d_tag == DT_VERNEEDNUM) { - VerNeedNum = Dyn.d_un.d_val; - break; - } - } - - const uint8_t *SecData = (const uint8_t *)Obj->base() + Sec->sh_offset; - const typename ELFO::Elf_Shdr *StrTab = - unwrapOrError(Obj->getSection(Sec->sh_link)); - - const uint8_t *P = SecData; - for (unsigned I = 0; I < VerNeedNum; ++I) { - const VerNeed *Need = reinterpret_cast<const VerNeed *>(P); - DictScope Entry(W, "Dependency"); - W.printNumber("Version", Need->vn_version); - W.printNumber("Count", Need->vn_cnt); - W.printString("FileName", - StringRef((const char *)(Obj->base() + StrTab->sh_offset + - Need->vn_file))); - - const uint8_t *PAux = P + Need->vn_aux; - for (unsigned J = 0; J < Need->vn_cnt; ++J) { - const VernAux *Aux = reinterpret_cast<const VernAux *>(PAux); - DictScope Entry(W, "Entry"); - W.printNumber("Hash", Aux->vna_hash); - W.printEnum("Flags", Aux->vna_flags, makeArrayRef(SymVersionFlags)); - W.printNumber("Index", Aux->vna_other); - W.printString("Name", - StringRef((const char *)(Obj->base() + StrTab->sh_offset + - Aux->vna_name))); - PAux += Aux->vna_next; - } - P += Need->vn_next; - } -} - -template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() { - // Dump version symbol section. - printVersionSymbolSection(this, ObjF->getELFFile(), dot_gnu_version_sec, W); - - // Dump version definition section. - printVersionDefinitionSection(this, ObjF->getELFFile(), dot_gnu_version_d_sec, W); + if (SymbolVersionDefSection) + LoadVersionDefs(SymbolVersionDefSection); - // Dump version dependency section. - printVersionDependencySection(this, ObjF->getELFFile(), dot_gnu_version_r_sec, W); + if (SymbolVersionNeedSection) + LoadVersionNeeds(SymbolVersionNeedSection); } template <typename ELFT> StringRef ELFDumper<ELFT>::getSymbolVersion(StringRef StrTab, - const Elf_Sym *symb, + const Elf_Sym *Sym, bool &IsDefault) const { // This is a dynamic symbol. Look in the GNU symbol version table. - if (!dot_gnu_version_sec) { + if (!SymbolVersionSection) { // No version table. IsDefault = false; - return StringRef(""); + return ""; } // Determine the position in the symbol table of this entry. - size_t entry_index = (reinterpret_cast<uintptr_t>(symb) - + size_t EntryIndex = (reinterpret_cast<uintptr_t>(Sym) - reinterpret_cast<uintptr_t>(DynSymRegion.Addr)) / sizeof(Elf_Sym); - // Get the corresponding version index entry - const Elf_Versym *vs = unwrapOrError( - ObjF->getELFFile()->template getEntry<Elf_Versym>(dot_gnu_version_sec, entry_index)); - size_t version_index = vs->vs_index & ELF::VERSYM_VERSION; + // Get the corresponding version index entry. + const Elf_Versym *Versym = + unwrapOrError(ObjF->getELFFile()->template getEntry<Elf_Versym>( + SymbolVersionSection, EntryIndex)); + return this->getSymbolVersionByIndex(StrTab, Versym->vs_index, IsDefault); +} + +static std::string maybeDemangle(StringRef Name) { + return opts::Demangle ? demangle(Name) : Name.str(); +} + +template <typename ELFT> +std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + StringRef StrTable = + unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec)); + Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec)); + if (Index >= Syms.size()) + reportError("Invalid symbol index"); + const Elf_Sym *Sym = &Syms[Index]; + return maybeDemangle(unwrapOrError(Sym->getName(StrTable))); +} + +template <typename ELFT> +StringRef ELFDumper<ELFT>::getSymbolVersionByIndex(StringRef StrTab, + uint32_t SymbolVersionIndex, + bool &IsDefault) const { + size_t VersionIndex = SymbolVersionIndex & VERSYM_VERSION; // Special markers for unversioned symbols. - if (version_index == ELF::VER_NDX_LOCAL || - version_index == ELF::VER_NDX_GLOBAL) { + if (VersionIndex == VER_NDX_LOCAL || VersionIndex == VER_NDX_GLOBAL) { IsDefault = false; - return StringRef(""); + return ""; } - // Lookup this symbol in the version table + // Lookup this symbol in the version table. LoadVersionMap(); - if (version_index >= VersionMap.size() || VersionMap[version_index].isNull()) + if (VersionIndex >= VersionMap.size() || VersionMap[VersionIndex].isNull()) reportError("Invalid version entry"); - const VersionMapEntry &entry = VersionMap[version_index]; + const VersionMapEntry &Entry = VersionMap[VersionIndex]; - // Get the version name string - size_t name_offset; - if (entry.isVerdef()) { + // Get the version name string. + size_t NameOffset; + if (Entry.isVerdef()) { // The first Verdaux entry holds the name. - name_offset = entry.getVerdef()->getAux()->vda_name; - IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN); + NameOffset = Entry.getVerdef()->getAux()->vda_name; + IsDefault = !(SymbolVersionIndex & VERSYM_HIDDEN); } else { - name_offset = entry.getVernaux()->vna_name; + NameOffset = Entry.getVernaux()->vna_name; IsDefault = false; } - if (name_offset >= StrTab.size()) + if (NameOffset >= StrTab.size()) reportError("Invalid string offset"); - return StringRef(StrTab.data() + name_offset); -} - -template <typename ELFT> -StringRef ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); - StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*DotSymtabSec)); - Elf_Sym_Range Syms = unwrapOrError(Obj->symbols(DotSymtabSec)); - if (Index >= Syms.size()) - reportError("Invalid symbol index"); - const Elf_Sym *Sym = &Syms[Index]; - return unwrapOrError(Sym->getName(StrTable)); + return StrTab.data() + NameOffset; } template <typename ELFT> std::string ELFDumper<ELFT>::getFullSymbolName(const Elf_Sym *Symbol, StringRef StrTable, bool IsDynamic) const { - StringRef SymbolName = unwrapOrError(Symbol->getName(StrTable)); + std::string SymbolName = + maybeDemangle(unwrapOrError(Symbol->getName(StrTable))); + + if (SymbolName.empty() && Symbol->getType() == ELF::STT_SECTION) { + unsigned SectionIndex; + StringRef SectionName; + Elf_Sym_Range Syms = + unwrapOrError(ObjF->getELFFile()->symbols(DotSymtabSec)); + getSectionNameIndex(Symbol, Syms.begin(), SectionName, SectionIndex); + return SectionName; + } + if (!IsDynamic) return SymbolName; - std::string FullSymbolName(SymbolName); - bool IsDefault; StringRef Version = getSymbolVersion(StrTable, &*Symbol, IsDefault); if (!Version.empty()) { - FullSymbolName += (IsDefault ? "@@" : "@"); - FullSymbolName += Version; + SymbolName += (IsDefault ? "@@" : "@"); + SymbolName += Version; } - return FullSymbolName; + return SymbolName; } template <typename ELFT> @@ -914,6 +852,11 @@ static const EnumEntry<unsigned> ElfOSABI[] = { {"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE} }; +static const EnumEntry<unsigned> SymVersionFlags[] = { + {"Base", "BASE", VER_FLG_BASE}, + {"Weak", "WEAK", VER_FLG_WEAK}, + {"Info", "INFO", VER_FLG_INFO}}; + static const EnumEntry<unsigned> AMDGPUElfOSABI[] = { {"AMDGPU_HSA", "AMDGPU - HSA", ELF::ELFOSABI_AMDGPU_HSA}, {"AMDGPU_PAL", "AMDGPU - PAL", ELF::ELFOSABI_AMDGPU_PAL}, @@ -1103,16 +1046,6 @@ static const EnumEntry<unsigned> ElfSymbolVisibilities[] = { {"HIDDEN", "HIDDEN", ELF::STV_HIDDEN}, {"PROTECTED", "PROTECTED", ELF::STV_PROTECTED}}; -static const EnumEntry<unsigned> ElfSymbolTypes[] = { - {"None", "NOTYPE", ELF::STT_NOTYPE}, - {"Object", "OBJECT", ELF::STT_OBJECT}, - {"Function", "FUNC", ELF::STT_FUNC}, - {"Section", "SECTION", ELF::STT_SECTION}, - {"File", "FILE", ELF::STT_FILE}, - {"Common", "COMMON", ELF::STT_COMMON}, - {"TLS", "TLS", ELF::STT_TLS}, - {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}}; - static const EnumEntry<unsigned> AMDGPUSymbolTypes[] = { { "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL } }; @@ -1205,14 +1138,12 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) { // program header type. switch (Arch) { case ELF::EM_ARM: - switch (Type) { - LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); - } + switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); } break; 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_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); @@ -1233,14 +1164,15 @@ static const char *getElfSegmentType(unsigned Arch, unsigned Type) { 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); + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK); + LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO); - LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE); - LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED); - LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA); + LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE); + LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED); + LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA); - default: return ""; + default: + return ""; } } @@ -1368,7 +1300,11 @@ static const EnumEntry<unsigned> ElfHeaderAMDGPUFlags[] = { LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX902), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX904), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX906), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX908), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX909), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011), + LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_XNACK), LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_SRAM_ECC) }; @@ -1420,68 +1356,118 @@ static const char *getElfMipsOptionsOdkType(unsigned Odk) { } template <typename ELFT> -ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, - ScopedPrinter &Writer) - : ObjDumper(Writer), ObjF(ObjF) { - SmallVector<const Elf_Phdr *, 4> LoadSegments; - const ELFFile<ELFT> *Obj = ObjF->getELFFile(); +void ELFDumper<ELFT>::loadDynamicTable(const ELFFile<ELFT> *Obj) { + // Try to locate the PT_DYNAMIC header. + const Elf_Phdr *DynamicPhdr = nullptr; for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { - if (Phdr.p_type == ELF::PT_DYNAMIC) { - DynamicTable = createDRIFrom(&Phdr, sizeof(Elf_Dyn)); + if (Phdr.p_type != ELF::PT_DYNAMIC) continue; - } - if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) + DynamicPhdr = &Phdr; + break; + } + + // Try to locate the .dynamic section in the sections header table. + const Elf_Shdr *DynamicSec = nullptr; + for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + if (Sec.sh_type != ELF::SHT_DYNAMIC) continue; - LoadSegments.push_back(&Phdr); + DynamicSec = &Sec; + break; + } + + // Information in the section header has priority over the information + // in a PT_DYNAMIC header. + // Ignore sh_entsize and use the expected value for entry size explicitly. + // This allows us to dump the dynamic sections with a broken sh_entsize + // field. + if (DynamicSec) { + DynamicTable = checkDRI({ObjF->getELFFile()->base() + DynamicSec->sh_offset, + DynamicSec->sh_size, sizeof(Elf_Dyn)}); + parseDynamicTable(); + } + + // If we have a PT_DYNAMIC header, we will either check the found dynamic + // section or take the dynamic table data directly from the header. + if (!DynamicPhdr) + return; + + if (DynamicPhdr->p_offset + DynamicPhdr->p_filesz > + ObjF->getMemoryBufferRef().getBufferSize()) + reportError( + "PT_DYNAMIC segment offset + size exceeds the size of the file"); + + if (!DynamicSec) { + DynamicTable = createDRIFrom(DynamicPhdr, sizeof(Elf_Dyn)); + parseDynamicTable(); + return; } + StringRef Name = unwrapOrError(Obj->getSectionName(DynamicSec)); + if (DynamicSec->sh_addr + DynamicSec->sh_size > + DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || + DynamicSec->sh_addr < DynamicPhdr->p_vaddr) + reportWarning("The SHT_DYNAMIC section '" + Name + + "' is not contained within the " + "PT_DYNAMIC segment"); + + if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr) + reportWarning("The SHT_DYNAMIC section '" + Name + + "' is not at the start of " + "PT_DYNAMIC segment"); +} + +template <typename ELFT> +ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, + ScopedPrinter &Writer) + : ObjDumper(Writer), ObjF(ObjF) { + const ELFFile<ELFT> *Obj = ObjF->getELFFile(); + for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { switch (Sec.sh_type) { case ELF::SHT_SYMTAB: - if (DotSymtabSec != nullptr) - reportError("Multiple SHT_SYMTAB"); - DotSymtabSec = &Sec; + if (!DotSymtabSec) + DotSymtabSec = &Sec; break; case ELF::SHT_DYNSYM: - if (DynSymRegion.Size) - reportError("Multiple SHT_DYNSYM"); - DynSymRegion = createDRIFrom(&Sec); - // This is only used (if Elf_Shdr present)for naming section in GNU style - DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec)); - DynamicStringTable = unwrapOrError(Obj->getStringTableForSymtab(Sec)); + if (!DynSymRegion.Size) { + DynSymRegion = createDRIFrom(&Sec); + // This is only used (if Elf_Shdr present)for naming section in GNU + // style + DynSymtabName = unwrapOrError(Obj->getSectionName(&Sec)); + + if (Expected<StringRef> E = Obj->getStringTableForSymtab(Sec)) + DynamicStringTable = *E; + else + warn(E.takeError()); + } break; case ELF::SHT_SYMTAB_SHNDX: ShndxTable = unwrapOrError(Obj->getSHNDXTable(Sec)); break; case ELF::SHT_GNU_versym: - if (dot_gnu_version_sec != nullptr) - reportError("Multiple SHT_GNU_versym"); - dot_gnu_version_sec = &Sec; + if (!SymbolVersionSection) + SymbolVersionSection = &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; + if (!SymbolVersionDefSection) + SymbolVersionDefSection = &Sec; break; case ELF::SHT_GNU_verneed: - if (dot_gnu_version_r_sec != nullptr) - reportError("Multiple SHT_GNU_verneed"); - dot_gnu_version_r_sec = &Sec; + if (!SymbolVersionNeedSection) + SymbolVersionNeedSection = &Sec; break; case ELF::SHT_LLVM_CALL_GRAPH_PROFILE: - if (DotCGProfileSec != nullptr) - reportError("Multiple .llvm.call-graph-profile"); - DotCGProfileSec = &Sec; + if (!DotCGProfileSec) + DotCGProfileSec = &Sec; break; case ELF::SHT_LLVM_ADDRSIG: - if (DotAddrsigSec != nullptr) - reportError("Multiple .llvm_addrsig"); - DotAddrsigSec = &Sec; + if (!DotAddrsigSec) + DotAddrsigSec = &Sec; break; } } - parseDynamicTable(LoadSegments); + loadDynamicTable(Obj); if (opts::Output == opts::GNU) ELFDumperStyle.reset(new GNUStyle<ELFT>(Writer, this)); @@ -1489,13 +1475,84 @@ ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> *ObjF, ELFDumperStyle.reset(new LLVMStyle<ELFT>(Writer, this)); } -template <typename ELFT> -void ELFDumper<ELFT>::parseDynamicTable( - ArrayRef<const Elf_Phdr *> LoadSegments) { - auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { +static const char *getTypeString(unsigned Arch, uint64_t Type) { +#define DYNAMIC_TAG(n, v) + switch (Arch) { + + case EM_AARCH64: + switch (Type) { +#define AARCH64_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef AARCH64_DYNAMIC_TAG + } + break; + + case EM_HEXAGON: + switch (Type) { +#define HEXAGON_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef HEXAGON_DYNAMIC_TAG + } + break; + + case EM_MIPS: + switch (Type) { +#define MIPS_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef MIPS_DYNAMIC_TAG + } + break; + + case EM_PPC64: + switch (Type) { +#define PPC64_DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef PPC64_DYNAMIC_TAG + } + break; + } +#undef DYNAMIC_TAG + switch (Type) { +// Now handle all dynamic tags except the architecture specific ones +#define AARCH64_DYNAMIC_TAG(name, value) +#define MIPS_DYNAMIC_TAG(name, value) +#define HEXAGON_DYNAMIC_TAG(name, value) +#define PPC64_DYNAMIC_TAG(name, value) +// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. +#define DYNAMIC_TAG_MARKER(name, value) +#define DYNAMIC_TAG(name, value) \ + case DT_##name: \ + return #name; +#include "llvm/BinaryFormat/DynamicTags.def" +#undef DYNAMIC_TAG +#undef AARCH64_DYNAMIC_TAG +#undef MIPS_DYNAMIC_TAG +#undef HEXAGON_DYNAMIC_TAG +#undef PPC64_DYNAMIC_TAG +#undef DYNAMIC_TAG_MARKER + default: + return "unknown"; + } +} + +template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { + auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * { auto MappedAddrOrError = ObjF->getELFFile()->toMappedAddr(VAddr); - if (!MappedAddrOrError) - report_fatal_error(MappedAddrOrError.takeError()); + if (!MappedAddrOrError) { + reportWarning("Unable to parse DT_" + + Twine(getTypeString( + ObjF->getELFFile()->getHeader()->e_machine, Tag)) + + ": " + llvm::toString(MappedAddrOrError.takeError())); + return nullptr; + } return MappedAddrOrError.get(); }; @@ -1505,25 +1562,26 @@ void ELFDumper<ELFT>::parseDynamicTable( for (const Elf_Dyn &Dyn : dynamic_table()) { switch (Dyn.d_tag) { case ELF::DT_HASH: - HashTable = - reinterpret_cast<const Elf_Hash *>(toMappedAddr(Dyn.getPtr())); + HashTable = reinterpret_cast<const Elf_Hash *>( + toMappedAddr(Dyn.getTag(), Dyn.getPtr())); break; case ELF::DT_GNU_HASH: - GnuHashTable = - reinterpret_cast<const Elf_GnuHash *>(toMappedAddr(Dyn.getPtr())); + GnuHashTable = reinterpret_cast<const Elf_GnuHash *>( + toMappedAddr(Dyn.getTag(), Dyn.getPtr())); break; case ELF::DT_STRTAB: - StringTableBegin = (const char *)toMappedAddr(Dyn.getPtr()); + StringTableBegin = reinterpret_cast<const char *>( + toMappedAddr(Dyn.getTag(), Dyn.getPtr())); break; case ELF::DT_STRSZ: StringTableSize = Dyn.getVal(); break; case ELF::DT_SYMTAB: - DynSymRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynSymRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); DynSymRegion.EntSize = sizeof(Elf_Sym); break; case ELF::DT_RELA: - DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_RELASZ: DynRelaRegion.Size = Dyn.getVal(); @@ -1535,7 +1593,7 @@ void ELFDumper<ELFT>::parseDynamicTable( SONameOffset = Dyn.getVal(); break; case ELF::DT_REL: - DynRelRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_RELSZ: DynRelRegion.Size = Dyn.getVal(); @@ -1545,7 +1603,7 @@ void ELFDumper<ELFT>::parseDynamicTable( break; case ELF::DT_RELR: case ELF::DT_ANDROID_RELR: - DynRelrRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynRelrRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_RELRSZ: case ELF::DT_ANDROID_RELRSZ: @@ -1565,7 +1623,7 @@ void ELFDumper<ELFT>::parseDynamicTable( Twine((uint64_t)Dyn.getVal())); break; case ELF::DT_JMPREL: - DynPLTRelRegion.Addr = toMappedAddr(Dyn.getPtr()); + DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); break; case ELF::DT_PLTRELSZ: DynPLTRelRegion.Size = Dyn.getVal(); @@ -1574,8 +1632,8 @@ void ELFDumper<ELFT>::parseDynamicTable( } if (StringTableBegin) DynamicStringTable = StringRef(StringTableBegin, StringTableSize); - if (SONameOffset) - SOName = getDynamicString(SONameOffset); + if (SONameOffset && SONameOffset < DynamicStringTable.size()) + SOName = DynamicStringTable.data() + SONameOffset; } template <typename ELFT> @@ -1593,37 +1651,52 @@ typename ELFDumper<ELFT>::Elf_Relr_Range ELFDumper<ELFT>::dyn_relrs() const { return DynRelrRegion.getAsArrayRef<Elf_Relr>(); } -template<class ELFT> -void ELFDumper<ELFT>::printFileHeaders() { +template <class ELFT> void ELFDumper<ELFT>::printFileHeaders() { ELFDumperStyle->printFileHeaders(ObjF->getELFFile()); } -template<class ELFT> -void ELFDumper<ELFT>::printSectionHeaders() { +template <class ELFT> void ELFDumper<ELFT>::printSectionHeaders() { ELFDumperStyle->printSectionHeaders(ObjF->getELFFile()); } -template<class ELFT> -void ELFDumper<ELFT>::printRelocations() { +template <class ELFT> void ELFDumper<ELFT>::printRelocations() { ELFDumperStyle->printRelocations(ObjF->getELFFile()); } -template <class ELFT> void ELFDumper<ELFT>::printProgramHeaders() { - ELFDumperStyle->printProgramHeaders(ObjF->getELFFile()); +template <class ELFT> +void ELFDumper<ELFT>::printProgramHeaders( + bool PrintProgramHeaders, cl::boolOrDefault PrintSectionMapping) { + ELFDumperStyle->printProgramHeaders(ObjF->getELFFile(), PrintProgramHeaders, + PrintSectionMapping); +} + +template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() { + // Dump version symbol section. + ELFDumperStyle->printVersionSymbolSection(ObjF->getELFFile(), + SymbolVersionSection); + + // Dump version definition section. + ELFDumperStyle->printVersionDefinitionSection(ObjF->getELFFile(), + SymbolVersionDefSection); + + // Dump version dependency section. + ELFDumperStyle->printVersionDependencySection(ObjF->getELFFile(), + SymbolVersionNeedSection); } template <class ELFT> void ELFDumper<ELFT>::printDynamicRelocations() { ELFDumperStyle->printDynamicRelocations(ObjF->getELFFile()); } -template<class ELFT> -void ELFDumper<ELFT>::printSymbols() { - ELFDumperStyle->printSymbols(ObjF->getELFFile()); +template <class ELFT> +void ELFDumper<ELFT>::printSymbols(bool PrintSymbols, + bool PrintDynamicSymbols) { + ELFDumperStyle->printSymbols(ObjF->getELFFile(), PrintSymbols, + PrintDynamicSymbols); } -template<class ELFT> -void ELFDumper<ELFT>::printDynamicSymbols() { - ELFDumperStyle->printDynamicSymbols(ObjF->getELFFile()); +template <class ELFT> void ELFDumper<ELFT>::printHashSymbols() { + ELFDumperStyle->printHashSymbols(ObjF->getELFFile()); } template <class ELFT> void ELFDumper<ELFT>::printHashHistogram() { @@ -1642,61 +1715,7 @@ template <class ELFT> void ELFDumper<ELFT>::printELFLinkerOptions() { ELFDumperStyle->printELFLinkerOptions(ObjF->getELFFile()); } -static const char *getTypeString(unsigned Arch, uint64_t Type) { -#define DYNAMIC_TAG(n, v) - switch (Arch) { - case EM_HEXAGON: - switch (Type) { -#define HEXAGON_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef HEXAGON_DYNAMIC_TAG - } - break; - - case EM_MIPS: - switch (Type) { -#define MIPS_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef MIPS_DYNAMIC_TAG - } - break; - - case EM_PPC64: - switch(Type) { -#define PPC64_DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef PPC64_DYNAMIC_TAG - } - break; - } -#undef DYNAMIC_TAG - switch (Type) { -// Now handle all dynamic tags except the architecture specific ones -#define MIPS_DYNAMIC_TAG(name, value) -#define HEXAGON_DYNAMIC_TAG(name, value) -#define PPC64_DYNAMIC_TAG(name, value) -// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc. -#define DYNAMIC_TAG_MARKER(name, value) -#define DYNAMIC_TAG(name, value) \ - case DT_##name: \ - return #name; -#include "llvm/BinaryFormat/DynamicTags.def" -#undef DYNAMIC_TAG -#undef MIPS_DYNAMIC_TAG -#undef HEXAGON_DYNAMIC_TAG -#undef PPC64_DYNAMIC_TAG -#undef DYNAMIC_TAG_MARKER - default: return "unknown"; - } -} - -#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ +#define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ { #enum, prefix##_##enum } static const EnumEntry<unsigned> ElfDynamicDTFlags[] = { @@ -1724,6 +1743,7 @@ static const EnumEntry<unsigned> ElfDynamicDTFlags1[] = { 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, DISPRELPND), LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODIRECT), LLVM_READOBJ_DT_FLAG_ENT(DF_1, IGNMULDEF), LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOKSYMS), @@ -1776,20 +1796,97 @@ void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) { } template <class ELFT> -StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const { - if (Value >= DynamicStringTable.size()) - reportError("Invalid dynamic string table reference"); - return StringRef(DynamicStringTable.data() + Value); -} - -static void printLibrary(raw_ostream &OS, const Twine &Tag, const Twine &Name) { - OS << Tag << ": [" << Name << "]"; -} +void ELFDumper<ELFT>::printDynamicEntry(raw_ostream &OS, uint64_t Type, + uint64_t Value) const { + const char *ConvChar = + (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64; + + // Handle custom printing of architecture specific tags + switch (ObjF->getELFFile()->getHeader()->e_machine) { + case EM_AARCH64: + switch (Type) { + case DT_AARCH64_BTI_PLT: + case DT_AARCH64_PAC_PLT: + OS << Value; + return; + default: + break; + } + break; + case EM_HEXAGON: + switch (Type) { + case DT_HEXAGON_VER: + OS << Value; + return; + case DT_HEXAGON_SYMSZ: + case DT_HEXAGON_PLT: + OS << format(ConvChar, Value); + return; + default: + break; + } + break; + case EM_MIPS: + switch (Type) { + case DT_MIPS_RLD_VERSION: + case DT_MIPS_LOCAL_GOTNO: + case DT_MIPS_SYMTABNO: + case DT_MIPS_UNREFEXTNO: + OS << Value; + return; + case DT_MIPS_TIME_STAMP: + case DT_MIPS_ICHECKSUM: + case DT_MIPS_IVERSION: + case DT_MIPS_BASE_ADDRESS: + case DT_MIPS_MSYM: + case DT_MIPS_CONFLICT: + case DT_MIPS_LIBLIST: + case DT_MIPS_CONFLICTNO: + case DT_MIPS_LIBLISTNO: + case DT_MIPS_GOTSYM: + case DT_MIPS_HIPAGENO: + case DT_MIPS_RLD_MAP: + case DT_MIPS_DELTA_CLASS: + case DT_MIPS_DELTA_CLASS_NO: + case DT_MIPS_DELTA_INSTANCE: + case DT_MIPS_DELTA_RELOC: + case DT_MIPS_DELTA_RELOC_NO: + case DT_MIPS_DELTA_SYM: + case DT_MIPS_DELTA_SYM_NO: + case DT_MIPS_DELTA_CLASSSYM: + case DT_MIPS_DELTA_CLASSSYM_NO: + case DT_MIPS_CXX_FLAGS: + case DT_MIPS_PIXIE_INIT: + case DT_MIPS_SYMBOL_LIB: + case DT_MIPS_LOCALPAGE_GOTIDX: + case DT_MIPS_LOCAL_GOTIDX: + case DT_MIPS_HIDDEN_GOTIDX: + case DT_MIPS_PROTECTED_GOTIDX: + case DT_MIPS_OPTIONS: + case DT_MIPS_INTERFACE: + case DT_MIPS_DYNSTR_ALIGN: + case DT_MIPS_INTERFACE_SIZE: + case DT_MIPS_RLD_TEXT_RESOLVE_ADDR: + case DT_MIPS_PERF_SUFFIX: + case DT_MIPS_COMPACT_SIZE: + case DT_MIPS_GP_VALUE: + case DT_MIPS_AUX_DYNAMIC: + case DT_MIPS_PLTGOT: + case DT_MIPS_RWPLT: + case DT_MIPS_RLD_MAP_REL: + OS << format(ConvChar, Value); + return; + case DT_MIPS_FLAGS: + printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); + return; + default: + break; + } + break; + default: + break; + } -template <class ELFT> -void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { - raw_ostream &OS = W.getOStream(); - const char* ConvChar = (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64; switch (Type) { case DT_PLTREL: if (Value == DT_REL) { @@ -1818,22 +1915,12 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { 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_RLD_MAP_REL: - case DT_MIPS_PLTGOT: - case DT_MIPS_OPTIONS: OS << format(ConvChar, Value); break; case DT_RELACOUNT: case DT_RELCOUNT: case DT_VERDEFNUM: 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: @@ -1851,24 +1938,30 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { OS << Value << " (bytes)"; break; case DT_NEEDED: - printLibrary(OS, "Shared library", getDynamicString(Value)); - break; case DT_SONAME: - printLibrary(OS, "Library soname", getDynamicString(Value)); - break; case DT_AUXILIARY: - printLibrary(OS, "Auxiliary library", getDynamicString(Value)); - break; + case DT_USED: case DT_FILTER: - printLibrary(OS, "Filter library", getDynamicString(Value)); - break; case DT_RPATH: - case DT_RUNPATH: - OS << getDynamicString(Value); - break; - case DT_MIPS_FLAGS: - printFlags(Value, makeArrayRef(ElfDynamicDTMipsFlags), OS); + case DT_RUNPATH: { + const std::map<uint64_t, const char*> TagNames = { + {DT_NEEDED, "Shared library"}, + {DT_SONAME, "Library soname"}, + {DT_AUXILIARY, "Auxiliary library"}, + {DT_USED, "Not needed object"}, + {DT_FILTER, "Filter library"}, + {DT_RPATH, "Library rpath"}, + {DT_RUNPATH, "Library runpath"}, + }; + OS << TagNames.at(Type) << ": "; + if (DynamicStringTable.empty()) + OS << "<String table is empty or was not found> "; + else if (Value < DynamicStringTable.size()) + OS << "[" << StringRef(DynamicStringTable.data() + Value) << "]"; + else + OS << "<Invalid offset 0x" << utohexstr(Value) << ">"; break; + } case DT_FLAGS: printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS); break; @@ -1881,14 +1974,9 @@ void ELFDumper<ELFT>::printValue(uint64_t Type, uint64_t Value) { } } -template<class ELFT> -void ELFDumper<ELFT>::printUnwindInfo() { - const unsigned Machine = ObjF->getELFFile()->getHeader()->e_machine; - if (Machine == EM_386 || Machine == EM_X86_64) { - DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF); - return Ctx.printUnwindInformation(); - } - W.startLine() << "UnwindInfo not implemented.\n"; +template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() { + DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF); + Ctx.printUnwindInformation(); } namespace { @@ -1898,73 +1986,40 @@ template <> void ELFDumper<ELF32LE>::printUnwindInfo() { const unsigned Machine = Obj->getHeader()->e_machine; if (Machine == EM_ARM) { ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, DotSymtabSec); - return Ctx.PrintUnwindInformation(); + Ctx.PrintUnwindInformation(); } - W.startLine() << "UnwindInfo not implemented.\n"; + DwarfCFIEH::PrinterContext<ELF32LE> Ctx(W, ObjF); + Ctx.printUnwindInformation(); } } // end anonymous namespace -template<class ELFT> -void ELFDumper<ELFT>::printDynamicTable() { - auto I = dynamic_table().begin(); - auto E = dynamic_table().end(); - - if (I == E) - return; - - --E; - while (I != E && E->getTag() == ELF::DT_NULL) - --E; - if (E->getTag() != ELF::DT_NULL) - ++E; - ++E; - - ptrdiff_t Total = std::distance(I, E); - if (Total == 0) - return; - - raw_ostream &OS = W.getOStream(); - W.startLine() << "DynamicSection [ (" << Total << " entries)\n"; - - bool Is64 = ELFT::Is64Bits; - - W.startLine() - << " Tag" << (Is64 ? " " : " ") << "Type" - << " " << "Name/Value\n"; - while (I != E) { - const Elf_Dyn &Entry = *I; - uintX_t Tag = Entry.getTag(); - ++I; - W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, opts::Output != opts::GNU) << " " - << format("%-21s", getTypeString(ObjF->getELFFile()->getHeader()->e_machine, Tag)); - printValue(Tag, Entry.getVal()); - OS << "\n"; - } - - W.startLine() << "]\n"; +template <class ELFT> void ELFDumper<ELFT>::printDynamicTable() { + ELFDumperStyle->printDynamic(ObjF->getELFFile()); } -template<class ELFT> -void ELFDumper<ELFT>::printNeededLibraries() { +template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() { ListScope D(W, "NeededLibraries"); using LibsTy = std::vector<StringRef>; LibsTy Libs; for (const auto &Entry : dynamic_table()) - if (Entry.d_tag == ELF::DT_NEEDED) - Libs.push_back(getDynamicString(Entry.d_un.d_val)); + if (Entry.d_tag == ELF::DT_NEEDED) { + uint64_t Value = Entry.d_un.d_val; + if (Value < DynamicStringTable.size()) + Libs.push_back(StringRef(DynamicStringTable.data() + Value)); + else + Libs.push_back("<Library name index out of range>"); + } - std::stable_sort(Libs.begin(), Libs.end()); + llvm::stable_sort(Libs); for (const auto &L : Libs) - W.startLine() << L << "\n"; + W.startLine() << L << "\n"; } - -template <typename ELFT> -void ELFDumper<ELFT>::printHashTable() { +template <typename ELFT> void ELFDumper<ELFT>::printHashTable() { DictScope D(W, "HashTable"); if (!HashTable) return; @@ -1974,8 +2029,7 @@ void ELFDumper<ELFT>::printHashTable() { W.printList("Chains", HashTable->chains()); } -template <typename ELFT> -void ELFDumper<ELFT>::printGnuHashTable() { +template <typename ELFT> void ELFDumper<ELFT>::printGnuHashTable() { DictScope D(W, "GnuHashTable"); if (!GnuHashTable) return; @@ -1996,8 +2050,7 @@ template <typename ELFT> void ELFDumper<ELFT>::printLoadName() { W.printString("LoadName", SOName); } -template <class ELFT> -void ELFDumper<ELFT>::printAttributes() { +template <class ELFT> void ELFDumper<ELFT>::printAttributes() { W.startLine() << "Attributes not implemented.\n"; } @@ -2486,7 +2539,7 @@ template <class ELFT> void ELFDumper<ELFT>::printStackMap() const { unwrapOrError(Obj->getSectionContents(StackMapSection)); prettyPrintStackMap( - W, StackMapV2Parser<ELFT::TargetEndianness>(StackMapContentsArray)); + W, StackMapParser<ELFT::TargetEndianness>(StackMapContentsArray)); } template <class ELFT> void ELFDumper<ELFT>::printGroupSections() { @@ -2527,7 +2580,8 @@ static std::string getSectionHeaderTableIndexString(const ELFFile<ELFT> *Obj) { ArrayRef<typename ELFT::Shdr> Arr = unwrapOrError(Obj->sections()); if (Arr.empty()) return "65535 (corrupt: out of range)"; - return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) + ")"; + return to_string(ElfHeader->e_shstrndx) + " (" + to_string(Arr[0].sh_link) + + ")"; } template <class ELFT> void GNUStyle<ELFT>::printFileHeaders(const ELFO *Obj) { @@ -2599,7 +2653,7 @@ struct GroupMember { struct GroupSection { StringRef Name; - StringRef Signature; + std::string Signature; uint64_t ShName; uint64_t Index; uint32_t Link; @@ -2630,13 +2684,13 @@ std::vector<GroupSection> getGroups(const ELFFile<ELFT> *Obj) { StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); StringRef Signature = StrTable.data() + Sym->st_name; - Ret.push_back({Name, - Signature, - Sec.sh_name, + Ret.push_back({Name, + maybeDemangle(Signature), + Sec.sh_name, I - 1, Sec.sh_link, Sec.sh_info, - Data[0], + Data[0], {}}); std::vector<GroupMember> &GM = Ret.back().Members; @@ -2691,53 +2745,57 @@ template <class ELFT> void GNUStyle<ELFT>::printGroupSections(const ELFO *Obj) { template <class ELFT> void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Shdr *SymTab, const Elf_Rela &R, bool IsRela) { - std::string Offset, Info, Addend, Value; - SmallString<32> RelocName; - StringRef TargetName; - const Elf_Sym *Sym = nullptr; - unsigned Width = ELFT::Is64Bits ? 16 : 8; - unsigned Bias = ELFT::Is64Bits ? 8 : 0; - - // First two fields are bit width dependent. The rest of them are after are - // fixed width. - Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias}; - Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); - Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab)); + const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&R, SymTab)); + std::string TargetName; if (Sym && Sym->getType() == ELF::STT_SECTION) { const Elf_Shdr *Sec = unwrapOrError( Obj->getSection(Sym, SymTab, this->dumper()->getShndxTable())); TargetName = unwrapOrError(Obj->getSectionName(Sec)); } else if (Sym) { StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); - TargetName = unwrapOrError(Sym->getName(StrTable)); + TargetName = this->dumper()->getFullSymbolName( + Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */); } + printRelocation(Obj, Sym, TargetName, R, IsRela); +} - if (Sym && IsRela) { - if (R.r_addend < 0) - Addend = " - "; - else - Addend = " + "; - } +template <class ELFT> +void GNUStyle<ELFT>::printRelocation(const ELFO *Obj, const Elf_Sym *Sym, + StringRef SymbolName, const Elf_Rela &R, + bool IsRela) { + // First two fields are bit width dependent. The rest of them are fixed width. + unsigned Bias = ELFT::Is64Bits ? 8 : 0; + Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias}; + unsigned Width = ELFT::Is64Bits ? 16 : 8; - Offset = to_string(format_hex_no_prefix(R.r_offset, Width)); - Info = to_string(format_hex_no_prefix(R.r_info, Width)); + Fields[0].Str = to_string(format_hex_no_prefix(R.r_offset, Width)); + Fields[1].Str = to_string(format_hex_no_prefix(R.r_info, Width)); - int64_t RelAddend = R.r_addend; - if (IsRela) - Addend += to_hexString(std::abs(RelAddend), false); - - if (Sym) - Value = to_string(format_hex_no_prefix(Sym->getValue(), Width)); - - Fields[0].Str = Offset; - Fields[1].Str = Info; - Fields[2].Str = RelocName; - Fields[3].Str = Value; - Fields[4].Str = TargetName; - for (auto &field : Fields) - printField(field); - OS << Addend; - OS << "\n"; + SmallString<32> RelocName; + Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); + Fields[2].Str = RelocName.c_str(); + + if (Sym && (!SymbolName.empty() || Sym->getValue() != 0)) + Fields[3].Str = to_string(format_hex_no_prefix(Sym->getValue(), Width)); + + Fields[4].Str = SymbolName; + for (const Field &F : Fields) + printField(F); + + std::string Addend; + if (IsRela) { + int64_t RelAddend = R.r_addend; + if (!SymbolName.empty()) { + if (R.r_addend < 0) { + Addend = " - "; + RelAddend = std::abs(RelAddend); + } else + Addend = " + "; + } + + Addend += to_hexString(RelAddend, false); + } + OS << Addend << "\n"; } template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) { @@ -2764,10 +2822,8 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocHeader(unsigned SType) { template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { bool HasRelocSections = false; for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { - if (Sec.sh_type != ELF::SHT_REL && - Sec.sh_type != ELF::SHT_RELA && - Sec.sh_type != ELF::SHT_RELR && - Sec.sh_type != ELF::SHT_ANDROID_REL && + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && + Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL && Sec.sh_type != ELF::SHT_ANDROID_RELA && Sec.sh_type != ELF::SHT_ANDROID_RELR) continue; @@ -2832,7 +2888,21 @@ template <class ELFT> void GNUStyle<ELFT>::printRelocations(const ELFO *Obj) { OS << "\nThere are no relocations in this file.\n"; } -std::string getSectionTypeString(unsigned Arch, unsigned Type) { +// Print the offset of a particular section from anyone of the ranges: +// [SHT_LOOS, SHT_HIOS], [SHT_LOPROC, SHT_HIPROC], [SHT_LOUSER, SHT_HIUSER]. +// If 'Type' does not fall within any of those ranges, then a string is +// returned as '<unknown>' followed by the type value. +static std::string getSectionTypeOffsetString(unsigned Type) { + if (Type >= SHT_LOOS && Type <= SHT_HIOS) + return "LOOS+0x" + to_hexString(Type - SHT_LOOS); + else if (Type >= SHT_LOPROC && Type <= SHT_HIPROC) + return "LOPROC+0x" + to_hexString(Type - SHT_LOPROC); + else if (Type >= SHT_LOUSER && Type <= SHT_HIUSER) + return "LOUSER+0x" + to_hexString(Type - SHT_LOUSER); + return "0x" + to_hexString(Type) + ": <unknown>"; +} + +static std::string getSectionTypeString(unsigned Arch, unsigned Type) { using namespace ELF; switch (Arch) { @@ -2863,10 +2933,10 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) { return "MIPS_REGINFO"; case SHT_MIPS_OPTIONS: return "MIPS_OPTIONS"; + case SHT_MIPS_DWARF: + return "MIPS_DWARF"; case SHT_MIPS_ABIFLAGS: return "MIPS_ABIFLAGS"; - case SHT_MIPS_DWARF: - return "SHT_MIPS_DWARF"; } break; } @@ -2905,6 +2975,10 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) { return "GROUP"; case SHT_SYMTAB_SHNDX: return "SYMTAB SECTION INDICES"; + case SHT_ANDROID_REL: + return "ANDROID_REL"; + case SHT_ANDROID_RELA: + return "ANDROID_RELA"; case SHT_RELR: case SHT_ANDROID_RELR: return "RELR"; @@ -2916,6 +2990,8 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) { return "LLVM_CALL_GRAPH_PROFILE"; case SHT_LLVM_ADDRSIG: return "LLVM_ADDRSIG"; + case SHT_LLVM_DEPENDENT_LIBRARIES: + return "LLVM_DEPENDENT_LIBRARIES"; // FIXME: Parse processor specific GNU attributes case SHT_GNU_ATTRIBUTES: return "ATTRIBUTES"; @@ -2928,69 +3004,65 @@ std::string getSectionTypeString(unsigned Arch, unsigned Type) { case SHT_GNU_versym: return "VERSYM"; default: - return ""; + return getSectionTypeOffsetString(Type); } return ""; } template <class ELFT> -void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { - size_t SectionIndex = 0; - std::string Number, Type, Size, Address, Offset, Flags, Link, Info, EntrySize, - Alignment; - unsigned Bias; - unsigned Width; - - if (ELFT::Is64Bits) { - Bias = 0; - Width = 16; - } else { - Bias = 8; - Width = 8; - } +static StringRef getSectionName(const typename ELFT::Shdr &Sec, + const ELFObjectFile<ELFT> &ElfObj, + ArrayRef<typename ELFT::Shdr> Sections) { + const ELFFile<ELFT> &Obj = *ElfObj.getELFFile(); + uint32_t Index = Obj.getHeader()->e_shstrndx; + if (Index == ELF::SHN_XINDEX) + Index = Sections[0].sh_link; + if (!Index) // no section string table. + return ""; + // TODO: Test a case when the sh_link of the section with index 0 is broken. + if (Index >= Sections.size()) + reportError(ElfObj.getFileName(), + createError("section header string table index " + + Twine(Index) + " does not exist")); + StringRef Data = toStringRef(unwrapOrError( + Obj.template getSectionContentsAsArray<uint8_t>(&Sections[Index]))); + return unwrapOrError(Obj.getSectionName(&Sec, Data)); +} +template <class ELFT> +void GNUStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { + unsigned Bias = ELFT::Is64Bits ? 0 : 8; ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections()); OS << "There are " << to_string(Sections.size()) << " section headers, starting at offset " << "0x" << to_hexString(Obj->getHeader()->e_shoff, false) << ":\n\n"; OS << "Section Headers:\n"; - Field Fields[11] = {{"[Nr]", 2}, - {"Name", 7}, - {"Type", 25}, - {"Address", 41}, - {"Off", 58 - Bias}, - {"Size", 65 - Bias}, - {"ES", 72 - Bias}, - {"Flg", 75 - Bias}, - {"Lk", 79 - Bias}, - {"Inf", 82 - Bias}, - {"Al", 86 - Bias}}; - for (auto &f : Fields) - printField(f); + Field Fields[11] = { + {"[Nr]", 2}, {"Name", 7}, {"Type", 25}, + {"Address", 41}, {"Off", 58 - Bias}, {"Size", 65 - Bias}, + {"ES", 72 - Bias}, {"Flg", 75 - Bias}, {"Lk", 79 - Bias}, + {"Inf", 82 - Bias}, {"Al", 86 - Bias}}; + for (auto &F : Fields) + printField(F); OS << "\n"; + const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject(); + size_t SectionIndex = 0; for (const Elf_Shdr &Sec : Sections) { - Number = to_string(SectionIndex); - Fields[0].Str = Number; - Fields[1].Str = unwrapOrError(Obj->getSectionName(&Sec)); - Type = getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type); - Fields[2].Str = Type; - Address = to_string(format_hex_no_prefix(Sec.sh_addr, Width)); - Fields[3].Str = Address; - Offset = to_string(format_hex_no_prefix(Sec.sh_offset, 6)); - Fields[4].Str = Offset; - Size = to_string(format_hex_no_prefix(Sec.sh_size, 6)); - Fields[5].Str = Size; - EntrySize = to_string(format_hex_no_prefix(Sec.sh_entsize, 2)); - Fields[6].Str = EntrySize; - Flags = getGNUFlags(Sec.sh_flags); - Fields[7].Str = Flags; - Link = to_string(Sec.sh_link); - Fields[8].Str = Link; - Info = to_string(Sec.sh_info); - Fields[9].Str = Info; - Alignment = to_string(Sec.sh_addralign); - Fields[10].Str = Alignment; + Fields[0].Str = to_string(SectionIndex); + Fields[1].Str = getSectionName(Sec, *ElfObj, Sections); + Fields[2].Str = + getSectionTypeString(Obj->getHeader()->e_machine, Sec.sh_type); + Fields[3].Str = + to_string(format_hex_no_prefix(Sec.sh_addr, ELFT::Is64Bits ? 16 : 8)); + Fields[4].Str = to_string(format_hex_no_prefix(Sec.sh_offset, 6)); + Fields[5].Str = to_string(format_hex_no_prefix(Sec.sh_size, 6)); + Fields[6].Str = to_string(format_hex_no_prefix(Sec.sh_entsize, 2)); + Fields[7].Str = getGNUFlags(Sec.sh_flags); + Fields[8].Str = to_string(Sec.sh_link); + Fields[9].Str = to_string(Sec.sh_info); + Fields[10].Str = to_string(Sec.sh_addralign); + OS.PadToColumn(Fields[0].Column); OS << "[" << right_justify(Fields[0].Str, 2) << "]"; for (int i = 1; i < 7; i++) @@ -3043,9 +3115,10 @@ std::string GNUStyle<ELFT>::getSymbolSectionNdx(const ELFO *Obj, case ELF::SHN_COMMON: return "COM"; case ELF::SHN_XINDEX: - SectionIndex = unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>( - Symbol, FirstSym, this->dumper()->getShndxTable())); - LLVM_FALLTHROUGH; + return to_string( + format_decimal(unwrapOrError(object::getExtendedSymbolTableIndex<ELFT>( + Symbol, FirstSym, this->dumper()->getShndxTable())), + 3)); default: // Find if: // Processor specific @@ -3072,7 +3145,6 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, bool IsDynamic) { static int Idx = 0; static bool Dynamic = true; - size_t Width; // If this function was called with a different value from IsDynamic // from last call, happens when we move from dynamic to static symbol @@ -3081,111 +3153,87 @@ void GNUStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, Idx = 0; Dynamic = false; } - std::string Num, Name, Value, Size, Binding, Type, Visibility, Section; - unsigned Bias = 0; - if (ELFT::Is64Bits) { - Bias = 8; - Width = 16; - } else { - Bias = 0; - Width = 8; - } + + unsigned Bias = ELFT::Is64Bits ? 8 : 0; Field Fields[8] = {0, 8, 17 + Bias, 23 + Bias, 31 + Bias, 38 + Bias, 47 + Bias, 51 + Bias}; - Num = to_string(format_decimal(Idx++, 6)) + ":"; - Value = to_string(format_hex_no_prefix(Symbol->st_value, Width)); - Size = to_string(format_decimal(Symbol->st_size, 5)); + Fields[0].Str = to_string(format_decimal(Idx++, 6)) + ":"; + Fields[1].Str = to_string( + format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 16 : 8)); + Fields[2].Str = to_string(format_decimal(Symbol->st_size, 5)); + unsigned char SymbolType = Symbol->getType(); if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU && SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) - Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes)); + Fields[3].Str = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes)); else - Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes)); - unsigned Vis = Symbol->getVisibility(); - Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); - Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities)); - Section = getSymbolSectionNdx(Obj, Symbol, FirstSym); - Name = this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); - Fields[0].Str = Num; - Fields[1].Str = Value; - Fields[2].Str = Size; - Fields[3].Str = Type; - Fields[4].Str = Binding; - Fields[5].Str = Visibility; - Fields[6].Str = Section; - Fields[7].Str = Name; + Fields[3].Str = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes)); + + Fields[4].Str = + printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); + Fields[5].Str = + printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities)); + Fields[6].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym); + Fields[7].Str = + this->dumper()->getFullSymbolName(Symbol, StrTable, IsDynamic); for (auto &Entry : Fields) printField(Entry); OS << "\n"; } + template <class ELFT> void GNUStyle<ELFT>::printHashedSymbol(const ELFO *Obj, const Elf_Sym *FirstSym, uint32_t Sym, StringRef StrTable, uint32_t Bucket) { - std::string Num, Buc, Name, Value, Size, Binding, Type, Visibility, Section; - unsigned Width, Bias = 0; - if (ELFT::Is64Bits) { - Bias = 8; - Width = 16; - } else { - Bias = 0; - Width = 8; - } + unsigned Bias = ELFT::Is64Bits ? 8 : 0; Field Fields[9] = {0, 6, 11, 20 + Bias, 25 + Bias, 34 + Bias, 41 + Bias, 49 + Bias, 53 + Bias}; - Num = to_string(format_decimal(Sym, 5)); - Buc = to_string(format_decimal(Bucket, 3)) + ":"; + Fields[0].Str = to_string(format_decimal(Sym, 5)); + Fields[1].Str = to_string(format_decimal(Bucket, 3)) + ":"; const auto Symbol = FirstSym + Sym; - Value = to_string(format_hex_no_prefix(Symbol->st_value, Width)); - Size = to_string(format_decimal(Symbol->st_size, 5)); + Fields[2].Str = to_string( + format_hex_no_prefix(Symbol->st_value, ELFT::Is64Bits ? 18 : 8)); + Fields[3].Str = to_string(format_decimal(Symbol->st_size, 5)); + unsigned char SymbolType = Symbol->getType(); if (Obj->getHeader()->e_machine == ELF::EM_AMDGPU && SymbolType >= ELF::STT_LOOS && SymbolType < ELF::STT_HIOS) - Type = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes)); + Fields[4].Str = printEnum(SymbolType, makeArrayRef(AMDGPUSymbolTypes)); else - Type = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes)); - unsigned Vis = Symbol->getVisibility(); - Binding = printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); - Visibility = printEnum(Vis, makeArrayRef(ElfSymbolVisibilities)); - Section = getSymbolSectionNdx(Obj, Symbol, FirstSym); - Name = this->dumper()->getFullSymbolName(Symbol, StrTable, true); - Fields[0].Str = Num; - Fields[1].Str = Buc; - Fields[2].Str = Value; - Fields[3].Str = Size; - Fields[4].Str = Type; - Fields[5].Str = Binding; - Fields[6].Str = Visibility; - Fields[7].Str = Section; - Fields[8].Str = Name; + Fields[4].Str = printEnum(SymbolType, makeArrayRef(ElfSymbolTypes)); + + Fields[5].Str = + printEnum(Symbol->getBinding(), makeArrayRef(ElfSymbolBindings)); + Fields[6].Str = + printEnum(Symbol->getVisibility(), makeArrayRef(ElfSymbolVisibilities)); + Fields[7].Str = getSymbolSectionNdx(Obj, Symbol, FirstSym); + Fields[8].Str = this->dumper()->getFullSymbolName(Symbol, StrTable, true); + for (auto &Entry : Fields) printField(Entry); OS << "\n"; } -template <class ELFT> void GNUStyle<ELFT>::printSymbols(const ELFO *Obj) { - if (opts::DynamicSymbols) +template <class ELFT> +void GNUStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols, + bool PrintDynamicSymbols) { + if (!PrintSymbols && !PrintDynamicSymbols) return; + // GNU readelf prints both the .dynsym and .symtab with --symbols. this->dumper()->printSymbolsHelper(true); - this->dumper()->printSymbolsHelper(false); + if (PrintSymbols) + this->dumper()->printSymbolsHelper(false); } -template <class ELFT> -void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) { +template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) { if (this->dumper()->getDynamicStringTable().empty()) return; auto StringTable = this->dumper()->getDynamicStringTable(); auto DynSyms = this->dumper()->dynamic_symbols(); - auto GnuHash = this->dumper()->getGnuHashTable(); - auto SysVHash = this->dumper()->getHashTable(); - - // If no hash or .gnu.hash found, try using symbol table - if (GnuHash == nullptr && SysVHash == nullptr) - this->dumper()->printSymbolsHelper(true); // Try printing .hash - if (this->dumper()->getHashTable()) { + if (auto SysVHash = this->dumper()->getHashTable()) { OS << "\n Symbol table of .hash for image:\n"; if (ELFT::Is64Bits) OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; @@ -3193,14 +3241,12 @@ void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) { OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; OS << "\n"; - uint32_t NBuckets = SysVHash->nbucket; - uint32_t NChains = SysVHash->nchain; auto Buckets = SysVHash->buckets(); auto Chains = SysVHash->chains(); - for (uint32_t Buc = 0; Buc < NBuckets; Buc++) { + for (uint32_t Buc = 0; Buc < SysVHash->nbucket; Buc++) { if (Buckets[Buc] == ELF::STN_UNDEF) continue; - for (uint32_t Ch = Buckets[Buc]; Ch < NChains; Ch = Chains[Ch]) { + for (uint32_t Ch = Buckets[Buc]; Ch < SysVHash->nchain; Ch = Chains[Ch]) { if (Ch == ELF::STN_UNDEF) break; printHashedSymbol(Obj, &DynSyms[0], Ch, StringTable, Buc); @@ -3209,16 +3255,15 @@ void GNUStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) { } // Try printing .gnu.hash - if (GnuHash) { + if (auto GnuHash = this->dumper()->getGnuHashTable()) { OS << "\n Symbol table of .gnu.hash for image:\n"; if (ELFT::Is64Bits) OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; else OS << " Num Buc: Value Size Type Bind Vis Ndx Name"; OS << "\n"; - uint32_t NBuckets = GnuHash->nbuckets; auto Buckets = GnuHash->buckets(); - for (uint32_t Buc = 0; Buc < NBuckets; Buc++) { + for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) { if (Buckets[Buc] == ELF::STN_UNDEF) continue; uint32_t Index = Buckets[Buc]; @@ -3266,8 +3311,8 @@ bool GNUStyle<ELFT>::checkoffsets(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) { (IsSpecial && Phdr.p_type != ELF::PT_TLS) ? 0 : Sec.sh_size; if (Sec.sh_offset >= Phdr.p_offset) return ((Sec.sh_offset + SectionSize <= Phdr.p_filesz + Phdr.p_offset) - /*only non-zero sized sections at end*/ && - (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz)); + /*only non-zero sized sections at end*/ + && (Sec.sh_offset + 1 <= Phdr.p_offset + Phdr.p_filesz)); return false; } @@ -3302,12 +3347,21 @@ bool GNUStyle<ELFT>::checkPTDynamic(const Elf_Phdr &Phdr, const Elf_Shdr &Sec) { } template <class ELFT> +void GNUStyle<ELFT>::printProgramHeaders( + const ELFO *Obj, bool PrintProgramHeaders, + cl::boolOrDefault PrintSectionMapping) { + if (PrintProgramHeaders) + printProgramHeaders(Obj); + + // Display the section mapping along with the program headers, unless + // -section-mapping is explicitly set to false. + if (PrintSectionMapping != cl::BOU_FALSE) + printSectionMapping(Obj); +} + +template <class ELFT> void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { unsigned Bias = ELFT::Is64Bits ? 8 : 0; - unsigned Width = ELFT::Is64Bits ? 18 : 10; - unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7; - std::string Type, Offset, VMA, LMA, FileSz, MemSz, Flag, Align; - const Elf_Ehdr *Header = Obj->getHeader(); Field Fields[8] = {2, 17, 26, 37 + Bias, 48 + Bias, 56 + Bias, 64 + Bias, 68 + Bias}; @@ -3323,23 +3377,18 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { else OS << " Type Offset VirtAddr PhysAddr FileSiz " << "MemSiz Flg Align\n"; + + unsigned Width = ELFT::Is64Bits ? 18 : 10; + unsigned SizeWidth = ELFT::Is64Bits ? 8 : 7; for (const auto &Phdr : unwrapOrError(Obj->program_headers())) { - Type = getElfPtType(Header->e_machine, Phdr.p_type); - Offset = to_string(format_hex(Phdr.p_offset, 8)); - VMA = to_string(format_hex(Phdr.p_vaddr, Width)); - LMA = to_string(format_hex(Phdr.p_paddr, Width)); - FileSz = to_string(format_hex(Phdr.p_filesz, SizeWidth)); - MemSz = to_string(format_hex(Phdr.p_memsz, SizeWidth)); - Flag = printPhdrFlags(Phdr.p_flags); - Align = to_string(format_hex(Phdr.p_align, 1)); - Fields[0].Str = Type; - Fields[1].Str = Offset; - Fields[2].Str = VMA; - Fields[3].Str = LMA; - Fields[4].Str = FileSz; - Fields[5].Str = MemSz; - Fields[6].Str = Flag; - Fields[7].Str = Align; + Fields[0].Str = getElfPtType(Header->e_machine, Phdr.p_type); + Fields[1].Str = to_string(format_hex(Phdr.p_offset, 8)); + Fields[2].Str = to_string(format_hex(Phdr.p_vaddr, Width)); + Fields[3].Str = to_string(format_hex(Phdr.p_paddr, Width)); + Fields[4].Str = to_string(format_hex(Phdr.p_filesz, SizeWidth)); + Fields[5].Str = to_string(format_hex(Phdr.p_memsz, SizeWidth)); + Fields[6].Str = printPhdrFlags(Phdr.p_flags); + Fields[7].Str = to_string(format_hex(Phdr.p_align, 1)); for (auto Field : Fields) printField(Field); if (Phdr.p_type == ELF::PT_INTERP) { @@ -3348,7 +3397,12 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { } OS << "\n"; } +} + +template <class ELFT> +void GNUStyle<ELFT>::printSectionMapping(const ELFO *Obj) { OS << "\n Section to Segment mapping:\n Segment Sections...\n"; + DenseSet<const Elf_Shdr *> BelongsToSegment; int Phnum = 0; for (const Elf_Phdr &Phdr : unwrapOrError(Obj->program_headers())) { std::string Sections; @@ -3363,58 +3417,66 @@ void GNUStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { Phdr.p_type != ELF::PT_TLS; if (!TbssInNonTLS && checkTLSSections(Phdr, Sec) && checkoffsets(Phdr, Sec) && checkVMA(Phdr, Sec) && - checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL)) + checkPTDynamic(Phdr, Sec) && (Sec.sh_type != ELF::SHT_NULL)) { Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + " "; + BelongsToSegment.insert(&Sec); + } } OS << Sections << "\n"; OS.flush(); } + + // Display sections that do not belong to a segment. + std::string Sections; + for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { + if (BelongsToSegment.find(&Sec) == BelongsToSegment.end()) + Sections += unwrapOrError(Obj->getSectionName(&Sec)).str() + ' '; + } + if (!Sections.empty()) { + OS << " None " << Sections << '\n'; + OS.flush(); + } } template <class ELFT> void GNUStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela R, bool IsRela) { - SmallString<32> RelocName; - StringRef SymbolName; - unsigned Width = ELFT::Is64Bits ? 16 : 8; - unsigned Bias = ELFT::Is64Bits ? 8 : 0; - // First two fields are bit width dependent. The rest of them are after are - // fixed width. - Field Fields[5] = {0, 10 + Bias, 19 + 2 * Bias, 42 + 2 * Bias, 53 + 2 * Bias}; - uint32_t SymIndex = R.getSymbol(Obj->isMips64EL()); const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; - Obj->getRelocationTypeName(R.getType(Obj->isMips64EL()), RelocName); - SymbolName = - unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())); - std::string Addend, Info, Offset, Value; - Offset = to_string(format_hex_no_prefix(R.r_offset, Width)); - Info = to_string(format_hex_no_prefix(R.r_info, Width)); - Value = to_string(format_hex_no_prefix(Sym->getValue(), Width)); - int64_t RelAddend = R.r_addend; - if (!SymbolName.empty() && IsRela) { - if (R.r_addend < 0) - Addend = " - "; - else - Addend = " + "; - } + std::string SymbolName = maybeDemangle( + unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()))); + printRelocation(Obj, Sym, SymbolName, R, IsRela); +} - if (SymbolName.empty() && Sym->getValue() == 0) - Value = ""; +template <class ELFT> void GNUStyle<ELFT>::printDynamic(const ELFO *Obj) { + Elf_Dyn_Range Table = this->dumper()->dynamic_table(); + if (Table.empty()) + return; - if (IsRela) - Addend += to_string(format_hex_no_prefix(std::abs(RelAddend), 1)); + const DynRegionInfo &DynamicTableRegion = + this->dumper()->getDynamicTableRegion(); + OS << "Dynamic section at offset " + << format_hex(reinterpret_cast<const uint8_t *>(DynamicTableRegion.Addr) - + Obj->base(), + 1) + << " contains " << Table.size() << " entries:\n"; - Fields[0].Str = Offset; - Fields[1].Str = Info; - Fields[2].Str = RelocName.c_str(); - Fields[3].Str = Value; - Fields[4].Str = SymbolName; - for (auto &Field : Fields) - printField(Field); - OS << Addend; - OS << "\n"; + bool Is64 = ELFT::Is64Bits; + if (Is64) + OS << " Tag Type Name/Value\n"; + else + OS << " Tag Type Name/Value\n"; + for (auto Entry : Table) { + uintX_t Tag = Entry.getTag(); + std::string TypeString = std::string("(") + + getTypeString(Obj->getHeader()->e_machine, Tag) + + ")"; + OS << " " << format_hex(Tag, Is64 ? 18 : 10) + << format(" %-20s ", TypeString.c_str()); + this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal()); + OS << "\n"; + } } template <class ELFT> @@ -3427,7 +3489,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { OS << "\n'RELA' relocation section at offset " << format_hex(reinterpret_cast<const uint8_t *>(DynRelaRegion.Addr) - Obj->base(), - 1) << " contains " << DynRelaRegion.Size << " bytes:\n"; + 1) + << " contains " << DynRelaRegion.Size << " bytes:\n"; printRelocHeader(ELF::SHT_RELA); for (const Elf_Rela &Rela : this->dumper()->dyn_relas()) printDynamicRelocation(Obj, Rela, true); @@ -3436,7 +3499,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { OS << "\n'REL' relocation section at offset " << format_hex(reinterpret_cast<const uint8_t *>(DynRelRegion.Addr) - Obj->base(), - 1) << " contains " << DynRelRegion.Size << " bytes:\n"; + 1) + << " contains " << DynRelRegion.Size << " bytes:\n"; printRelocHeader(ELF::SHT_REL); for (const Elf_Rel &Rel : this->dumper()->dyn_rels()) { Elf_Rela Rela; @@ -3450,7 +3514,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { OS << "\n'RELR' relocation section at offset " << format_hex(reinterpret_cast<const uint8_t *>(DynRelrRegion.Addr) - Obj->base(), - 1) << " contains " << DynRelrRegion.Size << " bytes:\n"; + 1) + << " contains " << DynRelrRegion.Size << " bytes:\n"; printRelocHeader(ELF::SHT_REL); Elf_Relr_Range Relrs = this->dumper()->dyn_relrs(); std::vector<Elf_Rela> RelrRelas = unwrapOrError(Obj->decode_relrs(Relrs)); @@ -3462,7 +3527,8 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { OS << "\n'PLT' relocation section at offset " << format_hex(reinterpret_cast<const uint8_t *>(DynPLTRelRegion.Addr) - Obj->base(), - 1) << " contains " << DynPLTRelRegion.Size << " bytes:\n"; + 1) + << " contains " << DynPLTRelRegion.Size << " bytes:\n"; } if (DynPLTRelRegion.EntSize == sizeof(Elf_Rela)) { printRelocHeader(ELF::SHT_RELA); @@ -3480,18 +3546,189 @@ void GNUStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { } } +template <class ELFT> +static void printGNUVersionSectionProlog(formatted_raw_ostream &OS, + const Twine &Name, unsigned EntriesNum, + const ELFFile<ELFT> *Obj, + const typename ELFT::Shdr *Sec) { + StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + OS << Name << " section '" << SecName << "' " + << "contains " << EntriesNum << " entries:\n"; + + const typename ELFT::Shdr *SymTab = + unwrapOrError(Obj->getSection(Sec->sh_link)); + StringRef SymTabName = unwrapOrError(Obj->getSectionName(SymTab)); + OS << " Addr: " << format_hex_no_prefix(Sec->sh_addr, 16) + << " Offset: " << format_hex(Sec->sh_offset, 8) + << " Link: " << Sec->sh_link << " (" << SymTabName << ")\n"; +} + +template <class ELFT> +void GNUStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) { + if (!Sec) + return; + + unsigned Entries = Sec->sh_size / sizeof(Elf_Versym); + printGNUVersionSectionProlog(OS, "Version symbols", Entries, Obj, Sec); + + const uint8_t *VersymBuf = + reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); + const ELFDumper<ELFT> *Dumper = this->dumper(); + StringRef StrTable = Dumper->getDynamicStringTable(); + + // readelf prints 4 entries per line. + for (uint64_t VersymRow = 0; VersymRow < Entries; VersymRow += 4) { + OS << " " << format_hex_no_prefix(VersymRow, 3) << ":"; + + for (uint64_t VersymIndex = 0; + (VersymIndex < 4) && (VersymIndex + VersymRow) < Entries; + ++VersymIndex) { + const Elf_Versym *Versym = + reinterpret_cast<const Elf_Versym *>(VersymBuf); + switch (Versym->vs_index) { + case 0: + OS << " 0 (*local*) "; + break; + case 1: + OS << " 1 (*global*) "; + break; + default: + OS << format("%4x%c", Versym->vs_index & VERSYM_VERSION, + Versym->vs_index & VERSYM_HIDDEN ? 'h' : ' '); + + bool IsDefault = true; + std::string VersionName = Dumper->getSymbolVersionByIndex( + StrTable, Versym->vs_index, IsDefault); + + if (!VersionName.empty()) + VersionName = "(" + VersionName + ")"; + else + VersionName = "(*invalid*)"; + OS << left_justify(VersionName, 13); + } + VersymBuf += sizeof(Elf_Versym); + } + OS << '\n'; + } + OS << '\n'; +} + +static std::string versionFlagToString(unsigned Flags) { + if (Flags == 0) + return "none"; + + std::string Ret; + auto AddFlag = [&Ret, &Flags](unsigned Flag, StringRef Name) { + if (!(Flags & Flag)) + return; + if (!Ret.empty()) + Ret += " | "; + Ret += Name; + Flags &= ~Flag; + }; + + AddFlag(VER_FLG_BASE, "BASE"); + AddFlag(VER_FLG_WEAK, "WEAK"); + AddFlag(VER_FLG_INFO, "INFO"); + AddFlag(~0, "<unknown>"); + return Ret; +} + +template <class ELFT> +void GNUStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) { + if (!Sec) + return; + + unsigned VerDefsNum = Sec->sh_info; + printGNUVersionSectionProlog(OS, "Version definition", VerDefsNum, Obj, Sec); + + const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link)); + StringRef StringTable( + reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset), + (size_t)StrTabSec->sh_size); + + const uint8_t *VerdefBuf = unwrapOrError(Obj->getSectionContents(Sec)).data(); + const uint8_t *Begin = VerdefBuf; + + while (VerDefsNum--) { + const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); + OS << format(" 0x%04x: Rev: %u Flags: %s Index: %u Cnt: %u", + VerdefBuf - Begin, (unsigned)Verdef->vd_version, + versionFlagToString(Verdef->vd_flags).c_str(), + (unsigned)Verdef->vd_ndx, (unsigned)Verdef->vd_cnt); + + const uint8_t *VerdauxBuf = VerdefBuf + Verdef->vd_aux; + const Elf_Verdaux *Verdaux = + reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); + OS << format(" Name: %s\n", + StringTable.drop_front(Verdaux->vda_name).data()); + + for (unsigned I = 1; I < Verdef->vd_cnt; ++I) { + VerdauxBuf += Verdaux->vda_next; + Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); + OS << format(" 0x%04x: Parent %u: %s\n", VerdauxBuf - Begin, I, + StringTable.drop_front(Verdaux->vda_name).data()); + } + + VerdefBuf += Verdef->vd_next; + } + OS << '\n'; +} + +template <class ELFT> +void GNUStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) { + if (!Sec) + return; + + unsigned VerneedNum = Sec->sh_info; + printGNUVersionSectionProlog(OS, "Version needs", VerneedNum, Obj, Sec); + + ArrayRef<uint8_t> SecData = unwrapOrError(Obj->getSectionContents(Sec)); + + const Elf_Shdr *StrTabSec = unwrapOrError(Obj->getSection(Sec->sh_link)); + StringRef StringTable = { + reinterpret_cast<const char *>(Obj->base() + StrTabSec->sh_offset), + (size_t)StrTabSec->sh_size}; + + const uint8_t *VerneedBuf = SecData.data(); + for (unsigned I = 0; I < VerneedNum; ++I) { + const Elf_Verneed *Verneed = + reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + + OS << format(" 0x%04x: Version: %u File: %s Cnt: %u\n", + reinterpret_cast<const uint8_t *>(Verneed) - SecData.begin(), + (unsigned)Verneed->vn_version, + StringTable.drop_front(Verneed->vn_file).data(), + (unsigned)Verneed->vn_cnt); + + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { + const Elf_Vernaux *Vernaux = + reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + + OS << format(" 0x%04x: Name: %s Flags: %s Version: %u\n", + reinterpret_cast<const uint8_t *>(Vernaux) - SecData.begin(), + StringTable.drop_front(Vernaux->vna_name).data(), + versionFlagToString(Vernaux->vna_flags).c_str(), + (unsigned)Vernaux->vna_other); + VernauxBuf += Vernaux->vna_next; + } + VerneedBuf += Verneed->vn_next; + } + OS << '\n'; +} + // Hash histogram shows statistics of how efficient the hash was for the // dynamic symbol table. The table shows number of hash buckets for different // lengths of chains as absolute number and percentage of the total buckets. // Additionally cumulative coverage of symbols for each set of buckets. template <class ELFT> void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) { - - const Elf_Hash *HashTable = this->dumper()->getHashTable(); - const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable(); - // Print histogram for .hash section - if (HashTable) { + if (const Elf_Hash *HashTable = this->dumper()->getHashTable()) { size_t NBucket = HashTable->nbucket; size_t NChain = HashTable->nchain; ArrayRef<Elf_Word> Buckets = HashTable->buckets(); @@ -3535,7 +3772,7 @@ void GNUStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) { } // Print histogram for .gnu.hash section - if (GnuHashTable) { + if (const Elf_GnuHash *GnuHashTable = this->dumper()->getGnuHashTable()) { size_t NBucket = GnuHashTable->nbuckets; ArrayRef<Elf_Word> Buckets = GnuHashTable->buckets(); unsigned NumSyms = this->dumper()->dynamic_symbols().size(); @@ -3595,6 +3832,24 @@ void GNUStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { OS << "GNUStyle::printAddrsig not implemented\n"; } +static StringRef getGenericNoteTypeName(const uint32_t NT) { + static const struct { + uint32_t ID; + const char *Name; + } Notes[] = { + {ELF::NT_VERSION, "NT_VERSION (version)"}, + {ELF::NT_ARCH, "NT_ARCH (architecture)"}, + {ELF::NT_GNU_BUILD_ATTRIBUTE_OPEN, "OPEN"}, + {ELF::NT_GNU_BUILD_ATTRIBUTE_FUNC, "func"}, + }; + + for (const auto &Note : Notes) + if (Note.ID == NT) + return Note.Name; + + return ""; +} + static std::string getGNUNoteTypeName(const uint32_t NT) { static const struct { uint32_t ID; @@ -3649,14 +3904,11 @@ static std::string getAMDNoteTypeName(const uint32_t NT) { static const struct { uint32_t ID; const char *Name; - } Notes[] = { - {ELF::NT_AMD_AMDGPU_HSA_METADATA, - "NT_AMD_AMDGPU_HSA_METADATA (HSA Metadata)"}, - {ELF::NT_AMD_AMDGPU_ISA, - "NT_AMD_AMDGPU_ISA (ISA Version)"}, - {ELF::NT_AMD_AMDGPU_PAL_METADATA, - "NT_AMD_AMDGPU_PAL_METADATA (PAL Metadata)"} - }; + } Notes[] = {{ELF::NT_AMD_AMDGPU_HSA_METADATA, + "NT_AMD_AMDGPU_HSA_METADATA (HSA Metadata)"}, + {ELF::NT_AMD_AMDGPU_ISA, "NT_AMD_AMDGPU_ISA (ISA Version)"}, + {ELF::NT_AMD_AMDGPU_PAL_METADATA, + "NT_AMD_AMDGPU_PAL_METADATA (PAL Metadata)"}}; for (const auto &Note : Notes) if (Note.ID == NT) @@ -3683,6 +3935,16 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize, ArrayRef<uint8_t> Data) { std::string str; raw_string_ostream OS(str); + uint32_t PrData; + auto DumpBit = [&](uint32_t Flag, StringRef Name) { + if (PrData & Flag) { + PrData &= ~Flag; + OS << Name; + if (PrData) + OS << ", "; + } + }; + switch (Type) { default: OS << format("<application-specific type 0x%x>", Type); @@ -3701,41 +3963,101 @@ static std::string getGNUProperty(uint32_t Type, uint32_t DataSize, if (DataSize) OS << format(" <corrupt length: 0x%x>", DataSize); return OS.str(); + case GNU_PROPERTY_AARCH64_FEATURE_1_AND: case GNU_PROPERTY_X86_FEATURE_1_AND: - OS << "X86 features: "; - if (DataSize != 4 && DataSize != 8) { + OS << ((Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) ? "aarch64 feature: " + : "x86 feature: "); + if (DataSize != 4) { OS << format("<corrupt length: 0x%x>", DataSize); return OS.str(); } - uint64_t CFProtection = - (DataSize == 4) - ? support::endian::read32<ELFT::TargetEndianness>(Data.data()) - : support::endian::read64<ELFT::TargetEndianness>(Data.data()); - if (CFProtection == 0) { - OS << "none"; + PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data()); + if (PrData == 0) { + OS << "<None>"; return OS.str(); } - if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_IBT) { - OS << "IBT"; - CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_IBT; - if (CFProtection) - OS << ", "; + if (Type == GNU_PROPERTY_AARCH64_FEATURE_1_AND) { + DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_BTI, "BTI"); + DumpBit(GNU_PROPERTY_AARCH64_FEATURE_1_PAC, "PAC"); + } else { + DumpBit(GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT"); + DumpBit(GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK"); } - if (CFProtection & GNU_PROPERTY_X86_FEATURE_1_SHSTK) { - OS << "SHSTK"; - CFProtection &= ~GNU_PROPERTY_X86_FEATURE_1_SHSTK; - if (CFProtection) - OS << ", "; + if (PrData) + OS << format("<unknown flags: 0x%x>", PrData); + return OS.str(); + case GNU_PROPERTY_X86_ISA_1_NEEDED: + case GNU_PROPERTY_X86_ISA_1_USED: + OS << "x86 ISA " + << (Type == GNU_PROPERTY_X86_ISA_1_NEEDED ? "needed: " : "used: "); + if (DataSize != 4) { + OS << format("<corrupt length: 0x%x>", DataSize); + return OS.str(); } - if (CFProtection) - OS << format("<unknown flags: 0x%llx>", CFProtection); + PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data()); + if (PrData == 0) { + OS << "<None>"; + return OS.str(); + } + DumpBit(GNU_PROPERTY_X86_ISA_1_CMOV, "CMOV"); + DumpBit(GNU_PROPERTY_X86_ISA_1_SSE, "SSE"); + DumpBit(GNU_PROPERTY_X86_ISA_1_SSE2, "SSE2"); + DumpBit(GNU_PROPERTY_X86_ISA_1_SSE3, "SSE3"); + DumpBit(GNU_PROPERTY_X86_ISA_1_SSSE3, "SSSE3"); + DumpBit(GNU_PROPERTY_X86_ISA_1_SSE4_1, "SSE4_1"); + DumpBit(GNU_PROPERTY_X86_ISA_1_SSE4_2, "SSE4_2"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX, "AVX"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX2, "AVX2"); + DumpBit(GNU_PROPERTY_X86_ISA_1_FMA, "FMA"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512F, "AVX512F"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512CD, "AVX512CD"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512ER, "AVX512ER"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512PF, "AVX512PF"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512VL, "AVX512VL"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512DQ, "AVX512DQ"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512BW, "AVX512BW"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_4FMAPS, "AVX512_4FMAPS"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_4VNNIW, "AVX512_4VNNIW"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_BITALG, "AVX512_BITALG"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_IFMA, "AVX512_IFMA"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VBMI, "AVX512_VBMI"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VBMI2, "AVX512_VBMI2"); + DumpBit(GNU_PROPERTY_X86_ISA_1_AVX512_VNNI, "AVX512_VNNI"); + if (PrData) + OS << format("<unknown flags: 0x%x>", PrData); + return OS.str(); + break; + case GNU_PROPERTY_X86_FEATURE_2_NEEDED: + case GNU_PROPERTY_X86_FEATURE_2_USED: + OS << "x86 feature " + << (Type == GNU_PROPERTY_X86_FEATURE_2_NEEDED ? "needed: " : "used: "); + if (DataSize != 4) { + OS << format("<corrupt length: 0x%x>", DataSize); + return OS.str(); + } + PrData = support::endian::read32<ELFT::TargetEndianness>(Data.data()); + if (PrData == 0) { + OS << "<None>"; + return OS.str(); + } + DumpBit(GNU_PROPERTY_X86_FEATURE_2_X86, "x86"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_X87, "x87"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_MMX, "MMX"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_XMM, "XMM"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_YMM, "YMM"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_ZMM, "ZMM"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_FXSR, "FXSR"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVE, "XSAVE"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVEOPT, "XSAVEOPT"); + DumpBit(GNU_PROPERTY_X86_FEATURE_2_XSAVEC, "XSAVEC"); + if (PrData) + OS << format("<unknown flags: 0x%x>", PrData); return OS.str(); } } template <typename ELFT> -static SmallVector<std::string, 4> -getGNUPropertyList(ArrayRef<uint8_t> Arr) { +static SmallVector<std::string, 4> getGNUPropertyList(ArrayRef<uint8_t> Arr) { using Elf_Word = typename ELFT::Word; SmallVector<std::string, 4> Properties; @@ -3770,12 +4092,11 @@ struct GNUAbiTag { bool IsValid; }; -template <typename ELFT> -static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) { +template <typename ELFT> static GNUAbiTag getGNUAbiTag(ArrayRef<uint8_t> Desc) { typedef typename ELFT::Word Elf_Word; - ArrayRef<Elf_Word> Words(reinterpret_cast<const Elf_Word*>(Desc.begin()), - reinterpret_cast<const Elf_Word*>(Desc.end())); + ArrayRef<Elf_Word> Words(reinterpret_cast<const Elf_Word *>(Desc.begin()), + reinterpret_cast<const Elf_Word *>(Desc.end())); if (Words.size() < 4) return {"", "", /*IsValid=*/false}; @@ -3846,24 +4167,13 @@ static AMDNote getAMDNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) { default: return {"", ""}; case ELF::NT_AMD_AMDGPU_HSA_METADATA: - return {"HSA Metadata", - std::string(reinterpret_cast<const char *>(Desc.data()), - Desc.size())}; + return { + "HSA Metadata", + std::string(reinterpret_cast<const char *>(Desc.data()), Desc.size())}; case ELF::NT_AMD_AMDGPU_ISA: - return {"ISA Version", - std::string(reinterpret_cast<const char *>(Desc.data()), - Desc.size())}; - case ELF::NT_AMD_AMDGPU_PAL_METADATA: - const uint32_t *PALMetadataBegin = - reinterpret_cast<const uint32_t *>(Desc.data()); - const uint32_t *PALMetadataEnd = PALMetadataBegin + Desc.size(); - std::vector<uint32_t> PALMetadata(PALMetadataBegin, PALMetadataEnd); - std::string PALMetadataString; - auto Error = AMDGPU::PALMD::toString(PALMetadata, PALMetadataString); - if (Error) { - return {"PAL Metadata", "Invalid"}; - } - return {"PAL Metadata", PALMetadataString}; + return { + "ISA Version", + std::string(reinterpret_cast<const char *>(Desc.data()), Desc.size())}; } } @@ -3877,36 +4187,28 @@ static AMDGPUNote getAMDGPUNote(uint32_t NoteType, ArrayRef<uint8_t> Desc) { switch (NoteType) { default: return {"", ""}; - case ELF::NT_AMDGPU_METADATA: + case ELF::NT_AMDGPU_METADATA: { auto MsgPackString = StringRef(reinterpret_cast<const char *>(Desc.data()), Desc.size()); - msgpack::Reader MsgPackReader(MsgPackString); - auto OptMsgPackNodeOrErr = msgpack::Node::read(MsgPackReader); - if (errorToBool(OptMsgPackNodeOrErr.takeError())) - return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"}; - auto &OptMsgPackNode = *OptMsgPackNodeOrErr; - if (!OptMsgPackNode) + msgpack::Document MsgPackDoc; + if (!MsgPackDoc.readFromBlob(MsgPackString, /*Multi=*/false)) return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"}; - auto &MsgPackNode = *OptMsgPackNode; AMDGPU::HSAMD::V3::MetadataVerifier Verifier(true); - if (!Verifier.verify(*MsgPackNode)) + if (!Verifier.verify(MsgPackDoc.getRoot())) return {"AMDGPU Metadata", "Invalid AMDGPU Metadata"}; std::string HSAMetadataString; raw_string_ostream StrOS(HSAMetadataString); - yaml::Output YOut(StrOS); - YOut << MsgPackNode; + MsgPackDoc.toYAML(StrOS); return {"AMDGPU Metadata", StrOS.str()}; } + } } template <class ELFT> void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { - const Elf_Ehdr *e = Obj->getHeader(); - bool IsCore = e->e_type == ELF::ET_CORE; - auto PrintHeader = [&](const typename ELFT::Off Offset, const typename ELFT::Addr Size) { OS << "Displaying notes found at file offset " << format_hex(Offset, 10) @@ -3938,12 +4240,16 @@ void GNUStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { if (!N.Type.empty()) OS << " " << N.Type << ":\n " << N.Value << '\n'; } else { - OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; + StringRef NoteType = getGenericNoteTypeName(Type); + if (!NoteType.empty()) + OS << NoteType; + else + OS << "Unknown note type: (" << format_hex(Type, 10) << ')'; } OS << '\n'; }; - if (IsCore) { + if (Obj->getHeader()->e_type == ELF::ET_CORE) { for (const auto &P : unwrapOrError(Obj->program_headers())) { if (P.p_type != PT_NOTE) continue; @@ -3992,7 +4298,10 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { << format_hex_no_prefix(Parser.getGp(), 8 + Bias) << "\n\n"; OS << " Reserved entries:\n"; - OS << " Address Access Initial Purpose\n"; + if (ELFT::Is64Bits) + OS << " Address Access Initial Purpose\n"; + else + OS << " Address Access Initial Purpose\n"; PrintEntry(Parser.getGotLazyResolver(), "Lazy resolver"); if (Parser.getGotModulePointer()) PrintEntry(Parser.getGotModulePointer(), "Module pointer (GNU extension)"); @@ -4000,7 +4309,10 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { if (!Parser.getLocalEntries().empty()) { OS << "\n"; OS << " Local entries:\n"; - OS << " Address Access Initial\n"; + if (ELFT::Is64Bits) + OS << " Address Access Initial\n"; + else + OS << " Address Access Initial\n"; for (auto &E : Parser.getLocalEntries()) PrintEntry(&E, ""); } @@ -4011,7 +4323,11 @@ void GNUStyle<ELFT>::printMipsGOT(const MipsGOTParser<ELFT> &Parser) { if (!Parser.getGlobalEntries().empty()) { OS << "\n"; OS << " Global entries:\n"; - OS << " Address Access Initial Sym.Val. Type Ndx Name\n"; + if (ELFT::Is64Bits) + OS << " Address Access Initial Sym.Val." + << " Type Ndx Name\n"; + else + OS << " Address Access Initial Sym.Val. Type Ndx Name\n"; for (auto &E : Parser.getGlobalEntries()) { const Elf_Sym *Sym = Parser.getGotSym(&E); std::string SymName = this->dumper()->getFullSymbolName( @@ -4045,7 +4361,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { size_t Bias = ELFT::Is64Bits ? 8 : 0; auto PrintEntry = [&](const Elf_Addr *E, StringRef Purpose) { OS.PadToColumn(2); - OS << format_hex_no_prefix(Parser.getGotAddress(E), 8 + Bias); + OS << format_hex_no_prefix(Parser.getPltAddress(E), 8 + Bias); OS.PadToColumn(11 + Bias); OS << format_hex_no_prefix(*E, 8 + Bias); OS.PadToColumn(20 + 2 * Bias); @@ -4058,7 +4374,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { OS << " Address Initial Purpose\n"; PrintEntry(Parser.getPltLazyResolver(), "PLT lazy resolver"); if (Parser.getPltModulePointer()) - PrintEntry(Parser.getGotModulePointer(), "Module pointer"); + PrintEntry(Parser.getPltModulePointer(), "Module pointer"); if (!Parser.getPltEntries().empty()) { OS << "\n"; @@ -4070,7 +4386,7 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { Sym, this->dumper()->getDynamicStringTable(), false); OS.PadToColumn(2); - OS << to_string(format_hex_no_prefix(Parser.getGotAddress(&E), 8 + Bias)); + OS << to_string(format_hex_no_prefix(Parser.getPltAddress(&E), 8 + Bias)); OS.PadToColumn(11 + Bias); OS << to_string(format_hex_no_prefix(E, 8 + Bias)); OS.PadToColumn(20 + 2 * Bias); @@ -4087,21 +4403,21 @@ void GNUStyle<ELFT>::printMipsPLT(const MipsGOTParser<ELFT> &Parser) { } template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { - const Elf_Ehdr *e = Obj->getHeader(); + const Elf_Ehdr *E = Obj->getHeader(); { DictScope D(W, "ElfHeader"); { DictScope D(W, "Ident"); - W.printBinary("Magic", makeArrayRef(e->e_ident).slice(ELF::EI_MAG0, 4)); - W.printEnum("Class", e->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass)); - W.printEnum("DataEncoding", e->e_ident[ELF::EI_DATA], + W.printBinary("Magic", makeArrayRef(E->e_ident).slice(ELF::EI_MAG0, 4)); + W.printEnum("Class", E->e_ident[ELF::EI_CLASS], makeArrayRef(ElfClass)); + W.printEnum("DataEncoding", E->e_ident[ELF::EI_DATA], makeArrayRef(ElfDataEncoding)); - W.printNumber("FileVersion", e->e_ident[ELF::EI_VERSION]); + W.printNumber("FileVersion", E->e_ident[ELF::EI_VERSION]); auto OSABI = makeArrayRef(ElfOSABI); - if (e->e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH && - e->e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) { - switch (e->e_machine) { + if (E->e_ident[ELF::EI_OSABI] >= ELF::ELFOSABI_FIRST_ARCH && + E->e_ident[ELF::EI_OSABI] <= ELF::ELFOSABI_LAST_ARCH) { + switch (E->e_machine) { case ELF::EM_AMDGPU: OSABI = makeArrayRef(AMDGPUElfOSABI); break; @@ -4113,34 +4429,35 @@ template <class ELFT> void LLVMStyle<ELFT>::printFileHeaders(const ELFO *Obj) { break; } } - W.printEnum("OS/ABI", e->e_ident[ELF::EI_OSABI], OSABI); - W.printNumber("ABIVersion", e->e_ident[ELF::EI_ABIVERSION]); - W.printBinary("Unused", makeArrayRef(e->e_ident).slice(ELF::EI_PAD)); + W.printEnum("OS/ABI", E->e_ident[ELF::EI_OSABI], OSABI); + W.printNumber("ABIVersion", E->e_ident[ELF::EI_ABIVERSION]); + W.printBinary("Unused", makeArrayRef(E->e_ident).slice(ELF::EI_PAD)); } - W.printEnum("Type", e->e_type, makeArrayRef(ElfObjectFileType)); - W.printEnum("Machine", e->e_machine, makeArrayRef(ElfMachineType)); - W.printNumber("Version", e->e_version); - W.printHex("Entry", e->e_entry); - W.printHex("ProgramHeaderOffset", e->e_phoff); - W.printHex("SectionHeaderOffset", e->e_shoff); - if (e->e_machine == EM_MIPS) - W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderMipsFlags), + W.printEnum("Type", E->e_type, makeArrayRef(ElfObjectFileType)); + W.printEnum("Machine", E->e_machine, makeArrayRef(ElfMachineType)); + W.printNumber("Version", E->e_version); + W.printHex("Entry", E->e_entry); + W.printHex("ProgramHeaderOffset", E->e_phoff); + W.printHex("SectionHeaderOffset", E->e_shoff); + if (E->e_machine == EM_MIPS) + W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderMipsFlags), unsigned(ELF::EF_MIPS_ARCH), unsigned(ELF::EF_MIPS_ABI), unsigned(ELF::EF_MIPS_MACH)); - else if (e->e_machine == EM_AMDGPU) - W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags), + else if (E->e_machine == EM_AMDGPU) + W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderAMDGPUFlags), unsigned(ELF::EF_AMDGPU_MACH)); - else if (e->e_machine == EM_RISCV) - W.printFlags("Flags", e->e_flags, makeArrayRef(ElfHeaderRISCVFlags)); + else if (E->e_machine == EM_RISCV) + W.printFlags("Flags", E->e_flags, makeArrayRef(ElfHeaderRISCVFlags)); else - W.printFlags("Flags", e->e_flags); - W.printNumber("HeaderSize", e->e_ehsize); - W.printNumber("ProgramHeaderEntrySize", e->e_phentsize); - W.printNumber("ProgramHeaderCount", e->e_phnum); - W.printNumber("SectionHeaderEntrySize", e->e_shentsize); + W.printFlags("Flags", E->e_flags); + W.printNumber("HeaderSize", E->e_ehsize); + W.printNumber("ProgramHeaderEntrySize", E->e_phentsize); + W.printNumber("ProgramHeaderCount", E->e_phnum); + W.printNumber("SectionHeaderEntrySize", E->e_shentsize); W.printString("SectionHeaderCount", getSectionHeadersNumString(Obj)); - W.printString("StringTableSectionIndex", getSectionHeaderTableIndexString(Obj)); + W.printString("StringTableSectionIndex", + getSectionHeaderTableIndexString(Obj)); } } @@ -4185,10 +4502,8 @@ template <class ELFT> void LLVMStyle<ELFT>::printRelocations(const ELFO *Obj) { for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { ++SectionNumber; - if (Sec.sh_type != ELF::SHT_REL && - Sec.sh_type != ELF::SHT_RELA && - Sec.sh_type != ELF::SHT_RELR && - Sec.sh_type != ELF::SHT_ANDROID_REL && + if (Sec.sh_type != ELF::SHT_REL && Sec.sh_type != ELF::SHT_RELA && + Sec.sh_type != ELF::SHT_RELR && Sec.sh_type != ELF::SHT_ANDROID_REL && Sec.sh_type != ELF::SHT_ANDROID_RELA && Sec.sh_type != ELF::SHT_ANDROID_RELR) continue; @@ -4249,7 +4564,7 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel, const Elf_Shdr *SymTab) { SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); - StringRef TargetName; + std::string TargetName; const Elf_Sym *Sym = unwrapOrError(Obj->getRelocationSymbol(&Rel, SymTab)); if (Sym && Sym->getType() == ELF::STT_SECTION) { const Elf_Shdr *Sec = unwrapOrError( @@ -4257,7 +4572,8 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel, TargetName = unwrapOrError(Obj->getSectionName(Sec)); } else if (Sym) { StringRef StrTable = unwrapOrError(Obj->getStringTableForSymtab(*SymTab)); - TargetName = unwrapOrError(Sym->getName(StrTable)); + TargetName = this->dumper()->getFullSymbolName( + Sym, StrTable, SymTab->sh_type == SHT_DYNSYM /* IsDynamic */); } if (opts::ExpandRelocs) { @@ -4270,8 +4586,8 @@ void LLVMStyle<ELFT>::printRelocation(const ELFO *Obj, Elf_Rela Rel, } else { raw_ostream &OS = W.startLine(); OS << W.hex(Rel.r_offset) << " " << RelocName << " " - << (!TargetName.empty() ? TargetName : "-") << " " - << W.hex(Rel.r_addend) << "\n"; + << (!TargetName.empty() ? TargetName : "-") << " " << W.hex(Rel.r_addend) + << "\n"; } } @@ -4280,13 +4596,12 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { ListScope SectionsD(W, "Sections"); int SectionIndex = -1; - for (const Elf_Shdr &Sec : unwrapOrError(Obj->sections())) { - ++SectionIndex; - - StringRef Name = unwrapOrError(Obj->getSectionName(&Sec)); - + ArrayRef<Elf_Shdr> Sections = unwrapOrError(Obj->sections()); + const ELFObjectFile<ELFT> *ElfObj = this->dumper()->getElfObject(); + for (const Elf_Shdr &Sec : Sections) { + StringRef Name = getSectionName(Sec, *ElfObj, Sections); DictScope SectionD(W, "Section"); - W.printNumber("Index", SectionIndex); + W.printNumber("Index", ++SectionIndex); W.printNumber("Name", Name, Sec.sh_name); W.printHex( "Type", @@ -4350,8 +4665,9 @@ void LLVMStyle<ELFT>::printSectionHeaders(const ELFO *Obj) { if (opts::SectionData && Sec.sh_type != ELF::SHT_NOBITS) { ArrayRef<uint8_t> Data = unwrapOrError(Obj->getSectionContents(&Sec)); - W.printBinaryBlock("SectionData", - StringRef((const char *)Data.data(), Data.size())); + W.printBinaryBlock( + "SectionData", + StringRef(reinterpret_cast<const char *>(Data.data()), Data.size())); } } } @@ -4402,6 +4718,15 @@ void LLVMStyle<ELFT>::printSymbol(const ELFO *Obj, const Elf_Sym *Symbol, W.printHex("Section", SectionName, SectionIndex); } +template <class ELFT> +void LLVMStyle<ELFT>::printSymbols(const ELFO *Obj, bool PrintSymbols, + bool PrintDynamicSymbols) { + if (PrintSymbols) + printSymbols(Obj); + if (PrintDynamicSymbols) + printDynamicSymbols(Obj); +} + template <class ELFT> void LLVMStyle<ELFT>::printSymbols(const ELFO *Obj) { ListScope Group(W, "Symbols"); this->dumper()->printSymbolsHelper(false); @@ -4413,6 +4738,31 @@ void LLVMStyle<ELFT>::printDynamicSymbols(const ELFO *Obj) { this->dumper()->printSymbolsHelper(true); } +template <class ELFT> void LLVMStyle<ELFT>::printDynamic(const ELFFile<ELFT> *Obj) { + Elf_Dyn_Range Table = this->dumper()->dynamic_table(); + if (Table.empty()) + return; + + raw_ostream &OS = W.getOStream(); + W.startLine() << "DynamicSection [ (" << Table.size() << " entries)\n"; + + bool Is64 = ELFT::Is64Bits; + if (Is64) + W.startLine() << " Tag Type Name/Value\n"; + else + W.startLine() << " Tag Type Name/Value\n"; + for (auto Entry : Table) { + uintX_t Tag = Entry.getTag(); + W.startLine() << " " << format_hex(Tag, Is64 ? 18 : 10, true) << " " + << format("%-21s", + getTypeString(Obj->getHeader()->e_machine, Tag)); + this->dumper()->printDynamicEntry(OS, Tag, Entry.getVal()); + OS << "\n"; + } + + W.startLine() << "]\n"; +} + template <class ELFT> void LLVMStyle<ELFT>::printDynamicRelocations(const ELFO *Obj) { const DynRegionInfo &DynRelRegion = this->dumper()->getDynRelRegion(); @@ -4459,11 +4809,11 @@ template <class ELFT> void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) { SmallString<32> RelocName; Obj->getRelocationTypeName(Rel.getType(Obj->isMips64EL()), RelocName); - StringRef SymbolName; + std::string SymbolName; uint32_t SymIndex = Rel.getSymbol(Obj->isMips64EL()); const Elf_Sym *Sym = this->dumper()->dynamic_symbols().begin() + SymIndex; - SymbolName = - unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable())); + SymbolName = maybeDemangle( + unwrapOrError(Sym->getName(this->dumper()->getDynamicStringTable()))); if (opts::ExpandRelocs) { DictScope Group(W, "Relocation"); W.printHex("Offset", Rel.r_offset); @@ -4473,12 +4823,22 @@ void LLVMStyle<ELFT>::printDynamicRelocation(const ELFO *Obj, Elf_Rela Rel) { } else { raw_ostream &OS = W.startLine(); OS << W.hex(Rel.r_offset) << " " << RelocName << " " - << (!SymbolName.empty() ? SymbolName : "-") << " " - << W.hex(Rel.r_addend) << "\n"; + << (!SymbolName.empty() ? SymbolName : "-") << " " << W.hex(Rel.r_addend) + << "\n"; } } template <class ELFT> +void LLVMStyle<ELFT>::printProgramHeaders( + const ELFO *Obj, bool PrintProgramHeaders, + cl::boolOrDefault PrintSectionMapping) { + if (PrintProgramHeaders) + printProgramHeaders(Obj); + if (PrintSectionMapping == cl::BOU_TRUE) + printSectionMapping(Obj); +} + +template <class ELFT> void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { ListScope L(W, "ProgramHeaders"); @@ -4498,6 +4858,125 @@ void LLVMStyle<ELFT>::printProgramHeaders(const ELFO *Obj) { } template <class ELFT> +void LLVMStyle<ELFT>::printVersionSymbolSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) { + DictScope SS(W, "Version symbols"); + if (!Sec) + return; + + StringRef SecName = unwrapOrError(Obj->getSectionName(Sec)); + W.printNumber("Section Name", SecName, Sec->sh_name); + W.printHex("Address", Sec->sh_addr); + W.printHex("Offset", Sec->sh_offset); + W.printNumber("Link", Sec->sh_link); + + const uint8_t *VersymBuf = + reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); + const ELFDumper<ELFT> *Dumper = this->dumper(); + StringRef StrTable = Dumper->getDynamicStringTable(); + + // Same number of entries in the dynamic symbol table (DT_SYMTAB). + ListScope Syms(W, "Symbols"); + for (const Elf_Sym &Sym : Dumper->dynamic_symbols()) { + DictScope S(W, "Symbol"); + const Elf_Versym *Versym = reinterpret_cast<const Elf_Versym *>(VersymBuf); + std::string FullSymbolName = + Dumper->getFullSymbolName(&Sym, StrTable, true /* IsDynamic */); + W.printNumber("Version", Versym->vs_index & VERSYM_VERSION); + W.printString("Name", FullSymbolName); + VersymBuf += sizeof(Elf_Versym); + } +} + +template <class ELFT> +void LLVMStyle<ELFT>::printVersionDefinitionSection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) { + DictScope SD(W, "SHT_GNU_verdef"); + if (!Sec) + return; + + const uint8_t *SecStartAddress = + reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); + const uint8_t *SecEndAddress = SecStartAddress + Sec->sh_size; + const uint8_t *VerdefBuf = SecStartAddress; + const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + + unsigned VerDefsNum = Sec->sh_info; + while (VerDefsNum--) { + if (VerdefBuf + sizeof(Elf_Verdef) > SecEndAddress) + // FIXME: report_fatal_error is not a good way to report error. We should + // emit a parsing error here and below. + report_fatal_error("invalid offset in the section"); + + const Elf_Verdef *Verdef = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); + DictScope Def(W, "Definition"); + W.printNumber("Version", Verdef->vd_version); + W.printEnum("Flags", Verdef->vd_flags, makeArrayRef(SymVersionFlags)); + W.printNumber("Index", Verdef->vd_ndx); + W.printNumber("Hash", Verdef->vd_hash); + W.printString("Name", StringRef(reinterpret_cast<const char *>( + Obj->base() + StrTab->sh_offset + + Verdef->getAux()->vda_name))); + if (!Verdef->vd_cnt) + report_fatal_error("at least one definition string must exist"); + if (Verdef->vd_cnt > 2) + report_fatal_error("more than one predecessor is not expected"); + + if (Verdef->vd_cnt == 2) { + const uint8_t *VerdauxBuf = + VerdefBuf + Verdef->vd_aux + Verdef->getAux()->vda_next; + const Elf_Verdaux *Verdaux = + reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); + W.printString("Predecessor", + StringRef(reinterpret_cast<const char *>( + Obj->base() + StrTab->sh_offset + Verdaux->vda_name))); + } + VerdefBuf += Verdef->vd_next; + } +} + +template <class ELFT> +void LLVMStyle<ELFT>::printVersionDependencySection(const ELFFile<ELFT> *Obj, + const Elf_Shdr *Sec) { + DictScope SD(W, "SHT_GNU_verneed"); + if (!Sec) + return; + + const uint8_t *SecData = + reinterpret_cast<const uint8_t *>(Obj->base() + Sec->sh_offset); + const Elf_Shdr *StrTab = unwrapOrError(Obj->getSection(Sec->sh_link)); + + const uint8_t *VerneedBuf = SecData; + unsigned VerneedNum = Sec->sh_info; + for (unsigned I = 0; I < VerneedNum; ++I) { + const Elf_Verneed *Verneed = + reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + DictScope Entry(W, "Dependency"); + W.printNumber("Version", Verneed->vn_version); + W.printNumber("Count", Verneed->vn_cnt); + W.printString("FileName", + StringRef(reinterpret_cast<const char *>( + Obj->base() + StrTab->sh_offset + Verneed->vn_file))); + + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + ListScope L(W, "Entries"); + for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { + const Elf_Vernaux *Vernaux = + reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + DictScope Entry(W, "Entry"); + W.printNumber("Hash", Vernaux->vna_hash); + W.printEnum("Flags", Vernaux->vna_flags, makeArrayRef(SymVersionFlags)); + W.printNumber("Index", Vernaux->vna_other); + W.printString("Name", + StringRef(reinterpret_cast<const char *>( + Obj->base() + StrTab->sh_offset + Vernaux->vna_name))); + VernauxBuf += Vernaux->vna_next; + } + VerneedBuf += Verneed->vn_next; + } +} + +template <class ELFT> void LLVMStyle<ELFT>::printHashHistogram(const ELFFile<ELFT> *Obj) { W.startLine() << "Hash Histogram not implemented!\n"; } @@ -4542,8 +5021,7 @@ void LLVMStyle<ELFT>::printAddrsig(const ELFFile<ELFT> *Obj) { } template <typename ELFT> -static void printGNUNoteLLVMStyle(uint32_t NoteType, - ArrayRef<uint8_t> Desc, +static void printGNUNoteLLVMStyle(uint32_t NoteType, ArrayRef<uint8_t> Desc, ScopedPrinter &W) { switch (NoteType) { default: @@ -4576,8 +5054,6 @@ static void printGNUNoteLLVMStyle(uint32_t NoteType, template <class ELFT> void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { ListScope L(W, "Notes"); - const Elf_Ehdr *e = Obj->getHeader(); - bool IsCore = e->e_type == ELF::ET_CORE; auto PrintHeader = [&](const typename ELFT::Off Offset, const typename ELFT::Addr Size) { @@ -4609,11 +5085,16 @@ void LLVMStyle<ELFT>::printNotes(const ELFFile<ELFT> *Obj) { if (!N.Type.empty()) W.printString(N.Type, N.Value); } else { - W.getOStream() << "Unknown note type: (" << format_hex(Type, 10) << ')'; + StringRef NoteType = getGenericNoteTypeName(Type); + if (!NoteType.empty()) + W.printString("Type", NoteType); + else + W.printString("Type", + "Unknown (" + to_string(format_hex(Type, 10)) + ")"); } }; - if (IsCore) { + if (Obj->getHeader()->e_type == ELF::ET_CORE) { for (const auto &P : unwrapOrError(Obj->program_headers())) { if (P.p_type != PT_NOTE) continue; |