X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FObject%2FELF.h;h=b0eaa3f5ed4d842667a4a3996f63609ff3e9d63c;hb=HEAD;hp=fc6fe6e49b99a90757ea05b8e8afbf0aaf8b900f;hpb=96a1f00376e05ea16dd6671685affb92fc8dde94;p=oota-llvm.git diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index fc6fe6e49b9..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; @@ -140,98 +53,22 @@ public: 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 Elf_GnuHash_Impl Elf_GnuHash; + typedef iterator_range Elf_Dyn_Range; 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 }; - }; - typedef iterator_range Elf_Sym_Range; -private: - typedef SmallVector Sections_t; - typedef DenseMap IndexMap_t; - - StringRef Buf; - const uint8_t *base() const { return reinterpret_cast(Buf.data()); } +private: + + StringRef Buf; + 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. - 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; - }; - - DynRegionInfo DynamicRegion; - DynRegionInfo DynHashRegion; - DynRegionInfo DynStrRegion; - 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; - } - }; - mutable SmallVector VersionMap; - void LoadVersionDefs(const Elf_Shdr *sec) const; - void LoadVersionNeeds(const Elf_Shdr *ec) const; - void LoadVersionMap() const; - - void scanDynamicTable(); public: template @@ -239,25 +76,20 @@ public: 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; + 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); @@ -272,79 +104,78 @@ public: Header->getDataEncoding() == ELF::ELFDATA2LSB; } + 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); + } + const Elf_Shdr *section_begin() const; const Elf_Shdr *section_end() const; Elf_Shdr_Range sections() const { return make_range(section_begin(), section_end()); } - const Elf_Sym *symbol_begin() const; - const Elf_Sym *symbol_end() const; - Elf_Sym_Range symbols() const { - return make_range(symbol_begin(), symbol_end()); - } - - 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)); - } - - const Elf_Sym *dynamic_symbol_begin() const { - if (!DotDynSymSec) + const Elf_Sym *symbol_begin(const Elf_Shdr *Sec) const { + if (!Sec) return nullptr; - if (DotDynSymSec->sh_entsize != sizeof(Elf_Sym)) + if (Sec->sh_entsize != sizeof(Elf_Sym)) report_fatal_error("Invalid symbol size"); - return reinterpret_cast(base() + DotDynSymSec->sh_offset); + return reinterpret_cast(base() + Sec->sh_offset); } - - const Elf_Sym *dynamic_symbol_end() const { - if (!DotDynSymSec) + const Elf_Sym *symbol_end(const Elf_Shdr *Sec) const { + if (!Sec) return nullptr; - return reinterpret_cast(base() + DotDynSymSec->sh_offset + - DotDynSymSec->sh_size); + 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 dynamic_symbols() const { - return make_range(dynamic_symbol_begin(), dynamic_symbol_end()); + Elf_Sym_Range symbols(const Elf_Shdr *Sec) const { + return make_range(symbol_begin(Sec), symbol_end(Sec)); } - 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); + 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_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); + 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 rela_begin(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 rela_end(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 rel_begin(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 rel_end(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. @@ -366,19 +197,23 @@ public: uint64_t getNumSections() const; uintX_t getStringTableIndex() const; - ELF::Elf64_Word getExtendedSymbolTableIndex(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; } - ErrorOr getSection(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(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; + const Elf_Sym *getSymbol(const Elf_Shdr *Sec, uint32_t Index) const { + return &*(symbol_begin(Sec) + Index); + } ErrorOr getSectionName(const Elf_Shdr *Section) const; + template + ErrorOr> getSectionContentsAsArray(const Elf_Shdr *Sec) const; ErrorOr > getSectionContents(const Elf_Shdr *Sec) const; - StringRef getLoadName() const; }; typedef ELFFile> ELF32LEFile; @@ -386,118 +221,50 @@ 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; - } -} - -// 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 -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; +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); - // Has the VersionMap already been loaded? - if (VersionMap.size() > 0) - return; - - // The first two version indexes are reserved. - // Index 0 is LOCAL, index 1 is GLOBAL. - VersionMap.push_back(VersionMapEntry()); - VersionMap.push_back(VersionMapEntry()); - - if (dot_gnu_version_d_sec) - LoadVersionDefs(dot_gnu_version_d_sec); - - if (dot_gnu_version_r_sec) - LoadVersionNeeds(dot_gnu_version_r_sec); -} - -template -ELF::Elf64_Word -ELFFile::getExtendedSymbolTableIndex(const Elf_Sym *symb) const { - assert(symb->st_shndx == ELF::SHN_XINDEX); - return ExtendedSymbolTable.lookup(symb); + // The size of the table was checked in getSHNDXTable. + return ShndxTable[Index]; } template ErrorOr::Elf_Shdr *> -ELFFile::getSection(const Elf_Sym *symb) const { - uint32_t Index = symb->st_shndx; +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(ExtendedSymbolTable.lookup(symb)); + return getSection(getExtendedSymbolTableIndex(Sym, SymTab, ShndxTable)); + if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE) return nullptr; - return getSection(symb->st_shndx); + return getSection(Sym->st_shndx); } template -const typename ELFFile::Elf_Sym * -ELFFile::getSymbol(uint32_t Index) const { - return &*(symbol_begin() + Index); +template +ErrorOr> +ELFFile::getSectionContentsAsArray(const Elf_Shdr *Sec) const { + uintX_t Offset = Sec->sh_offset; + uintX_t Size = Sec->sh_size; + + if (Size % sizeof(T)) + return object_error::parse_failed; + if (Offset + Size > Buf.size()) + return object_error::parse_failed; + + 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 @@ -537,18 +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); - 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()))); +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 @@ -585,10 +347,8 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) Header = reinterpret_cast(base()); - if (Header->e_shoff == 0) { - scanDynamicTable(); + if (Header->e_shoff == 0) return; - } const uint64_t SectionTableOffset = Header->e_shoff; @@ -609,118 +369,19 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) return; } - // Scan sections for special sections. - - 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_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; - DynStrRegion.Addr = SymtabOrErr->data(); - DynStrRegion.Size = SymtabOrErr->size(); - DynStrRegion.EntSize = 1; - break; - } - 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::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; - } - } - // Get string table sections. - ErrorOr StrTabSecOrErr = getSection(getStringTableIndex()); - if ((EC = StrTabSecOrErr.getError())) - return; + uintX_t StringTableIndex = getStringTableIndex(); + if (StringTableIndex) { + ErrorOr StrTabSecOrErr = getSection(StringTableIndex); + if ((EC = StrTabSecOrErr.getError())) + return; - ErrorOr SymtabOrErr = getStringTable(*StrTabSecOrErr); - if ((EC = SymtabOrErr.getError())) - return; - DotShstrtab = *SymtabOrErr; - - // 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; - } + ErrorOr StringTableOrErr = getStringTable(*StrTabSecOrErr); + if ((EC = StringTableOrErr.getError())) + return; + DotShstrtab = *StringTableOrErr; } - scanDynamicTable(); - EC = std::error_code(); } @@ -729,59 +390,6 @@ static bool compareAddr(uint64_t VAddr, const Elf_Phdr_Impl *Phdr) { return VAddr < Phdr->p_vaddr; } -template void ELFFile::scanDynamicTable() { - SmallVector LoadSegments; - for (const Elf_Phdr &Phdr : program_headers()) { - if (Phdr.p_type == ELF::PT_DYNAMIC) { - DynamicRegion.Addr = base() + Phdr.p_offset; - DynamicRegion.Size = Phdr.p_filesz; - DynamicRegion.EntSize = sizeof(Elf_Dyn); - continue; - } - if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) - continue; - LoadSegments.push_back(&Phdr); - } - - auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { - const Elf_Phdr **I = std::upper_bound( - LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr); - if (I == LoadSegments.begin()) - return nullptr; - --I; - return this->base() + (*I)->p_offset + (VAddr - (*I)->p_vaddr); - }; - - 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_STRTAB: - if (!DynStrRegion.Addr) - DynStrRegion.Addr = toMappedAddr(DynI->getPtr()); - break; - case ELF::DT_STRSZ: - if (!DynStrRegion.Size) - DynStrRegion.Size = DynI->getVal(); - 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 const typename ELFFile::Elf_Shdr *ELFFile::section_begin() const { if (Header->e_shentsize != sizeof(Elf_Shdr)) @@ -796,64 +404,31 @@ const typename ELFFile::Elf_Shdr *ELFFile::section_end() const { } template -const typename ELFFile::Elf_Sym *ELFFile::symbol_begin() const { - if (!dot_symtab_sec) +ErrorOr::Elf_Dyn *> +ELFFile::dynamic_table_begin(const Elf_Phdr *Phdr) const { + if (!Phdr) 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); + 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 -const typename ELFFile::Elf_Sym *ELFFile::symbol_end() const { - if (!dot_symtab_sec) +ErrorOr::Elf_Dyn *> +ELFFile::dynamic_table_end(const Elf_Phdr *Phdr) const { + if (!Phdr) return nullptr; - return reinterpret_cast(base() + dot_symtab_sec->sh_offset + - dot_symtab_sec->sh_size); -} - -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 -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 -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; + 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 @@ -901,127 +476,52 @@ ELFFile::getStringTable(const Elf_Shdr *Section) const { } template -const char *ELFFile::getDynamicString(uintX_t Offset) const { - if (Offset >= DynStrRegion.Size) - return nullptr; - return (const char *)DynStrRegion.Addr + Offset; -} - -template -ErrorOr -ELFFile::getStaticSymbolName(const Elf_Sym *Symb) const { - return Symb->getName(DotStrtab); +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; + 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::getDynamicSymbolName(const Elf_Sym *Symb) const { - return StringRef(getDynamicString(Symb->st_name)); -} - -template -ErrorOr ELFFile::getSymbolName(const Elf_Sym *Symb, - bool IsDynamic) const { - if (IsDynamic) - return getDynamicSymbolName(Symb); - return getStaticSymbolName(Symb); +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; + ErrorOr SectionOrErr = getSection(Sec.sh_link); + if (std::error_code EC = SectionOrErr.getError()) + return EC; + return getStringTable(*SectionOrErr); } template 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(DotShstrtab.data() + 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); - } - - // 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 = - (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(""); - } - - // 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) - 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