| //===- 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 ELFFile template class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_OBJECT_ELF_H |
| #define LLVM_OBJECT_ELF_H |
| |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/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 <algorithm> |
| #include <limits> |
| #include <utility> |
| |
| namespace llvm { |
| namespace object { |
| |
| StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type); |
| |
| // Subclasses of ELFFile may need this for template instantiation |
| inline std::pair<unsigned char, unsigned char> |
| getElfArchType(StringRef Object) { |
| if (Object.size() < ELF::EI_NIDENT) |
| return std::make_pair((uint8_t)ELF::ELFCLASSNONE, |
| (uint8_t)ELF::ELFDATANONE); |
| return std::make_pair((uint8_t)Object[ELF::EI_CLASS], |
| (uint8_t)Object[ELF::EI_DATA]); |
| } |
| |
| template <class ELFT> |
| class ELFFile { |
| public: |
| LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) |
| typedef typename std::conditional<ELFT::Is64Bits, |
| uint64_t, uint32_t>::type uintX_t; |
| |
| /// \brief Iterate over constant sized entities. |
| template <class EntT> |
| 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<pointer>(Current); |
| } |
| |
| pointer operator ->() { |
| assert(Current && "Attempted to dereference an invalid iterator!"); |
| return reinterpret_cast<pointer>(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 ++(int) { |
| ELFEntityIterator Tmp = *this; |
| ++*this; |
| return Tmp; |
| } |
| |
| ELFEntityIterator &operator =(const ELFEntityIterator &Other) { |
| EntitySize = Other.EntitySize; |
| Current = Other.Current; |
| return *this; |
| } |
| |
| 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<ELFT> Elf_Ehdr; |
| typedef Elf_Shdr_Impl<ELFT> Elf_Shdr; |
| typedef Elf_Sym_Impl<ELFT> Elf_Sym; |
| typedef Elf_Dyn_Impl<ELFT> Elf_Dyn; |
| typedef Elf_Phdr_Impl<ELFT> Elf_Phdr; |
| typedef Elf_Rel_Impl<ELFT, false> Elf_Rel; |
| typedef Elf_Rel_Impl<ELFT, true> Elf_Rela; |
| typedef Elf_Verdef_Impl<ELFT> Elf_Verdef; |
| typedef Elf_Verdaux_Impl<ELFT> Elf_Verdaux; |
| typedef Elf_Verneed_Impl<ELFT> Elf_Verneed; |
| typedef Elf_Vernaux_Impl<ELFT> Elf_Vernaux; |
| typedef Elf_Versym_Impl<ELFT> Elf_Versym; |
| typedef ELFEntityIterator<const Elf_Dyn> Elf_Dyn_Iter; |
| typedef iterator_range<Elf_Dyn_Iter> Elf_Dyn_Range; |
| typedef ELFEntityIterator<const Elf_Rela> Elf_Rela_Iter; |
| typedef ELFEntityIterator<const Elf_Rel> Elf_Rel_Iter; |
| typedef ELFEntityIterator<const Elf_Shdr> Elf_Shdr_Iter; |
| typedef iterator_range<Elf_Shdr_Iter> Elf_Shdr_Range; |
| |
| /// \brief Archive files are 2 byte aligned, so we need this for |
| /// PointerIntPair to work. |
| template <typename T> |
| class ArchivePointerTypeTraits { |
| public: |
| static inline const void *getAsVoidPointer(T *P) { return P; } |
| static inline T *getFromVoidPointer(const void *P) { |
| return static_cast<T *>(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<pointer>(Current.getPointer()); |
| } |
| |
| pointer operator->() { |
| assert(Current.getPointer() && |
| "Attempted to dereference an invalid iterator!"); |
| return reinterpret_cast<pointer>(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; |
| } |
| |
| Elf_Sym_Iter &operator=(const Elf_Sym_Iter &Other) { |
| EntitySize = Other.EntitySize; |
| Current = Other.Current; |
| 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<const char *, 1, bool, |
| ArchivePointerTypeTraits<const char> > Current; |
| }; |
| |
| private: |
| typedef SmallVector<const Elf_Shdr *, 2> Sections_t; |
| typedef DenseMap<unsigned, unsigned> IndexMap_t; |
| |
| StringRef Buf; |
| |
| const uint8_t *base() const { |
| return reinterpret_cast<const uint8_t *>(Buf.data()); |
| } |
| |
| 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<const Elf_Sym *, ELF::Elf64_Word> 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<const void*, 1> { |
| public: |
| // If the integer is 0, this is an Elf_Verdef*. |
| // If the integer is 1, this is an Elf_Vernaux*. |
| VersionMapEntry() : PointerIntPair<const void*, 1>(nullptr, 0) { } |
| VersionMapEntry(const Elf_Verdef *verdef) |
| : PointerIntPair<const void*, 1>(verdef, 0) { } |
| VersionMapEntry(const Elf_Vernaux *vernaux) |
| : PointerIntPair<const void*, 1>(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<VersionMapEntry, 16> VersionMap; |
| void LoadVersionDefs(const Elf_Shdr *sec) const; |
| void LoadVersionNeeds(const Elf_Shdr *ec) const; |
| void LoadVersionMap() const; |
| |
| public: |
| template<typename T> |
| const T *getEntry(uint32_t Section, uint32_t Entry) const; |
| template <typename T> |
| 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<StringRef> getSymbolVersion(const Elf_Shdr *section, |
| const Elf_Sym *Symb, |
| bool &IsDefault) const; |
| void VerifyStrTab(const Elf_Shdr *sh) const; |
| |
| StringRef getRelocationTypeName(uint32_t Type) const; |
| void getRelocationTypeName(uint32_t Type, |
| SmallVectorImpl<char> &Result) const; |
| |
| /// \brief Get the symbol table section and symbol for a given relocation. |
| template <class RelT> |
| std::pair<const Elf_Shdr *, const Elf_Sym *> |
| getRelocationSymbol(const Elf_Shdr *RelSec, const RelT *Rel) const; |
| |
| ELFFile(StringRef Object, std::error_code &ec); |
| |
| bool isMipsELF64() const { |
| return Header->e_machine == ELF::EM_MIPS && |
| Header->getFileClass() == ELF::ELFCLASS64; |
| } |
| |
| bool isMips64EL() const { |
| return Header->e_machine == ELF::EM_MIPS && |
| Header->getFileClass() == ELF::ELFCLASS64 && |
| 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()); |
| } |
| |
| Elf_Sym_Iter begin_symbols() const; |
| Elf_Sym_Iter end_symbols() const; |
| |
| 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)); |
| } |
| |
| 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); |
| } |
| |
| 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); |
| } |
| |
| 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_Iter end_rela(const Elf_Shdr *sec) const { |
| return Elf_Rela_Iter( |
| sec->sh_entsize, |
| (const char *)(base() + sec->sh_offset + sec->sh_size)); |
| } |
| |
| Elf_Rel_Iter begin_rel(const Elf_Shdr *sec) const { |
| return Elf_Rel_Iter(sec->sh_entsize, |
| (const char *)(base() + sec->sh_offset)); |
| } |
| |
| 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)); |
| } |
| |
| /// \brief Iterate over program header table. |
| typedef ELFEntityIterator<const Elf_Phdr> Elf_Phdr_Iter; |
| |
| Elf_Phdr_Iter begin_program_headers() const { |
| return Elf_Phdr_Iter(Header->e_phentsize, |
| (const char*)base() + Header->e_phoff); |
| } |
| |
| 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)); |
| } |
| |
| uint64_t getNumSections() const; |
| uintX_t getStringTableIndex() const; |
| ELF::Elf64_Word getSymbolTableIndex(const Elf_Sym *symb) 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<StringRef> 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<StringRef> getSymbolName(const Elf_Shdr *SymTab, |
| const Elf_Sym *Symb) const; |
| ErrorOr<StringRef> getSectionName(const Elf_Shdr *Section) const; |
| uint64_t getSymbolIndex(const Elf_Sym *sym) const; |
| ErrorOr<ArrayRef<uint8_t> > 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<ELFType<support::little, 2, false> > ELF32LEFile; |
| typedef ELFFile<ELFType<support::little, 2, true> > ELF64LEFile; |
| typedef ELFFile<ELFType<support::big, 2, false> > ELF32BEFile; |
| typedef ELFFile<ELFType<support::big, 2, true> > ELF64BEFile; |
| |
| // Iterate through the version definitions, and place each Elf_Verdef |
| // in the VersionMap according to its index. |
| template <class ELFT> |
| void ELFFile<ELFT>::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<const Elf_Verdef *>(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 <class ELFT> |
| void ELFFile<ELFT>::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<const Elf_Verneed *>(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<const Elf_Vernaux *>(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 <class ELFT> |
| void ELFFile<ELFT>::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; |
| |
| // 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 <class ELFT> |
| ELF::Elf64_Word ELFFile<ELFT>::getSymbolTableIndex(const Elf_Sym *symb) const { |
| if (symb->st_shndx == ELF::SHN_XINDEX) |
| return ExtendedSymbolTable.lookup(symb); |
| return symb->st_shndx; |
| } |
| |
| template <class ELFT> |
| const typename ELFFile<ELFT>::Elf_Shdr * |
| ELFFile<ELFT>::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); |
| } |
| |
| template <class ELFT> |
| const typename ELFFile<ELFT>::Elf_Sym * |
| ELFFile<ELFT>::getSymbol(uint32_t Index) const { |
| return &*(begin_symbols() + Index); |
| } |
| |
| template <class ELFT> |
| ErrorOr<ArrayRef<uint8_t> > |
| ELFFile<ELFT>::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 ArrayRef<uint8_t>(Start, Sec->sh_size); |
| } |
| |
| template <class ELFT> |
| StringRef ELFFile<ELFT>::getRelocationTypeName(uint32_t Type) const { |
| return getELFRelocationTypeName(Header->e_machine, Type); |
| } |
| |
| template <class ELFT> |
| void ELFFile<ELFT>::getRelocationTypeName(uint32_t Type, |
| SmallVectorImpl<char> &Result) const { |
| if (!isMipsELF64()) { |
| StringRef Name = getRelocationTypeName(Type); |
| Result.append(Name.begin(), Name.end()); |
| } else { |
| // The Mips N64 ABI allows up to three operations to be specified per |
| // relocation record. Unfortunately there's no easy way to test for the |
| // presence of N64 ELFs as they have no special flag that identifies them |
| // as being N64. We can safely assume at the moment that all Mips |
| // ELFCLASS64 ELFs are N64. New Mips64 ABIs should provide enough |
| // information to disambiguate between old vs new ABIs. |
| uint8_t Type1 = (Type >> 0) & 0xFF; |
| uint8_t Type2 = (Type >> 8) & 0xFF; |
| uint8_t Type3 = (Type >> 16) & 0xFF; |
| |
| // Concat all three relocation type names. |
| StringRef Name = getRelocationTypeName(Type1); |
| Result.append(Name.begin(), Name.end()); |
| |
| Name = getRelocationTypeName(Type2); |
| Result.append(1, '/'); |
| Result.append(Name.begin(), Name.end()); |
| |
| Name = getRelocationTypeName(Type3); |
| Result.append(1, '/'); |
| Result.append(Name.begin(), Name.end()); |
| } |
| } |
| |
| template <class ELFT> |
| template <class RelT> |
| std::pair<const typename ELFFile<ELFT>::Elf_Shdr *, |
| const typename ELFFile<ELFT>::Elf_Sym *> |
| ELFFile<ELFT>::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<Elf_Sym>(SymTable, Rel->getSymbol(isMips64EL()))); |
| } |
| |
| // Verify that the last byte in the string table in a null. |
| template <class ELFT> |
| void ELFFile<ELFT>::VerifyStrTab(const Elf_Shdr *sh) const { |
| const char *strtab = (const char *)base() + sh->sh_offset; |
| if (strtab[sh->sh_size - 1] != 0) |
| // FIXME: Proper error handling. |
| report_fatal_error("String table must end with a null terminator!"); |
| } |
| |
| template <class ELFT> |
| uint64_t ELFFile<ELFT>::getNumSections() const { |
| assert(Header && "Header not initialized!"); |
| if (Header->e_shnum == ELF::SHN_UNDEF && Header->e_shoff > 0) { |
| assert(SectionHeaderTable && "SectionHeaderTable not initialized!"); |
| return SectionHeaderTable->sh_size; |
| } |
| return Header->e_shnum; |
| } |
| |
| template <class ELFT> |
| typename ELFFile<ELFT>::uintX_t ELFFile<ELFT>::getStringTableIndex() const { |
| if (Header->e_shnum == ELF::SHN_UNDEF) { |
| if (Header->e_shstrndx == ELF::SHN_HIRESERVE) |
| return SectionHeaderTable->sh_link; |
| if (Header->e_shstrndx >= getNumSections()) |
| return 0; |
| } |
| return Header->e_shstrndx; |
| } |
| |
| template <class ELFT> |
| ELFFile<ELFT>::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) { |
| const uint64_t FileSize = Buf.size(); |
| |
| if (sizeof(Elf_Ehdr) > FileSize) |
| // FIXME: Proper error handling. |
| report_fatal_error("File too short!"); |
| |
| Header = reinterpret_cast<const Elf_Ehdr *>(base()); |
| |
| if (Header->e_shoff == 0) |
| return; |
| |
| const uint64_t SectionTableOffset = Header->e_shoff; |
| |
| if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) |
| // FIXME: Proper error handling. |
| report_fatal_error("Section header table goes past end of file!"); |
| |
| // The getNumSections() call below depends on SectionHeaderTable being set. |
| SectionHeaderTable = |
| reinterpret_cast<const Elf_Shdr *>(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; |
| } |
| } |
| |
| // 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<const Elf_Word*>(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; |
| } |
| } |
| |
| ec = std::error_code(); |
| } |
| |
| // Get the symbol table index in the symtab section given a symbol |
| template <class ELFT> |
| uint64_t ELFFile<ELFT>::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 <class ELFT> |
| typename ELFFile<ELFT>::Elf_Shdr_Iter ELFFile<ELFT>::begin_sections() const { |
| return Elf_Shdr_Iter(Header->e_shentsize, |
| (const char *)base() + Header->e_shoff); |
| } |
| |
| template <class ELFT> |
| typename ELFFile<ELFT>::Elf_Shdr_Iter ELFFile<ELFT>::end_sections() const { |
| return Elf_Shdr_Iter(Header->e_shentsize, |
| (const char *)base() + Header->e_shoff + |
| (getNumSections() * Header->e_shentsize)); |
| } |
| |
| template <class ELFT> |
| typename ELFFile<ELFT>::Elf_Sym_Iter ELFFile<ELFT>::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); |
| } |
| |
| template <class ELFT> |
| typename ELFFile<ELFT>::Elf_Sym_Iter ELFFile<ELFT>::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); |
| } |
| |
| template <class ELFT> |
| typename ELFFile<ELFT>::Elf_Dyn_Iter |
| ELFFile<ELFT>::begin_dynamic_table() const { |
| if (DynamicRegion.Addr) |
| return Elf_Dyn_Iter(DynamicRegion.EntSize, |
| (const char *)DynamicRegion.Addr); |
| return Elf_Dyn_Iter(0, nullptr); |
| } |
| |
| template <class ELFT> |
| typename ELFFile<ELFT>::Elf_Dyn_Iter |
| ELFFile<ELFT>::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; |
| } |
| |
| template <class ELFT> |
| StringRef ELFFile<ELFT>::getLoadName() const { |
| if (!dt_soname) { |
| dt_soname = ""; |
| // Find the DT_SONAME entry |
| for (const auto &Entry : dynamic_table()) |
| if (Entry.getTag() == ELF::DT_SONAME) { |
| dt_soname = getDynamicString(Entry.getVal()); |
| break; |
| } |
| } |
| return dt_soname; |
| } |
| |
| template <class ELFT> |
| template <typename T> |
| const T *ELFFile<ELFT>::getEntry(uint32_t Section, uint32_t Entry) const { |
| return getEntry<T>(getSection(Section), Entry); |
| } |
| |
| template <class ELFT> |
| template <typename T> |
| const T *ELFFile<ELFT>::getEntry(const Elf_Shdr *Section, |
| uint32_t Entry) const { |
| return reinterpret_cast<const T *>(base() + Section->sh_offset + |
| (Entry * Section->sh_entsize)); |
| } |
| |
| template <class ELFT> |
| const typename ELFFile<ELFT>::Elf_Shdr * |
| ELFFile<ELFT>::getSection(uint32_t index) const { |
| if (index == 0) |
| return nullptr; |
| if (!SectionHeaderTable || index >= getNumSections()) |
| // FIXME: Proper error handling. |
| report_fatal_error("Invalid section index!"); |
| |
| return reinterpret_cast<const Elf_Shdr *>( |
| reinterpret_cast<const char *>(SectionHeaderTable) |
| + (index * Header->e_shentsize)); |
| } |
| |
| template <class ELFT> |
| const char *ELFFile<ELFT>::getString(uint32_t section, |
| ELF::Elf32_Word offset) const { |
| return getString(getSection(section), offset); |
| } |
| |
| template <class ELFT> |
| const char *ELFFile<ELFT>::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 <class ELFT> |
| const char *ELFFile<ELFT>::getDynamicString(uintX_t Offset) const { |
| if (!DynStrRegion.Addr || Offset >= DynStrRegion.Size) |
| return nullptr; |
| return (const char *)DynStrRegion.Addr + Offset; |
| } |
| |
| template <class ELFT> |
| ErrorOr<StringRef> ELFFile<ELFT>::getSymbolName(Elf_Sym_Iter Sym) const { |
| if (!Sym.isDynamic()) |
| return getSymbolName(dot_symtab_sec, &*Sym); |
| |
| if (!DynStrRegion.Addr || Sym->st_name >= DynStrRegion.Size) |
| return object_error::parse_failed; |
| return StringRef(getDynamicString(Sym->st_name)); |
| } |
| |
| template <class ELFT> |
| ErrorOr<StringRef> ELFFile<ELFT>::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) |
| return object_error::parse_failed; |
| return StringRef(getString(StrTab, Symb->st_name)); |
| } |
| |
| template <class ELFT> |
| ErrorOr<StringRef> |
| ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section) const { |
| if (Section->sh_name >= dot_shstrtab_sec->sh_size) |
| return object_error::parse_failed; |
| return StringRef(getString(dot_shstrtab_sec, Section->sh_name)); |
| } |
| |
| template <class ELFT> |
| ErrorOr<StringRef> ELFFile<ELFT>::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<StringRef> 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<Elf_Versym>(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 |
| static inline unsigned elf_hash(StringRef &symbolName) { |
| unsigned h = 0, g; |
| for (unsigned i = 0, j = symbolName.size(); i < j; i++) { |
| h = (h << 4) + symbolName[i]; |
| g = h & 0xf0000000L; |
| if (g != 0) |
| h ^= g >> 24; |
| h &= ~g; |
| } |
| return h; |
| } |
| } // end namespace object |
| } // end namespace llvm |
| |
| #endif |