| //===- ELFDumper.cpp - ELF-specific dumper --------------------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| /// |
| /// \file |
| /// This file implements the ELF-specific dumper for llvm-readobj. |
| /// |
| //===----------------------------------------------------------------------===// |
| |
| #include "ARMEHABIPrinter.h" |
| #include "DwarfCFIEHPrinter.h" |
| #include "ObjDumper.h" |
| #include "StackMapPrinter.h" |
| #include "llvm-readobj.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/BitVector.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/DenseSet.h" |
| #include "llvm/ADT/MapVector.h" |
| #include "llvm/ADT/PointerIntPair.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/SmallString.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringExtras.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/ADT/Twine.h" |
| #include "llvm/BinaryFormat/AMDGPUMetadataVerifier.h" |
| #include "llvm/BinaryFormat/ELF.h" |
| #include "llvm/BinaryFormat/MsgPackDocument.h" |
| #include "llvm/Demangle/Demangle.h" |
| #include "llvm/Object/Archive.h" |
| #include "llvm/Object/ELF.h" |
| #include "llvm/Object/ELFObjectFile.h" |
| #include "llvm/Object/ELFTypes.h" |
| #include "llvm/Object/Error.h" |
| #include "llvm/Object/ObjectFile.h" |
| #include "llvm/Object/RelocationResolver.h" |
| #include "llvm/Object/StackMapParser.h" |
| #include "llvm/Support/AMDGPUMetadata.h" |
| #include "llvm/Support/ARMAttributeParser.h" |
| #include "llvm/Support/ARMBuildAttributes.h" |
| #include "llvm/Support/Casting.h" |
| #include "llvm/Support/Compiler.h" |
| #include "llvm/Support/Endian.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/Format.h" |
| #include "llvm/Support/FormatVariadic.h" |
| #include "llvm/Support/FormattedStream.h" |
| #include "llvm/Support/LEB128.h" |
| #include "llvm/Support/MSP430AttributeParser.h" |
| #include "llvm/Support/MSP430Attributes.h" |
| #include "llvm/Support/MathExtras.h" |
| #include "llvm/Support/MipsABIFlags.h" |
| #include "llvm/Support/RISCVAttributeParser.h" |
| #include "llvm/Support/RISCVAttributes.h" |
| #include "llvm/Support/ScopedPrinter.h" |
| #include "llvm/Support/raw_ostream.h" |
| #include <algorithm> |
| #include <cinttypes> |
| #include <cstddef> |
| #include <cstdint> |
| #include <cstdlib> |
| #include <iterator> |
| #include <memory> |
| #include <optional> |
| #include <string> |
| #include <system_error> |
| #include <vector> |
| |
| using namespace llvm; |
| using namespace llvm::object; |
| using namespace ELF; |
| |
| #define LLVM_READOBJ_ENUM_CASE(ns, enum) \ |
| case ns::enum: \ |
| return #enum; |
| |
| #define ENUM_ENT(enum, altName) \ |
| { #enum, altName, ELF::enum } |
| |
| #define ENUM_ENT_1(enum) \ |
| { #enum, #enum, ELF::enum } |
| |
| namespace { |
| |
| template <class ELFT> struct RelSymbol { |
| RelSymbol(const typename ELFT::Sym *S, StringRef N) |
| : Sym(S), Name(N.str()) {} |
| const typename ELFT::Sym *Sym; |
| std::string Name; |
| }; |
| |
| /// Represents a contiguous uniform range in the file. We cannot just create a |
| /// range directly because when creating one of these from the .dynamic table |
| /// the size, entity size and virtual address are different entries in arbitrary |
| /// order (DT_REL, DT_RELSZ, DT_RELENT for example). |
| struct DynRegionInfo { |
| DynRegionInfo(const Binary &Owner, const ObjDumper &D) |
| : Obj(&Owner), Dumper(&D) {} |
| DynRegionInfo(const Binary &Owner, const ObjDumper &D, const uint8_t *A, |
| uint64_t S, uint64_t ES) |
| : Addr(A), Size(S), EntSize(ES), Obj(&Owner), Dumper(&D) {} |
| |
| /// Address in current address space. |
| const uint8_t *Addr = nullptr; |
| /// Size in bytes of the region. |
| uint64_t Size = 0; |
| /// Size of each entity in the region. |
| uint64_t EntSize = 0; |
| |
| /// Owner object. Used for error reporting. |
| const Binary *Obj; |
| /// Dumper used for error reporting. |
| const ObjDumper *Dumper; |
| /// Error prefix. Used for error reporting to provide more information. |
| std::string Context; |
| /// Region size name. Used for error reporting. |
| StringRef SizePrintName = "size"; |
| /// Entry size name. Used for error reporting. If this field is empty, errors |
| /// will not mention the entry size. |
| StringRef EntSizePrintName = "entry size"; |
| |
| template <typename Type> ArrayRef<Type> getAsArrayRef() const { |
| const Type *Start = reinterpret_cast<const Type *>(Addr); |
| if (!Start) |
| return {Start, Start}; |
| |
| const uint64_t Offset = |
| Addr - (const uint8_t *)Obj->getMemoryBufferRef().getBufferStart(); |
| const uint64_t ObjSize = Obj->getMemoryBufferRef().getBufferSize(); |
| |
| if (Size > ObjSize - Offset) { |
| Dumper->reportUniqueWarning( |
| "unable to read data at 0x" + Twine::utohexstr(Offset) + |
| " of size 0x" + Twine::utohexstr(Size) + " (" + SizePrintName + |
| "): it goes past the end of the file of size 0x" + |
| Twine::utohexstr(ObjSize)); |
| return {Start, Start}; |
| } |
| |
| if (EntSize == sizeof(Type) && (Size % EntSize == 0)) |
| return {Start, Start + (Size / EntSize)}; |
| |
| std::string Msg; |
| if (!Context.empty()) |
| Msg += Context + " has "; |
| |
| Msg += ("invalid " + SizePrintName + " (0x" + Twine::utohexstr(Size) + ")") |
| .str(); |
| if (!EntSizePrintName.empty()) |
| Msg += |
| (" or " + EntSizePrintName + " (0x" + Twine::utohexstr(EntSize) + ")") |
| .str(); |
| |
| Dumper->reportUniqueWarning(Msg); |
| return {Start, Start}; |
| } |
| }; |
| |
| struct GroupMember { |
| StringRef Name; |
| uint64_t Index; |
| }; |
| |
| struct GroupSection { |
| StringRef Name; |
| std::string Signature; |
| uint64_t ShName; |
| uint64_t Index; |
| uint32_t Link; |
| uint32_t Info; |
| uint32_t Type; |
| std::vector<GroupMember> Members; |
| }; |
| |
| namespace { |
| |
| struct NoteType { |
| uint32_t ID; |
| StringRef Name; |
| }; |
| |
| } // namespace |
| |
| template <class ELFT> class Relocation { |
| public: |
| Relocation(const typename ELFT::Rel &R, bool IsMips64EL) |
| : Type(R.getType(IsMips64EL)), Symbol(R.getSymbol(IsMips64EL)), |
| Offset(R.r_offset), Info(R.r_info) {} |
| |
| Relocation(const typename ELFT::Rela &R, bool IsMips64EL) |
| : Relocation((const typename ELFT::Rel &)R, IsMips64EL) { |
| Addend = R.r_addend; |
| } |
| |
| uint32_t Type; |
| uint32_t Symbol; |
| typename ELFT::uint Offset; |
| typename ELFT::uint Info; |
| std::optional<int64_t> Addend; |
| }; |
| |
| template <class ELFT> class MipsGOTParser; |
| |
| template <typename ELFT> class ELFDumper : public ObjDumper { |
| LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
| |
| public: |
| ELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer); |
| |
| void printUnwindInfo() override; |
| void printNeededLibraries() override; |
| void printHashTable() override; |
| void printGnuHashTable() override; |
| void printLoadName() override; |
| void printVersionInfo() override; |
| void printArchSpecificInfo() override; |
| void printStackMap() const override; |
| void printMemtag() override; |
| ArrayRef<uint8_t> getMemtagGlobalsSectionContents(uint64_t ExpectedAddr); |
| |
| // Hash histogram shows statistics of how efficient the hash was for the |
| // dynamic symbol table. The table shows the number of hash buckets for |
| // different lengths of chains as an absolute number and percentage of the |
| // total buckets, and the cumulative coverage of symbols for each set of |
| // buckets. |
| void printHashHistograms() override; |
| |
| const object::ELFObjectFile<ELFT> &getElfObject() const { return ObjF; }; |
| |
| std::string describe(const Elf_Shdr &Sec) const; |
| |
| unsigned getHashTableEntSize() const { |
| // EM_S390 and ELF::EM_ALPHA platforms use 8-bytes entries in SHT_HASH |
| // sections. This violates the ELF specification. |
| if (Obj.getHeader().e_machine == ELF::EM_S390 || |
| Obj.getHeader().e_machine == ELF::EM_ALPHA) |
| return 8; |
| return 4; |
| } |
| |
| std::vector<EnumEntry<unsigned>> |
| getOtherFlagsFromSymbol(const Elf_Ehdr &Header, const Elf_Sym &Symbol) const; |
| |
| Elf_Dyn_Range dynamic_table() const { |
| // A valid .dynamic section contains an array of entries terminated |
| // with a DT_NULL entry. However, sometimes the section content may |
| // continue past the DT_NULL entry, so to dump the section correctly, |
| // we first find the end of the entries by iterating over them. |
| Elf_Dyn_Range Table = DynamicTable.template getAsArrayRef<Elf_Dyn>(); |
| |
| 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 { |
| if (!DynSymRegion) |
| return Elf_Sym_Range(); |
| return DynSymRegion->template getAsArrayRef<Elf_Sym>(); |
| } |
| |
| const Elf_Shdr *findSectionByName(StringRef Name) const; |
| |
| StringRef getDynamicStringTable() const { return DynamicStringTable; } |
| |
| protected: |
| virtual void printVersionSymbolSection(const Elf_Shdr *Sec) = 0; |
| virtual void printVersionDefinitionSection(const Elf_Shdr *Sec) = 0; |
| virtual void printVersionDependencySection(const Elf_Shdr *Sec) = 0; |
| |
| void |
| printDependentLibsHelper(function_ref<void(const Elf_Shdr &)> OnSectionStart, |
| function_ref<void(StringRef, uint64_t)> OnLibEntry); |
| |
| virtual void printRelRelaReloc(const Relocation<ELFT> &R, |
| const RelSymbol<ELFT> &RelSym) = 0; |
| virtual void printRelrReloc(const Elf_Relr &R) = 0; |
| virtual void printDynamicRelocHeader(unsigned Type, StringRef Name, |
| const DynRegionInfo &Reg) {} |
| void printReloc(const Relocation<ELFT> &R, unsigned RelIndex, |
| const Elf_Shdr &Sec, const Elf_Shdr *SymTab); |
| void printDynamicReloc(const Relocation<ELFT> &R); |
| void printDynamicRelocationsHelper(); |
| void printRelocationsHelper(const Elf_Shdr &Sec); |
| void forEachRelocationDo( |
| const Elf_Shdr &Sec, bool RawRelr, |
| llvm::function_ref<void(const Relocation<ELFT> &, unsigned, |
| const Elf_Shdr &, const Elf_Shdr *)> |
| RelRelaFn, |
| llvm::function_ref<void(const Elf_Relr &)> RelrFn); |
| |
| virtual void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, |
| bool NonVisibilityBitsUsed, |
| bool ExtraSymInfo) const {}; |
| virtual void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable, |
| std::optional<StringRef> StrTable, bool IsDynamic, |
| bool NonVisibilityBitsUsed, |
| bool ExtraSymInfo) const = 0; |
| |
| virtual void printMipsABIFlags() = 0; |
| virtual void printMipsGOT(const MipsGOTParser<ELFT> &Parser) = 0; |
| virtual void printMipsPLT(const MipsGOTParser<ELFT> &Parser) = 0; |
| |
| virtual void printMemtag( |
| const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, |
| const ArrayRef<uint8_t> AndroidNoteDesc, |
| const ArrayRef<std::pair<uint64_t, uint64_t>> Descriptors) = 0; |
| |
| virtual void printHashHistogram(const Elf_Hash &HashTable) const; |
| virtual void printGnuHashHistogram(const Elf_GnuHash &GnuHashTable) const; |
| virtual void printHashHistogramStats(size_t NBucket, size_t MaxChain, |
| size_t TotalSyms, ArrayRef<size_t> Count, |
| bool IsGnu) const = 0; |
| |
| Expected<ArrayRef<Elf_Versym>> |
| getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab, |
| StringRef *StrTab, const Elf_Shdr **SymTabSec) const; |
| StringRef getPrintableSectionName(const Elf_Shdr &Sec) const; |
| |
| std::vector<GroupSection> getGroups(); |
| |
| // Returns the function symbol index for the given address. Matches the |
| // symbol's section with FunctionSec when specified. |
| // Returns std::nullopt if no function symbol can be found for the address or |
| // in case it is not defined in the specified section. |
| SmallVector<uint32_t> getSymbolIndexesForFunctionAddress( |
| uint64_t SymValue, std::optional<const Elf_Shdr *> FunctionSec); |
| bool printFunctionStackSize(uint64_t SymValue, |
| std::optional<const Elf_Shdr *> FunctionSec, |
| const Elf_Shdr &StackSizeSec, DataExtractor Data, |
| uint64_t *Offset); |
| void printStackSize(const Relocation<ELFT> &R, const Elf_Shdr &RelocSec, |
| unsigned Ndx, const Elf_Shdr *SymTab, |
| const Elf_Shdr *FunctionSec, const Elf_Shdr &StackSizeSec, |
| const RelocationResolver &Resolver, DataExtractor Data); |
| virtual void printStackSizeEntry(uint64_t Size, |
| ArrayRef<std::string> FuncNames) = 0; |
| |
| void printRelocatableStackSizes(std::function<void()> PrintHeader); |
| void printNonRelocatableStackSizes(std::function<void()> PrintHeader); |
| |
| const object::ELFObjectFile<ELFT> &ObjF; |
| const ELFFile<ELFT> &Obj; |
| StringRef FileName; |
| |
| Expected<DynRegionInfo> createDRI(uint64_t Offset, uint64_t Size, |
| uint64_t EntSize) { |
| if (Offset + Size < Offset || Offset + Size > Obj.getBufSize()) |
| return createError("offset (0x" + Twine::utohexstr(Offset) + |
| ") + size (0x" + Twine::utohexstr(Size) + |
| ") is greater than the file size (0x" + |
| Twine::utohexstr(Obj.getBufSize()) + ")"); |
| return DynRegionInfo(ObjF, *this, Obj.base() + Offset, Size, EntSize); |
| } |
| |
| void printAttributes(unsigned, std::unique_ptr<ELFAttributeParser>, |
| support::endianness); |
| void printMipsReginfo(); |
| void printMipsOptions(); |
| |
| std::pair<const Elf_Phdr *, const Elf_Shdr *> findDynamic(); |
| void loadDynamicTable(); |
| void parseDynamicTable(); |
| |
| Expected<StringRef> getSymbolVersion(const Elf_Sym &Sym, |
| bool &IsDefault) const; |
| Expected<SmallVector<std::optional<VersionEntry>, 0> *> getVersionMap() const; |
| |
| DynRegionInfo DynRelRegion; |
| DynRegionInfo DynRelaRegion; |
| DynRegionInfo DynRelrRegion; |
| DynRegionInfo DynPLTRelRegion; |
| std::optional<DynRegionInfo> DynSymRegion; |
| DynRegionInfo DynSymTabShndxRegion; |
| DynRegionInfo DynamicTable; |
| StringRef DynamicStringTable; |
| const Elf_Hash *HashTable = nullptr; |
| const Elf_GnuHash *GnuHashTable = nullptr; |
| const Elf_Shdr *DotSymtabSec = nullptr; |
| const Elf_Shdr *DotDynsymSec = nullptr; |
| const Elf_Shdr *DotAddrsigSec = nullptr; |
| DenseMap<const Elf_Shdr *, ArrayRef<Elf_Word>> ShndxTables; |
| std::optional<uint64_t> SONameOffset; |
| std::optional<DenseMap<uint64_t, std::vector<uint32_t>>> AddressToIndexMap; |
| |
| const Elf_Shdr *SymbolVersionSection = nullptr; // .gnu.version |
| const Elf_Shdr *SymbolVersionNeedSection = nullptr; // .gnu.version_r |
| const Elf_Shdr *SymbolVersionDefSection = nullptr; // .gnu.version_d |
| |
| std::string getFullSymbolName(const Elf_Sym &Symbol, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable, |
| std::optional<StringRef> StrTable, |
| bool IsDynamic) const; |
| Expected<unsigned> |
| getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable) const; |
| Expected<StringRef> getSymbolSectionName(const Elf_Sym &Symbol, |
| unsigned SectionIndex) const; |
| std::string getStaticSymbolName(uint32_t Index) const; |
| StringRef getDynamicString(uint64_t Value) const; |
| |
| void printSymbolsHelper(bool IsDynamic, bool ExtraSymInfo) const; |
| std::string getDynamicEntry(uint64_t Type, uint64_t Value) const; |
| |
| Expected<RelSymbol<ELFT>> getRelocationTarget(const Relocation<ELFT> &R, |
| const Elf_Shdr *SymTab) const; |
| |
| ArrayRef<Elf_Word> getShndxTable(const Elf_Shdr *Symtab) const; |
| |
| private: |
| mutable SmallVector<std::optional<VersionEntry>, 0> VersionMap; |
| }; |
| |
| template <class ELFT> |
| std::string ELFDumper<ELFT>::describe(const Elf_Shdr &Sec) const { |
| return ::describe(Obj, Sec); |
| } |
| |
| namespace { |
| |
| template <class ELFT> struct SymtabLink { |
| typename ELFT::SymRange Symbols; |
| StringRef StringTable; |
| const typename ELFT::Shdr *SymTab; |
| }; |
| |
| // Returns the linked symbol table, symbols and associated string table for a |
| // given section. |
| template <class ELFT> |
| Expected<SymtabLink<ELFT>> getLinkAsSymtab(const ELFFile<ELFT> &Obj, |
| const typename ELFT::Shdr &Sec, |
| unsigned ExpectedType) { |
| Expected<const typename ELFT::Shdr *> SymtabOrErr = |
| Obj.getSection(Sec.sh_link); |
| if (!SymtabOrErr) |
| return createError("invalid section linked to " + describe(Obj, Sec) + |
| ": " + toString(SymtabOrErr.takeError())); |
| |
| if ((*SymtabOrErr)->sh_type != ExpectedType) |
| return createError( |
| "invalid section linked to " + describe(Obj, Sec) + ": expected " + |
| object::getELFSectionTypeName(Obj.getHeader().e_machine, ExpectedType) + |
| ", but got " + |
| object::getELFSectionTypeName(Obj.getHeader().e_machine, |
| (*SymtabOrErr)->sh_type)); |
| |
| Expected<StringRef> StrTabOrErr = Obj.getLinkAsStrtab(**SymtabOrErr); |
| if (!StrTabOrErr) |
| return createError( |
| "can't get a string table for the symbol table linked to " + |
| describe(Obj, Sec) + ": " + toString(StrTabOrErr.takeError())); |
| |
| Expected<typename ELFT::SymRange> SymsOrErr = Obj.symbols(*SymtabOrErr); |
| if (!SymsOrErr) |
| return createError("unable to read symbols from the " + describe(Obj, Sec) + |
| ": " + toString(SymsOrErr.takeError())); |
| |
| return SymtabLink<ELFT>{*SymsOrErr, *StrTabOrErr, *SymtabOrErr}; |
| } |
| |
| } // namespace |
| |
| template <class ELFT> |
| Expected<ArrayRef<typename ELFT::Versym>> |
| ELFDumper<ELFT>::getVersionTable(const Elf_Shdr &Sec, ArrayRef<Elf_Sym> *SymTab, |
| StringRef *StrTab, |
| const Elf_Shdr **SymTabSec) const { |
| assert((!SymTab && !StrTab && !SymTabSec) || (SymTab && StrTab && SymTabSec)); |
| if (reinterpret_cast<uintptr_t>(Obj.base() + Sec.sh_offset) % |
| sizeof(uint16_t) != |
| 0) |
| return createError("the " + describe(Sec) + " is misaligned"); |
| |
| Expected<ArrayRef<Elf_Versym>> VersionsOrErr = |
| Obj.template getSectionContentsAsArray<Elf_Versym>(Sec); |
| if (!VersionsOrErr) |
| return createError("cannot read content of " + describe(Sec) + ": " + |
| toString(VersionsOrErr.takeError())); |
| |
| Expected<SymtabLink<ELFT>> SymTabOrErr = |
| getLinkAsSymtab(Obj, Sec, SHT_DYNSYM); |
| if (!SymTabOrErr) { |
| reportUniqueWarning(SymTabOrErr.takeError()); |
| return *VersionsOrErr; |
| } |
| |
| if (SymTabOrErr->Symbols.size() != VersionsOrErr->size()) |
| reportUniqueWarning(describe(Sec) + ": the number of entries (" + |
| Twine(VersionsOrErr->size()) + |
| ") does not match the number of symbols (" + |
| Twine(SymTabOrErr->Symbols.size()) + |
| ") in the symbol table with index " + |
| Twine(Sec.sh_link)); |
| |
| if (SymTab) { |
| *SymTab = SymTabOrErr->Symbols; |
| *StrTab = SymTabOrErr->StringTable; |
| *SymTabSec = SymTabOrErr->SymTab; |
| } |
| return *VersionsOrErr; |
| } |
| |
| template <class ELFT> |
| void ELFDumper<ELFT>::printSymbolsHelper(bool IsDynamic, |
| bool ExtraSymInfo) const { |
| std::optional<StringRef> StrTable; |
| size_t Entries = 0; |
| Elf_Sym_Range Syms(nullptr, nullptr); |
| const Elf_Shdr *SymtabSec = IsDynamic ? DotDynsymSec : DotSymtabSec; |
| |
| if (IsDynamic) { |
| StrTable = DynamicStringTable; |
| Syms = dynamic_symbols(); |
| Entries = Syms.size(); |
| } else if (DotSymtabSec) { |
| if (Expected<StringRef> StrTableOrErr = |
| Obj.getStringTableForSymtab(*DotSymtabSec)) |
| StrTable = *StrTableOrErr; |
| else |
| reportUniqueWarning( |
| "unable to get the string table for the SHT_SYMTAB section: " + |
| toString(StrTableOrErr.takeError())); |
| |
| if (Expected<Elf_Sym_Range> SymsOrErr = Obj.symbols(DotSymtabSec)) |
| Syms = *SymsOrErr; |
| else |
| reportUniqueWarning( |
| "unable to read symbols from the SHT_SYMTAB section: " + |
| toString(SymsOrErr.takeError())); |
| Entries = DotSymtabSec->getEntityCount(); |
| } |
| if (Syms.empty()) |
| return; |
| |
| // The st_other field has 2 logical parts. The first two bits hold the symbol |
| // visibility (STV_*) and the remainder hold other platform-specific values. |
| bool NonVisibilityBitsUsed = |
| llvm::any_of(Syms, [](const Elf_Sym &S) { return S.st_other & ~0x3; }); |
| |
| DataRegion<Elf_Word> ShndxTable = |
| IsDynamic ? DataRegion<Elf_Word>( |
| (const Elf_Word *)this->DynSymTabShndxRegion.Addr, |
| this->getElfObject().getELFFile().end()) |
| : DataRegion<Elf_Word>(this->getShndxTable(SymtabSec)); |
| |
| printSymtabMessage(SymtabSec, Entries, NonVisibilityBitsUsed, ExtraSymInfo); |
| for (const Elf_Sym &Sym : Syms) |
| printSymbol(Sym, &Sym - Syms.begin(), ShndxTable, StrTable, IsDynamic, |
| NonVisibilityBitsUsed, ExtraSymInfo); |
| } |
| |
| template <typename ELFT> class GNUELFDumper : public ELFDumper<ELFT> { |
| formatted_raw_ostream &OS; |
| |
| public: |
| LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
| |
| GNUELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer) |
| : ELFDumper<ELFT>(ObjF, Writer), |
| OS(static_cast<formatted_raw_ostream &>(Writer.getOStream())) { |
| assert(&this->W.getOStream() == &llvm::fouts()); |
| } |
| |
| void printFileSummary(StringRef FileStr, ObjectFile &Obj, |
| ArrayRef<std::string> InputFilenames, |
| const Archive *A) override; |
| void printFileHeaders() override; |
| void printGroupSections() override; |
| void printRelocations() override; |
| void printSectionHeaders() override; |
| void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols, |
| bool ExtraSymInfo) override; |
| void printHashSymbols() override; |
| void printSectionDetails() override; |
| void printDependentLibs() override; |
| void printDynamicTable() override; |
| void printDynamicRelocations() override; |
| void printSymtabMessage(const Elf_Shdr *Symtab, size_t Offset, |
| bool NonVisibilityBitsUsed, |
| bool ExtraSymInfo) const override; |
| void printProgramHeaders(bool PrintProgramHeaders, |
| cl::boolOrDefault PrintSectionMapping) override; |
| void printVersionSymbolSection(const Elf_Shdr *Sec) override; |
| void printVersionDefinitionSection(const Elf_Shdr *Sec) override; |
| void printVersionDependencySection(const Elf_Shdr *Sec) override; |
| void printCGProfile() override; |
| void printBBAddrMaps() override; |
| void printAddrsig() override; |
| void printNotes() override; |
| void printELFLinkerOptions() override; |
| void printStackSizes() override; |
| void printMemtag( |
| const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, |
| const ArrayRef<uint8_t> AndroidNoteDesc, |
| const ArrayRef<std::pair<uint64_t, uint64_t>> Descriptors) override; |
| void printHashHistogramStats(size_t NBucket, size_t MaxChain, |
| size_t TotalSyms, ArrayRef<size_t> Count, |
| bool IsGnu) const override; |
| |
| private: |
| void printHashTableSymbols(const Elf_Hash &HashTable); |
| void printGnuHashTableSymbols(const Elf_GnuHash &GnuHashTable); |
| |
| struct Field { |
| std::string Str; |
| unsigned Column; |
| |
| Field(StringRef S, unsigned Col) : Str(std::string(S)), Column(Col) {} |
| Field(unsigned Col) : Column(Col) {} |
| }; |
| |
| template <typename T, typename TEnum> |
| std::string printFlags(T Value, ArrayRef<EnumEntry<TEnum>> EnumValues, |
| TEnum EnumMask1 = {}, TEnum EnumMask2 = {}, |
| TEnum EnumMask3 = {}) const { |
| std::string Str; |
| for (const EnumEntry<TEnum> &Flag : EnumValues) { |
| if (Flag.Value == 0) |
| continue; |
| |
| TEnum EnumMask{}; |
| if (Flag.Value & EnumMask1) |
| EnumMask = EnumMask1; |
| else if (Flag.Value & EnumMask2) |
| EnumMask = EnumMask2; |
| else if (Flag.Value & EnumMask3) |
| EnumMask = EnumMask3; |
| bool IsEnum = (Flag.Value & EnumMask) != 0; |
| if ((!IsEnum && (Value & Flag.Value) == Flag.Value) || |
| (IsEnum && (Value & EnumMask) == Flag.Value)) { |
| if (!Str.empty()) |
| Str += ", "; |
| Str += Flag.AltName; |
| } |
| } |
| return Str; |
| } |
| |
| formatted_raw_ostream &printField(struct Field F) const { |
| if (F.Column != 0) |
| OS.PadToColumn(F.Column); |
| OS << F.Str; |
| OS.flush(); |
| return OS; |
| } |
| void printHashedSymbol(const Elf_Sym *Sym, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable, StringRef StrTable, |
| uint32_t Bucket); |
| void printRelrReloc(const Elf_Relr &R) override; |
| void printRelRelaReloc(const Relocation<ELFT> &R, |
| const RelSymbol<ELFT> &RelSym) override; |
| void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable, |
| std::optional<StringRef> StrTable, bool IsDynamic, |
| bool NonVisibilityBitsUsed, |
| bool ExtraSymInfo) const override; |
| void printDynamicRelocHeader(unsigned Type, StringRef Name, |
| const DynRegionInfo &Reg) override; |
| |
| std::string getSymbolSectionNdx(const Elf_Sym &Symbol, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable, |
| bool ExtraSymInfo = false) const; |
| void printProgramHeaders() override; |
| void printSectionMapping() override; |
| void printGNUVersionSectionProlog(const typename ELFT::Shdr &Sec, |
| const Twine &Label, unsigned EntriesNum); |
| |
| void printStackSizeEntry(uint64_t Size, |
| ArrayRef<std::string> FuncNames) override; |
| |
| void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; |
| void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; |
| void printMipsABIFlags() override; |
| }; |
| |
| template <typename ELFT> class LLVMELFDumper : public ELFDumper<ELFT> { |
| public: |
| LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
| |
| LLVMELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer) |
| : ELFDumper<ELFT>(ObjF, Writer), W(Writer) {} |
| |
| void printFileHeaders() override; |
| void printGroupSections() override; |
| void printRelocations() override; |
| void printSectionHeaders() override; |
| void printSymbols(bool PrintSymbols, bool PrintDynamicSymbols, |
| bool ExtraSymInfo) override; |
| void printDependentLibs() override; |
| void printDynamicTable() override; |
| void printDynamicRelocations() override; |
| void printProgramHeaders(bool PrintProgramHeaders, |
| cl::boolOrDefault PrintSectionMapping) override; |
| void printVersionSymbolSection(const Elf_Shdr *Sec) override; |
| void printVersionDefinitionSection(const Elf_Shdr *Sec) override; |
| void printVersionDependencySection(const Elf_Shdr *Sec) override; |
| void printCGProfile() override; |
| void printBBAddrMaps() override; |
| void printAddrsig() override; |
| void printNotes() override; |
| void printELFLinkerOptions() override; |
| void printStackSizes() override; |
| void printMemtag( |
| const ArrayRef<std::pair<std::string, std::string>> DynamicEntries, |
| const ArrayRef<uint8_t> AndroidNoteDesc, |
| const ArrayRef<std::pair<uint64_t, uint64_t>> Descriptors) override; |
| void printSymbolSection(const Elf_Sym &Symbol, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable) const; |
| void printHashHistogramStats(size_t NBucket, size_t MaxChain, |
| size_t TotalSyms, ArrayRef<size_t> Count, |
| bool IsGnu) const override; |
| |
| private: |
| void printRelrReloc(const Elf_Relr &R) override; |
| void printRelRelaReloc(const Relocation<ELFT> &R, |
| const RelSymbol<ELFT> &RelSym) override; |
| |
| void printSymbol(const Elf_Sym &Symbol, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable, |
| std::optional<StringRef> StrTable, bool IsDynamic, |
| bool /*NonVisibilityBitsUsed*/, |
| bool /*ExtraSymInfo*/) const override; |
| void printProgramHeaders() override; |
| void printSectionMapping() override {} |
| void printStackSizeEntry(uint64_t Size, |
| ArrayRef<std::string> FuncNames) override; |
| |
| void printMipsGOT(const MipsGOTParser<ELFT> &Parser) override; |
| void printMipsPLT(const MipsGOTParser<ELFT> &Parser) override; |
| void printMipsABIFlags() override; |
| virtual void printZeroSymbolOtherField(const Elf_Sym &Symbol) const; |
| |
| protected: |
| virtual std::string getGroupSectionHeaderName() const; |
| void printSymbolOtherField(const Elf_Sym &Symbol) const; |
| virtual void printExpandedRelRelaReloc(const Relocation<ELFT> &R, |
| StringRef SymbolName, |
| StringRef RelocName); |
| virtual void printDefaultRelRelaReloc(const Relocation<ELFT> &R, |
| StringRef SymbolName, |
| StringRef RelocName); |
| virtual void printRelocationSectionInfo(const Elf_Shdr &Sec, StringRef Name, |
| const unsigned SecNdx); |
| virtual void printSectionGroupMembers(StringRef Name, uint64_t Idx) const; |
| virtual void printEmptyGroupMessage() const; |
| |
| ScopedPrinter &W; |
| }; |
| |
| // JSONELFDumper shares most of the same implementation as LLVMELFDumper except |
| // it uses a JSONScopedPrinter. |
| template <typename ELFT> class JSONELFDumper : public LLVMELFDumper<ELFT> { |
| public: |
| LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
| |
| JSONELFDumper(const object::ELFObjectFile<ELFT> &ObjF, ScopedPrinter &Writer) |
| : LLVMELFDumper<ELFT>(ObjF, Writer) {} |
| |
| std::string getGroupSectionHeaderName() const override; |
| |
| void printFileSummary(StringRef FileStr, ObjectFile &Obj, |
| ArrayRef<std::string> InputFilenames, |
| const Archive *A) override; |
| virtual void printZeroSymbolOtherField(const Elf_Sym &Symbol) const override; |
| |
| void printDefaultRelRelaReloc(const Relocation<ELFT> &R, |
| StringRef SymbolName, |
| StringRef RelocName) override; |
| |
| void printRelocationSectionInfo(const Elf_Shdr &Sec, StringRef Name, |
| const unsigned SecNdx) override; |
| |
| void printSectionGroupMembers(StringRef Name, uint64_t Idx) const override; |
| |
| void printEmptyGroupMessage() const override; |
| |
| private: |
| std::unique_ptr<DictScope> FileScope; |
| }; |
| |
| } // end anonymous namespace |
| |
| namespace llvm { |
| |
| template <class ELFT> |
| static std::unique_ptr<ObjDumper> |
| createELFDumper(const ELFObjectFile<ELFT> &Obj, ScopedPrinter &Writer) { |
| if (opts::Output == opts::GNU) |
| return std::make_unique<GNUELFDumper<ELFT>>(Obj, Writer); |
| else if (opts::Output == opts::JSON) |
| return std::make_unique<JSONELFDumper<ELFT>>(Obj, Writer); |
| return std::make_unique<LLVMELFDumper<ELFT>>(Obj, Writer); |
| } |
| |
| std::unique_ptr<ObjDumper> createELFDumper(const object::ELFObjectFileBase &Obj, |
| ScopedPrinter &Writer) { |
| // Little-endian 32-bit |
| if (const ELF32LEObjectFile *ELFObj = dyn_cast<ELF32LEObjectFile>(&Obj)) |
| return createELFDumper(*ELFObj, Writer); |
| |
| // Big-endian 32-bit |
| if (const ELF32BEObjectFile *ELFObj = dyn_cast<ELF32BEObjectFile>(&Obj)) |
| return createELFDumper(*ELFObj, Writer); |
| |
| // Little-endian 64-bit |
| if (const ELF64LEObjectFile *ELFObj = dyn_cast<ELF64LEObjectFile>(&Obj)) |
| return createELFDumper(*ELFObj, Writer); |
| |
| // Big-endian 64-bit |
| return createELFDumper(*cast<ELF64BEObjectFile>(&Obj), Writer); |
| } |
| |
| } // end namespace llvm |
| |
| template <class ELFT> |
| Expected<SmallVector<std::optional<VersionEntry>, 0> *> |
| ELFDumper<ELFT>::getVersionMap() const { |
| // If the VersionMap has already been loaded or if there is no dynamic symtab |
| // or version table, there is nothing to do. |
| if (!VersionMap.empty() || !DynSymRegion || !SymbolVersionSection) |
| return &VersionMap; |
| |
| Expected<SmallVector<std::optional<VersionEntry>, 0>> MapOrErr = |
| Obj.loadVersionMap(SymbolVersionNeedSection, SymbolVersionDefSection); |
| if (MapOrErr) |
| VersionMap = *MapOrErr; |
| else |
| return MapOrErr.takeError(); |
| |
| return &VersionMap; |
| } |
| |
| template <typename ELFT> |
| Expected<StringRef> ELFDumper<ELFT>::getSymbolVersion(const Elf_Sym &Sym, |
| bool &IsDefault) const { |
| // This is a dynamic symbol. Look in the GNU symbol version table. |
| if (!SymbolVersionSection) { |
| // No version table. |
| IsDefault = false; |
| return ""; |
| } |
| |
| assert(DynSymRegion && "DynSymRegion has not been initialised"); |
| // Determine the position in the symbol table of this entry. |
| size_t EntryIndex = (reinterpret_cast<uintptr_t>(&Sym) - |
| reinterpret_cast<uintptr_t>(DynSymRegion->Addr)) / |
| sizeof(Elf_Sym); |
| |
| // Get the corresponding version index entry. |
| Expected<const Elf_Versym *> EntryOrErr = |
| Obj.template getEntry<Elf_Versym>(*SymbolVersionSection, EntryIndex); |
| if (!EntryOrErr) |
| return EntryOrErr.takeError(); |
| |
| unsigned Version = (*EntryOrErr)->vs_index; |
| if (Version == VER_NDX_LOCAL || Version == VER_NDX_GLOBAL) { |
| IsDefault = false; |
| return ""; |
| } |
| |
| Expected<SmallVector<std::optional<VersionEntry>, 0> *> MapOrErr = |
| getVersionMap(); |
| if (!MapOrErr) |
| return MapOrErr.takeError(); |
| |
| return Obj.getSymbolVersionByIndex(Version, IsDefault, **MapOrErr, |
| Sym.st_shndx == ELF::SHN_UNDEF); |
| } |
| |
| template <typename ELFT> |
| Expected<RelSymbol<ELFT>> |
| ELFDumper<ELFT>::getRelocationTarget(const Relocation<ELFT> &R, |
| const Elf_Shdr *SymTab) const { |
| if (R.Symbol == 0) |
| return RelSymbol<ELFT>(nullptr, ""); |
| |
| Expected<const Elf_Sym *> SymOrErr = |
| Obj.template getEntry<Elf_Sym>(*SymTab, R.Symbol); |
| if (!SymOrErr) |
| return createError("unable to read an entry with index " + Twine(R.Symbol) + |
| " from " + describe(*SymTab) + ": " + |
| toString(SymOrErr.takeError())); |
| const Elf_Sym *Sym = *SymOrErr; |
| if (!Sym) |
| return RelSymbol<ELFT>(nullptr, ""); |
| |
| Expected<StringRef> StrTableOrErr = Obj.getStringTableForSymtab(*SymTab); |
| if (!StrTableOrErr) |
| return StrTableOrErr.takeError(); |
| |
| const Elf_Sym *FirstSym = |
| cantFail(Obj.template getEntry<Elf_Sym>(*SymTab, 0)); |
| std::string SymbolName = |
| getFullSymbolName(*Sym, Sym - FirstSym, getShndxTable(SymTab), |
| *StrTableOrErr, SymTab->sh_type == SHT_DYNSYM); |
| return RelSymbol<ELFT>(Sym, SymbolName); |
| } |
| |
| template <typename ELFT> |
| ArrayRef<typename ELFT::Word> |
| ELFDumper<ELFT>::getShndxTable(const Elf_Shdr *Symtab) const { |
| if (Symtab) { |
| auto It = ShndxTables.find(Symtab); |
| if (It != ShndxTables.end()) |
| return It->second; |
| } |
| return {}; |
| } |
| |
| static std::string maybeDemangle(StringRef Name) { |
| return opts::Demangle ? demangle(Name) : Name.str(); |
| } |
| |
| template <typename ELFT> |
| std::string ELFDumper<ELFT>::getStaticSymbolName(uint32_t Index) const { |
| auto Warn = [&](Error E) -> std::string { |
| reportUniqueWarning("unable to read the name of symbol with index " + |
| Twine(Index) + ": " + toString(std::move(E))); |
| return "<?>"; |
| }; |
| |
| Expected<const typename ELFT::Sym *> SymOrErr = |
| Obj.getSymbol(DotSymtabSec, Index); |
| if (!SymOrErr) |
| return Warn(SymOrErr.takeError()); |
| |
| Expected<StringRef> StrTabOrErr = Obj.getStringTableForSymtab(*DotSymtabSec); |
| if (!StrTabOrErr) |
| return Warn(StrTabOrErr.takeError()); |
| |
| Expected<StringRef> NameOrErr = (*SymOrErr)->getName(*StrTabOrErr); |
| if (!NameOrErr) |
| return Warn(NameOrErr.takeError()); |
| return maybeDemangle(*NameOrErr); |
| } |
| |
| template <typename ELFT> |
| std::string ELFDumper<ELFT>::getFullSymbolName( |
| const Elf_Sym &Symbol, unsigned SymIndex, DataRegion<Elf_Word> ShndxTable, |
| std::optional<StringRef> StrTable, bool IsDynamic) const { |
| if (!StrTable) |
| return "<?>"; |
| |
| std::string SymbolName; |
| if (Expected<StringRef> NameOrErr = Symbol.getName(*StrTable)) { |
| SymbolName = maybeDemangle(*NameOrErr); |
| } else { |
| reportUniqueWarning(NameOrErr.takeError()); |
| return "<?>"; |
| } |
| |
| if (SymbolName.empty() && Symbol.getType() == ELF::STT_SECTION) { |
| Expected<unsigned> SectionIndex = |
| getSymbolSectionIndex(Symbol, SymIndex, ShndxTable); |
| if (!SectionIndex) { |
| reportUniqueWarning(SectionIndex.takeError()); |
| return "<?>"; |
| } |
| Expected<StringRef> NameOrErr = getSymbolSectionName(Symbol, *SectionIndex); |
| if (!NameOrErr) { |
| reportUniqueWarning(NameOrErr.takeError()); |
| return ("<section " + Twine(*SectionIndex) + ">").str(); |
| } |
| return std::string(*NameOrErr); |
| } |
| |
| if (!IsDynamic) |
| return SymbolName; |
| |
| bool IsDefault; |
| Expected<StringRef> VersionOrErr = getSymbolVersion(Symbol, IsDefault); |
| if (!VersionOrErr) { |
| reportUniqueWarning(VersionOrErr.takeError()); |
| return SymbolName + "@<corrupt>"; |
| } |
| |
| if (!VersionOrErr->empty()) { |
| SymbolName += (IsDefault ? "@@" : "@"); |
| SymbolName += *VersionOrErr; |
| } |
| return SymbolName; |
| } |
| |
| template <typename ELFT> |
| Expected<unsigned> |
| ELFDumper<ELFT>::getSymbolSectionIndex(const Elf_Sym &Symbol, unsigned SymIndex, |
| DataRegion<Elf_Word> ShndxTable) const { |
| unsigned Ndx = Symbol.st_shndx; |
| if (Ndx == SHN_XINDEX) |
| return object::getExtendedSymbolTableIndex<ELFT>(Symbol, SymIndex, |
| ShndxTable); |
| if (Ndx != SHN_UNDEF && Ndx < SHN_LORESERVE) |
| return Ndx; |
| |
| auto CreateErr = [&](const Twine &Name, |
| std::optional<unsigned> Offset = std::nullopt) { |
| std::string Desc; |
| if (Offset) |
| Desc = (Name + "+0x" + Twine::utohexstr(*Offset)).str(); |
| else |
| Desc = Name.str(); |
| return createError( |
| "unable to get section index for symbol with st_shndx = 0x" + |
| Twine::utohexstr(Ndx) + " (" + Desc + ")"); |
| }; |
| |
| if (Ndx >= ELF::SHN_LOPROC && Ndx <= ELF::SHN_HIPROC) |
| return CreateErr("SHN_LOPROC", Ndx - ELF::SHN_LOPROC); |
| if (Ndx >= ELF::SHN_LOOS && Ndx <= ELF::SHN_HIOS) |
| return CreateErr("SHN_LOOS", Ndx - ELF::SHN_LOOS); |
| if (Ndx == ELF::SHN_UNDEF) |
| return CreateErr("SHN_UNDEF"); |
| if (Ndx == ELF::SHN_ABS) |
| return CreateErr("SHN_ABS"); |
| if (Ndx == ELF::SHN_COMMON) |
| return CreateErr("SHN_COMMON"); |
| return CreateErr("SHN_LORESERVE", Ndx - SHN_LORESERVE); |
| } |
| |
| template <typename ELFT> |
| Expected<StringRef> |
| ELFDumper<ELFT>::getSymbolSectionName(const Elf_Sym &Symbol, |
| unsigned SectionIndex) const { |
| Expected<const Elf_Shdr *> SecOrErr = Obj.getSection(SectionIndex); |
| if (!SecOrErr) |
| return SecOrErr.takeError(); |
| return Obj.getSectionName(**SecOrErr); |
| } |
| |
| template <class ELFO> |
| static const typename ELFO::Elf_Shdr * |
| findNotEmptySectionByAddress(const ELFO &Obj, StringRef FileName, |
| uint64_t Addr) { |
| for (const typename ELFO::Elf_Shdr &Shdr : cantFail(Obj.sections())) |
| if (Shdr.sh_addr == Addr && Shdr.sh_size > 0) |
| return &Shdr; |
| return nullptr; |
| } |
| |
| const EnumEntry<unsigned> ElfClass[] = { |
| {"None", "none", ELF::ELFCLASSNONE}, |
| {"32-bit", "ELF32", ELF::ELFCLASS32}, |
| {"64-bit", "ELF64", ELF::ELFCLASS64}, |
| }; |
| |
| const EnumEntry<unsigned> ElfDataEncoding[] = { |
| {"None", "none", ELF::ELFDATANONE}, |
| {"LittleEndian", "2's complement, little endian", ELF::ELFDATA2LSB}, |
| {"BigEndian", "2's complement, big endian", ELF::ELFDATA2MSB}, |
| }; |
| |
| const EnumEntry<unsigned> ElfObjectFileType[] = { |
| {"None", "NONE (none)", ELF::ET_NONE}, |
| {"Relocatable", "REL (Relocatable file)", ELF::ET_REL}, |
| {"Executable", "EXEC (Executable file)", ELF::ET_EXEC}, |
| {"SharedObject", "DYN (Shared object file)", ELF::ET_DYN}, |
| {"Core", "CORE (Core file)", ELF::ET_CORE}, |
| }; |
| |
| const EnumEntry<unsigned> ElfOSABI[] = { |
| {"SystemV", "UNIX - System V", ELF::ELFOSABI_NONE}, |
| {"HPUX", "UNIX - HP-UX", ELF::ELFOSABI_HPUX}, |
| {"NetBSD", "UNIX - NetBSD", ELF::ELFOSABI_NETBSD}, |
| {"GNU/Linux", "UNIX - GNU", ELF::ELFOSABI_LINUX}, |
| {"GNU/Hurd", "GNU/Hurd", ELF::ELFOSABI_HURD}, |
| {"Solaris", "UNIX - Solaris", ELF::ELFOSABI_SOLARIS}, |
| {"AIX", "UNIX - AIX", ELF::ELFOSABI_AIX}, |
| {"IRIX", "UNIX - IRIX", ELF::ELFOSABI_IRIX}, |
| {"FreeBSD", "UNIX - FreeBSD", ELF::ELFOSABI_FREEBSD}, |
| {"TRU64", "UNIX - TRU64", ELF::ELFOSABI_TRU64}, |
| {"Modesto", "Novell - Modesto", ELF::ELFOSABI_MODESTO}, |
| {"OpenBSD", "UNIX - OpenBSD", ELF::ELFOSABI_OPENBSD}, |
| {"OpenVMS", "VMS - OpenVMS", ELF::ELFOSABI_OPENVMS}, |
| {"NSK", "HP - Non-Stop Kernel", ELF::ELFOSABI_NSK}, |
| {"AROS", "AROS", ELF::ELFOSABI_AROS}, |
| {"FenixOS", "FenixOS", ELF::ELFOSABI_FENIXOS}, |
| {"CloudABI", "CloudABI", ELF::ELFOSABI_CLOUDABI}, |
| {"Standalone", "Standalone App", ELF::ELFOSABI_STANDALONE} |
| }; |
| |
| const EnumEntry<unsigned> AMDGPUElfOSABI[] = { |
| {"AMDGPU_HSA", "AMDGPU - HSA", ELF::ELFOSABI_AMDGPU_HSA}, |
| {"AMDGPU_PAL", "AMDGPU - PAL", ELF::ELFOSABI_AMDGPU_PAL}, |
| {"AMDGPU_MESA3D", "AMDGPU - MESA3D", ELF::ELFOSABI_AMDGPU_MESA3D} |
| }; |
| |
| const EnumEntry<unsigned> ARMElfOSABI[] = { |
| {"ARM", "ARM", ELF::ELFOSABI_ARM} |
| }; |
| |
| const EnumEntry<unsigned> C6000ElfOSABI[] = { |
| {"C6000_ELFABI", "Bare-metal C6000", ELF::ELFOSABI_C6000_ELFABI}, |
| {"C6000_LINUX", "Linux C6000", ELF::ELFOSABI_C6000_LINUX} |
| }; |
| |
| const EnumEntry<unsigned> ElfMachineType[] = { |
| ENUM_ENT(EM_NONE, "None"), |
| ENUM_ENT(EM_M32, "WE32100"), |
| ENUM_ENT(EM_SPARC, "Sparc"), |
| ENUM_ENT(EM_386, "Intel 80386"), |
| ENUM_ENT(EM_68K, "MC68000"), |
| ENUM_ENT(EM_88K, "MC88000"), |
| ENUM_ENT(EM_IAMCU, "EM_IAMCU"), |
| ENUM_ENT(EM_860, "Intel 80860"), |
| ENUM_ENT(EM_MIPS, "MIPS R3000"), |
| ENUM_ENT(EM_S370, "IBM System/370"), |
| ENUM_ENT(EM_MIPS_RS3_LE, "MIPS R3000 little-endian"), |
| ENUM_ENT(EM_PARISC, "HPPA"), |
| ENUM_ENT(EM_VPP500, "Fujitsu VPP500"), |
| ENUM_ENT(EM_SPARC32PLUS, "Sparc v8+"), |
| ENUM_ENT(EM_960, "Intel 80960"), |
| ENUM_ENT(EM_PPC, "PowerPC"), |
| ENUM_ENT(EM_PPC64, "PowerPC64"), |
| ENUM_ENT(EM_S390, "IBM S/390"), |
| ENUM_ENT(EM_SPU, "SPU"), |
| ENUM_ENT(EM_V800, "NEC V800 series"), |
| ENUM_ENT(EM_FR20, "Fujistsu FR20"), |
| ENUM_ENT(EM_RH32, "TRW RH-32"), |
| ENUM_ENT(EM_RCE, "Motorola RCE"), |
| ENUM_ENT(EM_ARM, "ARM"), |
| ENUM_ENT(EM_ALPHA, "EM_ALPHA"), |
| ENUM_ENT(EM_SH, "Hitachi SH"), |
| ENUM_ENT(EM_SPARCV9, "Sparc v9"), |
| ENUM_ENT(EM_TRICORE, "Siemens Tricore"), |
| ENUM_ENT(EM_ARC, "ARC"), |
| ENUM_ENT(EM_H8_300, "Hitachi H8/300"), |
| ENUM_ENT(EM_H8_300H, "Hitachi H8/300H"), |
| ENUM_ENT(EM_H8S, "Hitachi H8S"), |
| ENUM_ENT(EM_H8_500, "Hitachi H8/500"), |
| ENUM_ENT(EM_IA_64, "Intel IA-64"), |
| ENUM_ENT(EM_MIPS_X, "Stanford MIPS-X"), |
| ENUM_ENT(EM_COLDFIRE, "Motorola Coldfire"), |
| ENUM_ENT(EM_68HC12, "Motorola MC68HC12 Microcontroller"), |
| ENUM_ENT(EM_MMA, "Fujitsu Multimedia Accelerator"), |
| ENUM_ENT(EM_PCP, "Siemens PCP"), |
| ENUM_ENT(EM_NCPU, "Sony nCPU embedded RISC processor"), |
| ENUM_ENT(EM_NDR1, "Denso NDR1 microprocesspr"), |
| ENUM_ENT(EM_STARCORE, "Motorola Star*Core processor"), |
| ENUM_ENT(EM_ME16, "Toyota ME16 processor"), |
| ENUM_ENT(EM_ST100, "STMicroelectronics ST100 processor"), |
| ENUM_ENT(EM_TINYJ, "Advanced Logic Corp. TinyJ embedded processor"), |
| ENUM_ENT(EM_X86_64, "Advanced Micro Devices X86-64"), |
| ENUM_ENT(EM_PDSP, "Sony DSP processor"), |
| ENUM_ENT(EM_PDP10, "Digital Equipment Corp. PDP-10"), |
| ENUM_ENT(EM_PDP11, "Digital Equipment Corp. PDP-11"), |
| ENUM_ENT(EM_FX66, "Siemens FX66 microcontroller"), |
| ENUM_ENT(EM_ST9PLUS, "STMicroelectronics ST9+ 8/16 bit microcontroller"), |
| ENUM_ENT(EM_ST7, "STMicroelectronics ST7 8-bit microcontroller"), |
| ENUM_ENT(EM_68HC16, "Motorola MC68HC16 Microcontroller"), |
| ENUM_ENT(EM_68HC11, "Motorola MC68HC11 Microcontroller"), |
| ENUM_ENT(EM_68HC08, "Motorola MC68HC08 Microcontroller"), |
| ENUM_ENT(EM_68HC05, "Motorola MC68HC05 Microcontroller"), |
| ENUM_ENT(EM_SVX, "Silicon Graphics SVx"), |
| ENUM_ENT(EM_ST19, "STMicroelectronics ST19 8-bit microcontroller"), |
| ENUM_ENT(EM_VAX, "Digital VAX"), |
| ENUM_ENT(EM_CRIS, "Axis Communications 32-bit embedded processor"), |
| ENUM_ENT(EM_JAVELIN, "Infineon Technologies 32-bit embedded cpu"), |
| ENUM_ENT(EM_FIREPATH, "Element 14 64-bit DSP processor"), |
| ENUM_ENT(EM_ZSP, "LSI Logic's 16-bit DSP processor"), |
| ENUM_ENT(EM_MMIX, "Donald Knuth's educational 64-bit processor"), |
| ENUM_ENT(EM_HUANY, "Harvard Universitys's machine-independent object format"), |
| ENUM_ENT(EM_PRISM, "Vitesse Prism"), |
| ENUM_ENT(EM_AVR, "Atmel AVR 8-bit microcontroller"), |
| ENUM_ENT(EM_FR30, "Fujitsu FR30"), |
| ENUM_ENT(EM_D10V, "Mitsubishi D10V"), |
| ENUM_ENT(EM_D30V, "Mitsubishi D30V"), |
| ENUM_ENT(EM_V850, "NEC v850"), |
| ENUM_ENT(EM_M32R, "Renesas M32R (formerly Mitsubishi M32r)"), |
| ENUM_ENT(EM_MN10300, "Matsushita MN10300"), |
| ENUM_ENT(EM_MN10200, "Matsushita MN10200"), |
| ENUM_ENT(EM_PJ, "picoJava"), |
| ENUM_ENT(EM_OPENRISC, "OpenRISC 32-bit embedded processor"), |
| ENUM_ENT(EM_ARC_COMPACT, "EM_ARC_COMPACT"), |
| ENUM_ENT(EM_XTENSA, "Tensilica Xtensa Processor"), |
| ENUM_ENT(EM_VIDEOCORE, "Alphamosaic VideoCore processor"), |
| ENUM_ENT(EM_TMM_GPP, "Thompson Multimedia General Purpose Processor"), |
| ENUM_ENT(EM_NS32K, "National Semiconductor 32000 series"), |
| ENUM_ENT(EM_TPC, "Tenor Network TPC processor"), |
| ENUM_ENT(EM_SNP1K, "EM_SNP1K"), |
| ENUM_ENT(EM_ST200, "STMicroelectronics ST200 microcontroller"), |
| ENUM_ENT(EM_IP2K, "Ubicom IP2xxx 8-bit microcontrollers"), |
| ENUM_ENT(EM_MAX, "MAX Processor"), |
| ENUM_ENT(EM_CR, "National Semiconductor CompactRISC"), |
| ENUM_ENT(EM_F2MC16, "Fujitsu F2MC16"), |
| ENUM_ENT(EM_MSP430, "Texas Instruments msp430 microcontroller"), |
| ENUM_ENT(EM_BLACKFIN, "Analog Devices Blackfin"), |
| ENUM_ENT(EM_SE_C33, "S1C33 Family of Seiko Epson processors"), |
| ENUM_ENT(EM_SEP, "Sharp embedded microprocessor"), |
| ENUM_ENT(EM_ARCA, "Arca RISC microprocessor"), |
| ENUM_ENT(EM_UNICORE, "Unicore"), |
| ENUM_ENT(EM_EXCESS, "eXcess 16/32/64-bit configurable embedded CPU"), |
| ENUM_ENT(EM_DXP, "Icera Semiconductor Inc. Deep Execution Processor"), |
| ENUM_ENT(EM_ALTERA_NIOS2, "Altera Nios"), |
| ENUM_ENT(EM_CRX, "National Semiconductor CRX microprocessor"), |
| ENUM_ENT(EM_XGATE, "Motorola XGATE embedded processor"), |
| ENUM_ENT(EM_C166, "Infineon Technologies xc16x"), |
| ENUM_ENT(EM_M16C, "Renesas M16C"), |
| ENUM_ENT(EM_DSPIC30F, "Microchip Technology dsPIC30F Digital Signal Controller"), |
| ENUM_ENT(EM_CE, "Freescale Communication Engine RISC core"), |
| ENUM_ENT(EM_M32C, "Renesas M32C"), |
| ENUM_ENT(EM_TSK3000, "Altium TSK3000 core"), |
| ENUM_ENT(EM_RS08, "Freescale RS08 embedded processor"), |
| ENUM_ENT(EM_SHARC, "EM_SHARC"), |
| ENUM_ENT(EM_ECOG2, "Cyan Technology eCOG2 microprocessor"), |
| ENUM_ENT(EM_SCORE7, "SUNPLUS S+Core"), |
| ENUM_ENT(EM_DSP24, "New Japan Radio (NJR) 24-bit DSP Processor"), |
| ENUM_ENT(EM_VIDEOCORE3, "Broadcom VideoCore III processor"), |
| ENUM_ENT(EM_LATTICEMICO32, "Lattice Mico32"), |
| ENUM_ENT(EM_SE_C17, "Seiko Epson C17 family"), |
| ENUM_ENT(EM_TI_C6000, "Texas Instruments TMS320C6000 DSP family"), |
| ENUM_ENT(EM_TI_C2000, "Texas Instruments TMS320C2000 DSP family"), |
| ENUM_ENT(EM_TI_C5500, "Texas Instruments TMS320C55x DSP family"), |
| ENUM_ENT(EM_MMDSP_PLUS, "STMicroelectronics 64bit VLIW Data Signal Processor"), |
| ENUM_ENT(EM_CYPRESS_M8C, "Cypress M8C microprocessor"), |
| ENUM_ENT(EM_R32C, "Renesas R32C series microprocessors"), |
| ENUM_ENT(EM_TRIMEDIA, "NXP Semiconductors TriMedia architecture family"), |
| ENUM_ENT(EM_HEXAGON, "Qualcomm Hexagon"), |
| ENUM_ENT(EM_8051, "Intel 8051 and variants"), |
| ENUM_ENT(EM_STXP7X, "STMicroelectronics STxP7x family"), |
| ENUM_ENT(EM_NDS32, "Andes Technology compact code size embedded RISC processor family"), |
| ENUM_ENT(EM_ECOG1, "Cyan Technology eCOG1 microprocessor"), |
| // FIXME: Following EM_ECOG1X definitions is dead code since EM_ECOG1X has |
| // an identical number to EM_ECOG1. |
| ENUM_ENT(EM_ECOG1X, "Cyan Technology eCOG1X family"), |
| ENUM_ENT(EM_MAXQ30, "Dallas Semiconductor MAXQ30 Core microcontrollers"), |
| ENUM_ENT(EM_XIMO16, "New Japan Radio (NJR) 16-bit DSP Processor"), |
| ENUM_ENT(EM_MANIK, "M2000 Reconfigurable RISC Microprocessor"), |
| ENUM_ENT(EM_CRAYNV2, "Cray Inc. NV2 vector architecture"), |
| ENUM_ENT(EM_RX, "Renesas RX"), |
| ENUM_ENT(EM_METAG, "Imagination Technologies Meta processor architecture"), |
| ENUM_ENT(EM_MCST_ELBRUS, "MCST Elbrus general purpose hardware architecture"), |
| ENUM_ENT(EM_ECOG16, "Cyan Technology eCOG16 family"), |
| ENUM_ENT(EM_CR16, "National Semiconductor CompactRISC 16-bit processor"), |
| ENUM_ENT(EM_ETPU, "Freescale Extended Time Processing Unit"), |
| ENUM_ENT(EM_SLE9X, "Infineon Technologies SLE9X core"), |
| ENUM_ENT(EM_L10M, "EM_L10M"), |
| ENUM_ENT(EM_K10M, "EM_K10M"), |
| ENUM_ENT(EM_AARCH64, "AArch64"), |
| ENUM_ENT(EM_AVR32, "Atmel Corporation 32-bit microprocessor family"), |
| ENUM_ENT(EM_STM8, "STMicroeletronics STM8 8-bit microcontroller"), |
| ENUM_ENT(EM_TILE64, "Tilera TILE64 multicore architecture family"), |
| ENUM_ENT(EM_TILEPRO, "Tilera TILEPro multicore architecture family"), |
| ENUM_ENT(EM_MICROBLAZE, "Xilinx MicroBlaze 32-bit RISC soft processor core"), |
| ENUM_ENT(EM_CUDA, "NVIDIA CUDA architecture"), |
| ENUM_ENT(EM_TILEGX, "Tilera TILE-Gx multicore architecture family"), |
| ENUM_ENT(EM_CLOUDSHIELD, "EM_CLOUDSHIELD"), |
| ENUM_ENT(EM_COREA_1ST, "EM_COREA_1ST"), |
| ENUM_ENT(EM_COREA_2ND, "EM_COREA_2ND"), |
| ENUM_ENT(EM_ARC_COMPACT2, "EM_ARC_COMPACT2"), |
| ENUM_ENT(EM_OPEN8, "EM_OPEN8"), |
| ENUM_ENT(EM_RL78, "Renesas RL78"), |
| ENUM_ENT(EM_VIDEOCORE5, "Broadcom VideoCore V processor"), |
| ENUM_ENT(EM_78KOR, "EM_78KOR"), |
| ENUM_ENT(EM_56800EX, "EM_56800EX"), |
| ENUM_ENT(EM_AMDGPU, "EM_AMDGPU"), |
| ENUM_ENT(EM_RISCV, "RISC-V"), |
| ENUM_ENT(EM_LANAI, "EM_LANAI"), |
| ENUM_ENT(EM_BPF, "EM_BPF"), |
| ENUM_ENT(EM_VE, "NEC SX-Aurora Vector Engine"), |
| ENUM_ENT(EM_LOONGARCH, "LoongArch"), |
| }; |
| |
| const EnumEntry<unsigned> ElfSymbolBindings[] = { |
| {"Local", "LOCAL", ELF::STB_LOCAL}, |
| {"Global", "GLOBAL", ELF::STB_GLOBAL}, |
| {"Weak", "WEAK", ELF::STB_WEAK}, |
| {"Unique", "UNIQUE", ELF::STB_GNU_UNIQUE}}; |
| |
| const EnumEntry<unsigned> ElfSymbolVisibilities[] = { |
| {"DEFAULT", "DEFAULT", ELF::STV_DEFAULT}, |
| {"INTERNAL", "INTERNAL", ELF::STV_INTERNAL}, |
| {"HIDDEN", "HIDDEN", ELF::STV_HIDDEN}, |
| {"PROTECTED", "PROTECTED", ELF::STV_PROTECTED}}; |
| |
| const EnumEntry<unsigned> AMDGPUSymbolTypes[] = { |
| { "AMDGPU_HSA_KERNEL", ELF::STT_AMDGPU_HSA_KERNEL } |
| }; |
| |
| static const char *getGroupType(uint32_t Flag) { |
| if (Flag & ELF::GRP_COMDAT) |
| return "COMDAT"; |
| else |
| return "(unknown)"; |
| } |
| |
| const EnumEntry<unsigned> ElfSectionFlags[] = { |
| ENUM_ENT(SHF_WRITE, "W"), |
| ENUM_ENT(SHF_ALLOC, "A"), |
| ENUM_ENT(SHF_EXECINSTR, "X"), |
| ENUM_ENT(SHF_MERGE, "M"), |
| ENUM_ENT(SHF_STRINGS, "S"), |
| ENUM_ENT(SHF_INFO_LINK, "I"), |
| ENUM_ENT(SHF_LINK_ORDER, "L"), |
| ENUM_ENT(SHF_OS_NONCONFORMING, "O"), |
| ENUM_ENT(SHF_GROUP, "G"), |
| ENUM_ENT(SHF_TLS, "T"), |
| ENUM_ENT(SHF_COMPRESSED, "C"), |
| ENUM_ENT(SHF_EXCLUDE, "E"), |
| }; |
| |
| const EnumEntry<unsigned> ElfGNUSectionFlags[] = { |
| ENUM_ENT(SHF_GNU_RETAIN, "R") |
| }; |
| |
| const EnumEntry<unsigned> ElfSolarisSectionFlags[] = { |
| ENUM_ENT(SHF_SUNW_NODISCARD, "R") |
| }; |
| |
| const EnumEntry<unsigned> ElfXCoreSectionFlags[] = { |
| ENUM_ENT(XCORE_SHF_CP_SECTION, ""), |
| ENUM_ENT(XCORE_SHF_DP_SECTION, "") |
| }; |
| |
| const EnumEntry<unsigned> ElfARMSectionFlags[] = { |
| ENUM_ENT(SHF_ARM_PURECODE, "y") |
| }; |
| |
| const EnumEntry<unsigned> ElfHexagonSectionFlags[] = { |
| ENUM_ENT(SHF_HEX_GPREL, "") |
| }; |
| |
| const EnumEntry<unsigned> ElfMipsSectionFlags[] = { |
| ENUM_ENT(SHF_MIPS_NODUPES, ""), |
| ENUM_ENT(SHF_MIPS_NAMES, ""), |
| ENUM_ENT(SHF_MIPS_LOCAL, ""), |
| ENUM_ENT(SHF_MIPS_NOSTRIP, ""), |
| ENUM_ENT(SHF_MIPS_GPREL, ""), |
| ENUM_ENT(SHF_MIPS_MERGE, ""), |
| ENUM_ENT(SHF_MIPS_ADDR, ""), |
| ENUM_ENT(SHF_MIPS_STRING, "") |
| }; |
| |
| const EnumEntry<unsigned> ElfX86_64SectionFlags[] = { |
| ENUM_ENT(SHF_X86_64_LARGE, "l") |
| }; |
| |
| static std::vector<EnumEntry<unsigned>> |
| getSectionFlagsForTarget(unsigned EOSAbi, unsigned EMachine) { |
| std::vector<EnumEntry<unsigned>> Ret(std::begin(ElfSectionFlags), |
| std::end(ElfSectionFlags)); |
| switch (EOSAbi) { |
| case ELFOSABI_SOLARIS: |
| Ret.insert(Ret.end(), std::begin(ElfSolarisSectionFlags), |
| std::end(ElfSolarisSectionFlags)); |
| break; |
| default: |
| Ret.insert(Ret.end(), std::begin(ElfGNUSectionFlags), |
| std::end(ElfGNUSectionFlags)); |
| break; |
| } |
| switch (EMachine) { |
| case EM_ARM: |
| Ret.insert(Ret.end(), std::begin(ElfARMSectionFlags), |
| std::end(ElfARMSectionFlags)); |
| break; |
| case EM_HEXAGON: |
| Ret.insert(Ret.end(), std::begin(ElfHexagonSectionFlags), |
| std::end(ElfHexagonSectionFlags)); |
| break; |
| case EM_MIPS: |
| Ret.insert(Ret.end(), std::begin(ElfMipsSectionFlags), |
| std::end(ElfMipsSectionFlags)); |
| break; |
| case EM_X86_64: |
| Ret.insert(Ret.end(), std::begin(ElfX86_64SectionFlags), |
| std::end(ElfX86_64SectionFlags)); |
| break; |
| case EM_XCORE: |
| Ret.insert(Ret.end(), std::begin(ElfXCoreSectionFlags), |
| std::end(ElfXCoreSectionFlags)); |
| break; |
| default: |
| break; |
| } |
| return Ret; |
| } |
| |
| static std::string getGNUFlags(unsigned EOSAbi, unsigned EMachine, |
| uint64_t Flags) { |
| // Here we are trying to build the flags string in the same way as GNU does. |
| // It is not that straightforward. Imagine we have sh_flags == 0x90000000. |
| // SHF_EXCLUDE ("E") has a value of 0x80000000 and SHF_MASKPROC is 0xf0000000. |
| // GNU readelf will not print "E" or "Ep" in this case, but will print just |
| // "p". It only will print "E" when no other processor flag is set. |
| std::string Str; |
| bool HasUnknownFlag = false; |
| bool HasOSFlag = false; |
| bool HasProcFlag = false; |
| std::vector<EnumEntry<unsigned>> FlagsList = |
| getSectionFlagsForTarget(EOSAbi, EMachine); |
| while (Flags) { |
| // Take the least significant bit as a flag. |
| uint64_t Flag = Flags & -Flags; |
| Flags -= Flag; |
| |
| // Find the flag in the known flags list. |
| auto I = llvm::find_if(FlagsList, [=](const EnumEntry<unsigned> &E) { |
| // Flags with empty names are not printed in GNU style output. |
| return E.Value == Flag && !E.AltName.empty(); |
| }); |
| if (I != FlagsList.end()) { |
| Str += I->AltName; |
| continue; |
| } |
| |
| // If we did not find a matching regular flag, then we deal with an OS |
| // specific flag, processor specific flag or an unknown flag. |
| if (Flag & ELF::SHF_MASKOS) { |
| HasOSFlag = true; |
| Flags &= ~ELF::SHF_MASKOS; |
| } else if (Flag & ELF::SHF_MASKPROC) { |
| HasProcFlag = true; |
| // Mask off all the processor-specific bits. This removes the SHF_EXCLUDE |
| // bit if set so that it doesn't also get printed. |
| Flags &= ~ELF::SHF_MASKPROC; |
| } else { |
| HasUnknownFlag = true; |
| } |
| } |
| |
| // "o", "p" and "x" are printed last. |
| if (HasOSFlag) |
| Str += "o"; |
| if (HasProcFlag) |
| Str += "p"; |
| if (HasUnknownFlag) |
| Str += "x"; |
| return Str; |
| } |
| |
| static StringRef segmentTypeToString(unsigned Arch, unsigned Type) { |
| // Check potentially overlapped processor-specific program header type. |
| switch (Arch) { |
| case ELF::EM_ARM: |
| switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_ARM_EXIDX); } |
| 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_RTPROC); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_OPTIONS); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_MIPS_ABIFLAGS); |
| } |
| break; |
| case ELF::EM_RISCV: |
| switch (Type) { LLVM_READOBJ_ENUM_CASE(ELF, PT_RISCV_ATTRIBUTES); } |
| } |
| |
| switch (Type) { |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_NULL); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_LOAD); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_DYNAMIC); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_INTERP); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_NOTE); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_SHLIB); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_PHDR); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_TLS); |
| |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_EH_FRAME); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_SUNW_UNWIND); |
| |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_STACK); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_RELRO); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_GNU_PROPERTY); |
| |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_MUTABLE); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_RANDOMIZE); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_WXNEEDED); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_NOBTCFI); |
| LLVM_READOBJ_ENUM_CASE(ELF, PT_OPENBSD_BOOTDATA); |
| default: |
| return ""; |
| } |
| } |
| |
| static std::string getGNUPtType(unsigned Arch, unsigned Type) { |
| StringRef Seg = segmentTypeToString(Arch, Type); |
| if (Seg.empty()) |
| return std::string("<unknown>: ") + to_string(format_hex(Type, 1)); |
| |
| // E.g. "PT_ARM_EXIDX" -> "EXIDX". |
| if (Seg.consume_front("PT_ARM_")) |
| return Seg.str(); |
| |
| // E.g. "PT_MIPS_REGINFO" -> "REGINFO". |
| if (Seg.consume_front("PT_MIPS_")) |
| return Seg.str(); |
| |
| // E.g. "PT_RISCV_ATTRIBUTES" |
| if (Seg.consume_front("PT_RISCV_")) |
| return Seg.str(); |
| |
| // E.g. "PT_LOAD" -> "LOAD". |
| assert(Seg.startswith("PT_")); |
| return Seg.drop_front(3).str(); |
| } |
| |
| const EnumEntry<unsigned> ElfSegmentFlags[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, PF_X), |
| LLVM_READOBJ_ENUM_ENT(ELF, PF_W), |
| LLVM_READOBJ_ENUM_ENT(ELF, PF_R) |
| }; |
| |
| const EnumEntry<unsigned> ElfHeaderMipsFlags[] = { |
| ENUM_ENT(EF_MIPS_NOREORDER, "noreorder"), |
| ENUM_ENT(EF_MIPS_PIC, "pic"), |
| ENUM_ENT(EF_MIPS_CPIC, "cpic"), |
| ENUM_ENT(EF_MIPS_ABI2, "abi2"), |
| ENUM_ENT(EF_MIPS_32BITMODE, "32bitmode"), |
| ENUM_ENT(EF_MIPS_FP64, "fp64"), |
| ENUM_ENT(EF_MIPS_NAN2008, "nan2008"), |
| ENUM_ENT(EF_MIPS_ABI_O32, "o32"), |
| ENUM_ENT(EF_MIPS_ABI_O64, "o64"), |
| ENUM_ENT(EF_MIPS_ABI_EABI32, "eabi32"), |
| ENUM_ENT(EF_MIPS_ABI_EABI64, "eabi64"), |
| ENUM_ENT(EF_MIPS_MACH_3900, "3900"), |
| ENUM_ENT(EF_MIPS_MACH_4010, "4010"), |
| ENUM_ENT(EF_MIPS_MACH_4100, "4100"), |
| ENUM_ENT(EF_MIPS_MACH_4650, "4650"), |
| ENUM_ENT(EF_MIPS_MACH_4120, "4120"), |
| ENUM_ENT(EF_MIPS_MACH_4111, "4111"), |
| ENUM_ENT(EF_MIPS_MACH_SB1, "sb1"), |
| ENUM_ENT(EF_MIPS_MACH_OCTEON, "octeon"), |
| ENUM_ENT(EF_MIPS_MACH_XLR, "xlr"), |
| ENUM_ENT(EF_MIPS_MACH_OCTEON2, "octeon2"), |
| ENUM_ENT(EF_MIPS_MACH_OCTEON3, "octeon3"), |
| ENUM_ENT(EF_MIPS_MACH_5400, "5400"), |
| ENUM_ENT(EF_MIPS_MACH_5900, "5900"), |
| ENUM_ENT(EF_MIPS_MACH_5500, "5500"), |
| ENUM_ENT(EF_MIPS_MACH_9000, "9000"), |
| ENUM_ENT(EF_MIPS_MACH_LS2E, "loongson-2e"), |
| ENUM_ENT(EF_MIPS_MACH_LS2F, "loongson-2f"), |
| ENUM_ENT(EF_MIPS_MACH_LS3A, "loongson-3a"), |
| ENUM_ENT(EF_MIPS_MICROMIPS, "micromips"), |
| ENUM_ENT(EF_MIPS_ARCH_ASE_M16, "mips16"), |
| ENUM_ENT(EF_MIPS_ARCH_ASE_MDMX, "mdmx"), |
| ENUM_ENT(EF_MIPS_ARCH_1, "mips1"), |
| ENUM_ENT(EF_MIPS_ARCH_2, "mips2"), |
| ENUM_ENT(EF_MIPS_ARCH_3, "mips3"), |
| ENUM_ENT(EF_MIPS_ARCH_4, "mips4"), |
| ENUM_ENT(EF_MIPS_ARCH_5, "mips5"), |
| ENUM_ENT(EF_MIPS_ARCH_32, "mips32"), |
| ENUM_ENT(EF_MIPS_ARCH_64, "mips64"), |
| ENUM_ENT(EF_MIPS_ARCH_32R2, "mips32r2"), |
| ENUM_ENT(EF_MIPS_ARCH_64R2, "mips64r2"), |
| ENUM_ENT(EF_MIPS_ARCH_32R6, "mips32r6"), |
| ENUM_ENT(EF_MIPS_ARCH_64R6, "mips64r6") |
| }; |
| |
| const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion3[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_NONE), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R600), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R630), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RS880), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV670), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV710), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV730), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV770), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CEDAR), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CYPRESS), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_JUNIPER), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_REDWOOD), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_SUMO), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_BARTS), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAICOS), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAYMAN), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_TURKS), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX600), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX601), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX602), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX700), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX701), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX702), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX703), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX704), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX705), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX801), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX802), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX803), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX805), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX810), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX900), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX902), |
| 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_GFX90A), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90C), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX940), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX941), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX942), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1013), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1030), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1031), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1032), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1033), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1034), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1035), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1036), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1100), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1101), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1102), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1103), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1150), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1151), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_V3), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_V3) |
| }; |
| |
| const EnumEntry<unsigned> ElfHeaderAMDGPUFlagsABIVersion4[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_NONE), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R600), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_R630), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RS880), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV670), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV710), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV730), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_RV770), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CEDAR), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CYPRESS), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_JUNIPER), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_REDWOOD), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_SUMO), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_BARTS), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAICOS), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_CAYMAN), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_R600_TURKS), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX600), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX601), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX602), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX700), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX701), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX702), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX703), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX704), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX705), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX801), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX802), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX803), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX805), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX810), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX900), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX902), |
| 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_GFX90A), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX90C), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX940), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX941), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX942), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1010), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1011), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1012), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1013), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1030), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1031), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1032), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1033), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1034), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1035), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1036), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1100), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1101), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1102), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1103), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1150), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_MACH_AMDGCN_GFX1151), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_ANY_V4), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_OFF_V4), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_XNACK_ON_V4), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_ANY_V4), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_OFF_V4), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AMDGPU_FEATURE_SRAMECC_ON_V4) |
| }; |
| |
| const EnumEntry<unsigned> ElfHeaderRISCVFlags[] = { |
| ENUM_ENT(EF_RISCV_RVC, "RVC"), |
| ENUM_ENT(EF_RISCV_FLOAT_ABI_SINGLE, "single-float ABI"), |
| ENUM_ENT(EF_RISCV_FLOAT_ABI_DOUBLE, "double-float ABI"), |
| ENUM_ENT(EF_RISCV_FLOAT_ABI_QUAD, "quad-float ABI"), |
| ENUM_ENT(EF_RISCV_RVE, "RVE"), |
| ENUM_ENT(EF_RISCV_TSO, "TSO"), |
| }; |
| |
| const EnumEntry<unsigned> ElfHeaderAVRFlags[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR1), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR2), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR25), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR3), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR31), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR35), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR4), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR5), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR51), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVR6), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_AVRTINY), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_XMEGA1), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_XMEGA2), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_XMEGA3), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_XMEGA4), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_XMEGA5), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_XMEGA6), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_AVR_ARCH_XMEGA7), |
| ENUM_ENT(EF_AVR_LINKRELAX_PREPARED, "relaxable"), |
| }; |
| |
| const EnumEntry<unsigned> ElfHeaderLoongArchFlags[] = { |
| ENUM_ENT(EF_LOONGARCH_ABI_SOFT_FLOAT, "SOFT-FLOAT"), |
| ENUM_ENT(EF_LOONGARCH_ABI_SINGLE_FLOAT, "SINGLE-FLOAT"), |
| ENUM_ENT(EF_LOONGARCH_ABI_DOUBLE_FLOAT, "DOUBLE-FLOAT"), |
| ENUM_ENT(EF_LOONGARCH_OBJABI_V0, "OBJ-v0"), |
| ENUM_ENT(EF_LOONGARCH_OBJABI_V1, "OBJ-v1"), |
| }; |
| |
| static const EnumEntry<unsigned> ElfHeaderXtensaFlags[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_MACH_NONE), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_XT_INSN), |
| LLVM_READOBJ_ENUM_ENT(ELF, EF_XTENSA_XT_LIT) |
| }; |
| |
| const EnumEntry<unsigned> ElfSymOtherFlags[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, STV_INTERNAL), |
| LLVM_READOBJ_ENUM_ENT(ELF, STV_HIDDEN), |
| LLVM_READOBJ_ENUM_ENT(ELF, STV_PROTECTED) |
| }; |
| |
| const EnumEntry<unsigned> ElfMipsSymOtherFlags[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_OPTIONAL), |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_PLT), |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_PIC), |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_MICROMIPS) |
| }; |
| |
| const EnumEntry<unsigned> ElfAArch64SymOtherFlags[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_AARCH64_VARIANT_PCS) |
| }; |
| |
| const EnumEntry<unsigned> ElfMips16SymOtherFlags[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_OPTIONAL), |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_PLT), |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_MIPS_MIPS16) |
| }; |
| |
| const EnumEntry<unsigned> ElfRISCVSymOtherFlags[] = { |
| LLVM_READOBJ_ENUM_ENT(ELF, STO_RISCV_VARIANT_CC)}; |
| |
| static const char *getElfMipsOptionsOdkType(unsigned Odk) { |
| switch (Odk) { |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_NULL); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_REGINFO); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_EXCEPTIONS); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_PAD); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_HWPATCH); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_FILL); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_TAGS); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_HWAND); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_HWOR); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_GP_GROUP); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_IDENT); |
| LLVM_READOBJ_ENUM_CASE(ELF, ODK_PAGESIZE); |
| default: |
| return "Unknown"; |
| } |
| } |
| |
| template <typename ELFT> |
| std::pair<const typename ELFT::Phdr *, const typename ELFT::Shdr *> |
| ELFDumper<ELFT>::findDynamic() { |
| // Try to locate the PT_DYNAMIC header. |
| const Elf_Phdr *DynamicPhdr = nullptr; |
| if (Expected<ArrayRef<Elf_Phdr>> PhdrsOrErr = Obj.program_headers()) { |
| for (const Elf_Phdr &Phdr : *PhdrsOrErr) { |
| if (Phdr.p_type != ELF::PT_DYNAMIC) |
| continue; |
| DynamicPhdr = &Phdr; |
| break; |
| } |
| } else { |
| reportUniqueWarning( |
| "unable to read program headers to locate the PT_DYNAMIC segment: " + |
| toString(PhdrsOrErr.takeError())); |
| } |
| |
| // Try to locate the .dynamic section in the sections header table. |
| const Elf_Shdr *DynamicSec = nullptr; |
| for (const Elf_Shdr &Sec : cantFail(Obj.sections())) { |
| if (Sec.sh_type != ELF::SHT_DYNAMIC) |
| continue; |
| DynamicSec = &Sec; |
| break; |
| } |
| |
| if (DynamicPhdr && ((DynamicPhdr->p_offset + DynamicPhdr->p_filesz > |
| ObjF.getMemoryBufferRef().getBufferSize()) || |
| (DynamicPhdr->p_offset + DynamicPhdr->p_filesz < |
| DynamicPhdr->p_offset))) { |
| reportUniqueWarning( |
| "PT_DYNAMIC segment offset (0x" + |
| Twine::utohexstr(DynamicPhdr->p_offset) + ") + file size (0x" + |
| Twine::utohexstr(DynamicPhdr->p_filesz) + |
| ") exceeds the size of the file (0x" + |
| Twine::utohexstr(ObjF.getMemoryBufferRef().getBufferSize()) + ")"); |
| // Don't use the broken dynamic header. |
| DynamicPhdr = nullptr; |
| } |
| |
| if (DynamicPhdr && DynamicSec) { |
| if (DynamicSec->sh_addr + DynamicSec->sh_size > |
| DynamicPhdr->p_vaddr + DynamicPhdr->p_memsz || |
| DynamicSec->sh_addr < DynamicPhdr->p_vaddr) |
| reportUniqueWarning(describe(*DynamicSec) + |
| " is not contained within the " |
| "PT_DYNAMIC segment"); |
| |
| if (DynamicSec->sh_addr != DynamicPhdr->p_vaddr) |
| reportUniqueWarning(describe(*DynamicSec) + " is not at the start of " |
| "PT_DYNAMIC segment"); |
| } |
| |
| return std::make_pair(DynamicPhdr, DynamicSec); |
| } |
| |
| template <typename ELFT> |
| void ELFDumper<ELFT>::loadDynamicTable() { |
| const Elf_Phdr *DynamicPhdr; |
| const Elf_Shdr *DynamicSec; |
| std::tie(DynamicPhdr, DynamicSec) = findDynamic(); |
| if (!DynamicPhdr && !DynamicSec) |
| return; |
| |
| DynRegionInfo FromPhdr(ObjF, *this); |
| bool IsPhdrTableValid = false; |
| if (DynamicPhdr) { |
| // Use cantFail(), because p_offset/p_filesz fields of a PT_DYNAMIC are |
| // validated in findDynamic() and so createDRI() is not expected to fail. |
| FromPhdr = cantFail(createDRI(DynamicPhdr->p_offset, DynamicPhdr->p_filesz, |
| sizeof(Elf_Dyn))); |
| FromPhdr.SizePrintName = "PT_DYNAMIC size"; |
| FromPhdr.EntSizePrintName = ""; |
| IsPhdrTableValid = !FromPhdr.template getAsArrayRef<Elf_Dyn>().empty(); |
| } |
| |
| // Locate the dynamic table described in a section header. |
| // Ignore sh_entsize and use the expected value for entry size explicitly. |
| // This allows us to dump dynamic sections with a broken sh_entsize |
| // field. |
| DynRegionInfo FromSec(ObjF, *this); |
| bool IsSecTableValid = false; |
| if (DynamicSec) { |
| Expected<DynRegionInfo> RegOrErr = |
| createDRI(DynamicSec->sh_offset, DynamicSec->sh_size, sizeof(Elf_Dyn)); |
| if (RegOrErr) { |
| FromSec = *RegOrErr; |
| FromSec.Context = describe(*DynamicSec); |
| FromSec.EntSizePrintName = ""; |
| IsSecTableValid = !FromSec.template getAsArrayRef<Elf_Dyn>().empty(); |
| } else { |
| reportUniqueWarning("unable to read the dynamic table from " + |
| describe(*DynamicSec) + ": " + |
| toString(RegOrErr.takeError())); |
| } |
| } |
| |
| // When we only have information from one of the SHT_DYNAMIC section header or |
| // PT_DYNAMIC program header, just use that. |
| if (!DynamicPhdr || !DynamicSec) { |
| if ((DynamicPhdr && IsPhdrTableValid) || (DynamicSec && IsSecTableValid)) { |
| DynamicTable = DynamicPhdr ? FromPhdr : FromSec; |
| parseDynamicTable(); |
| } else { |
| reportUniqueWarning("no valid dynamic table was found"); |
| } |
| return; |
| } |
| |
| // At this point we have tables found from the section header and from the |
| // dynamic segment. Usually they match, but we have to do sanity checks to |
| // verify that. |
| |
| if (FromPhdr.Addr != FromSec.Addr) |
| reportUniqueWarning("SHT_DYNAMIC section header and PT_DYNAMIC " |
| "program header disagree about " |
| "the location of the dynamic table"); |
| |
| if (!IsPhdrTableValid && !IsSecTableValid) { |
| reportUniqueWarning("no valid dynamic table was found"); |
| return; |
| } |
| |
| // Information in the PT_DYNAMIC program header has priority over the |
| // information in a section header. |
| if (IsPhdrTableValid) { |
| if (!IsSecTableValid) |
| reportUniqueWarning( |
| "SHT_DYNAMIC dynamic table is invalid: PT_DYNAMIC will be used"); |
| DynamicTable = FromPhdr; |
| } else { |
| reportUniqueWarning( |
| "PT_DYNAMIC dynamic table is invalid: SHT_DYNAMIC will be used"); |
| DynamicTable = FromSec; |
| } |
| |
| parseDynamicTable(); |
| } |
| |
| template <typename ELFT> |
| ELFDumper<ELFT>::ELFDumper(const object::ELFObjectFile<ELFT> &O, |
| ScopedPrinter &Writer) |
| : ObjDumper(Writer, O.getFileName()), ObjF(O), Obj(O.getELFFile()), |
| FileName(O.getFileName()), DynRelRegion(O, *this), |
| DynRelaRegion(O, *this), DynRelrRegion(O, *this), |
| DynPLTRelRegion(O, *this), DynSymTabShndxRegion(O, *this), |
| DynamicTable(O, *this) { |
| if (!O.IsContentValid()) |
| return; |
| |
| typename ELFT::ShdrRange Sections = cantFail(Obj.sections()); |
| for (const Elf_Shdr &Sec : Sections) { |
| switch (Sec.sh_type) { |
| case ELF::SHT_SYMTAB: |
| if (!DotSymtabSec) |
| DotSymtabSec = &Sec; |
| break; |
| case ELF::SHT_DYNSYM: |
| if (!DotDynsymSec) |
| DotDynsymSec = &Sec; |
| |
| if (!DynSymRegion) { |
| Expected<DynRegionInfo> RegOrErr = |
| createDRI(Sec.sh_offset, Sec.sh_size, Sec.sh_entsize); |
| if (RegOrErr) { |
| DynSymRegion = *RegOrErr; |
| DynSymRegion->Context = describe(Sec); |
| |
| if (Expected<StringRef> E = Obj.getStringTableForSymtab(Sec)) |
| DynamicStringTable = *E; |
| else |
| reportUniqueWarning("unable to get the string table for the " + |
| describe(Sec) + ": " + toString(E.takeError())); |
| } else { |
| reportUniqueWarning("unable to read dynamic symbols from " + |
| describe(Sec) + ": " + |
| toString(RegOrErr.takeError())); |
| } |
| } |
| break; |
| case ELF::SHT_SYMTAB_SHNDX: { |
| uint32_t SymtabNdx = Sec.sh_link; |
| if (SymtabNdx >= Sections.size()) { |
| reportUniqueWarning( |
| "unable to get the associated symbol table for " + describe(Sec) + |
| ": sh_link (" + Twine(SymtabNdx) + |
| ") is greater than or equal to the total number of sections (" + |
| Twine(Sections.size()) + ")"); |
| continue; |
| } |
| |
| if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr = |
| Obj.getSHNDXTable(Sec)) { |
| if (!ShndxTables.insert({&Sections[SymtabNdx], *ShndxTableOrErr}) |
| .second) |
| reportUniqueWarning( |
| "multiple SHT_SYMTAB_SHNDX sections are linked to " + |
| describe(Sec)); |
| } else { |
| reportUniqueWarning(ShndxTableOrErr.takeError()); |
| } |
| break; |
| } |
| case ELF::SHT_GNU_versym: |
| if (!SymbolVersionSection) |
| SymbolVersionSection = &Sec; |
| break; |
| case ELF::SHT_GNU_verdef: |
| if (!SymbolVersionDefSection) |
| SymbolVersionDefSection = &Sec; |
| break; |
| case ELF::SHT_GNU_verneed: |
| if (!SymbolVersionNeedSection) |
| SymbolVersionNeedSection = &Sec; |
| break; |
| case ELF::SHT_LLVM_ADDRSIG: |
| if (!DotAddrsigSec) |
| DotAddrsigSec = &Sec; |
| break; |
| } |
| } |
| |
| loadDynamicTable(); |
| } |
| |
| template <typename ELFT> void ELFDumper<ELFT>::parseDynamicTable() { |
| auto toMappedAddr = [&](uint64_t Tag, uint64_t VAddr) -> const uint8_t * { |
| auto MappedAddrOrError = Obj.toMappedAddr(VAddr, [&](const Twine &Msg) { |
| this->reportUniqueWarning(Msg); |
| return Error::success(); |
| }); |
| if (!MappedAddrOrError) { |
| this->reportUniqueWarning("unable to parse DT_" + |
| Obj.getDynamicTagAsString(Tag) + ": " + |
| llvm::toString(MappedAddrOrError.takeError())); |
| return nullptr; |
| } |
| return MappedAddrOrError.get(); |
| }; |
| |
| const char *StringTableBegin = nullptr; |
| uint64_t StringTableSize = 0; |
| std::optional<DynRegionInfo> DynSymFromTable; |
| for (const Elf_Dyn &Dyn : dynamic_table()) { |
| switch (Dyn.d_tag) { |
| case ELF::DT_HASH: |
| 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.getTag(), Dyn.getPtr())); |
| break; |
| case ELF::DT_STRTAB: |
| StringTableBegin = reinterpret_cast<const char *>( |
| toMappedAddr(Dyn.getTag(), Dyn.getPtr())); |
| break; |
| case ELF::DT_STRSZ: |
| StringTableSize = Dyn.getVal(); |
| break; |
| case ELF::DT_SYMTAB: { |
| // If we can't map the DT_SYMTAB value to an address (e.g. when there are |
| // no program headers), we ignore its value. |
| if (const uint8_t *VA = toMappedAddr(Dyn.getTag(), Dyn.getPtr())) { |
| DynSymFromTable.emplace(ObjF, *this); |
| DynSymFromTable->Addr = VA; |
| DynSymFromTable->EntSize = sizeof(Elf_Sym); |
| DynSymFromTable->EntSizePrintName = ""; |
| } |
| break; |
| } |
| case ELF::DT_SYMENT: { |
| uint64_t Val = Dyn.getVal(); |
| if (Val != sizeof(Elf_Sym)) |
| this->reportUniqueWarning("DT_SYMENT value of 0x" + |
| Twine::utohexstr(Val) + |
| " is not the size of a symbol (0x" + |
| Twine::utohexstr(sizeof(Elf_Sym)) + ")"); |
| break; |
| } |
| case ELF::DT_RELA: |
| DynRelaRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); |
| break; |
| case ELF::DT_RELASZ: |
| DynRelaRegion.Size = Dyn.getVal(); |
| DynRelaRegion.SizePrintName = "DT_RELASZ value"; |
| break; |
| case ELF::DT_RELAENT: |
| DynRelaRegion.EntSize = Dyn.getVal(); |
| DynRelaRegion.EntSizePrintName = "DT_RELAENT value"; |
| break; |
| case ELF::DT_SONAME: |
| SONameOffset = Dyn.getVal(); |
| break; |
| case ELF::DT_REL: |
| DynRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); |
| break; |
| case ELF::DT_RELSZ: |
| DynRelRegion.Size = Dyn.getVal(); |
| DynRelRegion.SizePrintName = "DT_RELSZ value"; |
| break; |
| case ELF::DT_RELENT: |
| DynRelRegion.EntSize = Dyn.getVal(); |
| DynRelRegion.EntSizePrintName = "DT_RELENT value"; |
| break; |
| case ELF::DT_RELR: |
| case ELF::DT_ANDROID_RELR: |
| DynRelrRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); |
| break; |
| case ELF::DT_RELRSZ: |
| case ELF::DT_ANDROID_RELRSZ: |
| DynRelrRegion.Size = Dyn.getVal(); |
| DynRelrRegion.SizePrintName = Dyn.d_tag == ELF::DT_RELRSZ |
| ? "DT_RELRSZ value" |
| : "DT_ANDROID_RELRSZ value"; |
| break; |
| case ELF::DT_RELRENT: |
| case ELF::DT_ANDROID_RELRENT: |
| DynRelrRegion.EntSize = Dyn.getVal(); |
| DynRelrRegion.EntSizePrintName = Dyn.d_tag == ELF::DT_RELRENT |
| ? "DT_RELRENT value" |
| : "DT_ANDROID_RELRENT value"; |
| break; |
| case ELF::DT_PLTREL: |
| if (Dyn.getVal() == DT_REL) |
| DynPLTRelRegion.EntSize = sizeof(Elf_Rel); |
| else if (Dyn.getVal() == DT_RELA) |
| DynPLTRelRegion.EntSize = sizeof(Elf_Rela); |
| else |
| reportUniqueWarning(Twine("unknown DT_PLTREL value of ") + |
| Twine((uint64_t)Dyn.getVal())); |
| DynPLTRelRegion.EntSizePrintName = "PLTREL entry size"; |
| break; |
| case ELF::DT_JMPREL: |
| DynPLTRelRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); |
| break; |
| case ELF::DT_PLTRELSZ: |
| DynPLTRelRegion.Size = Dyn.getVal(); |
| DynPLTRelRegion.SizePrintName = "DT_PLTRELSZ value"; |
| break; |
| case ELF::DT_SYMTAB_SHNDX: |
| DynSymTabShndxRegion.Addr = toMappedAddr(Dyn.getTag(), Dyn.getPtr()); |
| DynSymTabShndxRegion.EntSize = sizeof(Elf_Word); |
| break; |
| } |
| } |
| |
| if (StringTableBegin) { |
| const uint64_t FileSize = Obj.getBufSize(); |
| const uint64_t Offset = (const uint8_t *)StringTableBegin - Obj.base(); |
| if (StringTableSize > FileSize - Offset) |
| reportUniqueWarning( |
| "the dynamic string table at 0x" + Twine::utohexstr(Offset) + |
| " goes past the end of the file (0x" + Twine::utohexstr(FileSize) + |
| ") with DT_STRSZ = 0x" + Twine::utohexstr(StringTableSize)); |
| else |
| DynamicStringTable = StringRef(StringTableBegin, StringTableSize); |
| } |
| |
| const bool IsHashTableSupported = getHashTableEntSize() == 4; |
| if (DynSymRegion) { |
| // Often we find the information about the dynamic symbol table |
| // location in the SHT_DYNSYM section header. However, the value in |
| // DT_SYMTAB has priority, because it is used by dynamic loaders to |
| // locate .dynsym at runtime. The location we find in the section header |
| // and the location we find here should match. |
| if (DynSymFromTable && DynSymFromTable->Addr != DynSymRegion->Addr) |
| reportUniqueWarning( |
| createError("SHT_DYNSYM section header and DT_SYMTAB disagree about " |
| "the location of the dynamic symbol table")); |
| |
| // According to the ELF gABI: "The number of symbol table entries should |
| // equal nchain". Check to see if the DT_HASH hash table nchain value |
| // conflicts with the number of symbols in the dynamic symbol table |
| // according to the section header. |
| if (HashTable && IsHashTableSupported) { |
| if (DynSymRegion->EntSize == 0) |
| reportUniqueWarning("SHT_DYNSYM section has sh_entsize == 0"); |
| else if (HashTable->nchain != DynSymRegion->Size / DynSymRegion->EntSize) |
| reportUniqueWarning( |
| "hash table nchain (" + Twine(HashTable->nchain) + |
| ") differs from symbol count derived from SHT_DYNSYM section " |
| "header (" + |
| Twine(DynSymRegion->Size / DynSymRegion->EntSize) + ")"); |
| } |
| } |
| |
| // Delay the creation of the actual dynamic symbol table until now, so that |
| // checks can always be made against the section header-based properties, |
| // without worrying about tag order. |
| if (DynSymFromTable) { |
| if (!DynSymRegion) { |
| DynSymRegion = DynSymFromTable; |
| } else { |
| DynSymRegion->Addr = DynSymFromTable->Addr; |
| DynSymRegion->EntSize = DynSymFromTable->EntSize; |
| DynSymRegion->EntSizePrintName = DynSymFromTable->EntSizePrintName; |
| } |
| } |
| |
| // Derive the dynamic symbol table size from the DT_HASH hash table, if |
| // present. |
| if (HashTable && IsHashTableSupported && DynSymRegion) { |
| const uint64_t FileSize = Obj.getBufSize(); |
| const uint64_t DerivedSize = |
| (uint64_t)HashTable->nchain * DynSymRegion->EntSize; |
| const uint64_t Offset = (const uint8_t *)DynSymRegion->Addr - Obj.base(); |
| if (DerivedSize > FileSize - Offset) |
| reportUniqueWarning( |
| "the size (0x" + Twine::utohexstr(DerivedSize) + |
| ") of the dynamic symbol table at 0x" + Twine::utohexstr(Offset) + |
| ", derived from the hash table, goes past the end of the file (0x" + |
| Twine::utohexstr(FileSize) + ") and will be ignored"); |
| else |
| DynSymRegion->Size = HashTable->nchain * DynSymRegion->EntSize; |
| } |
| } |
| |
| template <typename ELFT> void ELFDumper<ELFT>::printVersionInfo() { |
| // Dump version symbol section. |
| printVersionSymbolSection(SymbolVersionSection); |
| |
| // Dump version definition section. |
| printVersionDefinitionSection(SymbolVersionDefSection); |
| |
| // Dump version dependency section. |
| printVersionDependencySection(SymbolVersionNeedSection); |
| } |
| |
| #define LLVM_READOBJ_DT_FLAG_ENT(prefix, enum) \ |
| { #enum, prefix##_##enum } |
| |
| const EnumEntry<unsigned> ElfDynamicDTFlags[] = { |
| LLVM_READOBJ_DT_FLAG_ENT(DF, ORIGIN), |
| LLVM_READOBJ_DT_FLAG_ENT(DF, SYMBOLIC), |
| LLVM_READOBJ_DT_FLAG_ENT(DF, TEXTREL), |
| LLVM_READOBJ_DT_FLAG_ENT(DF, BIND_NOW), |
| LLVM_READOBJ_DT_FLAG_ENT(DF, STATIC_TLS) |
| }; |
| |
| const EnumEntry<unsigned> ElfDynamicDTFlags1[] = { |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOW), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAL), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, GROUP), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODELETE), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, LOADFLTR), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, INITFIRST), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOOPEN), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, ORIGIN), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, DIRECT), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, TRANS), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, INTERPOSE), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODEFLIB), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, NODUMP), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, CONFALT), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, ENDFILTEE), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, DISPRELDNE), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, 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), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, NOHDR), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, EDITED), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, NORELOC), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, SYMINTPOSE), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, GLOBAUDIT), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, SINGLETON), |
| LLVM_READOBJ_DT_FLAG_ENT(DF_1, PIE), |
| }; |
| |
| const EnumEntry<unsigned> ElfDynamicDTMipsFlags[] = { |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, NONE), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, QUICKSTART), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, NOTPOT), |
| LLVM_READOBJ_DT_FLAG_ENT(RHS, NO_LIBRARY_REPLACEMENT), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, NO_MOVE), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, SGI_ONLY), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, GUARANTEE_INIT), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, DELTA_C_PLUS_PLUS), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, GUARANTEE_START_INIT), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, PIXIE), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, DEFAULT_DELAY_LOAD), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, REQUICKSTART), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, REQUICKSTARTED), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, CORD), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, NO_UNRES_UNDEF), |
| LLVM_READOBJ_DT_FLAG_ENT(RHF, RLD_ORDER_SAFE) |
| }; |
| |
| #undef LLVM_READOBJ_DT_FLAG_ENT |
| |
| template <typename T, typename TFlag> |
| void printFlags(T Value, ArrayRef<EnumEntry<TFlag>> Flags, raw_ostream &OS) { |
| SmallVector<EnumEntry<TFlag>, 10> SetFlags; |
| for (const EnumEntry<TFlag> &Flag : Flags) |
| if (Flag.Value != 0 && (Value & Flag.Value) == Flag.Value) |
| SetFlags.push_back(Flag); |
| |
| for (const EnumEntry<TFlag> &Flag : SetFlags) |
| OS << Flag.Name << " "; |
| } |
| |
| template <class ELFT> |
| const typename ELFT::Shdr * |
| ELFDumper<ELFT>::findSectionByName(StringRef Name) const { |
| for (const Elf_Shdr &Shdr : cantFail(Obj.sections())) { |
| if (Expected<StringRef> NameOrErr = Obj.getSectionName(Shdr)) { |
| if (*NameOrErr == Name) |
| return &Shdr; |
| } else { |
| reportUniqueWarning("unable to read the name of " + describe(Shdr) + |
| ": " + toString(NameOrErr.takeError())); |
| } |
| } |
| return nullptr; |
| } |
| |
| template <class ELFT> |
| std::string ELFDumper<ELFT>::getDynamicEntry(uint64_t Type, |
| uint64_t Value) const { |
| auto FormatHexValue = [](uint64_t V) { |
| std::string Str; |
| raw_string_ostream OS(Str); |
| const char *ConvChar = |
| (opts::Output == opts::GNU) ? "0x%" PRIx64 : "0x%" PRIX64; |
| OS << format(ConvChar, V); |
| return OS.str(); |
| }; |
| |
| auto FormatFlags = [](uint64_t V, |
| llvm::ArrayRef<llvm::EnumEntry<unsigned int>> Array) { |
| std::string Str; |
| raw_string_ostream OS(Str); |
| printFlags(V, Array, OS); |
| return OS.str(); |
| }; |
| |
| // Handle custom printing of architecture specific tags |
| switch (Obj.getHeader().e_machine) { |
| case EM_AARCH64: |
| switch (Type) { |
| case DT_AARCH64_BTI_PLT: |
| case DT_AARCH64_PAC_PLT: |
| case DT_AARCH64_VARIANT_PCS: |
| case DT_AARCH64_MEMTAG_GLOBALSSZ: |
| return std::to_string(Value); |
| case DT_AARCH64_MEMTAG_MODE: |
| switch (Value) { |
| case 0: |
| return "Synchronous (0)"; |
| case 1: |
| return "Asynchronous (1)"; |
| default: |
| return (Twine("Unknown (") + Twine(Value) + ")").str(); |
| } |
| case DT_AARCH64_MEMTAG_HEAP: |
| case DT_AARCH64_MEMTAG_STACK: |
| switch (Value) { |
| case 0: |
| return "Disabled (0)"; |
| case 1: |
| return "Enabled (1)"; |
| default: |
| return (Twine("Unknown (") + Twine(Value) + ")").str(); |
| } |
| case DT_AARCH64_MEMTAG_GLOBALS: |
| return (Twine("0x") + utohexstr(Value, /*LowerCase=*/true)).str(); |
| default: |
| break; |
| } |
| break; |
| case EM_HEXAGON: |
| switch (Type) { |
| case DT_HEXAGON_VER: |
| return std::to_string(Value); |
| case DT_HEXAGON_SYMSZ: |
| case DT_HEXAGON_PLT: |
| return FormatHexValue(Value); |
| 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: |
| return std::to_string(Value); |
| 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: |
| case DT_MIPS_XHASH: |
| return FormatHexValue(Value); |
| case DT_MIPS_FLAGS: |
| return FormatFlags(Value, ArrayRef(ElfDynamicDTMipsFlags)); |
| default: |
| break; |
| } |
| break; |
| default: |
| break; |
| } |
| |
| switch (Type) { |
| case DT_PLTREL: |
| if (Value == DT_REL) |
| return "REL"; |
| if (Value == DT_RELA) |
| return "RELA"; |
| [[fallthrough]]; |
| case DT_PLTGOT: |
| case DT_HASH: |
| case DT_STRTAB: |
| case DT_SYMTAB: |
| case DT_RELA: |
| case DT_INIT: |
| case DT_FINI: |
| case DT_REL: |
| case DT_JMPREL: |
| case DT_INIT_ARRAY: |
| case DT_FINI_ARRAY: |
| case DT_PREINIT_ARRAY: |
| case DT_DEBUG: |
| case DT_VERDEF: |
| case DT_VERNEED: |
| case DT_VERSYM: |
| case DT_GNU_HASH: |
| case DT_NULL: |
| return FormatHexValue(Value); |
| case DT_RELACOUNT: |
| case DT_RELCOUNT: |
| case DT_VERDEFNUM: |
| case DT_VERNEEDNUM: |
| return std::to_string(Value); |
| case DT_PLTRELSZ: |
| case DT_RELASZ: |
| case DT_RELAENT: |
| case DT_STRSZ: |
| case DT_SYMENT: |
| case DT_RELSZ: |
| case DT_RELENT: |
| case DT_INIT_ARRAYSZ: |
| case DT_FINI_ARRAYSZ: |
| case DT_PREINIT_ARRAYSZ: |
| case DT_RELRSZ: |
| case DT_RELRENT: |
| case DT_ANDROID_RELSZ: |
| case DT_ANDROID_RELASZ: |
| return std::to_string(Value) + " (bytes)"; |
| case DT_NEEDED: |
| case DT_SONAME: |
| case DT_AUXILIARY: |
| case DT_USED: |
| case DT_FILTER: |
| case DT_RPATH: |
| 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"}, |
| }; |
| |
| return (Twine(TagNames.at(Type)) + ": [" + getDynamicString(Value) + "]") |
| .str(); |
| } |
| case DT_FLAGS: |
| return FormatFlags(Value, ArrayRef(ElfDynamicDTFlags)); |
| case DT_FLAGS_1: |
| return FormatFlags(Value, ArrayRef(ElfDynamicDTFlags1)); |
| default: |
| return FormatHexValue(Value); |
| } |
| } |
| |
| template <class ELFT> |
| StringRef ELFDumper<ELFT>::getDynamicString(uint64_t Value) const { |
| if (DynamicStringTable.empty() && !DynamicStringTable.data()) { |
| reportUniqueWarning("string table was not found"); |
| return "<?>"; |
| } |
| |
| auto WarnAndReturn = [this](const Twine &Msg, uint64_t Offset) { |
| reportUniqueWarning("string table at offset 0x" + Twine::utohexstr(Offset) + |
| Msg); |
| return "<?>"; |
| }; |
| |
| const uint64_t FileSize = Obj.getBufSize(); |
| const uint64_t Offset = |
| (const uint8_t *)DynamicStringTable.data() - Obj.base(); |
| if (DynamicStringTable.size() > FileSize - Offset) |
| return WarnAndReturn(" with size 0x" + |
| Twine::utohexstr(DynamicStringTable.size()) + |
| " goes past the end of the file (0x" + |
| Twine::utohexstr(FileSize) + ")", |
| Offset); |
| |
| if (Value >= DynamicStringTable.size()) |
| return WarnAndReturn( |
| ": unable to read the string at 0x" + Twine::utohexstr(Offset + Value) + |
| ": it goes past the end of the table (0x" + |
| Twine::utohexstr(Offset + DynamicStringTable.size()) + ")", |
| Offset); |
| |
| if (DynamicStringTable.back() != '\0') |
| return WarnAndReturn(": unable to read the string at 0x" + |
| Twine::utohexstr(Offset + Value) + |
| ": the string table is not null-terminated", |
| Offset); |
| |
| return DynamicStringTable.data() + Value; |
| } |
| |
| template <class ELFT> void ELFDumper<ELFT>::printUnwindInfo() { |
| DwarfCFIEH::PrinterContext<ELFT> Ctx(W, ObjF); |
| Ctx.printUnwindInformation(); |
| } |
| |
| // The namespace is needed to fix the compilation with GCC older than 7.0+. |
| namespace { |
| template <> void ELFDumper<ELF32LE>::printUnwindInfo() { |
| if (Obj.getHeader().e_machine == EM_ARM) { |
| ARM::EHABI::PrinterContext<ELF32LE> Ctx(W, Obj, ObjF.getFileName(), |
| DotSymtabSec); |
| Ctx.PrintUnwindInformation(); |
| } |
| DwarfCFIEH::PrinterContext<ELF32LE> Ctx(W, ObjF); |
| Ctx.printUnwindInformation(); |
| } |
| } // namespace |
| |
| template <class ELFT> void ELFDumper<ELFT>::printNeededLibraries() { |
| ListScope D(W, "NeededLibraries"); |
| |
| std::vector<StringRef> Libs; |
| for (const auto &Entry : dynamic_table()) |
| if (Entry.d_tag == ELF::DT_NEEDED) |
| Libs.push_back(getDynamicString(Entry.d_un.d_val)); |
| |
| llvm::sort(Libs); |
| |
| for (StringRef L : Libs) |
| W.startLine() << L << "\n"; |
| } |
| |
| template <class ELFT> |
| static Error checkHashTable(const ELFDumper<ELFT> &Dumper, |
| const typename ELFT::Hash *H, |
| bool *IsHeaderValid = nullptr) { |
| const ELFFile<ELFT> &Obj = Dumper.getElfObject().getELFFile(); |
| const uint64_t SecOffset = (const uint8_t *)H - Obj.base(); |
| if (Dumper.getHashTableEntSize() == 8) { |
| auto It = llvm::find_if(ElfMachineType, [&](const EnumEntry<unsigned> &E) { |
| return E.Value == Obj.getHeader().e_machine; |
| }); |
| if (IsHeaderValid) |
| *IsHeaderValid = false; |
| return createError("the hash table at 0x" + Twine::utohexstr(SecOffset) + |
| " is not supported: it contains non-standard 8 " |
| "byte entries on " + |
| It->AltName + " platform"); |
| } |
| |
| auto MakeError = [&](const Twine &Msg = "") { |
| return createError("the hash table at offset 0x" + |
| Twine::utohexstr(SecOffset) + |
| " goes past the end of the file (0x" + |
| Twine::utohexstr(Obj.getBufSize()) + ")" + Msg); |
| }; |
| |
| // Each SHT_HASH section starts from two 32-bit fields: nbucket and nchain. |
| const unsigned HeaderSize = 2 * sizeof(typename ELFT::Word); |
| |
| if (IsHeaderValid) |
| *IsHeaderValid = Obj.getBufSize() - SecOffset >= HeaderSize; |
| |
| if (Obj.getBufSize() - |