X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FObject%2FELF.h;h=79f01121c92c16c1892b8f4a3e43998ff8da0db3;hb=89a6fba75e7567f08b77d991642d0f167360f935;hp=aaeea1d2bf854950d5a68aa5f30e3204d6a90b0c;hpb=284a6bbae148e1b5a2696f13526bb8f64da62177;p=oota-llvm.git diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index aaeea1d2bf8..0fad59205cf 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -7,22 +7,27 @@ // //===----------------------------------------------------------------------===// // -// This file declares the ELFObjectFile template class. +// This file declares the ELFFile template class. // //===----------------------------------------------------------------------===// #ifndef LLVM_OBJECT_ELF_H #define LLVM_OBJECT_ELF_H +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/IntervalMap.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/Error.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" #include @@ -32,1452 +37,1001 @@ namespace llvm { namespace object { -// 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; -}; +StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type); -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; -}; +// Subclasses of ELFFile may need this for template instantiation +inline std::pair +getElfArchType(StringRef Object) { + if (Object.size() < ELF::EI_NIDENT) + return std::make_pair((uint8_t)ELF::ELFCLASSNONE, + (uint8_t)ELF::ELFDATANONE); + return std::make_pair((uint8_t)Object[ELF::EI_CLASS], + (uint8_t)Object[ELF::EI_DATA]); +} -/// 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; -}; +template +class ELFFile { +public: + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + typedef typename std::conditional::type uintX_t; + + /// \brief Iterate over constant sized entities. + template + class ELFEntityIterator { + public: + typedef ptrdiff_t difference_type; + typedef EntT value_type; + typedef std::forward_iterator_tag iterator_category; + typedef value_type &reference; + typedef value_type *pointer; + + /// \brief Default construct iterator. + ELFEntityIterator() : EntitySize(0), Current(nullptr) {} + ELFEntityIterator(uintX_t EntSize, const char *Start) + : EntitySize(EntSize), Current(Start) {} + + reference operator *() { + assert(Current && "Attempted to dereference an invalid iterator!"); + return *reinterpret_cast(Current); + } -// 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 -}; + pointer operator ->() { + assert(Current && "Attempted to dereference an invalid iterator!"); + return reinterpret_cast(Current); + } -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 -}; + bool operator ==(const ELFEntityIterator &Other) { + return Current == Other.Current; + } -template -struct Elf_Shdr_Impl : Elf_Shdr_Base { - using Elf_Shdr_Base::sh_entsize; - using Elf_Shdr_Base::sh_size; + bool operator !=(const ELFEntityIterator &Other) { + return !(*this == Other); + } - /// @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; - } -}; + ELFEntityIterator &operator ++() { + assert(Current && "Attempted to increment an invalid iterator!"); + Current += EntitySize; + return *this; + } -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 -}; + ELFEntityIterator &operator+(difference_type n) { + assert(Current && "Attempted to increment an invalid iterator!"); + Current += (n * EntitySize); + return *this; + } -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 -}; + ELFEntityIterator &operator-(difference_type n) { + assert(Current && "Attempted to subtract an invalid iterator!"); + Current -= (n * EntitySize); + return *this; + } -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); - } -}; + ELFEntityIterator operator ++(int) { + ELFEntityIterator Tmp = *this; + ++*this; + return Tmp; + } -template -struct Elf_Rel_Base; + difference_type operator -(const ELFEntityIterator &Other) const { + assert(EntitySize == Other.EntitySize && + "Subtracting iterators of different EntitySize!"); + return (Current - Other.Current) / EntitySize; + } -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 -}; + const char *get() const { return Current; } -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 -}; + uintX_t getEntSize() const { return EntitySize; } -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 -}; + private: + uintX_t EntitySize; + const char *Current; + }; -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. -}; + typedef Elf_Ehdr_Impl Elf_Ehdr; + typedef Elf_Shdr_Impl Elf_Shdr; + typedef Elf_Sym_Impl Elf_Sym; + typedef Elf_Dyn_Impl Elf_Dyn; + typedef Elf_Phdr_Impl Elf_Phdr; + 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 Elf_Hash_Impl Elf_Hash; + typedef ELFEntityIterator Elf_Dyn_Iter; + typedef iterator_range Elf_Dyn_Range; + typedef ELFEntityIterator Elf_Rela_Iter; + typedef ELFEntityIterator Elf_Rel_Iter; + typedef iterator_range Elf_Shdr_Range; + + /// \brief Archive files are 2 byte aligned, so we need this for + /// PointerIntPair to work. + template + class ArchivePointerTypeTraits { + public: + static inline const void *getAsVoidPointer(T *P) { return P; } + static inline T *getFromVoidPointer(const void *P) { + return static_cast(P); + } + enum { NumLowBitsAvailable = 1 }; + }; -template -struct Elf_Rel_Impl; + typedef iterator_range Elf_Sym_Range; -template -struct Elf_Rel_Impl - : Elf_Rel_Base { - using Elf_Rel_Base::r_info; - LLVM_ELF_IMPORT_TYPES(target_endianness, true) +private: + typedef SmallVector Sections_t; + typedef DenseMap IndexMap_t; - // 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); - } -}; + StringRef Buf; -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; + const uint8_t *base() const { + return reinterpret_cast(Buf.data()); } -}; + const Elf_Ehdr *Header; + const Elf_Shdr *SectionHeaderTable = nullptr; + StringRef DotShstrtab; // Section header string table. + StringRef DotStrtab; // Symbol header string table. + const Elf_Shdr *dot_symtab_sec = nullptr; // Symbol table section. + StringRef DynSymStrTab; // Dynnamic symbol string table. + const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. + const Elf_Hash *HashTable = nullptr; + + const Elf_Shdr *SymbolTableSectionHeaderIndex = nullptr; + DenseMap ExtendedSymbolTable; + + const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version + const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r + const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d + + /// \brief Represents a region described by entries in the .dynamic table. + struct DynRegionInfo { + DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} + /// \brief Address in current address space. + const void *Addr; + /// \brief Size in bytes of the region. + uintX_t Size; + /// \brief Size of each entity in the region. + uintX_t EntSize; + }; -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_Rel_Impl Elf_Rel; - typedef Elf_Rel_Impl Elf_Rela; - -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; + DynRegionInfo DynamicRegion; + DynRegionInfo DynHashRegion; + DynRegionInfo DynRelaRegion; + + // Pointer to SONAME entry in dynamic string table + // This is set the first time getLoadName is called. + mutable const char *dt_soname = nullptr; + + // 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(nullptr, 0) { } + VersionMapEntry(const Elf_Verdef *verdef) + : PointerIntPair(verdef, 0) { } + VersionMapEntry(const Elf_Vernaux *vernaux) + : PointerIntPair(vernaux, 1) { } + bool isNull() const { return getPointer() == nullptr; } + bool isVerdef() const { return !isNull() && getInt() == 0; } + bool isVernaux() const { return !isNull() && getInt() == 1; } + const Elf_Verdef *getVerdef() const { + return isVerdef() ? (const Elf_Verdef*)getPointer() : nullptr; + } + const Elf_Vernaux *getVernaux() const { + return isVernaux() ? (const Elf_Vernaux*)getPointer() : nullptr; } - 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; + mutable SmallVector VersionMap; + void LoadVersionDefs(const Elf_Shdr *sec) const; + void LoadVersionNeeds(const Elf_Shdr *ec) const; + void LoadVersionMap() const; - 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. - Sections_t SymbolTableSections; - IndexMap_t SymbolTableSectionsIndexMap; - DenseMap ExtendedSymbolTable; - - /// @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 getSymbolName(const Elf_Sym *Symb, StringRef &Res) const; - -protected: - const Elf_Sym *getSymbol(DataRefImpl Symb) const; // FIXME: Should be private? - void validateSymbol(DataRefImpl Symb) 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 isSymbolInternal(DataRefImpl Symb, bool &Res) const; - virtual error_code isSymbolGlobal(DataRefImpl Symb, bool &Res) const; - virtual error_code isSymbolWeak(DataRefImpl Symb, bool &Res) const; - virtual error_code getSymbolType(DataRefImpl Symb, SymbolRef::Type &Res) const; - virtual error_code isSymbolAbsolute(DataRefImpl Symb, bool &Res) const; - virtual error_code getSymbolSection(DataRefImpl Symb, - section_iterator &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 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; + void scanDynamicTable(); public: - ELFObjectFile(MemoryBuffer *Object, error_code &ec); - virtual symbol_iterator begin_symbols() const; - virtual symbol_iterator end_symbols() const; - virtual section_iterator begin_sections() const; - virtual section_iterator end_sections() const; - - virtual uint8_t getBytesInAddress() const; - virtual StringRef getFileFormatName() const; - virtual unsigned getArch() 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; - - // 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() == Binary::isELF; + template + const T *getEntry(uint32_t Section, uint32_t Entry) const; + template + const T *getEntry(const Elf_Shdr *Section, uint32_t Entry) const; + + const Elf_Shdr *getDotSymtabSec() const { return dot_symtab_sec; } + const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } + const Elf_Hash *getHashTable() const { return HashTable; } + + ErrorOr getStringTable(const Elf_Shdr *Section) const; + const char *getDynamicString(uintX_t Offset) const; + ErrorOr getSymbolVersion(const Elf_Shdr *section, + const Elf_Sym *Symb, + bool &IsDefault) const; + void VerifyStrTab(const Elf_Shdr *sh) const; + + StringRef getRelocationTypeName(uint32_t Type) const; + void getRelocationTypeName(uint32_t Type, + SmallVectorImpl &Result) const; + + /// \brief Get the symbol table section and symbol for a given relocation. + template + std::pair + getRelocationSymbol(const Elf_Shdr *RelSec, const RelT *Rel) const; + + ELFFile(StringRef Object, std::error_code &EC); + + bool isMipsELF64() const { + return Header->e_machine == ELF::EM_MIPS && + Header->getFileClass() == ELF::ELFCLASS64; } - static inline bool classof(const ELFObjectFile *v) { return true; } -}; -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. - ++Symb.d.b; - Symb.d.a = 1; // The 0th symbol in ELF is fake. - // Otherwise return the terminator. - if (Symb.d.b >= SymbolTableSections.size()) { - Symb.d.a = std::numeric_limits::max(); - Symb.d.b = std::numeric_limits::max(); - } + bool isMips64EL() const { + return Header->e_machine == ELF::EM_MIPS && + Header->getFileClass() == ELF::ELFCLASS64 && + Header->getDataEncoding() == ELF::ELFDATA2LSB; } - 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(symb, Result); -} - -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 -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); + const Elf_Shdr *section_begin() const; + const Elf_Shdr *section_end() const; + Elf_Shdr_Range sections() const { + return make_range(section_begin(), section_end()); } - 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; + const Elf_Sym *symbol_begin() const; + const Elf_Sym *symbol_end() const; + Elf_Sym_Range symbols() const { + return make_range(symbol_begin(), symbol_end()); } -} -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); + Elf_Dyn_Iter dynamic_table_begin() const; + /// \param NULLEnd use one past the first DT_NULL entry as the end instead of + /// the section size. + Elf_Dyn_Iter dynamic_table_end(bool NULLEnd = false) const; + Elf_Dyn_Range dynamic_table(bool NULLEnd = false) const { + return make_range(dynamic_table_begin(), dynamic_table_end(NULLEnd)); } - 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; + const Elf_Sym *dynamic_symbol_begin() const { + if (!DotDynSymSec) + return nullptr; + if (DotDynSymSec->sh_entsize != sizeof(Elf_Sym)) + report_fatal_error("Invalid symbol size"); + return reinterpret_cast(base() + DotDynSymSec->sh_offset); } -} - -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'; - } + const Elf_Sym *dynamic_symbol_end() const { + if (!DotDynSymSec) + return nullptr; + return reinterpret_cast(base() + DotDynSymSec->sh_offset + + DotDynSymSec->sh_size); } - 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; + Elf_Sym_Range dynamic_symbols() const { + return make_range(dynamic_symbol_begin(), dynamic_symbol_end()); } - 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'; + Elf_Rela_Iter dyn_rela_begin() const { + if (DynRelaRegion.Addr) + return Elf_Rela_Iter(DynRelaRegion.EntSize, + (const char *)DynRelaRegion.Addr); + return Elf_Rela_Iter(0, nullptr); } - 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; + Elf_Rela_Iter dyn_rela_end() const { + if (DynRelaRegion.Addr) + return Elf_Rela_Iter( + DynRelaRegion.EntSize, + (const char *)DynRelaRegion.Addr + DynRelaRegion.Size); + return Elf_Rela_Iter(0, nullptr); } - 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); + Elf_Rela_Iter rela_begin(const Elf_Shdr *sec) const { + return Elf_Rela_Iter(sec->sh_entsize, + (const char *)(base() + sec->sh_offset)); + } - if (getSymbolTableIndex(symb) == ELF::SHN_UNDEF) { - Result = SymbolRef::ST_External; - return object_error::success; + Elf_Rela_Iter rela_end(const Elf_Shdr *sec) const { + return Elf_Rela_Iter( + sec->sh_entsize, + (const char *)(base() + sec->sh_offset + sec->sh_size)); } - switch (symb->getType()) { - 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: - Result = SymbolRef::ST_Data; - break; - default: - Result = SymbolRef::ST_Other; - break; + Elf_Rel_Iter rel_begin(const Elf_Shdr *sec) const { + return Elf_Rel_Iter(sec->sh_entsize, + (const char *)(base() + sec->sh_offset)); } - return object_error::success; -} -template -error_code ELFObjectFile - ::isSymbolGlobal(DataRefImpl Symb, - bool &Result) const { - validateSymbol(Symb); - const Elf_Sym *symb = getSymbol(Symb); + Elf_Rel_Iter rel_end(const Elf_Shdr *sec) const { + return Elf_Rel_Iter(sec->sh_entsize, + (const char *)(base() + sec->sh_offset + sec->sh_size)); + } - Result = symb->getBinding() == ELF::STB_GLOBAL; - return object_error::success; -} + /// \brief Iterate over program header table. + typedef ELFEntityIterator Elf_Phdr_Iter; -template -error_code ELFObjectFile - ::isSymbolWeak(DataRefImpl Symb, - bool &Result) const { - validateSymbol(Symb); - const Elf_Sym *symb = getSymbol(Symb); + Elf_Phdr_Iter program_header_begin() const { + return Elf_Phdr_Iter(Header->e_phentsize, + (const char*)base() + Header->e_phoff); + } - Result = symb->getBinding() == ELF::STB_WEAK; - return object_error::success; -} + Elf_Phdr_Iter program_header_end() const { + return Elf_Phdr_Iter(Header->e_phentsize, + (const char*)base() + + Header->e_phoff + + (Header->e_phnum * Header->e_phentsize)); + } -template -error_code ELFObjectFile - ::isSymbolAbsolute(DataRefImpl Symb, bool &Res) const { - validateSymbol(Symb); - const Elf_Sym *symb = getSymbol(Symb); - Res = symb->st_shndx == ELF::SHN_ABS; - return object_error::success; -} + uint64_t getNumSections() const; + uintX_t getStringTableIndex() const; + ELF::Elf64_Word getExtendedSymbolTableIndex(const Elf_Sym *symb) const; + const Elf_Ehdr *getHeader() const { return Header; } + ErrorOr getSection(const Elf_Sym *symb) const; + ErrorOr getSection(uint32_t Index) const; + const Elf_Sym *getSymbol(uint32_t index) const; + + ErrorOr getStaticSymbolName(const Elf_Sym *Symb) const; + ErrorOr getDynamicSymbolName(const Elf_Sym *Symb) const; + ErrorOr getSymbolName(const Elf_Sym *Symb, bool IsDynamic) const; + + ErrorOr getSectionName(const Elf_Shdr *Section) const; + ErrorOr > getSectionContents(const Elf_Shdr *Sec) const; + StringRef getLoadName() const; +}; -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)); +typedef ELFFile> ELF32LEFile; +typedef ELFFile> ELF64LEFile; +typedef ELFFile> ELF32BEFile; +typedef ELFFile> ELF64BEFile; + +// Iterate through the version definitions, and place each Elf_Verdef +// in the VersionMap according to its index. +template +void ELFFile::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; } - return object_error::success; } -template -error_code ELFObjectFile - ::isSymbolInternal(DataRefImpl Symb, - bool &Result) const { - validateSymbol(Symb); - const Elf_Sym *symb = getSymbol(Symb); - - if ( symb->getType() == ELF::STT_FILE - || symb->getType() == ELF::STT_SECTION) - Result = true; - Result = false; - return object_error::success; +// Iterate through the versions needed section, and place each Elf_Vernaux +// in the VersionMap according to its index. +template +void ELFFile::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 -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 +void ELFFile::LoadVersionMap() const { + // If there is no dynamic symtab or version table, there is nothing to do. + if (!DotDynSymSec || !dot_gnu_version_sec) + return; -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; -} + // Has the VersionMap already been loaded? + if (VersionMap.size() > 0) + return; -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; -} + // The first two version indexes are reserved. + // Index 0 is LOCAL, index 1 is GLOBAL. + VersionMap.push_back(VersionMapEntry()); + VersionMap.push_back(VersionMapEntry()); -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; -} + if (dot_gnu_version_d_sec) + LoadVersionDefs(dot_gnu_version_d_sec); -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; + if (dot_gnu_version_r_sec) + LoadVersionNeeds(dot_gnu_version_r_sec); } -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 +ELF::Elf64_Word +ELFFile::getExtendedSymbolTableIndex(const Elf_Sym *symb) const { + assert(symb->st_shndx == ELF::SHN_XINDEX); + return ExtendedSymbolTable.lookup(symb); } -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 +ErrorOr::Elf_Shdr *> +ELFFile::getSection(const Elf_Sym *symb) const { + uint32_t Index = symb->st_shndx; + if (Index == ELF::SHN_XINDEX) + return getSection(ExtendedSymbolTable.lookup(symb)); + if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE) + return nullptr; + return getSection(symb->st_shndx); } -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 +const typename ELFFile::Elf_Sym * +ELFFile::getSymbol(uint32_t Index) const { + return &*(symbol_begin() + Index); } -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 +ErrorOr > +ELFFile::getSectionContents(const Elf_Shdr *Sec) const { + if (Sec->sh_offset + Sec->sh_size > Buf.size()) + return object_error::parse_failed; + const uint8_t *Start = base() + Sec->sh_offset; + return makeArrayRef(Start, Sec->sh_size); } -template -error_code ELFObjectFile - ::sectionContainsSymbol(DataRefImpl Sec, - DataRefImpl Symb, - bool &Result) const { - // FIXME: Unimplemented. - Result = false; - return object_error::success; +template +StringRef ELFFile::getRelocationTypeName(uint32_t Type) const { + return getELFRelocationTypeName(Header->e_machine, Type); } -template -relocation_iterator ELFObjectFile - ::getSectionRelBegin(DataRefImpl Sec) const { - DataRefImpl RelData; - memset(&RelData, 0, sizeof(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; +template +void ELFFile::getRelocationTypeName(uint32_t Type, + SmallVectorImpl &Result) const { + if (!isMipsELF64()) { + StringRef Name = getRelocationTypeName(Type); + Result.append(Name.begin(), Name.end()); + } else { + // The Mips N64 ABI allows up to three operations to be specified per + // relocation record. Unfortunately there's no easy way to test for the + // presence of N64 ELFs as they have no special flag that identifies them + // as being N64. We can safely assume at the moment that all Mips + // ELFCLASS64 ELFs are N64. New Mips64 ABIs should provide enough + // information to disambiguate between old vs new ABIs. + uint8_t Type1 = (Type >> 0) & 0xFF; + uint8_t Type2 = (Type >> 8) & 0xFF; + uint8_t Type3 = (Type >> 16) & 0xFF; + + // Concat all three relocation type names. + StringRef Name = getRelocationTypeName(Type1); + Result.append(Name.begin(), Name.end()); + + Name = getRelocationTypeName(Type2); + Result.append(1, '/'); + Result.append(Name.begin(), Name.end()); + + Name = getRelocationTypeName(Type3); + Result.append(1, '/'); + Result.append(Name.begin(), Name.end()); } - return relocation_iterator(RelocationRef(RelData, this)); } -template -relocation_iterator ELFObjectFile - ::getSectionRelEnd(DataRefImpl Sec) const { - DataRefImpl RelData; - memset(&RelData, 0, sizeof(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)); +template +template +std::pair::Elf_Shdr *, + const typename ELFFile::Elf_Sym *> +ELFFile::getRelocationSymbol(const Elf_Shdr *Sec, const RelT *Rel) const { + if (!Sec->sh_link) + return std::make_pair(nullptr, nullptr); + ErrorOr SymTableOrErr = getSection(Sec->sh_link); + if (std::error_code EC = SymTableOrErr.getError()) + report_fatal_error(EC.message()); + const Elf_Shdr *SymTable = *SymTableOrErr; + return std::make_pair( + SymTable, getEntry(SymTable, Rel->getSymbol(isMips64EL()))); } -// 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; - } +template +uint64_t ELFFile::getNumSections() const { + assert(Header && "Header not initialized!"); + if (Header->e_shnum == ELF::SHN_UNDEF && Header->e_shoff > 0) { + assert(SectionHeaderTable && "SectionHeaderTable not initialized!"); + return SectionHeaderTable->sh_size; } - Result = RelocationRef(Rel, this); - return object_error::success; + return Header->e_shnum; } -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; - } +template +typename ELFFile::uintX_t ELFFile::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; } - 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; + return Header->e_shstrndx; } -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; - } +template +ELFFile::ELFFile(StringRef Object, std::error_code &EC) + : Buf(Object) { + const uint64_t FileSize = Buf.size(); + + if (sizeof(Elf_Ehdr) > FileSize) { + // File too short! + EC = object_error::parse_failed; + return; } - Result = offset; - return object_error::success; -} + Header = reinterpret_cast(base()); -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; - } + if (Header->e_shoff == 0) { + scanDynamicTable(); + return; } - Result = offset - sec->sh_addr; - return object_error::success; -} + const uint64_t SectionTableOffset = Header->e_shoff; -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; - } + if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) { + // Section header table goes past end of file! + EC = object_error::parse_failed; + return; } - return object_error::success; -} -#define LLVM_ELF_SWITCH_RELOC_TYPE_NAME(enum) \ - case ELF::enum: res = #enum; break; + // The getNumSections() call below depends on SectionHeaderTable being set. + SectionHeaderTable = + reinterpret_cast(base() + SectionTableOffset); + const uint64_t SectionTableSize = getNumSections() * Header->e_shentsize; -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; - default: - res = "Unknown"; + if (SectionTableOffset + SectionTableSize > FileSize) { + // Section table goes past end of file! + EC = object_error::parse_failed; + return; } - 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; - } - } -} + // Scan sections for special sections. -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. + for (const Elf_Shdr &Sec : sections()) { + switch (Sec.sh_type) { + case ELF::SHT_HASH: + if (HashTable) { + EC = object_error::parse_failed; + return; + } + HashTable = reinterpret_cast(base() + Sec.sh_offset); break; - } - case ELF::SHT_RELA : { - type = getRela(Rel)->getType(); - symbol_index = getRela(Rel)->getSymbol(); - addend = getRela(Rel)->r_addend; + case ELF::SHT_SYMTAB_SHNDX: + if (SymbolTableSectionHeaderIndex) { + // More than one .symtab_shndx! + EC = object_error::parse_failed; + return; + } + SymbolTableSectionHeaderIndex = &Sec; + break; + case ELF::SHT_SYMTAB: { + if (dot_symtab_sec) { + // More than one .symtab! + EC = object_error::parse_failed; + return; + } + dot_symtab_sec = &Sec; + ErrorOr SectionOrErr = getSection(Sec.sh_link); + if ((EC = SectionOrErr.getError())) + return; + ErrorOr SymtabOrErr = getStringTable(*SectionOrErr); + if ((EC = SymtabOrErr.getError())) + return; + DotStrtab = *SymtabOrErr; + } break; + case ELF::SHT_DYNSYM: { + if (DotDynSymSec) { + // More than one .dynsym! + EC = object_error::parse_failed; + return; + } + DotDynSymSec = &Sec; + ErrorOr SectionOrErr = getSection(Sec.sh_link); + if ((EC = SectionOrErr.getError())) + return; + ErrorOr SymtabOrErr = getStringTable(*SectionOrErr); + if ((EC = SymtabOrErr.getError())) + return; + DynSymStrTab = *SymtabOrErr; break; } - } - const Elf_Sym *symb = getEntry(sec->sh_link, symbol_index); - StringRef symname; - if (error_code ec = getSymbolName(symb, symname)) - return ec; - switch (Header->e_machine) { - case ELF::EM_X86_64: - switch (type) { - case ELF::R_X86_64_32S: - res = symname; + case ELF::SHT_DYNAMIC: + if (DynamicRegion.Addr) { + // More than one .dynamic! + EC = object_error::parse_failed; + return; + } + DynamicRegion.Addr = base() + Sec.sh_offset; + DynamicRegion.Size = Sec.sh_size; + DynamicRegion.EntSize = Sec.sh_entsize; + break; + case ELF::SHT_GNU_versym: + if (dot_gnu_version_sec != nullptr) { + // More than one .gnu.version section! + EC = object_error::parse_failed; + return; + } + dot_gnu_version_sec = &Sec; + break; + case ELF::SHT_GNU_verdef: + if (dot_gnu_version_d_sec != nullptr) { + // More than one .gnu.version_d section! + EC = object_error::parse_failed; + return; + } + dot_gnu_version_d_sec = &Sec; break; - 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()); + case ELF::SHT_GNU_verneed: + if (dot_gnu_version_r_sec != nullptr) { + // More than one .gnu.version_r section! + EC = object_error::parse_failed; + return; } + dot_gnu_version_r_sec = &Sec; break; - default: - res = "Unknown"; } - break; - default: - res = "Unknown"; } - if (Result.empty()) - Result.append(res.begin(), res.end()); - return object_error::success; -} - -template -ELFObjectFile::ELFObjectFile(MemoryBuffer *Object - , error_code &ec) - : ObjectFile(Binary::isELF, Object, ec) - , isDyldELFObject(false) - , SectionHeaderTable(0) - , dot_shstrtab_sec(0) - , dot_strtab_sec(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) + // Get string table sections. + ErrorOr StrTabSecOrErr = getSection(getStringTableIndex()); + if ((EC = StrTabSecOrErr.getError())) 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; + ErrorOr SymtabOrErr = getStringTable(*StrTabSecOrErr); + if ((EC = SymtabOrErr.getError())) + return; + DotShstrtab = *SymtabOrErr; - 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; - for (uint64_t i = 0, e = getNumSections(); i != e; ++i) { - if (sh->sh_type == ELF::SHT_SYMTAB_SHNDX) { - if (SymbolTableSectionHeaderIndex) - // FIXME: Proper error handling. - report_fatal_error("More than one .symtab_shndx!"); - SymbolTableSectionHeaderIndex = sh; - } - if (sh->sh_type == ELF::SHT_SYMTAB) { - SymbolTableSectionsIndexMap[i] = SymbolTableSections.size(); - SymbolTableSections.push_back(sh); - } - if (sh->sh_type == ELF::SHT_REL || sh->sh_type == ELF::SHT_RELA) { - SectionRelocMap[getSection(sh->sh_info)].push_back(i); + // Build symbol name side-mapping if there is one. + if (SymbolTableSectionHeaderIndex) { + const Elf_Word *ShndxTable = reinterpret_cast(base() + + SymbolTableSectionHeaderIndex->sh_offset); + for (const Elf_Sym &S : symbols()) { + if (*ShndxTable != ELF::SHN_UNDEF) + ExtendedSymbolTable[&S] = *ShndxTable; + ++ShndxTable; } - ++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()); - } + scanDynamicTable(); - // 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. - if (((const char*)base() + dot_shstrtab_sec->sh_offset) - [dot_shstrtab_sec->sh_size - 1] != 0) - // FIXME: Proper error handling. - report_fatal_error("String table must end with a null terminator!"); - } + EC = std::error_code(); +} - // 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; - const char *dot_strtab = (const char*)base() + sh->sh_offset; - if (dot_strtab[sh->sh_size - 1] != 0) - // FIXME: Proper error handling. - report_fatal_error("String table must end with a null terminator!"); - } +template +void ELFFile::scanDynamicTable() { + // Build load-address to file-offset map. + typedef IntervalMap< + uintX_t, uintptr_t, + IntervalMapImpl::NodeSizer::LeafSize, + IntervalMapHalfOpenInfo> LoadMapT; + typename LoadMapT::Allocator Alloc; + LoadMapT LoadMap(Alloc); + + for (Elf_Phdr_Iter PhdrI = program_header_begin(), + PhdrE = program_header_end(); + PhdrI != PhdrE; ++PhdrI) { + if (PhdrI->p_type == ELF::PT_DYNAMIC) { + DynamicRegion.Addr = base() + PhdrI->p_offset; + DynamicRegion.Size = PhdrI->p_filesz; + DynamicRegion.EntSize = sizeof(Elf_Dyn); + continue; } + if (PhdrI->p_type != ELF::PT_LOAD) + continue; + if (PhdrI->p_filesz == 0) + continue; + LoadMap.insert(PhdrI->p_vaddr, PhdrI->p_vaddr + PhdrI->p_filesz, + PhdrI->p_offset); } - // 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; + auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { + auto I = LoadMap.find(VAddr); + if (I == LoadMap.end()) + return nullptr; + return this->base() + I.value() + (VAddr - I.start()); + }; + + for (Elf_Dyn_Iter DynI = dynamic_table_begin(), DynE = dynamic_table_end(); + DynI != DynE; ++DynI) { + switch (DynI->d_tag) { + case ELF::DT_HASH: + if (HashTable) + continue; + HashTable = + reinterpret_cast(toMappedAddr(DynI->getPtr())); + break; + case ELF::DT_RELA: + if (!DynRelaRegion.Addr) + DynRelaRegion.Addr = toMappedAddr(DynI->getPtr()); + break; + case ELF::DT_RELASZ: + DynRelaRegion.Size = DynI->getVal(); + break; + case ELF::DT_RELAENT: + DynRelaRegion.EntSize = DynI->getVal(); } } } -template -symbol_iterator ELFObjectFile - ::begin_symbols() const { - DataRefImpl SymbolData; - memset(&SymbolData, 0, sizeof(SymbolData)); - if (SymbolTableSections.size() == 0) { - 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; - } - return symbol_iterator(SymbolRef(SymbolData, this)); +template +const typename ELFFile::Elf_Shdr *ELFFile::section_begin() const { + if (Header->e_shentsize != sizeof(Elf_Shdr)) + report_fatal_error( + "Invalid section header entry size (e_shentsize) in ELF header"); + return reinterpret_cast(base() + Header->e_shoff); } -template -symbol_iterator ELFObjectFile - ::end_symbols() const { - DataRefImpl SymbolData; - memset(&SymbolData, 0, sizeof(SymbolData)); - SymbolData.d.a = std::numeric_limits::max(); - SymbolData.d.b = std::numeric_limits::max(); - return symbol_iterator(SymbolRef(SymbolData, this)); +template +const typename ELFFile::Elf_Shdr *ELFFile::section_end() const { + return section_begin() + getNumSections(); } -template -section_iterator ELFObjectFile - ::begin_sections() const { - DataRefImpl ret; - memset(&ret, 0, sizeof(DataRefImpl)); - ret.p = reinterpret_cast(base() + Header->e_shoff); - return section_iterator(SectionRef(ret, this)); +template +const typename ELFFile::Elf_Sym *ELFFile::symbol_begin() const { + if (!dot_symtab_sec) + return nullptr; + if (dot_symtab_sec->sh_entsize != sizeof(Elf_Sym)) + report_fatal_error("Invalid symbol size"); + return reinterpret_cast(base() + dot_symtab_sec->sh_offset); } -template -section_iterator ELFObjectFile - ::end_sections() const { - DataRefImpl ret; - memset(&ret, 0, sizeof(DataRefImpl)); - ret.p = reinterpret_cast(base() - + Header->e_shoff - + (Header->e_shentsize*getNumSections())); - return section_iterator(SectionRef(ret, this)); +template +const typename ELFFile::Elf_Sym *ELFFile::symbol_end() const { + if (!dot_symtab_sec) + return nullptr; + return reinterpret_cast(base() + dot_symtab_sec->sh_offset + + dot_symtab_sec->sh_size); } -template -uint8_t ELFObjectFile::getBytesInAddress() const { - return is64Bits ? 8 : 4; +template +typename ELFFile::Elf_Dyn_Iter +ELFFile::dynamic_table_begin() const { + if (DynamicRegion.Addr) + return Elf_Dyn_Iter(DynamicRegion.EntSize, + (const char *)DynamicRegion.Addr); + return Elf_Dyn_Iter(0, nullptr); } -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"; - 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 +typename ELFFile::Elf_Dyn_Iter +ELFFile::dynamic_table_end(bool NULLEnd) const { + if (!DynamicRegion.Addr) + return Elf_Dyn_Iter(0, nullptr); + Elf_Dyn_Iter Ret(DynamicRegion.EntSize, + (const char *)DynamicRegion.Addr + DynamicRegion.Size); + + if (NULLEnd) { + Elf_Dyn_Iter Start = dynamic_table_begin(); + while (Start != Ret && Start->getTag() != ELF::DT_NULL) + ++Start; + + // Include the DT_NULL. + if (Start != Ret) + ++Start; + Ret = Start; } + return Ret; } -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; - default: - return Triple::UnknownArch; +template +StringRef ELFFile::getLoadName() const { + if (!dt_soname) { + dt_soname = ""; + // Find the DT_SONAME entry + for (const auto &Entry : dynamic_table()) + if (Entry.getTag() == ELF::DT_SONAME) { + dt_soname = getDynamicString(Entry.getVal()); + break; + } } + return dt_soname; } -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 +template +const T *ELFFile::getEntry(uint32_t Section, uint32_t Entry) const { + ErrorOr Sec = getSection(Section); + if (std::error_code EC = Sec.getError()) + report_fatal_error(EC.message()); + return getEntry(*Sec, Entry); } -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 +const T *ELFFile::getEntry(const Elf_Shdr *Section, + uint32_t Entry) const { + return reinterpret_cast(base() + Section->sh_offset + + (Entry * Section->sh_entsize)); } +template +ErrorOr::Elf_Shdr *> +ELFFile::getSection(uint32_t Index) const { + assert(SectionHeaderTable && "SectionHeaderTable not initialized!"); + if (Index >= getNumSections()) + return object_error::invalid_section_index; -template -template -inline const T * -ELFObjectFile::getEntry(uint16_t Section, - uint32_t Entry) const { - return getEntry(getSection(Section), Entry); + return reinterpret_cast( + reinterpret_cast(SectionHeaderTable) + + (Index * Header->e_shentsize)); } -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 +ErrorOr +ELFFile::getStringTable(const Elf_Shdr *Section) const { + if (Section->sh_type != ELF::SHT_STRTAB) + return object_error::parse_failed; + uint64_t Offset = Section->sh_offset; + uint64_t Size = Section->sh_size; + if (Offset + Size > Buf.size()) + return object_error::parse_failed; + StringRef Data((const char *)base() + Section->sh_offset, Size); + if (Data[Size - 1] != '\0') + return object_error::string_table_non_null_end; + return Data; } -template -const typename ELFObjectFile::Elf_Sym * -ELFObjectFile::getSymbol(DataRefImpl Symb) const { - return getEntry(SymbolTableSections[Symb.d.b], Symb.d.a); +template +const char *ELFFile::getDynamicString(uintX_t Offset) const { + if (!DotDynSymSec || Offset >= DynSymStrTab.size()) + return nullptr; + return (const char *)DynSymStrTab.begin() + Offset; } -template -const typename ELFObjectFile::Elf_Rel * -ELFObjectFile::getRel(DataRefImpl Rel) const { - return getEntry(Rel.w.b, Rel.w.c); +template +ErrorOr +ELFFile::getStaticSymbolName(const Elf_Sym *Symb) const { + return Symb->getName(DotStrtab); } -template -const typename ELFObjectFile::Elf_Rela * -ELFObjectFile::getRela(DataRefImpl Rela) const { - return getEntry(Rela.w.b, Rela.w.c); +template +ErrorOr +ELFFile::getDynamicSymbolName(const Elf_Sym *Symb) const { + return StringRef(getDynamicString(Symb->st_name)); } -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 +ErrorOr ELFFile::getSymbolName(const Elf_Sym *Symb, + bool IsDynamic) const { + if (IsDynamic) + return getDynamicSymbolName(Symb); + return getStaticSymbolName(Symb); } -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 +ErrorOr +ELFFile::getSectionName(const Elf_Shdr *Section) const { + uint32_t Offset = Section->sh_name; + if (Offset >= DotShstrtab.size()) + return object_error::parse_failed; + return StringRef(DotShstrtab.data() + Offset); } -template -const char *ELFObjectFile - ::getString(uint32_t section, - ELF::Elf32_Word offset) const { - return getString(getSection(section), offset); -} +template +ErrorOr ELFFile::getSymbolVersion(const Elf_Shdr *section, + const Elf_Sym *symb, + bool &IsDefault) const { + StringRef StrTab; + if (section) { + ErrorOr StrTabOrErr = getStringTable(section); + if (std::error_code EC = StrTabOrErr.getError()) + return EC; + StrTab = *StrTabOrErr; + } + // Handle non-dynamic symbols. + if (section != DotDynSymSec && section != nullptr) { + // 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. + ErrorOr SymName = symb->getName(StrTab); + if (!SymName) + return SymName; + StringRef Name = *SymName; + size_t atpos = Name.find('@'); + if (atpos == StringRef::npos) { + IsDefault = false; + return StringRef(""); + } + ++atpos; + if (atpos < Name.size() && Name[atpos] == '@') { + IsDefault = true; + ++atpos; + } else { + IsDefault = false; + } + return Name.substr(atpos); + } -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; -} + // This is a dynamic symbol. Look in the GNU symbol version table. + if (!dot_gnu_version_sec) { + // No version table. + IsDefault = false; + return StringRef(""); + } -template -error_code ELFObjectFile - ::getSymbolName(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; + // Determine the position in the symbol table of this entry. + size_t entry_index = + (reinterpret_cast(symb) - DotDynSymSec->sh_offset - + reinterpret_cast(base())) / + sizeof(Elf_Sym); + + // 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) { + IsDefault = false; + return StringRef(""); } - // Use the default symbol table name section. - Result = getString(dot_strtab_sec, symb->st_name); - return object_error::success; -} + // Lookup this symbol in the version table + LoadVersionMap(); + if (version_index >= VersionMap.size() || VersionMap[version_index].isNull()) + return object_error::parse_failed; + 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; + } + // Set IsDefault + if (entry.isVerdef()) { + IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN); + } else { + IsDefault = false; + } + + if (name_offset >= DynSymStrTab.size()) + return object_error::parse_failed; + return StringRef(getDynamicString(name_offset)); } + +/// This function returns the hash value for a symbol in the .dynsym section +/// Name of the API remains consistent as specified in the libelf +/// REF : http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash +static inline unsigned elf_hash(StringRef &symbolName) { + unsigned h = 0, g; + for (unsigned i = 0, j = symbolName.size(); i < j; i++) { + h = (h << 4) + symbolName[i]; + g = h & 0xf0000000L; + if (g != 0) + h ^= g >> 24; + h &= ~g; + } + return h; } +} // end namespace object +} // end namespace llvm #endif