X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=include%2Fllvm%2FObject%2FELF.h;h=6ebb92f7ee8caf97317c117e42babc1fe3c03a2a;hb=9ed0d629ce9ee7a1a8d7231347ad3050d1f98732;hp=7ec47527939648b0346aa4cfbe5675c8589b5bfe;hpb=3a27979633d2d1c6e8ebf43b402a1147da7f0809;p=oota-llvm.git diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 7ec47527939..6ebb92f7ee8 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -139,10 +139,8 @@ 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 Elf_Hash_Impl Elf_Hash; + typedef iterator_range Elf_Dyn_Range; typedef iterator_range Elf_Shdr_Range; /// \brief Archive files are 2 byte aligned, so we need this for @@ -174,8 +172,8 @@ private: StringRef DotShstrtab; // Section header string table. StringRef DotStrtab; // Symbol header string table. const Elf_Shdr *dot_symtab_sec = nullptr; // Symbol table section. - StringRef DynSymStrTab; // Dynnamic symbol string table. const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. + const Elf_Hash *HashTable = nullptr; const Elf_Shdr *SymbolTableSectionHeaderIndex = nullptr; DenseMap ExtendedSymbolTable; @@ -196,12 +194,11 @@ private: }; 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; + // SONAME entry in dynamic string table + StringRef DTSoname; // Records for each version index the corresponding Verdef or Vernaux entry. // This is filled the first time LoadVersionMap() is called. @@ -229,12 +226,24 @@ private: void LoadVersionNeeds(const Elf_Shdr *ec) const; void LoadVersionMap() const; + void scanDynamicTable(); + 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 Elf_Shdr *getDotSymtabSec() const { return dot_symtab_sec; } + const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } + const Elf_Hash *getHashTable() const { return HashTable; } + StringRef getDynamicStringTable() const { + return StringRef((const char *)DynStrRegion.Addr, DynStrRegion.Size); + } + ErrorOr getStringTable(const Elf_Shdr *Section) const; + ErrorOr getStringTableForSymtab(const Elf_Shdr &Section) const; + const char *getDynamicString(uintX_t Offset) const; ErrorOr getSymbolVersion(const Elf_Shdr *section, const Elf_Sym *Symb, @@ -275,12 +284,10 @@ public: 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_Dyn *dynamic_table_begin() const; + const Elf_Dyn *dynamic_table_end() const; + Elf_Dyn_Range dynamic_table() const { + return make_range(dynamic_table_begin(), dynamic_table_end()); } const Elf_Sym *dynamic_symbol_begin() const { @@ -302,55 +309,75 @@ public: return make_range(dynamic_symbol_begin(), dynamic_symbol_end()); } - 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); + const Elf_Rela *dyn_rela_begin() const { + if (DynRelaRegion.Size && DynRelaRegion.EntSize != sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast(DynRelaRegion.Addr); + } + + const Elf_Rela *dyn_rela_end() const { + uint64_t Size = DynRelaRegion.Size; + if (Size % sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation table size"); + return dyn_rela_begin() + Size / sizeof(Elf_Rela); + } + + typedef iterator_range Elf_Rela_Range; + + Elf_Rela_Range dyn_relas() const { + return make_range(dyn_rela_begin(), dyn_rela_end()); + } + + 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. - 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 program_header_begin() 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 program_header_end() 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; @@ -361,12 +388,9 @@ public: 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; ErrorOr getSectionName(const Elf_Shdr *Section) const; - uint64_t getSymbolIndex(const Elf_Sym *sym) const; ErrorOr > getSectionContents(const Elf_Shdr *Sec) const; StringRef getLoadName() const; }; @@ -575,8 +599,10 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) Header = reinterpret_cast(base()); - if (Header->e_shoff == 0) + if (Header->e_shoff == 0) { + scanDynamicTable(); return; + } const uint64_t SectionTableOffset = Header->e_shoff; @@ -601,6 +627,13 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) 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! @@ -616,10 +649,7 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) return; } dot_symtab_sec = &Sec; - ErrorOr SectionOrErr = getSection(Sec.sh_link); - if ((EC = SectionOrErr.getError())) - return; - ErrorOr SymtabOrErr = getStringTable(*SectionOrErr); + ErrorOr SymtabOrErr = getStringTableForSymtab(Sec); if ((EC = SymtabOrErr.getError())) return; DotStrtab = *SymtabOrErr; @@ -631,25 +661,8 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) return; } DotDynSymSec = &Sec; - ErrorOr SectionOrErr = getSection(Sec.sh_link); - if ((EC = SectionOrErr.getError())) - return; - ErrorOr SymtabOrErr = getStringTable(*SectionOrErr); - if ((EC = SymtabOrErr.getError())) - return; - DynSymStrTab = *SymtabOrErr; 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! @@ -698,63 +711,76 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) } } - // Scan program headers. - for (Elf_Phdr_Iter PhdrI = program_header_begin(), - PhdrE = program_header_end(); - 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; + scanDynamicTable(); + + EC = std::error_code(); +} + +template +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; + 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()) + report_fatal_error("Virtual address is not in any segment"); + --I; + const Elf_Phdr &Phdr = **I; + uint64_t Delta = VAddr - Phdr.p_vaddr; + if (Delta >= Phdr.p_filesz) + report_fatal_error("Virtual address is not in any segment"); + return this->base() + Phdr.p_offset + Delta; + }; - // Scan dynamic table. - for (Elf_Dyn_Iter DynI = dynamic_table_begin(), DynE = dynamic_table_end(); - DynI != DynE; ++DynI) { - switch (DynI->d_tag) { - case ELF::DT_RELA: { - uint64_t VBase = 0; - const uint8_t *FBase = nullptr; - for (Elf_Phdr_Iter PhdrI = program_header_begin(), - PhdrE = program_header_end(); - PhdrI != PhdrE; ++PhdrI) { - if (PhdrI->p_type != ELF::PT_LOAD) - continue; - if (DynI->getPtr() >= PhdrI->p_vaddr && - DynI->getPtr() < PhdrI->p_vaddr + PhdrI->p_memsz) { - VBase = PhdrI->p_vaddr; - FBase = base() + PhdrI->p_offset; - break; - } - } - if (!VBase) - return; - DynRelaRegion.Addr = FBase + DynI->getPtr() - VBase; + uint64_t SONameOffset = 0; + for (const Elf_Dyn &Dyn : dynamic_table()) { + switch (Dyn.d_tag) { + case ELF::DT_HASH: + if (HashTable) + continue; + HashTable = + reinterpret_cast(toMappedAddr(Dyn.getPtr())); + break; + case ELF::DT_STRTAB: + if (!DynStrRegion.Addr) + DynStrRegion.Addr = toMappedAddr(Dyn.getPtr()); + break; + case ELF::DT_STRSZ: + if (!DynStrRegion.Size) + DynStrRegion.Size = Dyn.getVal(); + break; + case ELF::DT_RELA: + if (!DynRelaRegion.Addr) + DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr()); break; - } case ELF::DT_RELASZ: - DynRelaRegion.Size = DynI->getVal(); + DynRelaRegion.Size = Dyn.getVal(); break; case ELF::DT_RELAENT: - DynRelaRegion.EntSize = DynI->getVal(); + DynRelaRegion.EntSize = Dyn.getVal(); + break; + case ELF::DT_SONAME: + SONameOffset = Dyn.getVal(); + break; } } - - 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; + if (SONameOffset) + DTSoname = getDynamicString(SONameOffset); } template @@ -788,47 +814,24 @@ const typename ELFFile::Elf_Sym *ELFFile::symbol_end() const { } template -typename ELFFile::Elf_Dyn_Iter +const typename ELFFile::Elf_Dyn * ELFFile::dynamic_table_begin() const { - if (DynamicRegion.Addr) - return Elf_Dyn_Iter(DynamicRegion.EntSize, - (const char *)DynamicRegion.Addr); - return Elf_Dyn_Iter(0, nullptr); + return reinterpret_cast(DynamicRegion.Addr); } 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); +const typename ELFFile::Elf_Dyn * +ELFFile::dynamic_table_end() const { + uint64_t Size = DynamicRegion.Size; + if (Size % sizeof(Elf_Dyn)) + report_fatal_error("Invalid dynamic table 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; + return dynamic_table_begin() + Size / sizeof(Elf_Dyn); } 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; + return DTSoname; } template @@ -876,16 +879,21 @@ ELFFile::getStringTable(const Elf_Shdr *Section) const { } template -const char *ELFFile::getDynamicString(uintX_t Offset) const { - if (!DotDynSymSec || Offset >= DynSymStrTab.size()) - return nullptr; - return (const char *)DynSymStrTab.begin() + Offset; +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::getStaticSymbolName(const Elf_Sym *Symb) const { - return Symb->getName(DotStrtab); +const char *ELFFile::getDynamicString(uintX_t Offset) const { + if (Offset >= DynStrRegion.Size) + return nullptr; + return (const char *)DynStrRegion.Addr + Offset; } template @@ -894,14 +902,6 @@ 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); -} - template ErrorOr ELFFile::getSectionName(const Elf_Shdr *Section) const { @@ -992,7 +992,7 @@ ErrorOr ELFFile::getSymbolVersion(const Elf_Shdr *section, IsDefault = false; } - if (name_offset >= DynSymStrTab.size()) + if (name_offset >= DynStrRegion.Size) return object_error::parse_failed; return StringRef(getDynamicString(name_offset)); }