//===- ELF.h - ELF object file implementation -------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file declares the ELFObjectFile template class. // //===----------------------------------------------------------------------===// #ifndef LLVM_OBJECT_ELF_H #define LLVM_OBJECT_ELF_H #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include #include #include namespace llvm { namespace object { // Subclasses of ELFObjectFile may need this for template instantiation inline std::pair getElfArchType(MemoryBuffer *Object) { if (Object->getBufferSize() < ELF::EI_NIDENT) return std::make_pair((uint8_t)ELF::ELFCLASSNONE,(uint8_t)ELF::ELFDATANONE); return std::make_pair( (uint8_t)Object->getBufferStart()[ELF::EI_CLASS] , (uint8_t)Object->getBufferStart()[ELF::EI_DATA]); } // Templates to choose Elf_Addr and Elf_Off depending on is64Bits. template struct ELFDataTypeTypedefHelperCommon { typedef support::detail::packed_endian_specific_integral Elf_Half; typedef support::detail::packed_endian_specific_integral Elf_Word; typedef support::detail::packed_endian_specific_integral Elf_Sword; typedef support::detail::packed_endian_specific_integral Elf_Xword; typedef support::detail::packed_endian_specific_integral Elf_Sxword; }; template struct ELFDataTypeTypedefHelper; /// ELF 32bit types. template struct ELFDataTypeTypedefHelper : ELFDataTypeTypedefHelperCommon { typedef uint32_t value_type; typedef support::detail::packed_endian_specific_integral Elf_Addr; typedef support::detail::packed_endian_specific_integral Elf_Off; }; /// ELF 64bit types. template struct ELFDataTypeTypedefHelper : ELFDataTypeTypedefHelperCommon{ typedef uint64_t value_type; typedef support::detail::packed_endian_specific_integral Elf_Addr; typedef support::detail::packed_endian_specific_integral Elf_Off; }; // I really don't like doing this, but the alternative is copypasta. #define LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) \ typedef typename \ ELFDataTypeTypedefHelper::Elf_Addr Elf_Addr; \ typedef typename \ ELFDataTypeTypedefHelper::Elf_Off Elf_Off; \ typedef typename \ ELFDataTypeTypedefHelper::Elf_Half Elf_Half; \ typedef typename \ ELFDataTypeTypedefHelper::Elf_Word Elf_Word; \ typedef typename \ ELFDataTypeTypedefHelper::Elf_Sword Elf_Sword; \ typedef typename \ ELFDataTypeTypedefHelper::Elf_Xword Elf_Xword; \ typedef typename \ ELFDataTypeTypedefHelper::Elf_Sxword Elf_Sxword; // Section header. template struct Elf_Shdr_Base; template struct Elf_Shdr_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, false) Elf_Word sh_name; // Section name (index into string table) Elf_Word sh_type; // Section type (SHT_*) Elf_Word sh_flags; // Section flags (SHF_*) Elf_Addr sh_addr; // Address where section is to be loaded Elf_Off sh_offset; // File offset of section data, in bytes Elf_Word sh_size; // Size of section, in bytes Elf_Word sh_link; // Section type-specific header table index link Elf_Word sh_info; // Section type-specific extra information Elf_Word sh_addralign;// Section address alignment Elf_Word sh_entsize; // Size of records contained within the section }; template struct Elf_Shdr_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, true) Elf_Word sh_name; // Section name (index into string table) Elf_Word sh_type; // Section type (SHT_*) Elf_Xword sh_flags; // Section flags (SHF_*) Elf_Addr sh_addr; // Address where section is to be loaded Elf_Off sh_offset; // File offset of section data, in bytes Elf_Xword sh_size; // Size of section, in bytes Elf_Word sh_link; // Section type-specific header table index link Elf_Word sh_info; // Section type-specific extra information Elf_Xword sh_addralign;// Section address alignment Elf_Xword sh_entsize; // Size of records contained within the section }; template struct Elf_Shdr_Impl : Elf_Shdr_Base { using Elf_Shdr_Base::sh_entsize; using Elf_Shdr_Base::sh_size; /// @brief Get the number of entities this section contains if it has any. unsigned getEntityCount() const { if (sh_entsize == 0) return 0; return sh_size / sh_entsize; } }; template struct Elf_Sym_Base; template struct Elf_Sym_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, false) Elf_Word st_name; // Symbol name (index into string table) Elf_Addr st_value; // Value or address associated with the symbol Elf_Word st_size; // Size of the symbol unsigned char st_info; // Symbol's type and binding attributes unsigned char st_other; // Must be zero; reserved Elf_Half st_shndx; // Which section (header table index) it's defined in }; template struct Elf_Sym_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, true) Elf_Word st_name; // Symbol name (index into string table) unsigned char st_info; // Symbol's type and binding attributes unsigned char st_other; // Must be zero; reserved Elf_Half st_shndx; // Which section (header table index) it's defined in Elf_Addr st_value; // Value or address associated with the symbol Elf_Xword st_size; // Size of the symbol }; template struct Elf_Sym_Impl : Elf_Sym_Base { using Elf_Sym_Base::st_info; // These accessors and mutators correspond to the ELF32_ST_BIND, // ELF32_ST_TYPE, and ELF32_ST_INFO macros defined in the ELF specification: unsigned char getBinding() const { return st_info >> 4; } unsigned char getType() const { return st_info & 0x0f; } void setBinding(unsigned char b) { setBindingAndType(b, getType()); } void setType(unsigned char t) { setBindingAndType(getBinding(), t); } void setBindingAndType(unsigned char b, unsigned char t) { st_info = (b << 4) + (t & 0x0f); } }; /// Elf_Versym: This is the structure of entries in the SHT_GNU_versym section /// (.gnu.version). This structure is identical for ELF32 and ELF64. template struct Elf_Versym_Impl { LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) Elf_Half vs_index; // Version index with flags (e.g. VERSYM_HIDDEN) }; template struct Elf_Verdaux_Impl; /// Elf_Verdef: This is the structure of entries in the SHT_GNU_verdef section /// (.gnu.version_d). This structure is identical for ELF32 and ELF64. template struct Elf_Verdef_Impl { LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) typedef Elf_Verdaux_Impl Elf_Verdaux; Elf_Half vd_version; // Version of this structure (e.g. VER_DEF_CURRENT) Elf_Half vd_flags; // Bitwise flags (VER_DEF_*) Elf_Half vd_ndx; // Version index, used in .gnu.version entries Elf_Half vd_cnt; // Number of Verdaux entries Elf_Word vd_hash; // Hash of name Elf_Word vd_aux; // Offset to the first Verdaux entry (in bytes) Elf_Word vd_next; // Offset to the next Verdef entry (in bytes) /// Get the first Verdaux entry for this Verdef. const Elf_Verdaux *getAux() const { return reinterpret_cast((const char*)this + vd_aux); } }; /// Elf_Verdaux: This is the structure of auxiliary data in the SHT_GNU_verdef /// section (.gnu.version_d). This structure is identical for ELF32 and ELF64. template struct Elf_Verdaux_Impl { LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) Elf_Word vda_name; // Version name (offset in string table) Elf_Word vda_next; // Offset to next Verdaux entry (in bytes) }; /// Elf_Verneed: This is the structure of entries in the SHT_GNU_verneed /// section (.gnu.version_r). This structure is identical for ELF32 and ELF64. template struct Elf_Verneed_Impl { LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) Elf_Half vn_version; // Version of this structure (e.g. VER_NEED_CURRENT) Elf_Half vn_cnt; // Number of associated Vernaux entries Elf_Word vn_file; // Library name (string table offset) Elf_Word vn_aux; // Offset to first Vernaux entry (in bytes) Elf_Word vn_next; // Offset to next Verneed entry (in bytes) }; /// Elf_Vernaux: This is the structure of auxiliary data in SHT_GNU_verneed /// section (.gnu.version_r). This structure is identical for ELF32 and ELF64. template struct Elf_Vernaux_Impl { LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) Elf_Word vna_hash; // Hash of dependency name Elf_Half vna_flags; // Bitwise Flags (VER_FLAG_*) Elf_Half vna_other; // Version index, used in .gnu.version entries Elf_Word vna_name; // Dependency name Elf_Word vna_next; // Offset to next Vernaux entry (in bytes) }; /// Elf_Dyn_Base: This structure matches the form of entries in the dynamic /// table section (.dynamic) look like. template struct Elf_Dyn_Base; template struct Elf_Dyn_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, false) Elf_Sword d_tag; union { Elf_Word d_val; Elf_Addr d_ptr; } d_un; }; template struct Elf_Dyn_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, true) Elf_Sxword d_tag; union { Elf_Xword d_val; Elf_Addr d_ptr; } d_un; }; /// Elf_Dyn_Impl: This inherits from Elf_Dyn_Base, adding getters and setters. template struct Elf_Dyn_Impl : Elf_Dyn_Base { using Elf_Dyn_Base::d_tag; using Elf_Dyn_Base::d_un; int64_t getTag() const { return d_tag; } uint64_t getVal() const { return d_un.d_val; } uint64_t getPtr() const { return d_un.ptr; } }; template class ELFObjectFile; // DynRefImpl: Reference to an entry in the dynamic table // This is an ELF-specific interface. template class DynRefImpl { typedef Elf_Dyn_Impl Elf_Dyn; typedef ELFObjectFile OwningType; DataRefImpl DynPimpl; const OwningType *OwningObject; public: DynRefImpl() : OwningObject(NULL) { } DynRefImpl(DataRefImpl DynP, const OwningType *Owner); bool operator==(const DynRefImpl &Other) const; bool operator <(const DynRefImpl &Other) const; error_code getNext(DynRefImpl &Result) const; int64_t getTag() const; uint64_t getVal() const; uint64_t getPtr() const; DataRefImpl getRawDataRefImpl() const; }; // Elf_Rel: Elf Relocation template struct Elf_Rel_Base; template struct Elf_Rel_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, false) Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Word r_info; // Symbol table index and type of relocation to apply }; template struct Elf_Rel_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, true) Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Xword r_info; // Symbol table index and type of relocation to apply }; template struct Elf_Rel_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, false) Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Word r_info; // Symbol table index and type of relocation to apply Elf_Sword r_addend; // Compute value for relocatable field by adding this }; template struct Elf_Rel_Base { LLVM_ELF_IMPORT_TYPES(target_endianness, true) Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) Elf_Xword r_info; // Symbol table index and type of relocation to apply Elf_Sxword r_addend; // Compute value for relocatable field by adding this. }; template struct Elf_Rel_Impl; template struct Elf_Rel_Impl : Elf_Rel_Base { using Elf_Rel_Base::r_info; LLVM_ELF_IMPORT_TYPES(target_endianness, true) // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE, // and ELF64_R_INFO macros defined in the ELF specification: uint64_t getSymbol() const { return (r_info >> 32); } unsigned char getType() const { return (unsigned char) (r_info & 0xffffffffL); } void setSymbol(uint64_t s) { setSymbolAndType(s, getType()); } void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); } void setSymbolAndType(uint64_t s, unsigned char t) { r_info = (s << 32) + (t&0xffffffffL); } }; template struct Elf_Rel_Impl : Elf_Rel_Base { using Elf_Rel_Base::r_info; LLVM_ELF_IMPORT_TYPES(target_endianness, false) // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE, // and ELF32_R_INFO macros defined in the ELF specification: uint32_t getSymbol() const { return (r_info >> 8); } unsigned char getType() const { return (unsigned char) (r_info & 0x0ff); } void setSymbol(uint32_t s) { setSymbolAndType(s, getType()); } void setType(unsigned char t) { setSymbolAndType(getSymbol(), t); } void setSymbolAndType(uint32_t s, unsigned char t) { r_info = (s << 8) + t; } }; template class ELFObjectFile : public ObjectFile { LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) typedef Elf_Shdr_Impl Elf_Shdr; typedef Elf_Sym_Impl Elf_Sym; typedef Elf_Dyn_Impl Elf_Dyn; typedef Elf_Rel_Impl Elf_Rel; typedef Elf_Rel_Impl Elf_Rela; typedef Elf_Verdef_Impl Elf_Verdef; typedef Elf_Verdaux_Impl Elf_Verdaux; typedef Elf_Verneed_Impl Elf_Verneed; typedef Elf_Vernaux_Impl Elf_Vernaux; typedef Elf_Versym_Impl Elf_Versym; typedef DynRefImpl DynRef; typedef content_iterator dyn_iterator; protected: struct Elf_Ehdr { unsigned char e_ident[ELF::EI_NIDENT]; // ELF Identification bytes Elf_Half e_type; // Type of file (see ET_*) Elf_Half e_machine; // Required architecture for this file (see EM_*) Elf_Word e_version; // Must be equal to 1 Elf_Addr e_entry; // Address to jump to in order to start program Elf_Off e_phoff; // Program header table's file offset, in bytes Elf_Off e_shoff; // Section header table's file offset, in bytes Elf_Word e_flags; // Processor-specific flags Elf_Half e_ehsize; // Size of ELF header, in bytes Elf_Half e_phentsize;// Size of an entry in the program header table Elf_Half e_phnum; // Number of entries in the program header table Elf_Half e_shentsize;// Size of an entry in the section header table Elf_Half e_shnum; // Number of entries in the section header table Elf_Half e_shstrndx; // Section header table index of section name // string table bool checkMagic() const { return (memcmp(e_ident, ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0; } unsigned char getFileClass() const { return e_ident[ELF::EI_CLASS]; } unsigned char getDataEncoding() const { return e_ident[ELF::EI_DATA]; } }; // This flag is used for classof, to distinguish ELFObjectFile from // its subclass. If more subclasses will be created, this flag will // have to become an enum. bool isDyldELFObject; private: typedef SmallVector Sections_t; typedef DenseMap IndexMap_t; typedef DenseMap > RelocMap_t; const Elf_Ehdr *Header; const Elf_Shdr *SectionHeaderTable; const Elf_Shdr *dot_shstrtab_sec; // Section header string table. const Elf_Shdr *dot_strtab_sec; // Symbol header string table. const Elf_Shdr *dot_dynstr_sec; // Dynamic symbol string table. // SymbolTableSections[0] always points to the dynamic string table section // header, or NULL if there is no dynamic string table. Sections_t SymbolTableSections; IndexMap_t SymbolTableSectionsIndexMap; DenseMap ExtendedSymbolTable; const Elf_Shdr *dot_dynamic_sec; // .dynamic const Elf_Shdr *dot_gnu_version_sec; // .gnu.version const Elf_Shdr *dot_gnu_version_r_sec; // .gnu.version_r const Elf_Shdr *dot_gnu_version_d_sec; // .gnu.version_d // Pointer to SONAME entry in dynamic string table // This is set the first time getLoadName is called. mutable const char *dt_soname; // Records for each version index the corresponding Verdef or Vernaux entry. // This is filled the first time LoadVersionMap() is called. class VersionMapEntry : public PointerIntPair { public: // If the integer is 0, this is an Elf_Verdef*. // If the integer is 1, this is an Elf_Vernaux*. VersionMapEntry() : PointerIntPair(NULL, 0) { } VersionMapEntry(const Elf_Verdef *verdef) : PointerIntPair(verdef, 0) { } VersionMapEntry(const Elf_Vernaux *vernaux) : PointerIntPair(vernaux, 1) { } bool isNull() const { return getPointer() == NULL; } bool isVerdef() const { return !isNull() && getInt() == 0; } bool isVernaux() const { return !isNull() && getInt() == 1; } const Elf_Verdef *getVerdef() const { return isVerdef() ? (const Elf_Verdef*)getPointer() : NULL; } const Elf_Vernaux *getVernaux() const { return isVernaux() ? (const Elf_Vernaux*)getPointer() : NULL; } }; mutable SmallVector VersionMap; void LoadVersionDefs(const Elf_Shdr *sec) const; void LoadVersionNeeds(const Elf_Shdr *ec) const; void LoadVersionMap() const; /// @brief Map sections to an array of relocation sections that reference /// them sorted by section index. RelocMap_t SectionRelocMap; /// @brief Get the relocation section that contains \a Rel. const Elf_Shdr *getRelSection(DataRefImpl Rel) const { return getSection(Rel.w.b); } bool isRelocationHasAddend(DataRefImpl Rel) const; template const T *getEntry(uint16_t Section, uint32_t Entry) const; template const T *getEntry(const Elf_Shdr *Section, uint32_t Entry) const; const Elf_Shdr *getSection(DataRefImpl index) const; const Elf_Shdr *getSection(uint32_t index) const; const Elf_Rel *getRel(DataRefImpl Rel) const; const Elf_Rela *getRela(DataRefImpl Rela) const; const char *getString(uint32_t section, uint32_t offset) const; const char *getString(const Elf_Shdr *section, uint32_t offset) const; error_code getSymbolVersion(const Elf_Shdr *section, const Elf_Sym *Symb, StringRef &Version, bool &IsDefault) const; void VerifyStrTab(const Elf_Shdr *sh) const; protected: const Elf_Sym *getSymbol(DataRefImpl Symb) const; // FIXME: Should be private? void validateSymbol(DataRefImpl Symb) const; public: error_code getSymbolName(const Elf_Shdr *section, const Elf_Sym *Symb, StringRef &Res) const; error_code getSectionName(const Elf_Shdr *section, StringRef &Res) const; const Elf_Dyn *getDyn(DataRefImpl DynData) const; error_code getSymbolVersion(SymbolRef Symb, StringRef &Version, bool &IsDefault) const; protected: virtual error_code getSymbolNext(DataRefImpl Symb, SymbolRef &Res) const; virtual error_code getSymbolName(DataRefImpl Symb, StringRef &Res) const; virtual error_code getSymbolFileOffset(DataRefImpl Symb, uint64_t &Res) const; virtual error_code getSymbolAddress(DataRefImpl Symb, uint64_t &Res) const; virtual error_code getSymbolSize(DataRefImpl Symb, uint64_t &Res) const; virtual error_code getSymbolNMTypeChar(DataRefImpl Symb, char &Res) const; virtual error_code getSymbolFlags(DataRefImpl Symb, uint32_t &Res) const; virtual error_code getSymbolType(DataRefImpl Symb, SymbolRef::Type &Res) const; virtual error_code getSymbolSection(DataRefImpl Symb, section_iterator &Res) const; friend class DynRefImpl; virtual error_code getDynNext(DataRefImpl DynData, DynRef &Result) const; virtual error_code getLibraryNext(DataRefImpl Data, LibraryRef &Result) const; virtual error_code getLibraryPath(DataRefImpl Data, StringRef &Res) const; virtual error_code getSectionNext(DataRefImpl Sec, SectionRef &Res) const; virtual error_code getSectionName(DataRefImpl Sec, StringRef &Res) const; virtual error_code getSectionAddress(DataRefImpl Sec, uint64_t &Res) const; virtual error_code getSectionSize(DataRefImpl Sec, uint64_t &Res) const; virtual error_code getSectionContents(DataRefImpl Sec, StringRef &Res) const; virtual error_code getSectionAlignment(DataRefImpl Sec, uint64_t &Res) const; virtual error_code isSectionText(DataRefImpl Sec, bool &Res) const; virtual error_code isSectionData(DataRefImpl Sec, bool &Res) const; virtual error_code isSectionBSS(DataRefImpl Sec, bool &Res) const; virtual error_code isSectionRequiredForExecution(DataRefImpl Sec, bool &Res) const; virtual error_code isSectionVirtual(DataRefImpl Sec, bool &Res) const; virtual error_code isSectionZeroInit(DataRefImpl Sec, bool &Res) const; virtual error_code sectionContainsSymbol(DataRefImpl Sec, DataRefImpl Symb, bool &Result) const; virtual relocation_iterator getSectionRelBegin(DataRefImpl Sec) const; virtual relocation_iterator getSectionRelEnd(DataRefImpl Sec) const; virtual error_code getRelocationNext(DataRefImpl Rel, RelocationRef &Res) const; virtual error_code getRelocationAddress(DataRefImpl Rel, uint64_t &Res) const; virtual error_code getRelocationOffset(DataRefImpl Rel, uint64_t &Res) const; virtual error_code getRelocationSymbol(DataRefImpl Rel, SymbolRef &Res) const; virtual error_code getRelocationType(DataRefImpl Rel, uint64_t &Res) const; virtual error_code getRelocationTypeName(DataRefImpl Rel, SmallVectorImpl &Result) const; virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, int64_t &Res) const; virtual error_code getRelocationValueString(DataRefImpl Rel, SmallVectorImpl &Result) const; public: ELFObjectFile(MemoryBuffer *Object, error_code &ec); virtual symbol_iterator begin_symbols() const; virtual symbol_iterator end_symbols() const; virtual symbol_iterator begin_dynamic_symbols() const; virtual symbol_iterator end_dynamic_symbols() const; virtual section_iterator begin_sections() const; virtual section_iterator end_sections() const; virtual library_iterator begin_libraries_needed() const; virtual library_iterator end_libraries_needed() const; virtual dyn_iterator begin_dynamic_table() const; virtual dyn_iterator end_dynamic_table() const; virtual uint8_t getBytesInAddress() const; virtual StringRef getFileFormatName() const; virtual StringRef getObjectType() const { return "ELF"; } virtual unsigned getArch() const; virtual StringRef getLoadName() const; virtual error_code getSectionContents(const Elf_Shdr *sec, StringRef &Res) const; uint64_t getNumSections() const; uint64_t getStringTableIndex() const; ELF::Elf64_Word getSymbolTableIndex(const Elf_Sym *symb) const; const Elf_Shdr *getSection(const Elf_Sym *symb) const; const Elf_Shdr *getElfSection(section_iterator &It) const; const Elf_Sym *getElfSymbol(symbol_iterator &It) const; // Methods for type inquiry through isa, cast, and dyn_cast bool isDyldType() const { return isDyldELFObject; } static inline bool classof(const Binary *v) { return v->getType() == getELFType(target_endianness == support::little, is64Bits); } static inline bool classof(const ELFObjectFile *v) { return true; } }; // Iterate through the version definitions, and place each Elf_Verdef // in the VersionMap according to its index. template void ELFObjectFile:: LoadVersionDefs(const Elf_Shdr *sec) const { unsigned vd_size = sec->sh_size; // Size of section in bytes unsigned vd_count = sec->sh_info; // Number of Verdef entries const char *sec_start = (const char*)base() + sec->sh_offset; const char *sec_end = sec_start + vd_size; // The first Verdef entry is at the start of the section. const char *p = sec_start; for (unsigned i = 0; i < vd_count; i++) { if (p + sizeof(Elf_Verdef) > sec_end) report_fatal_error("Section ended unexpectedly while scanning " "version definitions."); const Elf_Verdef *vd = reinterpret_cast(p); if (vd->vd_version != ELF::VER_DEF_CURRENT) report_fatal_error("Unexpected verdef version"); size_t index = vd->vd_ndx & ELF::VERSYM_VERSION; if (index >= VersionMap.size()) VersionMap.resize(index+1); VersionMap[index] = VersionMapEntry(vd); p += vd->vd_next; } } // Iterate through the versions needed section, and place each Elf_Vernaux // in the VersionMap according to its index. template void ELFObjectFile:: LoadVersionNeeds(const Elf_Shdr *sec) const { unsigned vn_size = sec->sh_size; // Size of section in bytes unsigned vn_count = sec->sh_info; // Number of Verneed entries const char *sec_start = (const char*)base() + sec->sh_offset; const char *sec_end = sec_start + vn_size; // The first Verneed entry is at the start of the section. const char *p = sec_start; for (unsigned i = 0; i < vn_count; i++) { if (p + sizeof(Elf_Verneed) > sec_end) report_fatal_error("Section ended unexpectedly while scanning " "version needed records."); const Elf_Verneed *vn = reinterpret_cast(p); if (vn->vn_version != ELF::VER_NEED_CURRENT) report_fatal_error("Unexpected verneed version"); // Iterate through the Vernaux entries const char *paux = p + vn->vn_aux; for (unsigned j = 0; j < vn->vn_cnt; j++) { if (paux + sizeof(Elf_Vernaux) > sec_end) report_fatal_error("Section ended unexpected while scanning auxiliary " "version needed records."); const Elf_Vernaux *vna = reinterpret_cast(paux); size_t index = vna->vna_other & ELF::VERSYM_VERSION; if (index >= VersionMap.size()) VersionMap.resize(index+1); VersionMap[index] = VersionMapEntry(vna); paux += vna->vna_next; } p += vn->vn_next; } } template void ELFObjectFile::LoadVersionMap() const { // If there is no dynamic symtab or version table, there is nothing to do. if (SymbolTableSections[0] == NULL || dot_gnu_version_sec == NULL) return; // Has the VersionMap already been loaded? if (VersionMap.size() > 0) return; // The first two version indexes are reserved. // Index 0 is LOCAL, index 1 is GLOBAL. VersionMap.push_back(VersionMapEntry()); VersionMap.push_back(VersionMapEntry()); if (dot_gnu_version_d_sec) LoadVersionDefs(dot_gnu_version_d_sec); if (dot_gnu_version_r_sec) LoadVersionNeeds(dot_gnu_version_r_sec); } template void ELFObjectFile ::validateSymbol(DataRefImpl Symb) const { const Elf_Sym *symb = getSymbol(Symb); const Elf_Shdr *SymbolTableSection = SymbolTableSections[Symb.d.b]; // FIXME: We really need to do proper error handling in the case of an invalid // input file. Because we don't use exceptions, I think we'll just pass // an error object around. if (!( symb && SymbolTableSection && symb >= (const Elf_Sym*)(base() + SymbolTableSection->sh_offset) && symb < (const Elf_Sym*)(base() + SymbolTableSection->sh_offset + SymbolTableSection->sh_size))) // FIXME: Proper error handling. report_fatal_error("Symb must point to a valid symbol!"); } template error_code ELFObjectFile ::getSymbolNext(DataRefImpl Symb, SymbolRef &Result) const { validateSymbol(Symb); const Elf_Shdr *SymbolTableSection = SymbolTableSections[Symb.d.b]; ++Symb.d.a; // Check to see if we are at the end of this symbol table. if (Symb.d.a >= SymbolTableSection->getEntityCount()) { // We are at the end. If there are other symbol tables, jump to them. // If the symbol table is .dynsym, we are iterating dynamic symbols, // and there is only one table of these. if (Symb.d.b != 0) { ++Symb.d.b; Symb.d.a = 1; // The 0th symbol in ELF is fake. } // Otherwise return the terminator. if (Symb.d.b == 0 || Symb.d.b >= SymbolTableSections.size()) { Symb.d.a = std::numeric_limits::max(); Symb.d.b = std::numeric_limits::max(); } } Result = SymbolRef(Symb, this); return object_error::success; } template error_code ELFObjectFile ::getSymbolName(DataRefImpl Symb, StringRef &Result) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); return getSymbolName(SymbolTableSections[Symb.d.b], symb, Result); } template error_code ELFObjectFile ::getSymbolVersion(SymbolRef SymRef, StringRef &Version, bool &IsDefault) const { DataRefImpl Symb = SymRef.getRawDataRefImpl(); validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); return getSymbolVersion(SymbolTableSections[Symb.d.b], symb, Version, IsDefault); } template ELF::Elf64_Word ELFObjectFile ::getSymbolTableIndex(const Elf_Sym *symb) const { if (symb->st_shndx == ELF::SHN_XINDEX) return ExtendedSymbolTable.lookup(symb); return symb->st_shndx; } template const typename ELFObjectFile::Elf_Shdr * ELFObjectFile ::getSection(const Elf_Sym *symb) const { if (symb->st_shndx == ELF::SHN_XINDEX) return getSection(ExtendedSymbolTable.lookup(symb)); if (symb->st_shndx >= ELF::SHN_LORESERVE) return 0; return getSection(symb->st_shndx); } template const typename ELFObjectFile::Elf_Shdr * ELFObjectFile ::getElfSection(section_iterator &It) const { llvm::object::DataRefImpl ShdrRef = It->getRawDataRefImpl(); return reinterpret_cast(ShdrRef.p); } template const typename ELFObjectFile::Elf_Sym * ELFObjectFile ::getElfSymbol(symbol_iterator &It) const { return getSymbol(It->getRawDataRefImpl()); } template error_code ELFObjectFile ::getSymbolFileOffset(DataRefImpl Symb, uint64_t &Result) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); const Elf_Shdr *Section; switch (getSymbolTableIndex(symb)) { case ELF::SHN_COMMON: // Unintialized symbols have no offset in the object file case ELF::SHN_UNDEF: Result = UnknownAddressOrSize; return object_error::success; case ELF::SHN_ABS: Result = symb->st_value; return object_error::success; default: Section = getSection(symb); } switch (symb->getType()) { case ELF::STT_SECTION: Result = Section ? Section->sh_addr : UnknownAddressOrSize; return object_error::success; case ELF::STT_FUNC: case ELF::STT_OBJECT: case ELF::STT_NOTYPE: Result = symb->st_value + (Section ? Section->sh_offset : 0); return object_error::success; default: Result = UnknownAddressOrSize; return object_error::success; } } template error_code ELFObjectFile ::getSymbolAddress(DataRefImpl Symb, uint64_t &Result) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); const Elf_Shdr *Section; switch (getSymbolTableIndex(symb)) { case ELF::SHN_COMMON: case ELF::SHN_UNDEF: Result = UnknownAddressOrSize; return object_error::success; case ELF::SHN_ABS: Result = symb->st_value; return object_error::success; default: Section = getSection(symb); } switch (symb->getType()) { case ELF::STT_SECTION: Result = Section ? Section->sh_addr : UnknownAddressOrSize; return object_error::success; case ELF::STT_FUNC: case ELF::STT_OBJECT: case ELF::STT_NOTYPE: Result = symb->st_value + (Section ? Section->sh_addr : 0); return object_error::success; default: Result = UnknownAddressOrSize; return object_error::success; } } template error_code ELFObjectFile ::getSymbolSize(DataRefImpl Symb, uint64_t &Result) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); if (symb->st_size == 0) Result = UnknownAddressOrSize; Result = symb->st_size; return object_error::success; } template error_code ELFObjectFile ::getSymbolNMTypeChar(DataRefImpl Symb, char &Result) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); const Elf_Shdr *Section = getSection(symb); char ret = '?'; if (Section) { switch (Section->sh_type) { case ELF::SHT_PROGBITS: case ELF::SHT_DYNAMIC: switch (Section->sh_flags) { case (ELF::SHF_ALLOC | ELF::SHF_EXECINSTR): ret = 't'; break; case (ELF::SHF_ALLOC | ELF::SHF_WRITE): ret = 'd'; break; case ELF::SHF_ALLOC: case (ELF::SHF_ALLOC | ELF::SHF_MERGE): case (ELF::SHF_ALLOC | ELF::SHF_MERGE | ELF::SHF_STRINGS): ret = 'r'; break; } break; case ELF::SHT_NOBITS: ret = 'b'; } } switch (getSymbolTableIndex(symb)) { case ELF::SHN_UNDEF: if (ret == '?') ret = 'U'; break; case ELF::SHN_ABS: ret = 'a'; break; case ELF::SHN_COMMON: ret = 'c'; break; } switch (symb->getBinding()) { case ELF::STB_GLOBAL: ret = ::toupper(ret); break; case ELF::STB_WEAK: if (getSymbolTableIndex(symb) == ELF::SHN_UNDEF) ret = 'w'; else if (symb->getType() == ELF::STT_OBJECT) ret = 'V'; else ret = 'W'; } if (ret == '?' && symb->getType() == ELF::STT_SECTION) { StringRef name; if (error_code ec = getSymbolName(Symb, name)) return ec; Result = StringSwitch(name) .StartsWith(".debug", 'N') .StartsWith(".note", 'n') .Default('?'); return object_error::success; } Result = ret; return object_error::success; } template error_code ELFObjectFile ::getSymbolType(DataRefImpl Symb, SymbolRef::Type &Result) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); switch (symb->getType()) { case ELF::STT_NOTYPE: Result = SymbolRef::ST_Unknown; break; case ELF::STT_SECTION: Result = SymbolRef::ST_Debug; break; case ELF::STT_FILE: Result = SymbolRef::ST_File; break; case ELF::STT_FUNC: Result = SymbolRef::ST_Function; break; case ELF::STT_OBJECT: case ELF::STT_COMMON: case ELF::STT_TLS: Result = SymbolRef::ST_Data; break; default: Result = SymbolRef::ST_Other; break; } return object_error::success; } template error_code ELFObjectFile ::getSymbolFlags(DataRefImpl Symb, uint32_t &Result) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); Result = SymbolRef::SF_None; if (symb->getBinding() != ELF::STB_LOCAL) Result |= SymbolRef::SF_Global; if (symb->getBinding() == ELF::STB_WEAK) Result |= SymbolRef::SF_Weak; if (symb->st_shndx == ELF::SHN_ABS) Result |= SymbolRef::SF_Absolute; if (symb->getType() == ELF::STT_FILE || symb->getType() == ELF::STT_SECTION) Result |= SymbolRef::SF_FormatSpecific; if (getSymbolTableIndex(symb) == ELF::SHN_UNDEF) Result |= SymbolRef::SF_Undefined; if (symb->getType() == ELF::STT_COMMON || getSymbolTableIndex(symb) == ELF::SHN_COMMON) Result |= SymbolRef::SF_Common; if (symb->getType() == ELF::STT_TLS) Result |= SymbolRef::SF_ThreadLocal; return object_error::success; } template error_code ELFObjectFile ::getSymbolSection(DataRefImpl Symb, section_iterator &Res) const { validateSymbol(Symb); const Elf_Sym *symb = getSymbol(Symb); const Elf_Shdr *sec = getSection(symb); if (!sec) Res = end_sections(); else { DataRefImpl Sec; Sec.p = reinterpret_cast(sec); Res = section_iterator(SectionRef(Sec, this)); } return object_error::success; } template error_code ELFObjectFile ::getSectionNext(DataRefImpl Sec, SectionRef &Result) const { const uint8_t *sec = reinterpret_cast(Sec.p); sec += Header->e_shentsize; Sec.p = reinterpret_cast(sec); Result = SectionRef(Sec, this); return object_error::success; } template error_code ELFObjectFile ::getSectionName(DataRefImpl Sec, StringRef &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); Result = StringRef(getString(dot_shstrtab_sec, sec->sh_name)); return object_error::success; } template error_code ELFObjectFile ::getSectionAddress(DataRefImpl Sec, uint64_t &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); Result = sec->sh_addr; return object_error::success; } template error_code ELFObjectFile ::getSectionSize(DataRefImpl Sec, uint64_t &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); Result = sec->sh_size; return object_error::success; } template error_code ELFObjectFile ::getSectionContents(DataRefImpl Sec, StringRef &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); const char *start = (const char*)base() + sec->sh_offset; Result = StringRef(start, sec->sh_size); return object_error::success; } template error_code ELFObjectFile ::getSectionContents(const Elf_Shdr *Sec, StringRef &Result) const { const char *start = (const char*)base() + Sec->sh_offset; Result = StringRef(start, Sec->sh_size); return object_error::success; } template error_code ELFObjectFile ::getSectionAlignment(DataRefImpl Sec, uint64_t &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); Result = sec->sh_addralign; return object_error::success; } template error_code ELFObjectFile ::isSectionText(DataRefImpl Sec, bool &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); if (sec->sh_flags & ELF::SHF_EXECINSTR) Result = true; else Result = false; return object_error::success; } template error_code ELFObjectFile ::isSectionData(DataRefImpl Sec, bool &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); if (sec->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) && sec->sh_type == ELF::SHT_PROGBITS) Result = true; else Result = false; return object_error::success; } template error_code ELFObjectFile ::isSectionBSS(DataRefImpl Sec, bool &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); if (sec->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) && sec->sh_type == ELF::SHT_NOBITS) Result = true; else Result = false; return object_error::success; } template error_code ELFObjectFile ::isSectionRequiredForExecution(DataRefImpl Sec, bool &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); if (sec->sh_flags & ELF::SHF_ALLOC) Result = true; else Result = false; return object_error::success; } template error_code ELFObjectFile ::isSectionVirtual(DataRefImpl Sec, bool &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); if (sec->sh_type == ELF::SHT_NOBITS) Result = true; else Result = false; return object_error::success; } template error_code ELFObjectFile::isSectionZeroInit(DataRefImpl Sec, bool &Result) const { const Elf_Shdr *sec = reinterpret_cast(Sec.p); // For ELF, all zero-init sections are virtual (that is, they occupy no space // in the object image) and vice versa. if (sec->sh_flags & ELF::SHT_NOBITS) Result = true; else Result = false; return object_error::success; } template error_code ELFObjectFile ::sectionContainsSymbol(DataRefImpl Sec, DataRefImpl Symb, bool &Result) const { // FIXME: Unimplemented. Result = false; return object_error::success; } template relocation_iterator ELFObjectFile ::getSectionRelBegin(DataRefImpl Sec) const { DataRefImpl RelData; const Elf_Shdr *sec = reinterpret_cast(Sec.p); typename RelocMap_t::const_iterator ittr = SectionRelocMap.find(sec); if (sec != 0 && ittr != SectionRelocMap.end()) { RelData.w.a = getSection(ittr->second[0])->sh_info; RelData.w.b = ittr->second[0]; RelData.w.c = 0; } return relocation_iterator(RelocationRef(RelData, this)); } template relocation_iterator ELFObjectFile ::getSectionRelEnd(DataRefImpl Sec) const { DataRefImpl RelData; const Elf_Shdr *sec = reinterpret_cast(Sec.p); typename RelocMap_t::const_iterator ittr = SectionRelocMap.find(sec); if (sec != 0 && ittr != SectionRelocMap.end()) { // Get the index of the last relocation section for this section. std::size_t relocsecindex = ittr->second[ittr->second.size() - 1]; const Elf_Shdr *relocsec = getSection(relocsecindex); RelData.w.a = relocsec->sh_info; RelData.w.b = relocsecindex; RelData.w.c = relocsec->sh_size / relocsec->sh_entsize; } return relocation_iterator(RelocationRef(RelData, this)); } // Relocations template error_code ELFObjectFile ::getRelocationNext(DataRefImpl Rel, RelocationRef &Result) const { ++Rel.w.c; const Elf_Shdr *relocsec = getSection(Rel.w.b); if (Rel.w.c >= (relocsec->sh_size / relocsec->sh_entsize)) { // We have reached the end of the relocations for this section. See if there // is another relocation section. typename RelocMap_t::mapped_type relocseclist = SectionRelocMap.lookup(getSection(Rel.w.a)); // Do a binary search for the current reloc section index (which must be // present). Then get the next one. typename RelocMap_t::mapped_type::const_iterator loc = std::lower_bound(relocseclist.begin(), relocseclist.end(), Rel.w.b); ++loc; // If there is no next one, don't do anything. The ++Rel.w.c above sets Rel // to the end iterator. if (loc != relocseclist.end()) { Rel.w.b = *loc; Rel.w.a = 0; } } Result = RelocationRef(Rel, this); return object_error::success; } template error_code ELFObjectFile ::getRelocationSymbol(DataRefImpl Rel, SymbolRef &Result) const { uint32_t symbolIdx; const Elf_Shdr *sec = getSection(Rel.w.b); switch (sec->sh_type) { default : report_fatal_error("Invalid section type in Rel!"); case ELF::SHT_REL : { symbolIdx = getRel(Rel)->getSymbol(); break; } case ELF::SHT_RELA : { symbolIdx = getRela(Rel)->getSymbol(); break; } } DataRefImpl SymbolData; IndexMap_t::const_iterator it = SymbolTableSectionsIndexMap.find(sec->sh_link); if (it == SymbolTableSectionsIndexMap.end()) report_fatal_error("Relocation symbol table not found!"); SymbolData.d.a = symbolIdx; SymbolData.d.b = it->second; Result = SymbolRef(SymbolData, this); return object_error::success; } template error_code ELFObjectFile ::getRelocationAddress(DataRefImpl Rel, uint64_t &Result) const { uint64_t offset; const Elf_Shdr *sec = getSection(Rel.w.b); switch (sec->sh_type) { default : report_fatal_error("Invalid section type in Rel!"); case ELF::SHT_REL : { offset = getRel(Rel)->r_offset; break; } case ELF::SHT_RELA : { offset = getRela(Rel)->r_offset; break; } } Result = offset; return object_error::success; } template error_code ELFObjectFile ::getRelocationOffset(DataRefImpl Rel, uint64_t &Result) const { uint64_t offset; const Elf_Shdr *sec = getSection(Rel.w.b); switch (sec->sh_type) { default : report_fatal_error("Invalid section type in Rel!"); case ELF::SHT_REL : { offset = getRel(Rel)->r_offset; break; } case ELF::SHT_RELA : { offset = getRela(Rel)->r_offset; break; } } Result = offset - sec->sh_addr; return object_error::success; } template error_code ELFObjectFile ::getRelocationType(DataRefImpl Rel, uint64_t &Result) const { const Elf_Shdr *sec = getSection(Rel.w.b); switch (sec->sh_type) { default : report_fatal_error("Invalid section type in Rel!"); case ELF::SHT_REL : { Result = getRel(Rel)->getType(); break; } case ELF::SHT_RELA : { Result = getRela(Rel)->getType(); break; } } return object_error::success; } #define LLVM_ELF_SWITCH_RELOC_TYPE_NAME(enum) \ case ELF::enum: res = #enum; break; template error_code ELFObjectFile ::getRelocationTypeName(DataRefImpl Rel, SmallVectorImpl &Result) const { const Elf_Shdr *sec = getSection(Rel.w.b); uint8_t type; StringRef res; switch (sec->sh_type) { default : return object_error::parse_failed; case ELF::SHT_REL : { type = getRel(Rel)->getType(); break; } case ELF::SHT_RELA : { type = getRela(Rel)->getType(); break; } } switch (Header->e_machine) { case ELF::EM_X86_64: switch (type) { LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_NONE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_64); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PC32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOT32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PLT32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_COPY); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GLOB_DAT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_JUMP_SLOT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_RELATIVE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTPCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_32S); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PC16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PC8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_DTPMOD64); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_DTPOFF64); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TPOFF64); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TLSGD); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TLSLD); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_DTPOFF32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTTPOFF); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TPOFF32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_PC64); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTOFF64); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTPC32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_SIZE32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_SIZE64); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_GOTPC32_TLSDESC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TLSDESC_CALL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_X86_64_TLSDESC); default: res = "Unknown"; } break; case ELF::EM_386: switch (type) { LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_NONE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_PC32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_GOT32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_PLT32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_COPY); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_GLOB_DAT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_JUMP_SLOT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_RELATIVE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_GOTOFF); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_GOTPC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_32PLT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_TPOFF); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_IE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GOTIE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_PC16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_PC8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD_PUSH); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD_CALL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GD_POP); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM_PUSH); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM_CALL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDM_POP); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LDO_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_IE_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_LE_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_DTPMOD32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_DTPOFF32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_TPOFF32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_GOTDESC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_DESC_CALL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_TLS_DESC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_386_IRELATIVE); default: res = "Unknown"; } break; case ELF::EM_ARM: switch (type) { LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_NONE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PC24); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ABS32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_REL32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDR_PC_G0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ABS16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ABS12); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_ABS5); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ABS8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_SBREL32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_CALL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_PC8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_BREL_ADJ); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_DESC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_SWI8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_XPC25); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_XPC22); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_DTPMOD32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_DTPOFF32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_TPOFF32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_COPY); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GLOB_DAT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_JUMP_SLOT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_RELATIVE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GOTOFF32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_BASE_PREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GOT_BREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PLT32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_CALL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_JUMP24); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_JUMP24); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_BASE_ABS); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_PCREL_7_0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_PCREL_15_8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_PCREL_23_15); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDR_SBREL_11_0_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_SBREL_19_12_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_SBREL_27_20_CK); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TARGET1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_SBREL31); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_V4BX); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TARGET2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PREL31); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_MOVW_ABS_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_MOVT_ABS); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_MOVW_PREL_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_MOVT_PREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_MOVW_ABS_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_MOVT_ABS); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_MOVW_PREL_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_MOVT_PREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_JUMP19); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_JUMP6); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_ALU_PREL_11_0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_PC12); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ABS32_NOI); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_REL32_NOI); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_PC_G0_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_PC_G0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_PC_G1_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_PC_G1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_PC_G2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDR_PC_G1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDR_PC_G2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDRS_PC_G0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDRS_PC_G1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDRS_PC_G2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDC_PC_G0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDC_PC_G1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDC_PC_G2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_SB_G0_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_SB_G0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_SB_G1_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_SB_G1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ALU_SB_G2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDR_SB_G0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDR_SB_G1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDR_SB_G2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDRS_SB_G0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDRS_SB_G1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDRS_SB_G2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDC_SB_G0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDC_SB_G1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_LDC_SB_G2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_MOVW_BREL_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_MOVT_BREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_MOVW_BREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_MOVW_BREL_NC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_MOVT_BREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_MOVW_BREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_GOTDESC); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_CALL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_DESCSEQ); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_TLS_CALL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PLT32_ABS); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GOT_ABS); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GOT_PREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GOT_BREL12); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GOTOFF12); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GOTRELAX); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GNU_VTENTRY); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_GNU_VTINHERIT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_JUMP11); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_JUMP8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_GD32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_LDM32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_LDO32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_IE32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_LE32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_LDO12); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_LE12); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_TLS_IE12GP); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_3); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_4); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_5); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_6); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_7); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_9); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_10); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_11); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_12); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_13); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_14); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_PRIVATE_15); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_ME_TOO); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_TLS_DESCSEQ16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_ARM_THM_TLS_DESCSEQ32); default: res = "Unknown"; } break; case ELF::EM_HEXAGON: switch (type) { LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_NONE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B22_PCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B15_PCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B7_PCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_LO16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_HI16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_8); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GPREL16_0); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GPREL16_1); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GPREL16_2); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GPREL16_3); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_HL16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B13_PCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B9_PCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B32_PCREL_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_32_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B22_PCREL_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B15_PCREL_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B13_PCREL_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B9_PCREL_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_B7_PCREL_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_16_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_12_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_11_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_10_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_9_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_8_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_7_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_32_PCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_COPY); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GLOB_DAT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_JMP_SLOT); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_RELATIVE); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_PLT_B22_PCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOTREL_LO16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOTREL_HI16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOTREL_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOT_LO16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOT_HI16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOT_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOT_16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_DTPMOD_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_DTPREL_LO16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_DTPREL_HI16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_DTPREL_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_DTPREL_16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GD_PLT_B22_PCREL); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GD_GOT_LO16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GD_GOT_HI16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GD_GOT_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GD_GOT_16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_LO16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_HI16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_GOT_LO16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_GOT_HI16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_GOT_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_GOT_16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_TPREL_LO16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_TPREL_HI16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_TPREL_32); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_TPREL_16); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_6_PCREL_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOTREL_32_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOTREL_16_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOTREL_11_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOT_32_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOT_16_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GOT_11_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_DTPREL_32_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_DTPREL_16_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_DTPREL_11_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GD_GOT_32_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GD_GOT_16_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_GD_GOT_11_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_32_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_16_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_GOT_32_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_GOT_16_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_IE_GOT_11_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_TPREL_32_6_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_TPREL_16_X); LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_HEX_TPREL_11_X); default: res = "Unknown"; } break; default: res = "Unknown"; } Result.append(res.begin(), res.end()); return object_error::success; } #undef LLVM_ELF_SWITCH_RELOC_TYPE_NAME template error_code ELFObjectFile ::getRelocationAdditionalInfo(DataRefImpl Rel, int64_t &Result) const { const Elf_Shdr *sec = getSection(Rel.w.b); switch (sec->sh_type) { default : report_fatal_error("Invalid section type in Rel!"); case ELF::SHT_REL : { Result = 0; return object_error::success; } case ELF::SHT_RELA : { Result = getRela(Rel)->r_addend; return object_error::success; } } } template error_code ELFObjectFile ::getRelocationValueString(DataRefImpl Rel, SmallVectorImpl &Result) const { const Elf_Shdr *sec = getSection(Rel.w.b); uint8_t type; StringRef res; int64_t addend = 0; uint16_t symbol_index = 0; switch (sec->sh_type) { default: return object_error::parse_failed; case ELF::SHT_REL: { type = getRel(Rel)->getType(); symbol_index = getRel(Rel)->getSymbol(); // TODO: Read implicit addend from section data. break; } case ELF::SHT_RELA: { type = getRela(Rel)->getType(); symbol_index = getRela(Rel)->getSymbol(); addend = getRela(Rel)->r_addend; break; } } const Elf_Sym *symb = getEntry(sec->sh_link, symbol_index); StringRef symname; if (error_code ec = getSymbolName(getSection(sec->sh_link), symb, symname)) return ec; switch (Header->e_machine) { case ELF::EM_X86_64: switch (type) { case ELF::R_X86_64_PC8: case ELF::R_X86_64_PC16: case ELF::R_X86_64_PC32: { std::string fmtbuf; raw_string_ostream fmt(fmtbuf); fmt << symname << (addend < 0 ? "" : "+") << addend << "-P"; fmt.flush(); Result.append(fmtbuf.begin(), fmtbuf.end()); } break; case ELF::R_X86_64_8: case ELF::R_X86_64_16: case ELF::R_X86_64_32: case ELF::R_X86_64_32S: case ELF::R_X86_64_64: { std::string fmtbuf; raw_string_ostream fmt(fmtbuf); fmt << symname << (addend < 0 ? "" : "+") << addend; fmt.flush(); Result.append(fmtbuf.begin(), fmtbuf.end()); } break; default: res = "Unknown"; } break; case ELF::EM_ARM: case ELF::EM_HEXAGON: res = symname; break; default: res = "Unknown"; } if (Result.empty()) Result.append(res.begin(), res.end()); return object_error::success; } // Verify that the last byte in the string table in a null. template void ELFObjectFile ::VerifyStrTab(const Elf_Shdr *sh) const { const char *strtab = (const char*)base() + sh->sh_offset; if (strtab[sh->sh_size - 1] != 0) // FIXME: Proper error handling. report_fatal_error("String table must end with a null terminator!"); } template ELFObjectFile::ELFObjectFile(MemoryBuffer *Object , error_code &ec) : ObjectFile(getELFType(target_endianness == support::little, is64Bits), Object, ec) , isDyldELFObject(false) , SectionHeaderTable(0) , dot_shstrtab_sec(0) , dot_strtab_sec(0) , dot_dynstr_sec(0) , dot_dynamic_sec(0) , dot_gnu_version_sec(0) , dot_gnu_version_r_sec(0) , dot_gnu_version_d_sec(0) , dt_soname(0) { const uint64_t FileSize = Data->getBufferSize(); if (sizeof(Elf_Ehdr) > FileSize) // FIXME: Proper error handling. report_fatal_error("File too short!"); Header = reinterpret_cast(base()); if (Header->e_shoff == 0) return; const uint64_t SectionTableOffset = Header->e_shoff; if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) // FIXME: Proper error handling. report_fatal_error("Section header table goes past end of file!"); // The getNumSections() call below depends on SectionHeaderTable being set. SectionHeaderTable = reinterpret_cast(base() + SectionTableOffset); const uint64_t SectionTableSize = getNumSections() * Header->e_shentsize; if (SectionTableOffset + SectionTableSize > FileSize) // FIXME: Proper error handling. report_fatal_error("Section table goes past end of file!"); // To find the symbol tables we walk the section table to find SHT_SYMTAB. const Elf_Shdr* SymbolTableSectionHeaderIndex = 0; const Elf_Shdr* sh = SectionHeaderTable; // Reserve SymbolTableSections[0] for .dynsym SymbolTableSections.push_back(NULL); for (uint64_t i = 0, e = getNumSections(); i != e; ++i) { switch (sh->sh_type) { case ELF::SHT_SYMTAB_SHNDX: { if (SymbolTableSectionHeaderIndex) // FIXME: Proper error handling. report_fatal_error("More than one .symtab_shndx!"); SymbolTableSectionHeaderIndex = sh; break; } case ELF::SHT_SYMTAB: { SymbolTableSectionsIndexMap[i] = SymbolTableSections.size(); SymbolTableSections.push_back(sh); break; } case ELF::SHT_DYNSYM: { if (SymbolTableSections[0] != NULL) // FIXME: Proper error handling. report_fatal_error("More than one .dynsym!"); SymbolTableSectionsIndexMap[i] = 0; SymbolTableSections[0] = sh; break; } case ELF::SHT_REL: case ELF::SHT_RELA: { SectionRelocMap[getSection(sh->sh_info)].push_back(i); break; } case ELF::SHT_DYNAMIC: { if (dot_dynamic_sec != NULL) // FIXME: Proper error handling. report_fatal_error("More than one .dynamic!"); dot_dynamic_sec = sh; break; } case ELF::SHT_GNU_versym: { if (dot_gnu_version_sec != NULL) // FIXME: Proper error handling. report_fatal_error("More than one .gnu.version section!"); dot_gnu_version_sec = sh; break; } case ELF::SHT_GNU_verdef: { if (dot_gnu_version_d_sec != NULL) // FIXME: Proper error handling. report_fatal_error("More than one .gnu.version_d section!"); dot_gnu_version_d_sec = sh; break; } case ELF::SHT_GNU_verneed: { if (dot_gnu_version_r_sec != NULL) // FIXME: Proper error handling. report_fatal_error("More than one .gnu.version_r section!"); dot_gnu_version_r_sec = sh; break; } } ++sh; } // Sort section relocation lists by index. for (typename RelocMap_t::iterator i = SectionRelocMap.begin(), e = SectionRelocMap.end(); i != e; ++i) { std::sort(i->second.begin(), i->second.end()); } // Get string table sections. dot_shstrtab_sec = getSection(getStringTableIndex()); if (dot_shstrtab_sec) { // Verify that the last byte in the string table in a null. VerifyStrTab(dot_shstrtab_sec); } // Merge this into the above loop. for (const char *i = reinterpret_cast(SectionHeaderTable), *e = i + getNumSections() * Header->e_shentsize; i != e; i += Header->e_shentsize) { const Elf_Shdr *sh = reinterpret_cast(i); if (sh->sh_type == ELF::SHT_STRTAB) { StringRef SectionName(getString(dot_shstrtab_sec, sh->sh_name)); if (SectionName == ".strtab") { if (dot_strtab_sec != 0) // FIXME: Proper error handling. report_fatal_error("Already found section named .strtab!"); dot_strtab_sec = sh; VerifyStrTab(dot_strtab_sec); } else if (SectionName == ".dynstr") { if (dot_dynstr_sec != 0) // FIXME: Proper error handling. report_fatal_error("Already found section named .dynstr!"); dot_dynstr_sec = sh; VerifyStrTab(dot_dynstr_sec); } } } // Build symbol name side-mapping if there is one. if (SymbolTableSectionHeaderIndex) { const Elf_Word *ShndxTable = reinterpret_cast(base() + SymbolTableSectionHeaderIndex->sh_offset); error_code ec; for (symbol_iterator si = begin_symbols(), se = end_symbols(); si != se; si.increment(ec)) { if (ec) report_fatal_error("Fewer extended symbol table entries than symbols!"); if (*ShndxTable != ELF::SHN_UNDEF) ExtendedSymbolTable[getSymbol(si->getRawDataRefImpl())] = *ShndxTable; ++ShndxTable; } } } template symbol_iterator ELFObjectFile ::begin_symbols() const { DataRefImpl SymbolData; if (SymbolTableSections.size() <= 1) { SymbolData.d.a = std::numeric_limits::max(); SymbolData.d.b = std::numeric_limits::max(); } else { SymbolData.d.a = 1; // The 0th symbol in ELF is fake. SymbolData.d.b = 1; // The 0th table is .dynsym } return symbol_iterator(SymbolRef(SymbolData, this)); } template symbol_iterator ELFObjectFile ::end_symbols() const { DataRefImpl SymbolData; SymbolData.d.a = std::numeric_limits::max(); SymbolData.d.b = std::numeric_limits::max(); return symbol_iterator(SymbolRef(SymbolData, this)); } template symbol_iterator ELFObjectFile ::begin_dynamic_symbols() const { DataRefImpl SymbolData; if (SymbolTableSections[0] == NULL) { SymbolData.d.a = std::numeric_limits::max(); SymbolData.d.b = std::numeric_limits::max(); } else { SymbolData.d.a = 1; // The 0th symbol in ELF is fake. SymbolData.d.b = 0; // The 0th table is .dynsym } return symbol_iterator(SymbolRef(SymbolData, this)); } template symbol_iterator ELFObjectFile ::end_dynamic_symbols() const { DataRefImpl SymbolData; SymbolData.d.a = std::numeric_limits::max(); SymbolData.d.b = std::numeric_limits::max(); return symbol_iterator(SymbolRef(SymbolData, this)); } template section_iterator ELFObjectFile ::begin_sections() const { DataRefImpl ret; ret.p = reinterpret_cast(base() + Header->e_shoff); return section_iterator(SectionRef(ret, this)); } template section_iterator ELFObjectFile ::end_sections() const { DataRefImpl ret; ret.p = reinterpret_cast(base() + Header->e_shoff + (Header->e_shentsize*getNumSections())); return section_iterator(SectionRef(ret, this)); } template typename ELFObjectFile::dyn_iterator ELFObjectFile::begin_dynamic_table() const { DataRefImpl DynData; if (dot_dynamic_sec == NULL || dot_dynamic_sec->sh_size == 0) { DynData.d.a = std::numeric_limits::max(); } else { DynData.d.a = 0; } return dyn_iterator(DynRef(DynData, this)); } template typename ELFObjectFile::dyn_iterator ELFObjectFile ::end_dynamic_table() const { DataRefImpl DynData; DynData.d.a = std::numeric_limits::max(); return dyn_iterator(DynRef(DynData, this)); } template error_code ELFObjectFile ::getDynNext(DataRefImpl DynData, DynRef &Result) const { ++DynData.d.a; // Check to see if we are at the end of .dynamic if (DynData.d.a >= dot_dynamic_sec->getEntityCount()) { // We are at the end. Return the terminator. DynData.d.a = std::numeric_limits::max(); } Result = DynRef(DynData, this); return object_error::success; } template StringRef ELFObjectFile::getLoadName() const { if (!dt_soname) { // Find the DT_SONAME entry dyn_iterator it = begin_dynamic_table(); dyn_iterator ie = end_dynamic_table(); error_code ec; while (it != ie) { if (it->getTag() == ELF::DT_SONAME) break; it.increment(ec); if (ec) report_fatal_error("dynamic table iteration failed"); } if (it != ie) { if (dot_dynstr_sec == NULL) report_fatal_error("Dynamic string table is missing"); dt_soname = getString(dot_dynstr_sec, it->getVal()); } else { dt_soname = ""; } } return dt_soname; } template library_iterator ELFObjectFile ::begin_libraries_needed() const { // Find the first DT_NEEDED entry dyn_iterator i = begin_dynamic_table(); dyn_iterator e = end_dynamic_table(); error_code ec; while (i != e) { if (i->getTag() == ELF::DT_NEEDED) break; i.increment(ec); if (ec) report_fatal_error("dynamic table iteration failed"); } // Use the same DataRefImpl format as DynRef. return library_iterator(LibraryRef(i->getRawDataRefImpl(), this)); } template error_code ELFObjectFile ::getLibraryNext(DataRefImpl Data, LibraryRef &Result) const { // Use the same DataRefImpl format as DynRef. dyn_iterator i = dyn_iterator(DynRef(Data, this)); dyn_iterator e = end_dynamic_table(); // Skip the current dynamic table entry. error_code ec; if (i != e) { i.increment(ec); // TODO: proper error handling if (ec) report_fatal_error("dynamic table iteration failed"); } // Find the next DT_NEEDED entry. while (i != e) { if (i->getTag() == ELF::DT_NEEDED) break; i.increment(ec); if (ec) report_fatal_error("dynamic table iteration failed"); } Result = LibraryRef(i->getRawDataRefImpl(), this); return object_error::success; } template error_code ELFObjectFile ::getLibraryPath(DataRefImpl Data, StringRef &Res) const { dyn_iterator i = dyn_iterator(DynRef(Data, this)); if (i == end_dynamic_table()) report_fatal_error("getLibraryPath() called on iterator end"); if (i->getTag() != ELF::DT_NEEDED) report_fatal_error("Invalid library_iterator"); // This uses .dynstr to lookup the name of the DT_NEEDED entry. // THis works as long as DT_STRTAB == .dynstr. This is true most of // the time, but the specification allows exceptions. // TODO: This should really use DT_STRTAB instead. Doing this requires // reading the program headers. if (dot_dynstr_sec == NULL) report_fatal_error("Dynamic string table is missing"); Res = getString(dot_dynstr_sec, i->getVal()); return object_error::success; } template library_iterator ELFObjectFile ::end_libraries_needed() const { dyn_iterator e = end_dynamic_table(); // Use the same DataRefImpl format as DynRef. return library_iterator(LibraryRef(e->getRawDataRefImpl(), this)); } template uint8_t ELFObjectFile::getBytesInAddress() const { return is64Bits ? 8 : 4; } template StringRef ELFObjectFile ::getFileFormatName() const { switch(Header->e_ident[ELF::EI_CLASS]) { case ELF::ELFCLASS32: switch(Header->e_machine) { case ELF::EM_386: return "ELF32-i386"; case ELF::EM_X86_64: return "ELF32-x86-64"; case ELF::EM_ARM: return "ELF32-arm"; case ELF::EM_HEXAGON: return "ELF32-hexagon"; default: return "ELF32-unknown"; } case ELF::ELFCLASS64: switch(Header->e_machine) { case ELF::EM_386: return "ELF64-i386"; case ELF::EM_X86_64: return "ELF64-x86-64"; default: return "ELF64-unknown"; } default: // FIXME: Proper error handling. report_fatal_error("Invalid ELFCLASS!"); } } template unsigned ELFObjectFile::getArch() const { switch(Header->e_machine) { case ELF::EM_386: return Triple::x86; case ELF::EM_X86_64: return Triple::x86_64; case ELF::EM_ARM: return Triple::arm; case ELF::EM_HEXAGON: return Triple::hexagon; case ELF::EM_MIPS: return (target_endianness == support::little) ? Triple::mipsel : Triple::mips; default: return Triple::UnknownArch; } } template uint64_t ELFObjectFile::getNumSections() const { assert(Header && "Header not initialized!"); if (Header->e_shnum == ELF::SHN_UNDEF) { assert(SectionHeaderTable && "SectionHeaderTable not initialized!"); return SectionHeaderTable->sh_size; } return Header->e_shnum; } template uint64_t ELFObjectFile::getStringTableIndex() const { if (Header->e_shnum == ELF::SHN_UNDEF) { if (Header->e_shstrndx == ELF::SHN_HIRESERVE) return SectionHeaderTable->sh_link; if (Header->e_shstrndx >= getNumSections()) return 0; } return Header->e_shstrndx; } template template inline const T * ELFObjectFile::getEntry(uint16_t Section, uint32_t Entry) const { return getEntry(getSection(Section), Entry); } template template inline const T * ELFObjectFile::getEntry(const Elf_Shdr * Section, uint32_t Entry) const { return reinterpret_cast( base() + Section->sh_offset + (Entry * Section->sh_entsize)); } template const typename ELFObjectFile::Elf_Sym * ELFObjectFile::getSymbol(DataRefImpl Symb) const { return getEntry(SymbolTableSections[Symb.d.b], Symb.d.a); } template const typename ELFObjectFile::Elf_Dyn * ELFObjectFile::getDyn(DataRefImpl DynData) const { return getEntry(dot_dynamic_sec, DynData.d.a); } template const typename ELFObjectFile::Elf_Rel * ELFObjectFile::getRel(DataRefImpl Rel) const { return getEntry(Rel.w.b, Rel.w.c); } template const typename ELFObjectFile::Elf_Rela * ELFObjectFile::getRela(DataRefImpl Rela) const { return getEntry(Rela.w.b, Rela.w.c); } template const typename ELFObjectFile::Elf_Shdr * ELFObjectFile::getSection(DataRefImpl Symb) const { const Elf_Shdr *sec = getSection(Symb.d.b); if (sec->sh_type != ELF::SHT_SYMTAB || sec->sh_type != ELF::SHT_DYNSYM) // FIXME: Proper error handling. report_fatal_error("Invalid symbol table section!"); return sec; } template const typename ELFObjectFile::Elf_Shdr * ELFObjectFile::getSection(uint32_t index) const { if (index == 0) return 0; if (!SectionHeaderTable || index >= getNumSections()) // FIXME: Proper error handling. report_fatal_error("Invalid section index!"); return reinterpret_cast( reinterpret_cast(SectionHeaderTable) + (index * Header->e_shentsize)); } template const char *ELFObjectFile ::getString(uint32_t section, ELF::Elf32_Word offset) const { return getString(getSection(section), offset); } template const char *ELFObjectFile ::getString(const Elf_Shdr *section, ELF::Elf32_Word offset) const { assert(section && section->sh_type == ELF::SHT_STRTAB && "Invalid section!"); if (offset >= section->sh_size) // FIXME: Proper error handling. report_fatal_error("Symbol name offset outside of string table!"); return (const char *)base() + section->sh_offset + offset; } template error_code ELFObjectFile ::getSymbolName(const Elf_Shdr *section, const Elf_Sym *symb, StringRef &Result) const { if (symb->st_name == 0) { const Elf_Shdr *section = getSection(symb); if (!section) Result = ""; else Result = getString(dot_shstrtab_sec, section->sh_name); return object_error::success; } if (section == SymbolTableSections[0]) { // Symbol is in .dynsym, use .dynstr string table Result = getString(dot_dynstr_sec, symb->st_name); } else { // Use the default symbol table name section. Result = getString(dot_strtab_sec, symb->st_name); } return object_error::success; } template error_code ELFObjectFile ::getSectionName(const Elf_Shdr *section, StringRef &Result) const { Result = StringRef(getString(dot_shstrtab_sec, section->sh_name)); return object_error::success; } template error_code ELFObjectFile ::getSymbolVersion(const Elf_Shdr *section, const Elf_Sym *symb, StringRef &Version, bool &IsDefault) const { // Handle non-dynamic symbols. if (section != SymbolTableSections[0]) { // Non-dynamic symbols can have versions in their names // A name of the form 'foo@V1' indicates version 'V1', non-default. // A name of the form 'foo@@V2' indicates version 'V2', default version. StringRef Name; error_code ec = getSymbolName(section, symb, Name); if (ec != object_error::success) return ec; size_t atpos = Name.find('@'); if (atpos == StringRef::npos) { Version = ""; IsDefault = false; return object_error::success; } ++atpos; if (atpos < Name.size() && Name[atpos] == '@') { IsDefault = true; ++atpos; } else { IsDefault = false; } Version = Name.substr(atpos); return object_error::success; } // This is a dynamic symbol. Look in the GNU symbol version table. if (dot_gnu_version_sec == NULL) { // No version table. Version = ""; IsDefault = false; return object_error::success; } // Determine the position in the symbol table of this entry. const char *sec_start = (const char*)base() + section->sh_offset; size_t entry_index = ((const char*)symb - sec_start)/section->sh_entsize; // Get the corresponding version index entry const Elf_Versym *vs = getEntry(dot_gnu_version_sec, entry_index); size_t version_index = vs->vs_index & ELF::VERSYM_VERSION; // Special markers for unversioned symbols. if (version_index == ELF::VER_NDX_LOCAL || version_index == ELF::VER_NDX_GLOBAL) { Version = ""; IsDefault = false; return object_error::success; } // Lookup this symbol in the version table LoadVersionMap(); if (version_index >= VersionMap.size() || VersionMap[version_index].isNull()) report_fatal_error("Symbol has version index without corresponding " "define or reference entry"); const VersionMapEntry &entry = VersionMap[version_index]; // Get the version name string size_t name_offset; if (entry.isVerdef()) { // The first Verdaux entry holds the name. name_offset = entry.getVerdef()->getAux()->vda_name; } else { name_offset = entry.getVernaux()->vna_name; } Version = getString(dot_dynstr_sec, name_offset); // Set IsDefault if (entry.isVerdef()) { IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN); } else { IsDefault = false; } return object_error::success; } template inline DynRefImpl ::DynRefImpl(DataRefImpl DynP, const OwningType *Owner) : DynPimpl(DynP) , OwningObject(Owner) {} template inline bool DynRefImpl ::operator==(const DynRefImpl &Other) const { return DynPimpl == Other.DynPimpl; } template inline bool DynRefImpl ::operator <(const DynRefImpl &Other) const { return DynPimpl < Other.DynPimpl; } template inline error_code DynRefImpl ::getNext(DynRefImpl &Result) const { return OwningObject->getDynNext(DynPimpl, Result); } template inline int64_t DynRefImpl ::getTag() const { return OwningObject->getDyn(DynPimpl)->d_tag; } template inline uint64_t DynRefImpl ::getVal() const { return OwningObject->getDyn(DynPimpl)->d_un.d_val; } template inline uint64_t DynRefImpl ::getPtr() const { return OwningObject->getDyn(DynPimpl)->d_un.d_ptr; } template inline DataRefImpl DynRefImpl ::getRawDataRefImpl() const { return DynPimpl; } /// This is a generic interface for retrieving GNU symbol version /// information from an ELFObjectFile. static inline error_code GetELFSymbolVersion(const ObjectFile *Obj, const SymbolRef &Sym, StringRef &Version, bool &IsDefault) { // Little-endian 32-bit if (const ELFObjectFile *ELFObj = dyn_cast >(Obj)) return ELFObj->getSymbolVersion(Sym, Version, IsDefault); // Big-endian 32-bit if (const ELFObjectFile *ELFObj = dyn_cast >(Obj)) return ELFObj->getSymbolVersion(Sym, Version, IsDefault); // Little-endian 64-bit if (const ELFObjectFile *ELFObj = dyn_cast >(Obj)) return ELFObj->getSymbolVersion(Sym, Version, IsDefault); // Big-endian 64-bit if (const ELFObjectFile *ELFObj = dyn_cast >(Obj)) return ELFObj->getSymbolVersion(Sym, Version, IsDefault); llvm_unreachable("Object passed to GetELFSymbolVersion() is not ELF"); } } } #endif