//===- 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/SmallVector.h" #include "llvm/Object/ELFTypes.h" #include "llvm/Support/MemoryBuffer.h" namespace llvm { namespace object { StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type); // Subclasses of ELFFile may need this for template instantiation inline std::pair getElfArchType(StringRef Object) { if (Object.size() < ELF::EI_NIDENT) return std::make_pair((uint8_t)ELF::ELFCLASSNONE, (uint8_t)ELF::ELFDATANONE); return std::make_pair((uint8_t)Object[ELF::EI_CLASS], (uint8_t)Object[ELF::EI_DATA]); } template class ELFFile { public: LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) typedef typename std::conditional::type uintX_t; typedef Elf_Ehdr_Impl Elf_Ehdr; typedef Elf_Shdr_Impl Elf_Shdr; typedef Elf_Sym_Impl Elf_Sym; typedef Elf_Dyn_Impl Elf_Dyn; typedef Elf_Phdr_Impl Elf_Phdr; typedef Elf_Rel_Impl Elf_Rel; typedef Elf_Rel_Impl Elf_Rela; typedef Elf_Verdef_Impl Elf_Verdef; typedef Elf_Verdaux_Impl Elf_Verdaux; typedef Elf_Verneed_Impl Elf_Verneed; typedef Elf_Vernaux_Impl Elf_Vernaux; typedef Elf_Versym_Impl Elf_Versym; typedef Elf_Hash_Impl Elf_Hash; typedef 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 = 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; 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 for a given relocation. const Elf_Sym *getRelocationSymbol(const Elf_Rel *Rel, const Elf_Shdr *SymTab) 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; } 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 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)); } 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); } 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_Range relas(const Elf_Shdr *Sec) const { return make_range(rela_begin(Sec), rela_end(Sec)); } 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); } 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); } 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. 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); } const Elf_Phdr *program_header_end() const { return program_header_begin() + Header->e_phnum; } 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; 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 *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; template ErrorOr> getSectionContentsAsArray(const Elf_Shdr *Sec) const; ErrorOr > getSectionContents(const Elf_Shdr *Sec) const; }; typedef ELFFile> ELF32LEFile; typedef ELFFile> ELF64LEFile; typedef ELFFile> ELF32BEFile; typedef ELFFile> ELF64BEFile; template 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); // The size of the table was checked in getSHNDXTable. return ShndxTable[Index]; } template 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)); if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE) return nullptr; return getSection(Sym->st_shndx); } template 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> ELFFile::getSectionContents(const Elf_Shdr *Sec) const { return getSectionContentsAsArray(Sec); } template StringRef ELFFile::getRelocationTypeName(uint32_t Type) const { return getELFRelocationTypeName(Header->e_machine, Type); } template void ELFFile::getRelocationTypeName(uint32_t Type, SmallVectorImpl &Result) const { if (!isMipsELF64()) { StringRef Name = getRelocationTypeName(Type); Result.append(Name.begin(), Name.end()); } else { // The Mips N64 ABI allows up to three operations to be specified per // relocation record. Unfortunately there's no easy way to test for the // presence of N64 ELFs as they have no special flag that identifies them // as being N64. We can safely assume at the moment that all Mips // ELFCLASS64 ELFs are N64. New Mips64 ABIs should provide enough // information to disambiguate between old vs new ABIs. uint8_t Type1 = (Type >> 0) & 0xFF; uint8_t Type2 = (Type >> 8) & 0xFF; uint8_t Type3 = (Type >> 16) & 0xFF; // Concat all three relocation type names. StringRef Name = getRelocationTypeName(Type1); Result.append(Name.begin(), Name.end()); Name = getRelocationTypeName(Type2); Result.append(1, '/'); Result.append(Name.begin(), Name.end()); Name = getRelocationTypeName(Type3); Result.append(1, '/'); Result.append(Name.begin(), Name.end()); } } template 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 uint64_t ELFFile::getNumSections() const { assert(Header && "Header not initialized!"); if (Header->e_shnum == ELF::SHN_UNDEF && Header->e_shoff > 0) { assert(SectionHeaderTable && "SectionHeaderTable not initialized!"); return SectionHeaderTable->sh_size; } return Header->e_shnum; } template typename ELFFile::uintX_t ELFFile::getStringTableIndex() const { if (Header->e_shnum == ELF::SHN_UNDEF) { if (Header->e_shstrndx == ELF::SHN_HIRESERVE) return SectionHeaderTable->sh_link; if (Header->e_shstrndx >= getNumSections()) return 0; } return Header->e_shstrndx; } template ELFFile::ELFFile(StringRef Object, std::error_code &EC) : Buf(Object) { const uint64_t FileSize = Buf.size(); if (sizeof(Elf_Ehdr) > FileSize) { // File too short! EC = object_error::parse_failed; return; } Header = reinterpret_cast(base()); if (Header->e_shoff == 0) return; const uint64_t SectionTableOffset = Header->e_shoff; 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) { // Section table goes past end of file! EC = object_error::parse_failed; return; } // Get string table sections. 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(); } template static bool compareAddr(uint64_t VAddr, const Elf_Phdr_Impl *Phdr) { return VAddr < Phdr->p_vaddr; } template const typename ELFFile::Elf_Shdr *ELFFile::section_begin() const { if (Header->e_shentsize != sizeof(Elf_Shdr)) report_fatal_error( "Invalid section header entry size (e_shentsize) in ELF header"); return reinterpret_cast(base() + Header->e_shoff); } template const typename ELFFile::Elf_Shdr *ELFFile::section_end() const { return section_begin() + getNumSections(); } template 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 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 { ErrorOr Sec = getSection(Section); if (std::error_code EC = Sec.getError()) report_fatal_error(EC.message()); return getEntry(*Sec, Entry); } template template const T *ELFFile::getEntry(const Elf_Shdr *Section, uint32_t Entry) const { return reinterpret_cast(base() + Section->sh_offset + (Entry * Section->sh_entsize)); } template ErrorOr::Elf_Shdr *> ELFFile::getSection(uint32_t Index) const { assert(SectionHeaderTable && "SectionHeaderTable not initialized!"); if (Index >= getNumSections()) return object_error::invalid_section_index; return reinterpret_cast( reinterpret_cast(SectionHeaderTable) + (Index * Header->e_shentsize)); } template ErrorOr ELFFile::getStringTable(const Elf_Shdr *Section) const { if (Section->sh_type != ELF::SHT_STRTAB) return object_error::parse_failed; uint64_t Offset = Section->sh_offset; uint64_t Size = Section->sh_size; if (Offset + Size > Buf.size()) return object_error::parse_failed; StringRef Data((const char *)base() + Section->sh_offset, Size); if (Data[Size - 1] != '\0') return object_error::string_table_non_null_end; return Data; } template 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::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); } /// 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