diff options
Diffstat (limited to 'include/llvm/Object')
-rw-r--r-- | include/llvm/Object/ELF.h | 2970 | ||||
-rw-r--r-- | include/llvm/Object/ObjectFile.h | 3 |
2 files changed, 2971 insertions, 2 deletions
diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h new file mode 100644 index 0000000000..3e73ff4673 --- /dev/null +++ b/include/llvm/Object/ELF.h @@ -0,0 +1,2970 @@ +//===- 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/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 <algorithm> +#include <limits> +#include <utility> + +namespace llvm { +namespace object { + +// Templates to choose Elf_Addr and Elf_Off depending on is64Bits. +template<support::endianness target_endianness> +struct ELFDataTypeTypedefHelperCommon { + typedef support::detail::packed_endian_specific_integral + <uint16_t, target_endianness, support::aligned> Elf_Half; + typedef support::detail::packed_endian_specific_integral + <uint32_t, target_endianness, support::aligned> Elf_Word; + typedef support::detail::packed_endian_specific_integral + <int32_t, target_endianness, support::aligned> Elf_Sword; + typedef support::detail::packed_endian_specific_integral + <uint64_t, target_endianness, support::aligned> Elf_Xword; + typedef support::detail::packed_endian_specific_integral + <int64_t, target_endianness, support::aligned> Elf_Sxword; +}; + +template<support::endianness target_endianness, bool is64Bits> +struct ELFDataTypeTypedefHelper; + +/// ELF 32bit types. +template<support::endianness target_endianness> +struct ELFDataTypeTypedefHelper<target_endianness, false> + : ELFDataTypeTypedefHelperCommon<target_endianness> { + typedef uint32_t value_type; + typedef support::detail::packed_endian_specific_integral + <value_type, target_endianness, support::aligned> Elf_Addr; + typedef support::detail::packed_endian_specific_integral + <value_type, target_endianness, support::aligned> Elf_Off; +}; + +/// ELF 64bit types. +template<support::endianness target_endianness> +struct ELFDataTypeTypedefHelper<target_endianness, true> + : ELFDataTypeTypedefHelperCommon<target_endianness>{ + typedef uint64_t value_type; + typedef support::detail::packed_endian_specific_integral + <value_type, target_endianness, support::aligned> Elf_Addr; + typedef support::detail::packed_endian_specific_integral + <value_type, target_endianness, support::aligned> 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<target_endianness, is64Bits>::Elf_Addr Elf_Addr; \ +typedef typename \ + ELFDataTypeTypedefHelper<target_endianness, is64Bits>::Elf_Off Elf_Off; \ +typedef typename \ + ELFDataTypeTypedefHelper<target_endianness, is64Bits>::Elf_Half Elf_Half; \ +typedef typename \ + ELFDataTypeTypedefHelper<target_endianness, is64Bits>::Elf_Word Elf_Word; \ +typedef typename \ + ELFDataTypeTypedefHelper<target_endianness, is64Bits>::Elf_Sword Elf_Sword; \ +typedef typename \ + ELFDataTypeTypedefHelper<target_endianness, is64Bits>::Elf_Xword Elf_Xword; \ +typedef typename \ + ELFDataTypeTypedefHelper<target_endianness, is64Bits>::Elf_Sxword Elf_Sxword; + + // Section header. +template<support::endianness target_endianness, bool is64Bits> +struct Elf_Shdr_Base; + +template<support::endianness target_endianness> +struct Elf_Shdr_Base<target_endianness, false> { + 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<support::endianness target_endianness> +struct Elf_Shdr_Base<target_endianness, true> { + 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<support::endianness target_endianness, bool is64Bits> +struct Elf_Shdr_Impl : Elf_Shdr_Base<target_endianness, is64Bits> { + using Elf_Shdr_Base<target_endianness, is64Bits>::sh_entsize; + using Elf_Shdr_Base<target_endianness, is64Bits>::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<support::endianness target_endianness, bool is64Bits> +struct Elf_Sym_Base; + +template<support::endianness target_endianness> +struct Elf_Sym_Base<target_endianness, false> { + 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<support::endianness target_endianness> +struct Elf_Sym_Base<target_endianness, true> { + 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<support::endianness target_endianness, bool is64Bits> +struct Elf_Sym_Impl : Elf_Sym_Base<target_endianness, is64Bits> { + using Elf_Sym_Base<target_endianness, is64Bits>::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); + } +}; + +template<support::endianness target_endianness, bool is64Bits, bool isRela> +struct Elf_Rel_Base; + +template<support::endianness target_endianness> +struct Elf_Rel_Base<target_endianness, false, false> { + 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<support::endianness target_endianness> +struct Elf_Rel_Base<target_endianness, true, false> { + 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<support::endianness target_endianness> +struct Elf_Rel_Base<target_endianness, false, true> { + 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<support::endianness target_endianness> +struct Elf_Rel_Base<target_endianness, true, true> { + 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<support::endianness target_endianness, bool is64Bits, bool isRela> +struct Elf_Rel_Impl; + +template<support::endianness target_endianness, bool isRela> +struct Elf_Rel_Impl<target_endianness, true, isRela> + : Elf_Rel_Base<target_endianness, true, isRela> { + using Elf_Rel_Base<target_endianness, true, isRela>::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<support::endianness target_endianness, bool isRela> +struct Elf_Rel_Impl<target_endianness, false, isRela> + : Elf_Rel_Base<target_endianness, false, isRela> { + using Elf_Rel_Base<target_endianness, false, isRela>::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<support::endianness target_endianness, bool is64Bits> +class ELFObjectFile : public ObjectFile { + LLVM_ELF_IMPORT_TYPES(target_endianness, is64Bits) + + typedef Elf_Shdr_Impl<target_endianness, is64Bits> Elf_Shdr; + typedef Elf_Sym_Impl<target_endianness, is64Bits> Elf_Sym; + typedef Elf_Rel_Impl<target_endianness, is64Bits, false> Elf_Rel; + typedef Elf_Rel_Impl<target_endianness, is64Bits, true> 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; + } + 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<const Elf_Shdr*, 1> Sections_t; + typedef DenseMap<unsigned, unsigned> IndexMap_t; + typedef DenseMap<const Elf_Shdr*, SmallVector<uint32_t, 1> > 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. + Sections_t SymbolTableSections; + IndexMap_t SymbolTableSectionsIndexMap; + DenseMap<const Elf_Sym*, ELF::Elf64_Word> 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<typename T> + const T *getEntry(uint16_t Section, uint32_t Entry) const; + template<typename T> + 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<char> &Result) const; + virtual error_code getRelocationAdditionalInfo(DataRefImpl Rel, + int64_t &Res) const; + virtual error_code getRelocationValueString(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const; + +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; + } + static inline bool classof(const ELFObjectFile *v) { return true; } +}; + +template<support::endianness target_endianness, bool is64Bits> +void ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<uint32_t>::max(); + Symb.d.b = std::numeric_limits<uint32_t>::max(); + } + } + + Result = SymbolRef(Symb, this); + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getSymbolName(DataRefImpl Symb, + StringRef &Result) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + return getSymbolName(symb, Result); +} + +template<support::endianness target_endianness, bool is64Bits> +ELF::Elf64_Word ELFObjectFile<target_endianness, is64Bits> + ::getSymbolTableIndex(const Elf_Sym *symb) const { + if (symb->st_shndx == ELF::SHN_XINDEX) + return ExtendedSymbolTable.lookup(symb); + return symb->st_shndx; +} + +template<support::endianness target_endianness, bool is64Bits> +const typename ELFObjectFile<target_endianness, is64Bits>::Elf_Shdr * +ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<char>(name) + .StartsWith(".debug", 'N') + .StartsWith(".note", 'n') + .Default('?'); + return object_error::success; + } + + Result = ret; + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getSymbolType(DataRefImpl Symb, + SymbolRef::Type &Result) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + + if (getSymbolTableIndex(symb) == ELF::SHN_UNDEF) { + Result = SymbolRef::ST_External; + return object_error::success; + } + + 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; + } + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::isSymbolGlobal(DataRefImpl Symb, + bool &Result) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + + Result = symb->getBinding() == ELF::STB_GLOBAL; + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::isSymbolWeak(DataRefImpl Symb, + bool &Result) const { + validateSymbol(Symb); + const Elf_Sym *symb = getSymbol(Symb); + + Result = symb->getBinding() == ELF::STB_WEAK; + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<intptr_t>(sec); + Res = section_iterator(SectionRef(Sec, this)); + } + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getSectionNext(DataRefImpl Sec, SectionRef &Result) const { + const uint8_t *sec = reinterpret_cast<const uint8_t *>(Sec.p); + sec += Header->e_shentsize; + Sec.p = reinterpret_cast<intptr_t>(sec); + Result = SectionRef(Sec, this); + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getSectionName(DataRefImpl Sec, + StringRef &Result) const { + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); + Result = StringRef(getString(dot_shstrtab_sec, sec->sh_name)); + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getSectionAddress(DataRefImpl Sec, + uint64_t &Result) const { + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); + Result = sec->sh_addr; + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getSectionSize(DataRefImpl Sec, + uint64_t &Result) const { + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); + Result = sec->sh_size; + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getSectionContents(DataRefImpl Sec, + StringRef &Result) const { + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); + const char *start = (const char*)base() + sec->sh_offset; + Result = StringRef(start, sec->sh_size); + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getSectionAlignment(DataRefImpl Sec, + uint64_t &Result) const { + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); + Result = sec->sh_addralign; + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::isSectionText(DataRefImpl Sec, + bool &Result) const { + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(Sec.p); + if (sec->sh_flags & ELF::SHF_EXECINSTR) + Result = true; + else + Result = false; + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::isSectionData(DataRefImpl Sec, + bool &Result) const { + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::isSectionBSS(DataRefImpl Sec, + bool &Result) const { + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::sectionContainsSymbol(DataRefImpl Sec, + DataRefImpl Symb, + bool &Result) const { + // FIXME: Unimplemented. + Result = false; + return object_error::success; +} + +template<support::endianness target_endianness, bool is64Bits> +relocation_iterator ELFObjectFile<target_endianness, is64Bits> + ::getSectionRelBegin(DataRefImpl Sec) const { + DataRefImpl RelData; + memset(&RelData, 0, sizeof(RelData)); + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(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<support::endianness target_endianness, bool is64Bits> +relocation_iterator ELFObjectFile<target_endianness, is64Bits> + ::getSectionRelEnd(DataRefImpl Sec) const { + DataRefImpl RelData; + memset(&RelData, 0, sizeof(RelData)); + const Elf_Shdr *sec = reinterpret_cast<const Elf_Shdr *>(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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::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<support::endianness target_endianness, bool is64Bits> +error_code ELFObjectFile<target_endianness, is64Bits> + ::getRelocationAddress(DataRefImpl Rel, + uint64_t &Re |