X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FObject%2FELF.h;h=b0eaa3f5ed4d842667a4a3996f63609ff3e9d63c;hb=HEAD;hp=ddabf59f309e33a712f50a8ea08f23c5f52dfadb;hpb=abc795d1f640be232d4b759aa0d519a0d84f32cd;p=oota-llvm.git diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index ddabf59f309..b0eaa3f5ed4 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -14,24 +14,9 @@ #ifndef LLVM_OBJECT_ELF_H #define LLVM_OBJECT_ELF_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.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 -#include -#include namespace llvm { namespace object { @@ -55,78 +40,6 @@ public: 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); - } - - pointer operator ->() { - assert(Current && "Attempted to dereference an invalid iterator!"); - return reinterpret_cast(Current); - } - - bool operator ==(const ELFEntityIterator &Other) { - return Current == Other.Current; - } - - bool operator !=(const ELFEntityIterator &Other) { - return !(*this == Other); - } - - ELFEntityIterator &operator ++() { - assert(Current && "Attempted to increment an invalid iterator!"); - Current += EntitySize; - return *this; - } - - ELFEntityIterator &operator+(difference_type n) { - assert(Current && "Attempted to increment an invalid iterator!"); - Current += (n * EntitySize); - return *this; - } - - ELFEntityIterator &operator-(difference_type n) { - assert(Current && "Attempted to subtract an invalid iterator!"); - Current -= (n * EntitySize); - return *this; - } - - ELFEntityIterator operator ++(int) { - ELFEntityIterator Tmp = *this; - ++*this; - return Tmp; - } - - difference_type operator -(const ELFEntityIterator &Other) const { - assert(EntitySize == Other.EntitySize && - "Subtracting iterators of different EntitySize!"); - return (Current - Other.Current) / EntitySize; - } - - const char *get() const { return Current; } - - uintX_t getEntSize() const { return EntitySize; } - - private: - uintX_t EntitySize; - const char *Current; - }; - typedef Elf_Ehdr_Impl Elf_Ehdr; typedef Elf_Shdr_Impl Elf_Shdr; typedef Elf_Sym_Impl Elf_Sym; @@ -139,186 +52,46 @@ public: typedef Elf_Verneed_Impl Elf_Verneed; typedef Elf_Vernaux_Impl Elf_Vernaux; typedef Elf_Versym_Impl Elf_Versym; - typedef ELFEntityIterator Elf_Dyn_Iter; - typedef iterator_range Elf_Dyn_Range; - typedef ELFEntityIterator Elf_Rela_Iter; - typedef ELFEntityIterator Elf_Rel_Iter; - typedef ELFEntityIterator Elf_Shdr_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 }; - }; - - class Elf_Sym_Iter { - public: - typedef ptrdiff_t difference_type; - typedef const Elf_Sym value_type; - typedef std::random_access_iterator_tag iterator_category; - typedef value_type &reference; - typedef value_type *pointer; - - /// \brief Default construct iterator. - Elf_Sym_Iter() : EntitySize(0), Current(0, false) {} - Elf_Sym_Iter(uintX_t EntSize, const char *Start, bool IsDynamic) - : EntitySize(EntSize), Current(Start, IsDynamic) {} - - reference operator*() { - assert(Current.getPointer() && - "Attempted to dereference an invalid iterator!"); - return *reinterpret_cast(Current.getPointer()); - } - - pointer operator->() { - assert(Current.getPointer() && - "Attempted to dereference an invalid iterator!"); - return reinterpret_cast(Current.getPointer()); - } - - bool operator==(const Elf_Sym_Iter &Other) { - return Current == Other.Current; - } - - bool operator!=(const Elf_Sym_Iter &Other) { return !(*this == Other); } - - Elf_Sym_Iter &operator++() { - assert(Current.getPointer() && - "Attempted to increment an invalid iterator!"); - Current.setPointer(Current.getPointer() + EntitySize); - return *this; - } - - Elf_Sym_Iter operator++(int) { - Elf_Sym_Iter Tmp = *this; - ++*this; - return Tmp; - } - - Elf_Sym_Iter operator+(difference_type Dist) { - assert(Current.getPointer() && - "Attempted to increment an invalid iterator!"); - Current.setPointer(Current.getPointer() + EntitySize * Dist); - return *this; - } - - difference_type operator-(const Elf_Sym_Iter &Other) const { - assert(EntitySize == Other.EntitySize && - "Subtracting iterators of different EntitySize!"); - return (Current.getPointer() - Other.Current.getPointer()) / EntitySize; - } - - const char *get() const { return Current.getPointer(); } - - bool isDynamic() const { return Current.getInt(); } - - uintX_t getEntSize() const { return EntitySize; } - - private: - uintX_t EntitySize; - PointerIntPair > Current; - }; - -private: - typedef SmallVector Sections_t; - typedef DenseMap IndexMap_t; - - StringRef Buf; + typedef Elf_Hash_Impl Elf_Hash; + typedef Elf_GnuHash_Impl Elf_GnuHash; + typedef iterator_range Elf_Dyn_Range; + typedef iterator_range Elf_Shdr_Range; + typedef iterator_range Elf_Sym_Range; const uint8_t *base() const { return reinterpret_cast(Buf.data()); } +private: + + StringRef Buf; + const Elf_Ehdr *Header; - const Elf_Shdr *SectionHeaderTable; - const Elf_Shdr *dot_shstrtab_sec; // Section header string table. - const Elf_Shdr *dot_strtab_sec; // Symbol header string table. - const Elf_Shdr *dot_symtab_sec; // Symbol table section. - - const Elf_Shdr *SymbolTableSectionHeaderIndex; - DenseMap ExtendedSymbolTable; - - const Elf_Shdr *dot_gnu_version_sec; // .gnu.version - const Elf_Shdr *dot_gnu_version_r_sec; // .gnu.version_r - const Elf_Shdr *dot_gnu_version_d_sec; // .gnu.version_d - - /// \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; - }; - - DynRegionInfo DynamicRegion; - DynRegionInfo DynHashRegion; - DynRegionInfo DynStrRegion; - DynRegionInfo DynSymRegion; - - // Pointer to SONAME entry in dynamic string table - // This is set the first time getLoadName is called. - mutable const char *dt_soname; - - // Records for each version index the corresponding Verdef or Vernaux entry. - // This is filled the first time LoadVersionMap() is called. - class VersionMapEntry : public PointerIntPair { - public: - // If the integer is 0, this is an Elf_Verdef*. - // If the integer is 1, this is an Elf_Vernaux*. - VersionMapEntry() : PointerIntPair(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; - } - }; - mutable SmallVector VersionMap; - void LoadVersionDefs(const Elf_Shdr *sec) const; - void LoadVersionNeeds(const Elf_Shdr *ec) const; - void LoadVersionMap() const; + const Elf_Shdr *SectionHeaderTable = nullptr; + StringRef DotShstrtab; // Section header string table. public: template const T *getEntry(uint32_t Section, uint32_t Entry) const; template const T *getEntry(const Elf_Shdr *Section, uint32_t Entry) const; - const char *getString(uint32_t section, uint32_t offset) const; - const char *getString(const Elf_Shdr *section, uint32_t offset) const; - const char *getDynamicString(uintX_t Offset) const; - ErrorOr getSymbolVersion(const Elf_Shdr *section, - const Elf_Sym *Symb, - bool &IsDefault) const; + + ErrorOr getStringTable(const Elf_Shdr *Section) const; + ErrorOr getStringTableForSymtab(const Elf_Shdr &Section) const; + + ErrorOr> getSHNDXTable(const Elf_Shdr &Section) 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; + /// \brief Get the symbol for a given relocation. + const Elf_Sym *getRelocationSymbol(const Elf_Rel *Rel, + const Elf_Shdr *SymTab) const; - ELFFile(StringRef Object, std::error_code &ec); + ELFFile(StringRef Object, std::error_code &EC); bool isMipsELF64() const { return Header->e_machine == ELF::EM_MIPS && @@ -331,216 +104,167 @@ public: Header->getDataEncoding() == ELF::ELFDATA2LSB; } - Elf_Shdr_Iter begin_sections() const; - Elf_Shdr_Iter end_sections() const; - Elf_Shdr_Range sections() const { - return make_range(begin_sections(), end_sections()); + ErrorOr dynamic_table_begin(const Elf_Phdr *Phdr) const; + ErrorOr dynamic_table_end(const Elf_Phdr *Phdr) const; + ErrorOr dynamic_table(const Elf_Phdr *Phdr) const { + ErrorOr Begin = dynamic_table_begin(Phdr); + if (std::error_code EC = Begin.getError()) + return EC; + ErrorOr End = dynamic_table_end(Phdr); + if (std::error_code EC = End.getError()) + return EC; + return make_range(*Begin, *End); } - Elf_Sym_Iter begin_symbols() const; - Elf_Sym_Iter end_symbols() const; + const Elf_Shdr *section_begin() const; + const Elf_Shdr *section_end() const; + Elf_Shdr_Range sections() const { + return make_range(section_begin(), section_end()); + } - Elf_Dyn_Iter begin_dynamic_table() const; - /// \param NULLEnd use one past the first DT_NULL entry as the end instead of - /// the section size. - Elf_Dyn_Iter end_dynamic_table(bool NULLEnd = false) const; - Elf_Dyn_Range dynamic_table(bool NULLEnd = false) const { - return make_range(begin_dynamic_table(), end_dynamic_table(NULLEnd)); + const Elf_Sym *symbol_begin(const Elf_Shdr *Sec) const { + if (!Sec) + return nullptr; + if (Sec->sh_entsize != sizeof(Elf_Sym)) + report_fatal_error("Invalid symbol size"); + return reinterpret_cast(base() + Sec->sh_offset); + } + const Elf_Sym *symbol_end(const Elf_Shdr *Sec) const { + if (!Sec) + return nullptr; + uint64_t Size = Sec->sh_size; + if (Size % sizeof(Elf_Sym)) + report_fatal_error("Invalid symbol table size"); + return symbol_begin(Sec) + Size / sizeof(Elf_Sym); + } + Elf_Sym_Range symbols(const Elf_Shdr *Sec) const { + return make_range(symbol_begin(Sec), symbol_end(Sec)); } - Elf_Sym_Iter begin_dynamic_symbols() const { - if (DynSymRegion.Addr) - return Elf_Sym_Iter(DynSymRegion.EntSize, (const char *)DynSymRegion.Addr, - true); - return Elf_Sym_Iter(0, nullptr, true); + typedef iterator_range Elf_Rela_Range; + + const Elf_Rela *rela_begin(const Elf_Shdr *sec) const { + if (sec->sh_entsize != sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast(base() + sec->sh_offset); } - Elf_Sym_Iter end_dynamic_symbols() const { - if (DynSymRegion.Addr) - return Elf_Sym_Iter(DynSymRegion.EntSize, - (const char *)DynSymRegion.Addr + DynSymRegion.Size, - true); - return Elf_Sym_Iter(0, nullptr, true); + const Elf_Rela *rela_end(const Elf_Shdr *sec) const { + uint64_t Size = sec->sh_size; + if (Size % sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation table size"); + return rela_begin(sec) + Size / sizeof(Elf_Rela); } - Elf_Rela_Iter begin_rela(const Elf_Shdr *sec) const { - return Elf_Rela_Iter(sec->sh_entsize, - (const char *)(base() + sec->sh_offset)); + Elf_Rela_Range relas(const Elf_Shdr *Sec) const { + return make_range(rela_begin(Sec), rela_end(Sec)); } - Elf_Rela_Iter end_rela(const Elf_Shdr *sec) const { - return Elf_Rela_Iter( - sec->sh_entsize, - (const char *)(base() + sec->sh_offset + sec->sh_size)); + const Elf_Rel *rel_begin(const Elf_Shdr *sec) const { + if (sec->sh_entsize != sizeof(Elf_Rel)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast(base() + sec->sh_offset); } - Elf_Rel_Iter begin_rel(const Elf_Shdr *sec) const { - return Elf_Rel_Iter(sec->sh_entsize, - (const char *)(base() + sec->sh_offset)); + const Elf_Rel *rel_end(const Elf_Shdr *sec) const { + uint64_t Size = sec->sh_size; + if (Size % sizeof(Elf_Rel)) + report_fatal_error("Invalid relocation table size"); + return rel_begin(sec) + Size / sizeof(Elf_Rel); } - Elf_Rel_Iter end_rel(const Elf_Shdr *sec) const { - return Elf_Rel_Iter(sec->sh_entsize, - (const char *)(base() + sec->sh_offset + sec->sh_size)); + typedef iterator_range Elf_Rel_Range; + Elf_Rel_Range rels(const Elf_Shdr *Sec) const { + return make_range(rel_begin(Sec), rel_end(Sec)); } /// \brief Iterate over program header table. - typedef ELFEntityIterator Elf_Phdr_Iter; + const Elf_Phdr *program_header_begin() const { + if (Header->e_phnum && Header->e_phentsize != sizeof(Elf_Phdr)) + report_fatal_error("Invalid program header size"); + return reinterpret_cast(base() + Header->e_phoff); + } - Elf_Phdr_Iter begin_program_headers() const { - return Elf_Phdr_Iter(Header->e_phentsize, - (const char*)base() + Header->e_phoff); + const Elf_Phdr *program_header_end() const { + return program_header_begin() + Header->e_phnum; } - Elf_Phdr_Iter end_program_headers() const { - return Elf_Phdr_Iter(Header->e_phentsize, - (const char*)base() + - Header->e_phoff + - (Header->e_phnum * Header->e_phentsize)); + typedef iterator_range Elf_Phdr_Range; + + const Elf_Phdr_Range program_headers() const { + return make_range(program_header_begin(), program_header_end()); } uint64_t getNumSections() const; uintX_t getStringTableIndex() const; - ELF::Elf64_Word getSymbolTableIndex(const Elf_Sym *symb) const; + uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym, + const Elf_Shdr *SymTab, + ArrayRef ShndxTable) const; const Elf_Ehdr *getHeader() const { return Header; } - const Elf_Shdr *getSection(const Elf_Sym *symb) const; - const Elf_Shdr *getSection(uint32_t Index) const; - const Elf_Sym *getSymbol(uint32_t index) const; - - ErrorOr getSymbolName(Elf_Sym_Iter Sym) const; - - /// \brief Get the name of \p Symb. - /// \param SymTab The symbol table section \p Symb is contained in. - /// \param Symb The symbol to get the name of. - /// - /// \p SymTab is used to lookup the string table to use to get the symbol's - /// name. - ErrorOr getSymbolName(const Elf_Shdr *SymTab, - const Elf_Sym *Symb) const; + ErrorOr getSection(const Elf_Sym *Sym, + const Elf_Shdr *SymTab, + ArrayRef ShndxTable) const; + ErrorOr getSection(uint32_t Index) const; + + const Elf_Sym *getSymbol(const Elf_Shdr *Sec, uint32_t Index) const { + return &*(symbol_begin(Sec) + Index); + } + ErrorOr getSectionName(const Elf_Shdr *Section) const; - uint64_t getSymbolIndex(const Elf_Sym *sym) const; + template + ErrorOr> getSectionContentsAsArray(const Elf_Shdr *Sec) const; ErrorOr > getSectionContents(const Elf_Shdr *Sec) const; - StringRef getLoadName() const; }; -// Use an alignment of 2 for the typedefs since that is the worst case for -// ELF files in archives. -typedef ELFFile > ELF32LEFile; -typedef ELFFile > ELF64LEFile; -typedef ELFFile > ELF32BEFile; -typedef ELFFile > ELF64BEFile; +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; - } -} +uint32_t ELFFile::getExtendedSymbolTableIndex( + const Elf_Sym *Sym, const Elf_Shdr *SymTab, + ArrayRef ShndxTable) const { + assert(Sym->st_shndx == ELF::SHN_XINDEX); + unsigned Index = Sym - symbol_begin(SymTab); -// 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; - } + // The size of the table was checked in getSHNDXTable. + return ShndxTable[Index]; } template -void ELFFile::LoadVersionMap() const { - // If there is no dynamic symtab or version table, there is nothing to do. - if (!DynSymRegion.Addr || !dot_gnu_version_sec) - return; - - // Has the VersionMap already been loaded? - if (VersionMap.size() > 0) - return; +ErrorOr::Elf_Shdr *> +ELFFile::getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, + ArrayRef ShndxTable) const { + uint32_t Index = Sym->st_shndx; + if (Index == ELF::SHN_XINDEX) + return getSection(getExtendedSymbolTableIndex(Sym, SymTab, ShndxTable)); - // The first two version indexes are reserved. - // Index 0 is LOCAL, index 1 is GLOBAL. - VersionMap.push_back(VersionMapEntry()); - VersionMap.push_back(VersionMapEntry()); - - if (dot_gnu_version_d_sec) - LoadVersionDefs(dot_gnu_version_d_sec); - - if (dot_gnu_version_r_sec) - LoadVersionNeeds(dot_gnu_version_r_sec); + if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE) + return nullptr; + return getSection(Sym->st_shndx); } template -ELF::Elf64_Word ELFFile::getSymbolTableIndex(const Elf_Sym *symb) const { - if (symb->st_shndx == ELF::SHN_XINDEX) - return ExtendedSymbolTable.lookup(symb); - return symb->st_shndx; -} +template +ErrorOr> +ELFFile::getSectionContentsAsArray(const Elf_Shdr *Sec) const { + uintX_t Offset = Sec->sh_offset; + uintX_t Size = Sec->sh_size; -template -const typename ELFFile::Elf_Shdr * -ELFFile::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 nullptr; - return getSection(symb->st_shndx); -} + if (Size % sizeof(T)) + return object_error::parse_failed; + if (Offset + Size > Buf.size()) + return object_error::parse_failed; -template -const typename ELFFile::Elf_Sym * -ELFFile::getSymbol(uint32_t Index) const { - return &*(begin_symbols() + Index); + const T *Start = reinterpret_cast(base() + Offset); + return makeArrayRef(Start, Size / sizeof(T)); } template -ErrorOr > +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); + return getSectionContentsAsArray(Sec); } template @@ -580,24 +304,13 @@ void ELFFile::getRelocationTypeName(uint32_t Type, } 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); - const Elf_Shdr *SymTable = getSection(Sec->sh_link); - return std::make_pair( - SymTable, getEntry(SymTable, Rel->getSymbol(isMips64EL()))); -} - -// Verify that the last byte in the string table in a null. -template -void ELFFile::VerifyStrTab(const Elf_Shdr *sh) const { - const char *strtab = (const char *)base() + sh->sh_offset; - if (strtab[sh->sh_size - 1] != 0) - // FIXME: Proper error handling. - report_fatal_error("String table must end with a null terminator!"); +const typename ELFFile::Elf_Sym * +ELFFile::getRelocationSymbol(const Elf_Rel *Rel, + const Elf_Shdr *SymTab) const { + uint32_t Index = Rel->getSymbol(isMips64EL()); + if (Index == 0) + return nullptr; + return getEntry(SymTab, Index); } template @@ -622,17 +335,15 @@ typename ELFFile::uintX_t ELFFile::getStringTableIndex() const { } template -ELFFile::ELFFile(StringRef Object, std::error_code &ec) - : Buf(Object), SectionHeaderTable(nullptr), dot_shstrtab_sec(nullptr), - dot_strtab_sec(nullptr), dot_symtab_sec(nullptr), - SymbolTableSectionHeaderIndex(nullptr), dot_gnu_version_sec(nullptr), - dot_gnu_version_r_sec(nullptr), dot_gnu_version_d_sec(nullptr), - dt_soname(nullptr) { +ELFFile::ELFFile(StringRef Object, std::error_code &EC) + : Buf(Object) { const uint64_t FileSize = Buf.size(); - if (sizeof(Elf_Ehdr) > FileSize) - // FIXME: Proper error handling. - report_fatal_error("File too short!"); + if (sizeof(Elf_Ehdr) > FileSize) { + // File too short! + EC = object_error::parse_failed; + return; + } Header = reinterpret_cast(base()); @@ -641,203 +352,92 @@ ELFFile::ELFFile(StringRef Object, std::error_code &ec) 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!"); + if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) { + // Section header table goes past end of file! + EC = object_error::parse_failed; + return; + } // The getNumSections() call below depends on SectionHeaderTable being set. SectionHeaderTable = reinterpret_cast(base() + SectionTableOffset); const uint64_t SectionTableSize = getNumSections() * Header->e_shentsize; - if (SectionTableOffset + SectionTableSize > FileSize) - // FIXME: Proper error handling. - report_fatal_error("Section table goes past end of file!"); - - // Scan sections for special sections. - - for (const Elf_Shdr &Sec : sections()) { - switch (Sec.sh_type) { - case ELF::SHT_SYMTAB_SHNDX: - if (SymbolTableSectionHeaderIndex) - // FIXME: Proper error handling. - report_fatal_error("More than one .symtab_shndx!"); - SymbolTableSectionHeaderIndex = &Sec; - break; - case ELF::SHT_SYMTAB: - if (dot_symtab_sec) - // FIXME: Proper error handling. - report_fatal_error("More than one .symtab!"); - dot_symtab_sec = &Sec; - dot_strtab_sec = getSection(Sec.sh_link); - break; - case ELF::SHT_DYNSYM: { - if (DynSymRegion.Addr) - // FIXME: Proper error handling. - report_fatal_error("More than one .dynsym!"); - DynSymRegion.Addr = base() + Sec.sh_offset; - DynSymRegion.Size = Sec.sh_size; - DynSymRegion.EntSize = Sec.sh_entsize; - const Elf_Shdr *DynStr = getSection(Sec.sh_link); - DynStrRegion.Addr = base() + DynStr->sh_offset; - DynStrRegion.Size = DynStr->sh_size; - DynStrRegion.EntSize = DynStr->sh_entsize; - break; - } - case ELF::SHT_DYNAMIC: - if (DynamicRegion.Addr) - // FIXME: Proper error handling. - report_fatal_error("More than one .dynamic!"); - 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) - // FIXME: Proper error handling. - report_fatal_error("More than one .gnu.version section!"); - dot_gnu_version_sec = &Sec; - break; - case ELF::SHT_GNU_verdef: - if (dot_gnu_version_d_sec != nullptr) - // FIXME: Proper error handling. - report_fatal_error("More than one .gnu.version_d section!"); - dot_gnu_version_d_sec = &Sec; - break; - case ELF::SHT_GNU_verneed: - if (dot_gnu_version_r_sec != nullptr) - // FIXME: Proper error handling. - report_fatal_error("More than one .gnu.version_r section!"); - dot_gnu_version_r_sec = &Sec; - break; - } + if (SectionTableOffset + SectionTableSize > FileSize) { + // Section table goes past end of file! + EC = object_error::parse_failed; + return; } // Get string table sections. - dot_shstrtab_sec = getSection(getStringTableIndex()); - if (dot_shstrtab_sec) { - // Verify that the last byte in the string table in a null. - VerifyStrTab(dot_shstrtab_sec); - } - - // Build symbol name side-mapping if there is one. - if (SymbolTableSectionHeaderIndex) { - const Elf_Word *ShndxTable = reinterpret_cast(base() + - SymbolTableSectionHeaderIndex->sh_offset); - for (Elf_Sym_Iter SI = begin_symbols(), SE = end_symbols(); SI != SE; - ++SI) { - if (*ShndxTable != ELF::SHN_UNDEF) - ExtendedSymbolTable[&*SI] = *ShndxTable; - ++ShndxTable; - } - } - - // Scan program headers. - for (Elf_Phdr_Iter PhdrI = begin_program_headers(), - PhdrE = end_program_headers(); - 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); - break; - } + uintX_t StringTableIndex = getStringTableIndex(); + if (StringTableIndex) { + ErrorOr StrTabSecOrErr = getSection(StringTableIndex); + if ((EC = StrTabSecOrErr.getError())) + return; + + ErrorOr StringTableOrErr = getStringTable(*StrTabSecOrErr); + if ((EC = StringTableOrErr.getError())) + return; + DotShstrtab = *StringTableOrErr; } - ec = std::error_code(); -} - -// Get the symbol table index in the symtab section given a symbol -template -uint64_t ELFFile::getSymbolIndex(const Elf_Sym *Sym) const { - uintptr_t SymLoc = uintptr_t(Sym); - uintptr_t SymTabLoc = uintptr_t(base() + dot_symtab_sec->sh_offset); - assert(SymLoc > SymTabLoc && "Symbol not in symbol table!"); - uint64_t SymOffset = SymLoc - SymTabLoc; - assert(SymOffset % dot_symtab_sec->sh_entsize == 0 && - "Symbol not multiple of symbol size!"); - return SymOffset / dot_symtab_sec->sh_entsize; -} - -template -typename ELFFile::Elf_Shdr_Iter ELFFile::begin_sections() const { - return Elf_Shdr_Iter(Header->e_shentsize, - (const char *)base() + Header->e_shoff); + EC = std::error_code(); } template -typename ELFFile::Elf_Shdr_Iter ELFFile::end_sections() const { - return Elf_Shdr_Iter(Header->e_shentsize, - (const char *)base() + Header->e_shoff + - (getNumSections() * Header->e_shentsize)); +static bool compareAddr(uint64_t VAddr, const Elf_Phdr_Impl *Phdr) { + return VAddr < Phdr->p_vaddr; } template -typename ELFFile::Elf_Sym_Iter ELFFile::begin_symbols() const { - if (!dot_symtab_sec) - return Elf_Sym_Iter(0, nullptr, false); - return Elf_Sym_Iter(dot_symtab_sec->sh_entsize, - (const char *)base() + dot_symtab_sec->sh_offset, false); +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 -typename ELFFile::Elf_Sym_Iter ELFFile::end_symbols() const { - if (!dot_symtab_sec) - return Elf_Sym_Iter(0, nullptr, false); - return Elf_Sym_Iter(dot_symtab_sec->sh_entsize, - (const char *)base() + dot_symtab_sec->sh_offset + - dot_symtab_sec->sh_size, - false); +const typename ELFFile::Elf_Shdr *ELFFile::section_end() const { + return section_begin() + getNumSections(); } template -typename ELFFile::Elf_Dyn_Iter -ELFFile::begin_dynamic_table() const { - if (DynamicRegion.Addr) - return Elf_Dyn_Iter(DynamicRegion.EntSize, - (const char *)DynamicRegion.Addr); - return Elf_Dyn_Iter(0, nullptr); -} - -template -typename ELFFile::Elf_Dyn_Iter -ELFFile::end_dynamic_table(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 = begin_dynamic_table(); - while (Start != Ret && Start->getTag() != ELF::DT_NULL) - ++Start; - - // Include the DT_NULL. - if (Start != Ret) - ++Start; - Ret = Start; - } - return Ret; +ErrorOr::Elf_Dyn *> +ELFFile::dynamic_table_begin(const Elf_Phdr *Phdr) const { + if (!Phdr) + return nullptr; + assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header"); + uintX_t Offset = Phdr->p_offset; + if (Offset > Buf.size()) + return object_error::parse_failed; + return reinterpret_cast(base() + Offset); } 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; +ErrorOr::Elf_Dyn *> +ELFFile::dynamic_table_end(const Elf_Phdr *Phdr) const { + if (!Phdr) + return nullptr; + assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header"); + uintX_t Size = Phdr->p_filesz; + if (Size % sizeof(Elf_Dyn)) + return object_error::elf_invalid_dynamic_table_size; + // FIKME: Check for overflow? + uintX_t End = Phdr->p_offset + Size; + if (End > Buf.size()) + return object_error::parse_failed; + return reinterpret_cast(base() + End); } template template const T *ELFFile::getEntry(uint32_t Section, uint32_t Entry) const { - return getEntry(getSection(Section), Entry); + ErrorOr Sec = getSection(Section); + if (std::error_code EC = Sec.getError()) + report_fatal_error(EC.message()); + return getEntry(*Sec, Entry); } template @@ -849,150 +449,77 @@ const T *ELFFile::getEntry(const Elf_Shdr *Section, } template -const typename ELFFile::Elf_Shdr * -ELFFile::getSection(uint32_t index) const { - if (index == 0) - return nullptr; - if (!SectionHeaderTable || index >= getNumSections()) - // FIXME: Proper error handling. - report_fatal_error("Invalid section index!"); +ErrorOr::Elf_Shdr *> +ELFFile::getSection(uint32_t Index) const { + assert(SectionHeaderTable && "SectionHeaderTable not initialized!"); + if (Index >= getNumSections()) + return object_error::invalid_section_index; return reinterpret_cast( - reinterpret_cast(SectionHeaderTable) - + (index * Header->e_shentsize)); -} - -template -const char *ELFFile::getString(uint32_t section, - ELF::Elf32_Word offset) const { - return getString(getSection(section), offset); -} - -template -const char *ELFFile::getString(const Elf_Shdr *section, - ELF::Elf32_Word offset) const { - assert(section && section->sh_type == ELF::SHT_STRTAB && "Invalid section!"); - if (offset >= section->sh_size) - // FIXME: Proper error handling. - report_fatal_error("Symbol name offset outside of string table!"); - return (const char *)base() + section->sh_offset + offset; -} - -template -const char *ELFFile::getDynamicString(uintX_t Offset) const { - if (!DynStrRegion.Addr || Offset >= DynStrRegion.Size) - return nullptr; - return (const char *)DynStrRegion.Addr + Offset; + reinterpret_cast(SectionHeaderTable) + + (Index * Header->e_shentsize)); } template -ErrorOr ELFFile::getSymbolName(Elf_Sym_Iter Sym) const { - if (!Sym.isDynamic()) - return getSymbolName(dot_symtab_sec, &*Sym); - - if (!DynStrRegion.Addr || Sym->st_name >= DynStrRegion.Size) +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; - return StringRef(getDynamicString(Sym->st_name)); + 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 -ErrorOr ELFFile::getSymbolName(const Elf_Shdr *Section, - const Elf_Sym *Symb) const { - if (Symb->st_name == 0) { - const Elf_Shdr *ContainingSec = getSection(Symb); - if (ContainingSec) - return getSectionName(ContainingSec); - } - - const Elf_Shdr *StrTab = getSection(Section->sh_link); - if (Symb->st_name >= StrTab->sh_size) +ErrorOr::Elf_Word>> +ELFFile::getSHNDXTable(const Elf_Shdr &Section) const { + assert(Section.sh_type == ELF::SHT_SYMTAB_SHNDX); + const Elf_Word *ShndxTableBegin = + reinterpret_cast(base() + Section.sh_offset); + uintX_t Size = Section.sh_size; + if (Size % sizeof(uint32_t)) + return object_error::parse_failed; + uintX_t NumSymbols = Size / sizeof(uint32_t); + const Elf_Word *ShndxTableEnd = ShndxTableBegin + NumSymbols; + if (reinterpret_cast(ShndxTableEnd) > Buf.end()) return object_error::parse_failed; - return StringRef(getString(StrTab, Symb->st_name)); + ErrorOr SymTableOrErr = getSection(Section.sh_link); + if (std::error_code EC = SymTableOrErr.getError()) + return EC; + const Elf_Shdr &SymTable = **SymTableOrErr; + if (SymTable.sh_type != ELF::SHT_SYMTAB && + SymTable.sh_type != ELF::SHT_DYNSYM) + return object_error::parse_failed; + if (NumSymbols != (SymTable.sh_size / sizeof(Elf_Sym))) + return object_error::parse_failed; + return makeArrayRef(ShndxTableBegin, ShndxTableEnd); } template ErrorOr -ELFFile::getSectionName(const Elf_Shdr *Section) const { - if (Section->sh_name >= dot_shstrtab_sec->sh_size) +ELFFile::getStringTableForSymtab(const Elf_Shdr &Sec) const { + if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM) return object_error::parse_failed; - return StringRef(getString(dot_shstrtab_sec, Section->sh_name)); + ErrorOr SectionOrErr = getSection(Sec.sh_link); + if (std::error_code EC = SectionOrErr.getError()) + return EC; + return getStringTable(*SectionOrErr); } template -ErrorOr ELFFile::getSymbolVersion(const Elf_Shdr *section, - const Elf_Sym *symb, - bool &IsDefault) const { - // Handle non-dynamic symbols. - if (section != DynSymRegion.Addr && 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 = getSymbolName(section, symb); - 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); - } - - // This is a dynamic symbol. Look in the GNU symbol version table. - if (!dot_gnu_version_sec) { - // No version table. - IsDefault = false; - return StringRef(""); - } - - // Determine the position in the symbol table of this entry. - size_t entry_index = ((const char *)symb - (const char *)DynSymRegion.Addr) / - DynSymRegion.EntSize; - - // Get the corresponding version index entry - const Elf_Versym *vs = getEntry(dot_gnu_version_sec, entry_index); - size_t version_index = vs->vs_index & ELF::VERSYM_VERSION; - - // Special markers for unversioned symbols. - if (version_index == ELF::VER_NDX_LOCAL || - version_index == ELF::VER_NDX_GLOBAL) { - IsDefault = false; - return StringRef(""); - } - - // 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 >= DynStrRegion.Size) +ErrorOr +ELFFile::getSectionName(const Elf_Shdr *Section) const { + uint32_t Offset = Section->sh_name; + if (Offset == 0) + return StringRef(); + if (Offset >= DotShstrtab.size()) return object_error::parse_failed; - return StringRef(getDynamicString(name_offset)); + return StringRef(DotShstrtab.data() + Offset); } /// This function returns the hash value for a symbol in the .dynsym section