diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:30 +0300 |
commit | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch) | |
tree | 012bb94d777798f1f56ac1cec429509766d05181 /contrib/libs/llvm12/include/llvm/Object/ELF.h | |
parent | 6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff) | |
download | ydb-2598ef1d0aee359b4b6d5fdd1758916d5907d04f.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 1 of 2.
Diffstat (limited to 'contrib/libs/llvm12/include/llvm/Object/ELF.h')
-rw-r--r-- | contrib/libs/llvm12/include/llvm/Object/ELF.h | 1168 |
1 files changed, 584 insertions, 584 deletions
diff --git a/contrib/libs/llvm12/include/llvm/Object/ELF.h b/contrib/libs/llvm12/include/llvm/Object/ELF.h index 20e25a9ee2..e68397b898 100644 --- a/contrib/libs/llvm12/include/llvm/Object/ELF.h +++ b/contrib/libs/llvm12/include/llvm/Object/ELF.h @@ -37,43 +37,43 @@ namespace llvm { namespace object { -struct VerdAux { - unsigned Offset; - std::string Name; -}; - -struct VerDef { - unsigned Offset; - unsigned Version; - unsigned Flags; - unsigned Ndx; - unsigned Cnt; - unsigned Hash; - std::string Name; - std::vector<VerdAux> AuxV; -}; - -struct VernAux { - unsigned Hash; - unsigned Flags; - unsigned Other; - unsigned Offset; - std::string Name; -}; - -struct VerNeed { - unsigned Version; - unsigned Cnt; - unsigned Offset; - std::string File; - std::vector<VernAux> AuxV; -}; - -struct VersionEntry { - std::string Name; - bool IsVerDef; -}; - +struct VerdAux { + unsigned Offset; + std::string Name; +}; + +struct VerDef { + unsigned Offset; + unsigned Version; + unsigned Flags; + unsigned Ndx; + unsigned Cnt; + unsigned Hash; + std::string Name; + std::vector<VerdAux> AuxV; +}; + +struct VernAux { + unsigned Hash; + unsigned Flags; + unsigned Other; + unsigned Offset; + std::string Name; +}; + +struct VerNeed { + unsigned Version; + unsigned Cnt; + unsigned Offset; + std::string File; + std::vector<VernAux> AuxV; +}; + +struct VersionEntry { + std::string Name; + bool IsVerDef; +}; + StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type); uint32_t getELFRelativeRelocationType(uint32_t Machine); StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type); @@ -92,51 +92,51 @@ static inline Error createError(const Twine &Err) { return make_error<StringError>(Err, object_error::parse_failed); } -enum PPCInstrMasks : uint64_t { - PADDI_R12_NO_DISP = 0x0610000039800000, - PLD_R12_NO_DISP = 0x04100000E5800000, - MTCTR_R12 = 0x7D8903A6, - BCTR = 0x4E800420, -}; - +enum PPCInstrMasks : uint64_t { + PADDI_R12_NO_DISP = 0x0610000039800000, + PLD_R12_NO_DISP = 0x04100000E5800000, + MTCTR_R12 = 0x7D8903A6, + BCTR = 0x4E800420, +}; + template <class ELFT> class ELFFile; -template <class T> struct DataRegion { - // This constructor is used when we know the start and the size of a data - // region. We assume that Arr does not go past the end of the file. - DataRegion(ArrayRef<T> Arr) : First(Arr.data()), Size(Arr.size()) {} - - // Sometimes we only know the start of a data region. We still don't want to - // read past the end of the file, so we provide the end of a buffer. - DataRegion(const T *Data, const uint8_t *BufferEnd) - : First(Data), BufEnd(BufferEnd) {} - - Expected<T> operator[](uint64_t N) { - assert(Size || BufEnd); - if (Size) { - if (N >= *Size) - return createError( - "the index is greater than or equal to the number of entries (" + - Twine(*Size) + ")"); - } else { - const uint8_t *EntryStart = (const uint8_t *)First + N * sizeof(T); - if (EntryStart + sizeof(T) > BufEnd) - return createError("can't read past the end of the file"); - } - return *(First + N); - } - - const T *First; - Optional<uint64_t> Size = None; - const uint8_t *BufEnd = nullptr; -}; - +template <class T> struct DataRegion { + // This constructor is used when we know the start and the size of a data + // region. We assume that Arr does not go past the end of the file. + DataRegion(ArrayRef<T> Arr) : First(Arr.data()), Size(Arr.size()) {} + + // Sometimes we only know the start of a data region. We still don't want to + // read past the end of the file, so we provide the end of a buffer. + DataRegion(const T *Data, const uint8_t *BufferEnd) + : First(Data), BufEnd(BufferEnd) {} + + Expected<T> operator[](uint64_t N) { + assert(Size || BufEnd); + if (Size) { + if (N >= *Size) + return createError( + "the index is greater than or equal to the number of entries (" + + Twine(*Size) + ")"); + } else { + const uint8_t *EntryStart = (const uint8_t *)First + N * sizeof(T); + if (EntryStart + sizeof(T) > BufEnd) + return createError("can't read past the end of the file"); + } + return *(First + N); + } + + const T *First; + Optional<uint64_t> Size = None; + const uint8_t *BufEnd = nullptr; +}; + template <class ELFT> -std::string getSecIndexForError(const ELFFile<ELFT> &Obj, - const typename ELFT::Shdr &Sec) { - auto TableOrErr = Obj.sections(); +std::string getSecIndexForError(const ELFFile<ELFT> &Obj, + const typename ELFT::Shdr &Sec) { + auto TableOrErr = Obj.sections(); if (TableOrErr) - return "[index " + std::to_string(&Sec - &TableOrErr->front()) + "]"; + return "[index " + std::to_string(&Sec - &TableOrErr->front()) + "]"; // To make this helper be more convenient for error reporting purposes we // drop the error. But really it should never be triggered. Before this point, // our code should have called 'sections()' and reported a proper error on @@ -146,21 +146,21 @@ std::string getSecIndexForError(const ELFFile<ELFT> &Obj, } template <class ELFT> -static std::string describe(const ELFFile<ELFT> &Obj, - const typename ELFT::Shdr &Sec) { - unsigned SecNdx = &Sec - &cantFail(Obj.sections()).front(); - return (object::getELFSectionTypeName(Obj.getHeader().e_machine, - Sec.sh_type) + - " section with index " + Twine(SecNdx)) - .str(); -} - -template <class ELFT> -std::string getPhdrIndexForError(const ELFFile<ELFT> &Obj, - const typename ELFT::Phdr &Phdr) { - auto Headers = Obj.program_headers(); +static std::string describe(const ELFFile<ELFT> &Obj, + const typename ELFT::Shdr &Sec) { + unsigned SecNdx = &Sec - &cantFail(Obj.sections()).front(); + return (object::getELFSectionTypeName(Obj.getHeader().e_machine, + Sec.sh_type) + + " section with index " + Twine(SecNdx)) + .str(); +} + +template <class ELFT> +std::string getPhdrIndexForError(const ELFFile<ELFT> &Obj, + const typename ELFT::Phdr &Phdr) { + auto Headers = Obj.program_headers(); if (Headers) - return ("[index " + Twine(&Phdr - &Headers->front()) + "]").str(); + return ("[index " + Twine(&Phdr - &Headers->front()) + "]").str(); // See comment in the getSecIndexForError() above. llvm::consumeError(Headers.takeError()); return "[unknown index]"; @@ -183,7 +183,7 @@ public: using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>; const uint8_t *base() const { return Buf.bytes_begin(); } - const uint8_t *end() const { return base() + getBufSize(); } + const uint8_t *end() const { return base() + getBufSize(); } size_t getBufSize() const { return Buf.size(); } @@ -193,39 +193,39 @@ private: ELFFile(StringRef Object); public: - const Elf_Ehdr &getHeader() const { - return *reinterpret_cast<const Elf_Ehdr *>(base()); + const Elf_Ehdr &getHeader() const { + return *reinterpret_cast<const Elf_Ehdr *>(base()); } template <typename T> Expected<const T *> getEntry(uint32_t Section, uint32_t Entry) const; template <typename T> - Expected<const T *> getEntry(const Elf_Shdr &Section, uint32_t Entry) const; + Expected<const T *> getEntry(const Elf_Shdr &Section, uint32_t Entry) const; - Expected<std::vector<VerDef>> - getVersionDefinitions(const Elf_Shdr &Sec) const; - Expected<std::vector<VerNeed>> getVersionDependencies( - const Elf_Shdr &Sec, - WarningHandler WarnHandler = &defaultWarningHandler) const; + Expected<std::vector<VerDef>> + getVersionDefinitions(const Elf_Shdr &Sec) const; + Expected<std::vector<VerNeed>> getVersionDependencies( + const Elf_Shdr &Sec, + WarningHandler WarnHandler = &defaultWarningHandler) const; Expected<StringRef> - getSymbolVersionByIndex(uint32_t SymbolVersionIndex, bool &IsDefault, - SmallVector<Optional<VersionEntry>, 0> &VersionMap, - Optional<bool> IsSymHidden) const; - - Expected<StringRef> - getStringTable(const Elf_Shdr &Section, + getSymbolVersionByIndex(uint32_t SymbolVersionIndex, bool &IsDefault, + SmallVector<Optional<VersionEntry>, 0> &VersionMap, + Optional<bool> IsSymHidden) const; + + Expected<StringRef> + getStringTable(const Elf_Shdr &Section, WarningHandler WarnHandler = &defaultWarningHandler) const; Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const; Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section, Elf_Shdr_Range Sections) const; - Expected<StringRef> getLinkAsStrtab(const typename ELFT::Shdr &Sec) const; + Expected<StringRef> getLinkAsStrtab(const typename ELFT::Shdr &Sec) const; Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section) const; Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section, Elf_Shdr_Range Sections) const; - Expected<uint64_t> getDynSymtabSize() const; - + Expected<uint64_t> getDynSymtabSize() const; + StringRef getRelocationTypeName(uint32_t Type) const; void getRelocationTypeName(uint32_t Type, SmallVectorImpl<char> &Result) const; @@ -235,21 +235,21 @@ public: std::string getDynamicTagAsString(uint64_t Type) const; /// Get the symbol for a given relocation. - Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel &Rel, + Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel &Rel, const Elf_Shdr *SymTab) const; - Expected<SmallVector<Optional<VersionEntry>, 0>> - loadVersionMap(const Elf_Shdr *VerNeedSec, const Elf_Shdr *VerDefSec) const; - + Expected<SmallVector<Optional<VersionEntry>, 0>> + loadVersionMap(const Elf_Shdr *VerNeedSec, const Elf_Shdr *VerDefSec) const; + static Expected<ELFFile> create(StringRef Object); bool isLE() const { - return getHeader().getDataEncoding() == ELF::ELFDATA2LSB; + return getHeader().getDataEncoding() == ELF::ELFDATA2LSB; } bool isMipsELF64() const { - return getHeader().e_machine == ELF::EM_MIPS && - getHeader().getFileClass() == ELF::ELFCLASS64; + return getHeader().e_machine == ELF::EM_MIPS && + getHeader().getFileClass() == ELF::ELFCLASS64; } bool isMips64EL() const { return isMipsELF64() && isLE(); } @@ -258,50 +258,50 @@ public: Expected<Elf_Dyn_Range> dynamicEntries() const; - Expected<const uint8_t *> - toMappedAddr(uint64_t VAddr, - WarningHandler WarnHandler = &defaultWarningHandler) const; + Expected<const uint8_t *> + toMappedAddr(uint64_t VAddr, + WarningHandler WarnHandler = &defaultWarningHandler) const; Expected<Elf_Sym_Range> symbols(const Elf_Shdr *Sec) const { if (!Sec) return makeArrayRef<Elf_Sym>(nullptr, nullptr); - return getSectionContentsAsArray<Elf_Sym>(*Sec); + return getSectionContentsAsArray<Elf_Sym>(*Sec); } - Expected<Elf_Rela_Range> relas(const Elf_Shdr &Sec) const { + Expected<Elf_Rela_Range> relas(const Elf_Shdr &Sec) const { return getSectionContentsAsArray<Elf_Rela>(Sec); } - Expected<Elf_Rel_Range> rels(const Elf_Shdr &Sec) const { + Expected<Elf_Rel_Range> rels(const Elf_Shdr &Sec) const { return getSectionContentsAsArray<Elf_Rel>(Sec); } - Expected<Elf_Relr_Range> relrs(const Elf_Shdr &Sec) const { + Expected<Elf_Relr_Range> relrs(const Elf_Shdr &Sec) const { return getSectionContentsAsArray<Elf_Relr>(Sec); } - std::vector<Elf_Rel> decode_relrs(Elf_Relr_Range relrs) const; + std::vector<Elf_Rel> decode_relrs(Elf_Relr_Range relrs) const; - Expected<std::vector<Elf_Rela>> android_relas(const Elf_Shdr &Sec) const; + Expected<std::vector<Elf_Rela>> android_relas(const Elf_Shdr &Sec) const; /// Iterate over program header table. Expected<Elf_Phdr_Range> program_headers() const { - if (getHeader().e_phnum && getHeader().e_phentsize != sizeof(Elf_Phdr)) + if (getHeader().e_phnum && getHeader().e_phentsize != sizeof(Elf_Phdr)) return createError("invalid e_phentsize: " + - Twine(getHeader().e_phentsize)); + Twine(getHeader().e_phentsize)); uint64_t HeadersSize = - (uint64_t)getHeader().e_phnum * getHeader().e_phentsize; - uint64_t PhOff = getHeader().e_phoff; + (uint64_t)getHeader().e_phnum * getHeader().e_phentsize; + uint64_t PhOff = getHeader().e_phoff; if (PhOff + HeadersSize < PhOff || PhOff + HeadersSize > getBufSize()) return createError("program headers are longer than binary of size " + Twine(getBufSize()) + ": e_phoff = 0x" + - Twine::utohexstr(getHeader().e_phoff) + - ", e_phnum = " + Twine(getHeader().e_phnum) + - ", e_phentsize = " + Twine(getHeader().e_phentsize)); + Twine::utohexstr(getHeader().e_phoff) + + ", e_phnum = " + Twine(getHeader().e_phnum) + + ", e_phentsize = " + Twine(getHeader().e_phentsize)); auto *Begin = reinterpret_cast<const Elf_Phdr *>(base() + PhOff); - return makeArrayRef(Begin, Begin + getHeader().e_phnum); + return makeArrayRef(Begin, Begin + getHeader().e_phnum); } /// Get an iterator over notes in a program header. @@ -315,9 +315,9 @@ public: assert(Phdr.p_type == ELF::PT_NOTE && "Phdr is not of type PT_NOTE"); ErrorAsOutParameter ErrAsOutParam(&Err); if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) { - Err = - createError("invalid offset (0x" + Twine::utohexstr(Phdr.p_offset) + - ") or size (0x" + Twine::utohexstr(Phdr.p_filesz) + ")"); + Err = + createError("invalid offset (0x" + Twine::utohexstr(Phdr.p_offset) + + ") or size (0x" + Twine::utohexstr(Phdr.p_filesz) + ")"); return Elf_Note_Iterator(Err); } return Elf_Note_Iterator(base() + Phdr.p_offset, Phdr.p_filesz, Err); @@ -334,9 +334,9 @@ public: assert(Shdr.sh_type == ELF::SHT_NOTE && "Shdr is not of type SHT_NOTE"); ErrorAsOutParameter ErrAsOutParam(&Err); if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) { - Err = - createError("invalid offset (0x" + Twine::utohexstr(Shdr.sh_offset) + - ") or size (0x" + Twine::utohexstr(Shdr.sh_size) + ")"); + Err = + createError("invalid offset (0x" + Twine::utohexstr(Shdr.sh_offset) + + ") or size (0x" + Twine::utohexstr(Shdr.sh_size) + ")"); return Elf_Note_Iterator(Err); } return Elf_Note_Iterator(base() + Shdr.sh_offset, Shdr.sh_size, Err); @@ -374,28 +374,28 @@ public: Expected<StringRef> getSectionStringTable( Elf_Shdr_Range Sections, WarningHandler WarnHandler = &defaultWarningHandler) const; - Expected<uint32_t> getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms, - DataRegion<Elf_Word> ShndxTable) const; - Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym, + Expected<uint32_t> getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms, + DataRegion<Elf_Word> ShndxTable) const; + Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab, - DataRegion<Elf_Word> ShndxTable) const; - Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym, + DataRegion<Elf_Word> ShndxTable) const; + Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym, Elf_Sym_Range Symtab, - DataRegion<Elf_Word> ShndxTable) const; + DataRegion<Elf_Word> ShndxTable) const; Expected<const Elf_Shdr *> getSection(uint32_t Index) const; Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec, uint32_t Index) const; Expected<StringRef> - getSectionName(const Elf_Shdr &Section, + getSectionName(const Elf_Shdr &Section, WarningHandler WarnHandler = &defaultWarningHandler) const; - Expected<StringRef> getSectionName(const Elf_Shdr &Section, + Expected<StringRef> getSectionName(const Elf_Shdr &Section, StringRef DotShstrtab) const; template <typename T> - Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr &Sec) const; - Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr &Sec) const; - Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) const; + Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr &Sec) const; + Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr &Sec) const; + Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) const; }; using ELF32LEFile = ELFFile<ELF32LE>; @@ -413,30 +413,30 @@ getSection(typename ELFT::ShdrRange Sections, uint32_t Index) { template <class ELFT> inline Expected<uint32_t> -getExtendedSymbolTableIndex(const typename ELFT::Sym &Sym, unsigned SymIndex, - DataRegion<typename ELFT::Word> ShndxTable) { - assert(Sym.st_shndx == ELF::SHN_XINDEX); - if (!ShndxTable.First) +getExtendedSymbolTableIndex(const typename ELFT::Sym &Sym, unsigned SymIndex, + DataRegion<typename ELFT::Word> ShndxTable) { + assert(Sym.st_shndx == ELF::SHN_XINDEX); + if (!ShndxTable.First) return createError( - "found an extended symbol index (" + Twine(SymIndex) + - "), but unable to locate the extended symbol index table"); - - Expected<typename ELFT::Word> TableOrErr = ShndxTable[SymIndex]; - if (!TableOrErr) - return createError("unable to read an extended symbol table at index " + - Twine(SymIndex) + ": " + - toString(TableOrErr.takeError())); - return *TableOrErr; + "found an extended symbol index (" + Twine(SymIndex) + + "), but unable to locate the extended symbol index table"); + + Expected<typename ELFT::Word> TableOrErr = ShndxTable[SymIndex]; + if (!TableOrErr) + return createError("unable to read an extended symbol table at index " + + Twine(SymIndex) + ": " + + toString(TableOrErr.takeError())); + return *TableOrErr; } template <class ELFT> Expected<uint32_t> -ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms, - DataRegion<Elf_Word> ShndxTable) const { - uint32_t Index = Sym.st_shndx; +ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms, + DataRegion<Elf_Word> ShndxTable) const { + uint32_t Index = Sym.st_shndx; if (Index == ELF::SHN_XINDEX) { - Expected<uint32_t> ErrorOrIndex = - getExtendedSymbolTableIndex<ELFT>(Sym, &Sym - Syms.begin(), ShndxTable); + Expected<uint32_t> ErrorOrIndex = + getExtendedSymbolTableIndex<ELFT>(Sym, &Sym - Syms.begin(), ShndxTable); if (!ErrorOrIndex) return ErrorOrIndex.takeError(); return *ErrorOrIndex; @@ -448,8 +448,8 @@ ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms, template <class ELFT> Expected<const typename ELFT::Shdr *> -ELFFile<ELFT>::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab, - DataRegion<Elf_Word> ShndxTable) const { +ELFFile<ELFT>::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab, + DataRegion<Elf_Word> ShndxTable) const { auto SymsOrErr = symbols(SymTab); if (!SymsOrErr) return SymsOrErr.takeError(); @@ -458,8 +458,8 @@ ELFFile<ELFT>::getSection(const Elf_Sym &Sym, const Elf_Shdr *SymTab, template <class ELFT> Expected<const typename ELFT::Shdr *> -ELFFile<ELFT>::getSection(const Elf_Sym &Sym, Elf_Sym_Range Symbols, - DataRegion<Elf_Word> ShndxTable) const { +ELFFile<ELFT>::getSection(const Elf_Sym &Sym, Elf_Sym_Range Symbols, + DataRegion<Elf_Word> ShndxTable) const { auto IndexOrErr = getSectionIndex(Sym, Symbols, ShndxTable); if (!IndexOrErr) return IndexOrErr.takeError(); @@ -479,7 +479,7 @@ ELFFile<ELFT>::getSymbol(const Elf_Shdr *Sec, uint32_t Index) const { Elf_Sym_Range Symbols = *SymsOrErr; if (Index >= Symbols.size()) return createError("unable to get symbol from section " + - getSecIndexForError(*this, *Sec) + + getSecIndexForError(*this, *Sec) + ": invalid symbol index (" + Twine(Index) + ")"); return &Symbols[Index]; } @@ -487,27 +487,27 @@ ELFFile<ELFT>::getSymbol(const Elf_Shdr *Sec, uint32_t Index) const { template <class ELFT> template <typename T> Expected<ArrayRef<T>> -ELFFile<ELFT>::getSectionContentsAsArray(const Elf_Shdr &Sec) const { - if (Sec.sh_entsize != sizeof(T) && sizeof(T) != 1) - return createError("section " + getSecIndexForError(*this, Sec) + - " has invalid sh_entsize: expected " + Twine(sizeof(T)) + - ", but got " + Twine(Sec.sh_entsize)); +ELFFile<ELFT>::getSectionContentsAsArray(const Elf_Shdr &Sec) const { + if (Sec.sh_entsize != sizeof(T) && sizeof(T) != 1) + return createError("section " + getSecIndexForError(*this, Sec) + + " has invalid sh_entsize: expected " + Twine(sizeof(T)) + + ", but got " + Twine(Sec.sh_entsize)); - uintX_t Offset = Sec.sh_offset; - uintX_t Size = Sec.sh_size; + uintX_t Offset = Sec.sh_offset; + uintX_t Size = Sec.sh_size; if (Size % sizeof(T)) - return createError("section " + getSecIndexForError(*this, Sec) + + return createError("section " + getSecIndexForError(*this, Sec) + " has an invalid sh_size (" + Twine(Size) + ") which is not a multiple of its sh_entsize (" + - Twine(Sec.sh_entsize) + ")"); + Twine(Sec.sh_entsize) + ")"); if (std::numeric_limits<uintX_t>::max() - Offset < Size) - return createError("section " + getSecIndexForError(*this, Sec) + + return createError("section " + getSecIndexForError(*this, Sec) + " has a sh_offset (0x" + Twine::utohexstr(Offset) + ") + sh_size (0x" + Twine::utohexstr(Size) + ") that cannot be represented"); if (Offset + Size > Buf.size()) - return createError("section " + getSecIndexForError(*this, Sec) + + return createError("section " + getSecIndexForError(*this, Sec) + " has a sh_offset (0x" + Twine::utohexstr(Offset) + ") + sh_size (0x" + Twine::utohexstr(Size) + ") that is greater than the file size (0x" + @@ -523,17 +523,17 @@ ELFFile<ELFT>::getSectionContentsAsArray(const Elf_Shdr &Sec) const { template <class ELFT> Expected<ArrayRef<uint8_t>> -ELFFile<ELFT>::getSegmentContents(const Elf_Phdr &Phdr) const { - uintX_t Offset = Phdr.p_offset; - uintX_t Size = Phdr.p_filesz; +ELFFile<ELFT>::getSegmentContents(const Elf_Phdr &Phdr) const { + uintX_t Offset = Phdr.p_offset; + uintX_t Size = Phdr.p_filesz; if (std::numeric_limits<uintX_t>::max() - Offset < Size) - return createError("program header " + getPhdrIndexForError(*this, Phdr) + + return createError("program header " + getPhdrIndexForError(*this, Phdr) + " has a p_offset (0x" + Twine::utohexstr(Offset) + ") + p_filesz (0x" + Twine::utohexstr(Size) + ") that cannot be represented"); if (Offset + Size > Buf.size()) - return createError("program header " + getPhdrIndexForError(*this, Phdr) + + return createError("program header " + getPhdrIndexForError(*this, Phdr) + " has a p_offset (0x" + Twine::utohexstr(Offset) + ") + p_filesz (0x" + Twine::utohexstr(Size) + ") that is greater than the file size (0x" + @@ -543,13 +543,13 @@ ELFFile<ELFT>::getSegmentContents(const Elf_Phdr &Phdr) const { template <class ELFT> Expected<ArrayRef<uint8_t>> -ELFFile<ELFT>::getSectionContents(const Elf_Shdr &Sec) const { +ELFFile<ELFT>::getSectionContents(const Elf_Shdr &Sec) const { return getSectionContentsAsArray<uint8_t>(Sec); } template <class ELFT> StringRef ELFFile<ELFT>::getRelocationTypeName(uint32_t Type) const { - return getELFRelocationTypeName(getHeader().e_machine, Type); + return getELFRelocationTypeName(getHeader().e_machine, Type); } template <class ELFT> @@ -585,61 +585,61 @@ void ELFFile<ELFT>::getRelocationTypeName(uint32_t Type, template <class ELFT> uint32_t ELFFile<ELFT>::getRelativeRelocationType() const { - return getELFRelativeRelocationType(getHeader().e_machine); -} - -template <class ELFT> -Expected<SmallVector<Optional<VersionEntry>, 0>> -ELFFile<ELFT>::loadVersionMap(const Elf_Shdr *VerNeedSec, - const Elf_Shdr *VerDefSec) const { - SmallVector<Optional<VersionEntry>, 0> VersionMap; - - // The first two version indexes are reserved. - // Index 0 is VER_NDX_LOCAL, index 1 is VER_NDX_GLOBAL. - VersionMap.push_back(VersionEntry()); - VersionMap.push_back(VersionEntry()); - - auto InsertEntry = [&](unsigned N, StringRef Version, bool IsVerdef) { - if (N >= VersionMap.size()) - VersionMap.resize(N + 1); - VersionMap[N] = {std::string(Version), IsVerdef}; - }; - - if (VerDefSec) { - Expected<std::vector<VerDef>> Defs = getVersionDefinitions(*VerDefSec); - if (!Defs) - return Defs.takeError(); - for (const VerDef &Def : *Defs) - InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true); - } - - if (VerNeedSec) { - Expected<std::vector<VerNeed>> Deps = getVersionDependencies(*VerNeedSec); - if (!Deps) - return Deps.takeError(); - for (const VerNeed &Dep : *Deps) - for (const VernAux &Aux : Dep.AuxV) - InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false); - } - - return VersionMap; + return getELFRelativeRelocationType(getHeader().e_machine); } template <class ELFT> +Expected<SmallVector<Optional<VersionEntry>, 0>> +ELFFile<ELFT>::loadVersionMap(const Elf_Shdr *VerNeedSec, + const Elf_Shdr *VerDefSec) const { + SmallVector<Optional<VersionEntry>, 0> VersionMap; + + // The first two version indexes are reserved. + // Index 0 is VER_NDX_LOCAL, index 1 is VER_NDX_GLOBAL. + VersionMap.push_back(VersionEntry()); + VersionMap.push_back(VersionEntry()); + + auto InsertEntry = [&](unsigned N, StringRef Version, bool IsVerdef) { + if (N >= VersionMap.size()) + VersionMap.resize(N + 1); + VersionMap[N] = {std::string(Version), IsVerdef}; + }; + + if (VerDefSec) { + Expected<std::vector<VerDef>> Defs = getVersionDefinitions(*VerDefSec); + if (!Defs) + return Defs.takeError(); + for (const VerDef &Def : *Defs) + InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true); + } + + if (VerNeedSec) { + Expected<std::vector<VerNeed>> Deps = getVersionDependencies(*VerNeedSec); + if (!Deps) + return Deps.takeError(); + for (const VerNeed &Dep : *Deps) + for (const VernAux &Aux : Dep.AuxV) + InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false); + } + + return VersionMap; +} + +template <class ELFT> Expected<const typename ELFT::Sym *> -ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel &Rel, +ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel &Rel, const Elf_Shdr *SymTab) const { - uint32_t Index = Rel.getSymbol(isMips64EL()); + uint32_t Index = Rel.getSymbol(isMips64EL()); if (Index == 0) return nullptr; - return getEntry<Elf_Sym>(*SymTab, Index); + return getEntry<Elf_Sym>(*SymTab, Index); } template <class ELFT> Expected<StringRef> ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections, WarningHandler WarnHandler) const { - uint32_t Index = getHeader().e_shstrndx; + uint32_t Index = getHeader().e_shstrndx; if (Index == ELF::SHN_XINDEX) { // If the section name string table section index is greater than // or equal to SHN_LORESERVE, then the actual index of the section name @@ -657,102 +657,102 @@ ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections, if (Index >= Sections.size()) return createError("section header string table index " + Twine(Index) + " does not exist"); - return getStringTable(Sections[Index], WarnHandler); -} - -/// This function finds the number of dynamic symbols using a GNU hash table. -/// -/// @param Table The GNU hash table for .dynsym. -template <class ELFT> -static Expected<uint64_t> -getDynSymtabSizeFromGnuHash(const typename ELFT::GnuHash &Table, - const void *BufEnd) { - using Elf_Word = typename ELFT::Word; - if (Table.nbuckets == 0) - return Table.symndx + 1; - uint64_t LastSymIdx = 0; - // Find the index of the first symbol in the last chain. - for (Elf_Word Val : Table.buckets()) - LastSymIdx = std::max(LastSymIdx, (uint64_t)Val); - const Elf_Word *It = - reinterpret_cast<const Elf_Word *>(Table.values(LastSymIdx).end()); - // Locate the end of the chain to find the last symbol index. - while (It < BufEnd && (*It & 1) == 0) { - ++LastSymIdx; - ++It; - } - if (It >= BufEnd) { - return createStringError( - object_error::parse_failed, - "no terminator found for GNU hash section before buffer end"); - } - return LastSymIdx + 1; -} - -/// This function determines the number of dynamic symbols. It reads section -/// headers first. If section headers are not available, the number of -/// symbols will be inferred by parsing dynamic hash tables. -template <class ELFT> -Expected<uint64_t> ELFFile<ELFT>::getDynSymtabSize() const { - // Read .dynsym section header first if available. - Expected<Elf_Shdr_Range> SectionsOrError = sections(); - if (!SectionsOrError) - return SectionsOrError.takeError(); - for (const Elf_Shdr &Sec : *SectionsOrError) { - if (Sec.sh_type == ELF::SHT_DYNSYM) { - if (Sec.sh_size % Sec.sh_entsize != 0) { - return createStringError(object_error::parse_failed, - "SHT_DYNSYM section has sh_size (" + - Twine(Sec.sh_size) + ") % sh_entsize (" + - Twine(Sec.sh_entsize) + ") that is not 0"); - } - return Sec.sh_size / Sec.sh_entsize; - } - } - - if (!SectionsOrError->empty()) { - // Section headers are available but .dynsym header is not found. - // Return 0 as .dynsym does not exist. - return 0; - } - - // Section headers do not exist. Falling back to infer - // upper bound of .dynsym from .gnu.hash and .hash. - Expected<Elf_Dyn_Range> DynTable = dynamicEntries(); - if (!DynTable) - return DynTable.takeError(); - llvm::Optional<uint64_t> ElfHash; - llvm::Optional<uint64_t> ElfGnuHash; - for (const Elf_Dyn &Entry : *DynTable) { - switch (Entry.d_tag) { - case ELF::DT_HASH: - ElfHash = Entry.d_un.d_ptr; - break; - case ELF::DT_GNU_HASH: - ElfGnuHash = Entry.d_un.d_ptr; - break; - } - } - if (ElfGnuHash) { - Expected<const uint8_t *> TablePtr = toMappedAddr(*ElfGnuHash); - if (!TablePtr) - return TablePtr.takeError(); - const Elf_GnuHash *Table = - reinterpret_cast<const Elf_GnuHash *>(TablePtr.get()); - return getDynSymtabSizeFromGnuHash<ELFT>(*Table, this->Buf.bytes_end()); - } - - // Search SYSV hash table to try to find the upper bound of dynsym. - if (ElfHash) { - Expected<const uint8_t *> TablePtr = toMappedAddr(*ElfHash); - if (!TablePtr) - return TablePtr.takeError(); - const Elf_Hash *Table = reinterpret_cast<const Elf_Hash *>(TablePtr.get()); - return Table->nchain; - } - return 0; + return getStringTable(Sections[Index], WarnHandler); } +/// This function finds the number of dynamic symbols using a GNU hash table. +/// +/// @param Table The GNU hash table for .dynsym. +template <class ELFT> +static Expected<uint64_t> +getDynSymtabSizeFromGnuHash(const typename ELFT::GnuHash &Table, + const void *BufEnd) { + using Elf_Word = typename ELFT::Word; + if (Table.nbuckets == 0) + return Table.symndx + 1; + uint64_t LastSymIdx = 0; + // Find the index of the first symbol in the last chain. + for (Elf_Word Val : Table.buckets()) + LastSymIdx = std::max(LastSymIdx, (uint64_t)Val); + const Elf_Word *It = + reinterpret_cast<const Elf_Word *>(Table.values(LastSymIdx).end()); + // Locate the end of the chain to find the last symbol index. + while (It < BufEnd && (*It & 1) == 0) { + ++LastSymIdx; + ++It; + } + if (It >= BufEnd) { + return createStringError( + object_error::parse_failed, + "no terminator found for GNU hash section before buffer end"); + } + return LastSymIdx + 1; +} + +/// This function determines the number of dynamic symbols. It reads section +/// headers first. If section headers are not available, the number of +/// symbols will be inferred by parsing dynamic hash tables. +template <class ELFT> +Expected<uint64_t> ELFFile<ELFT>::getDynSymtabSize() const { + // Read .dynsym section header first if available. + Expected<Elf_Shdr_Range> SectionsOrError = sections(); + if (!SectionsOrError) + return SectionsOrError.takeError(); + for (const Elf_Shdr &Sec : *SectionsOrError) { + if (Sec.sh_type == ELF::SHT_DYNSYM) { + if (Sec.sh_size % Sec.sh_entsize != 0) { + return createStringError(object_error::parse_failed, + "SHT_DYNSYM section has sh_size (" + + Twine(Sec.sh_size) + ") % sh_entsize (" + + Twine(Sec.sh_entsize) + ") that is not 0"); + } + return Sec.sh_size / Sec.sh_entsize; + } + } + + if (!SectionsOrError->empty()) { + // Section headers are available but .dynsym header is not found. + // Return 0 as .dynsym does not exist. + return 0; + } + + // Section headers do not exist. Falling back to infer + // upper bound of .dynsym from .gnu.hash and .hash. + Expected<Elf_Dyn_Range> DynTable = dynamicEntries(); + if (!DynTable) + return DynTable.takeError(); + llvm::Optional<uint64_t> ElfHash; + llvm::Optional<uint64_t> ElfGnuHash; + for (const Elf_Dyn &Entry : *DynTable) { + switch (Entry.d_tag) { + case ELF::DT_HASH: + ElfHash = Entry.d_un.d_ptr; + break; + case ELF::DT_GNU_HASH: + ElfGnuHash = Entry.d_un.d_ptr; + break; + } + } + if (ElfGnuHash) { + Expected<const uint8_t *> TablePtr = toMappedAddr(*ElfGnuHash); + if (!TablePtr) + return TablePtr.takeError(); + const Elf_GnuHash *Table = + reinterpret_cast<const Elf_GnuHash *>(TablePtr.get()); + return getDynSymtabSizeFromGnuHash<ELFT>(*Table, this->Buf.bytes_end()); + } + + // Search SYSV hash table to try to find the upper bound of dynsym. + if (ElfHash) { + Expected<const uint8_t *> TablePtr = toMappedAddr(*ElfHash); + if (!TablePtr) + return TablePtr.takeError(); + const Elf_Hash *Table = reinterpret_cast<const Elf_Hash *>(TablePtr.get()); + return Table->nchain; + } + return 0; +} + template <class ELFT> ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {} template <class ELFT> @@ -766,13 +766,13 @@ Expected<ELFFile<ELFT>> ELFFile<ELFT>::create(StringRef Object) { template <class ELFT> Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const { - const uintX_t SectionTableOffset = getHeader().e_shoff; + const uintX_t SectionTableOffset = getHeader().e_shoff; if (SectionTableOffset == 0) return ArrayRef<Elf_Shdr>(); - if (getHeader().e_shentsize != sizeof(Elf_Shdr)) + if (getHeader().e_shentsize != sizeof(Elf_Shdr)) return createError("invalid e_shentsize in ELF header: " + - Twine(getHeader().e_shentsize)); + Twine(getHeader().e_shentsize)); const uint64_t FileSize = Buf.size(); if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize || @@ -789,7 +789,7 @@ Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const { const Elf_Shdr *First = reinterpret_cast<const Elf_Shdr *>(base() + SectionTableOffset); - uintX_t NumSections = getHeader().e_shnum; + uintX_t NumSections = getHeader().e_shnum; if (NumSections == 0) NumSections = First->sh_size; @@ -820,231 +820,231 @@ Expected<const T *> ELFFile<ELFT>::getEntry(uint32_t Section, auto SecOrErr = getSection(Section); if (!SecOrErr) return SecOrErr.takeError(); - return getEntry<T>(**SecOrErr, Entry); + return getEntry<T>(**SecOrErr, Entry); } template <class ELFT> template <typename T> -Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr &Section, +Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr &Section, uint32_t Entry) const { - Expected<ArrayRef<T>> EntriesOrErr = getSectionContentsAsArray<T>(Section); - if (!EntriesOrErr) - return EntriesOrErr.takeError(); - - ArrayRef<T> Arr = *EntriesOrErr; - if (Entry >= Arr.size()) - return createError( - "can't read an entry at 0x" + - Twine::utohexstr(Entry * static_cast<uint64_t>(sizeof(T))) + - ": it goes past the end of the section (0x" + - Twine::utohexstr(Section.sh_size) + ")"); - return &Arr[Entry]; -} - -template <typename ELFT> -Expected<StringRef> ELFFile<ELFT>::getSymbolVersionByIndex( - uint32_t SymbolVersionIndex, bool &IsDefault, - SmallVector<Optional<VersionEntry>, 0> &VersionMap, - Optional<bool> IsSymHidden) const { - size_t VersionIndex = SymbolVersionIndex & llvm::ELF::VERSYM_VERSION; - - // Special markers for unversioned symbols. - if (VersionIndex == llvm::ELF::VER_NDX_LOCAL || - VersionIndex == llvm::ELF::VER_NDX_GLOBAL) { - IsDefault = false; - return ""; - } - - // Lookup this symbol in the version table. - if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex]) - return createError("SHT_GNU_versym section refers to a version index " + - Twine(VersionIndex) + " which is missing"); - - const VersionEntry &Entry = *VersionMap[VersionIndex]; - // A default version (@@) is only available for defined symbols. - if (!Entry.IsVerDef || IsSymHidden.getValueOr(false)) - IsDefault = false; - else - IsDefault = !(SymbolVersionIndex & llvm::ELF::VERSYM_HIDDEN); - return Entry.Name.c_str(); -} - -template <class ELFT> -Expected<std::vector<VerDef>> -ELFFile<ELFT>::getVersionDefinitions(const Elf_Shdr &Sec) const { - Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec); - if (!StrTabOrErr) - return StrTabOrErr.takeError(); - - Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); - if (!ContentsOrErr) - return createError("cannot read content of " + describe(*this, Sec) + ": " + - toString(ContentsOrErr.takeError())); - - const uint8_t *Start = ContentsOrErr->data(); - const uint8_t *End = Start + ContentsOrErr->size(); - - auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf, - unsigned VerDefNdx) -> Expected<VerdAux> { - if (VerdauxBuf + sizeof(Elf_Verdaux) > End) - return createError("invalid " + describe(*this, Sec) + - ": version definition " + Twine(VerDefNdx) + - " refers to an auxiliary entry that goes past the end " - "of the section"); - - auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); - VerdauxBuf += Verdaux->vda_next; - - VerdAux Aux; - Aux.Offset = VerdauxBuf - Start; - if (Verdaux->vda_name <= StrTabOrErr->size()) - Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name)); - else - Aux.Name = ("<invalid vda_name: " + Twine(Verdaux->vda_name) + ">").str(); - return Aux; - }; - - std::vector<VerDef> Ret; - const uint8_t *VerdefBuf = Start; - for (unsigned I = 1; I <= /*VerDefsNum=*/Sec.sh_info; ++I) { - if (VerdefBuf + sizeof(Elf_Verdef) > End) - return createError("invalid " + describe(*this, Sec) + - ": version definition " + Twine(I) + - " goes past the end of the section"); - - if (reinterpret_cast<uintptr_t>(VerdefBuf) % sizeof(uint32_t) != 0) - return createError( - "invalid " + describe(*this, Sec) + - ": found a misaligned version definition entry at offset 0x" + - Twine::utohexstr(VerdefBuf - Start)); - - unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf); - if (Version != 1) - return createError("unable to dump " + describe(*this, Sec) + - ": version " + Twine(Version) + - " is not yet supported"); - - const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); - VerDef &VD = *Ret.emplace(Ret.end()); - VD.Offset = VerdefBuf - Start; - VD.Version = D->vd_version; - VD.Flags = D->vd_flags; - VD.Ndx = D->vd_ndx; - VD.Cnt = D->vd_cnt; - VD.Hash = D->vd_hash; - - const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux; - for (unsigned J = 0; J < D->vd_cnt; ++J) { - if (reinterpret_cast<uintptr_t>(VerdauxBuf) % sizeof(uint32_t) != 0) - return createError("invalid " + describe(*this, Sec) + - ": found a misaligned auxiliary entry at offset 0x" + - Twine::utohexstr(VerdauxBuf - Start)); - - Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I); - if (!AuxOrErr) - return AuxOrErr.takeError(); - - if (J == 0) - VD.Name = AuxOrErr->Name; - else - VD.AuxV.push_back(*AuxOrErr); - } - - VerdefBuf += D->vd_next; - } - - return Ret; -} - -template <class ELFT> -Expected<std::vector<VerNeed>> -ELFFile<ELFT>::getVersionDependencies(const Elf_Shdr &Sec, - WarningHandler WarnHandler) const { - StringRef StrTab; - Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec); - if (!StrTabOrErr) { - if (Error E = WarnHandler(toString(StrTabOrErr.takeError()))) - return std::move(E); - } else { - StrTab = *StrTabOrErr; - } - - Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); - if (!ContentsOrErr) - return createError("cannot read content of " + describe(*this, Sec) + ": " + - toString(ContentsOrErr.takeError())); - - const uint8_t *Start = ContentsOrErr->data(); - const uint8_t *End = Start + ContentsOrErr->size(); - const uint8_t *VerneedBuf = Start; - - std::vector<VerNeed> Ret; - for (unsigned I = 1; I <= /*VerneedNum=*/Sec.sh_info; ++I) { - if (VerneedBuf + sizeof(Elf_Verdef) > End) - return createError("invalid " + describe(*this, Sec) + - ": version dependency " + Twine(I) + - " goes past the end of the section"); - - if (reinterpret_cast<uintptr_t>(VerneedBuf) % sizeof(uint32_t) != 0) - return createError( - "invalid " + describe(*this, Sec) + - ": found a misaligned version dependency entry at offset 0x" + - Twine::utohexstr(VerneedBuf - Start)); - - unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf); - if (Version != 1) - return createError("unable to dump " + describe(*this, Sec) + - ": version " + Twine(Version) + - " is not yet supported"); - - const Elf_Verneed *Verneed = - reinterpret_cast<const Elf_Verneed *>(VerneedBuf); - - VerNeed &VN = *Ret.emplace(Ret.end()); - VN.Version = Verneed->vn_version; - VN.Cnt = Verneed->vn_cnt; - VN.Offset = VerneedBuf - Start; - - if (Verneed->vn_file < StrTab.size()) - VN.File = std::string(StrTab.drop_front(Verneed->vn_file)); - else - VN.File = ("<corrupt vn_file: " + Twine(Verneed->vn_file) + ">").str(); - - const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; - for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { - if (reinterpret_cast<uintptr_t>(VernauxBuf) % sizeof(uint32_t) != 0) - return createError("invalid " + describe(*this, Sec) + - ": found a misaligned auxiliary entry at offset 0x" + - Twine::utohexstr(VernauxBuf - Start)); - - if (VernauxBuf + sizeof(Elf_Vernaux) > End) - return createError( - "invalid " + describe(*this, Sec) + ": version dependency " + - Twine(I) + - " refers to an auxiliary entry that goes past the end " - "of the section"); - - const Elf_Vernaux *Vernaux = - reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); - - VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end()); - Aux.Hash = Vernaux->vna_hash; - Aux.Flags = Vernaux->vna_flags; - Aux.Other = Vernaux->vna_other; - Aux.Offset = VernauxBuf - Start; - if (StrTab.size() <= Vernaux->vna_name) - Aux.Name = "<corrupt>"; - else - Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name)); - - VernauxBuf += Vernaux->vna_next; - } - VerneedBuf += Verneed->vn_next; - } - return Ret; + Expected<ArrayRef<T>> EntriesOrErr = getSectionContentsAsArray<T>(Section); + if (!EntriesOrErr) + return EntriesOrErr.takeError(); + + ArrayRef<T> Arr = *EntriesOrErr; + if (Entry >= Arr.size()) + return createError( + "can't read an entry at 0x" + + Twine::utohexstr(Entry * static_cast<uint64_t>(sizeof(T))) + + ": it goes past the end of the section (0x" + + Twine::utohexstr(Section.sh_size) + ")"); + return &Arr[Entry]; } +template <typename ELFT> +Expected<StringRef> ELFFile<ELFT>::getSymbolVersionByIndex( + uint32_t SymbolVersionIndex, bool &IsDefault, + SmallVector<Optional<VersionEntry>, 0> &VersionMap, + Optional<bool> IsSymHidden) const { + size_t VersionIndex = SymbolVersionIndex & llvm::ELF::VERSYM_VERSION; + + // Special markers for unversioned symbols. + if (VersionIndex == llvm::ELF::VER_NDX_LOCAL || + VersionIndex == llvm::ELF::VER_NDX_GLOBAL) { + IsDefault = false; + return ""; + } + + // Lookup this symbol in the version table. + if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex]) + return createError("SHT_GNU_versym section refers to a version index " + + Twine(VersionIndex) + " which is missing"); + + const VersionEntry &Entry = *VersionMap[VersionIndex]; + // A default version (@@) is only available for defined symbols. + if (!Entry.IsVerDef || IsSymHidden.getValueOr(false)) + IsDefault = false; + else + IsDefault = !(SymbolVersionIndex & llvm::ELF::VERSYM_HIDDEN); + return Entry.Name.c_str(); +} + template <class ELFT> +Expected<std::vector<VerDef>> +ELFFile<ELFT>::getVersionDefinitions(const Elf_Shdr &Sec) const { + Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + + Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return createError("cannot read content of " + describe(*this, Sec) + ": " + + toString(ContentsOrErr.takeError())); + + const uint8_t *Start = ContentsOrErr->data(); + const uint8_t *End = Start + ContentsOrErr->size(); + + auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf, + unsigned VerDefNdx) -> Expected<VerdAux> { + if (VerdauxBuf + sizeof(Elf_Verdaux) > End) + return createError("invalid " + describe(*this, Sec) + + ": version definition " + Twine(VerDefNdx) + + " refers to an auxiliary entry that goes past the end " + "of the section"); + + auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); + VerdauxBuf += Verdaux->vda_next; + + VerdAux Aux; + Aux.Offset = VerdauxBuf - Start; + if (Verdaux->vda_name <= StrTabOrErr->size()) + Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name)); + else + Aux.Name = ("<invalid vda_name: " + Twine(Verdaux->vda_name) + ">").str(); + return Aux; + }; + + std::vector<VerDef> Ret; + const uint8_t *VerdefBuf = Start; + for (unsigned I = 1; I <= /*VerDefsNum=*/Sec.sh_info; ++I) { + if (VerdefBuf + sizeof(Elf_Verdef) > End) + return createError("invalid " + describe(*this, Sec) + + ": version definition " + Twine(I) + + " goes past the end of the section"); + + if (reinterpret_cast<uintptr_t>(VerdefBuf) % sizeof(uint32_t) != 0) + return createError( + "invalid " + describe(*this, Sec) + + ": found a misaligned version definition entry at offset 0x" + + Twine::utohexstr(VerdefBuf - Start)); + + unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf); + if (Version != 1) + return createError("unable to dump " + describe(*this, Sec) + + ": version " + Twine(Version) + + " is not yet supported"); + + const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); + VerDef &VD = *Ret.emplace(Ret.end()); + VD.Offset = VerdefBuf - Start; + VD.Version = D->vd_version; + VD.Flags = D->vd_flags; + VD.Ndx = D->vd_ndx; + VD.Cnt = D->vd_cnt; + VD.Hash = D->vd_hash; + + const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux; + for (unsigned J = 0; J < D->vd_cnt; ++J) { + if (reinterpret_cast<uintptr_t>(VerdauxBuf) % sizeof(uint32_t) != 0) + return createError("invalid " + describe(*this, Sec) + + ": found a misaligned auxiliary entry at offset 0x" + + Twine::utohexstr(VerdauxBuf - Start)); + + Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I); + if (!AuxOrErr) + return AuxOrErr.takeError(); + + if (J == 0) + VD.Name = AuxOrErr->Name; + else + VD.AuxV.push_back(*AuxOrErr); + } + + VerdefBuf += D->vd_next; + } + + return Ret; +} + +template <class ELFT> +Expected<std::vector<VerNeed>> +ELFFile<ELFT>::getVersionDependencies(const Elf_Shdr &Sec, + WarningHandler WarnHandler) const { + StringRef StrTab; + Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec); + if (!StrTabOrErr) { + if (Error E = WarnHandler(toString(StrTabOrErr.takeError()))) + return std::move(E); + } else { + StrTab = *StrTabOrErr; + } + + Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return createError("cannot read content of " + describe(*this, Sec) + ": " + + toString(ContentsOrErr.takeError())); + + const uint8_t *Start = ContentsOrErr->data(); + const uint8_t *End = Start + ContentsOrErr->size(); + const uint8_t *VerneedBuf = Start; + + std::vector<VerNeed> Ret; + for (unsigned I = 1; I <= /*VerneedNum=*/Sec.sh_info; ++I) { + if (VerneedBuf + sizeof(Elf_Verdef) > End) + return createError("invalid " + describe(*this, Sec) + + ": version dependency " + Twine(I) + + " goes past the end of the section"); + + if (reinterpret_cast<uintptr_t>(VerneedBuf) % sizeof(uint32_t) != 0) + return createError( + "invalid " + describe(*this, Sec) + + ": found a misaligned version dependency entry at offset 0x" + + Twine::utohexstr(VerneedBuf - Start)); + + unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf); + if (Version != 1) + return createError("unable to dump " + describe(*this, Sec) + + ": version " + Twine(Version) + + " is not yet supported"); + + const Elf_Verneed *Verneed = + reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + + VerNeed &VN = *Ret.emplace(Ret.end()); + VN.Version = Verneed->vn_version; + VN.Cnt = Verneed->vn_cnt; + VN.Offset = VerneedBuf - Start; + + if (Verneed->vn_file < StrTab.size()) + VN.File = std::string(StrTab.drop_front(Verneed->vn_file)); + else + VN.File = ("<corrupt vn_file: " + Twine(Verneed->vn_file) + ">").str(); + + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { + if (reinterpret_cast<uintptr_t>(VernauxBuf) % sizeof(uint32_t) != 0) + return createError("invalid " + describe(*this, Sec) + + ": found a misaligned auxiliary entry at offset 0x" + + Twine::utohexstr(VernauxBuf - Start)); + + if (VernauxBuf + sizeof(Elf_Vernaux) > End) + return createError( + "invalid " + describe(*this, Sec) + ": version dependency " + + Twine(I) + + " refers to an auxiliary entry that goes past the end " + "of the section"); + + const Elf_Vernaux *Vernaux = + reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + + VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end()); + Aux.Hash = Vernaux->vna_hash; + Aux.Flags = Vernaux->vna_flags; + Aux.Other = Vernaux->vna_other; + Aux.Offset = VernauxBuf - Start; + if (StrTab.size() <= Vernaux->vna_name) + Aux.Name = "<corrupt>"; + else + Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name)); + + VernauxBuf += Vernaux->vna_next; + } + VerneedBuf += Verneed->vn_next; + } + return Ret; +} + +template <class ELFT> Expected<const typename ELFT::Shdr *> ELFFile<ELFT>::getSection(uint32_t Index) const { auto TableOrErr = sections(); @@ -1055,14 +1055,14 @@ ELFFile<ELFT>::getSection(uint32_t Index) const { template <class ELFT> Expected<StringRef> -ELFFile<ELFT>::getStringTable(const Elf_Shdr &Section, +ELFFile<ELFT>::getStringTable(const Elf_Shdr &Section, WarningHandler WarnHandler) const { - if (Section.sh_type != ELF::SHT_STRTAB) + if (Section.sh_type != ELF::SHT_STRTAB) if (Error E = WarnHandler("invalid sh_type for string table section " + - getSecIndexForError(*this, Section) + + getSecIndexForError(*this, Section) + ": expected SHT_STRTAB, but got " + object::getELFSectionTypeName( - getHeader().e_machine, Section.sh_type))) + getHeader().e_machine, Section.sh_type))) return std::move(E); auto V = getSectionContentsAsArray<char>(Section); @@ -1071,10 +1071,10 @@ ELFFile<ELFT>::getStringTable(const Elf_Shdr &Section, ArrayRef<char> Data = *V; if (Data.empty()) return createError("SHT_STRTAB string table section " + - getSecIndexForError(*this, Section) + " is empty"); + getSecIndexForError(*this, Section) + " is empty"); if (Data.back() != '\0') return createError("SHT_STRTAB string table section " + - getSecIndexForError(*this, Section) + + getSecIndexForError(*this, Section) + " is non-null terminated"); return StringRef(Data.begin(), Data.size()); } @@ -1093,7 +1093,7 @@ Expected<ArrayRef<typename ELFT::Word>> ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section, Elf_Shdr_Range Sections) const { assert(Section.sh_type == ELF::SHT_SYMTAB_SHNDX); - auto VOrErr = getSectionContentsAsArray<Elf_Word>(Section); + auto VOrErr = getSectionContentsAsArray<Elf_Word>(Section); if (!VOrErr) return VOrErr.takeError(); ArrayRef<Elf_Word> V = *VOrErr; @@ -1103,10 +1103,10 @@ ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section, const Elf_Shdr &SymTable = **SymTableOrErr; if (SymTable.sh_type != ELF::SHT_SYMTAB && SymTable.sh_type != ELF::SHT_DYNSYM) - return createError( - "SHT_SYMTAB_SHNDX section is linked with " + - object::getELFSectionTypeName(getHeader().e_machine, SymTable.sh_type) + - " section (expected SHT_SYMTAB/SHT_DYNSYM)"); + return createError( + "SHT_SYMTAB_SHNDX section is linked with " + + object::getELFSectionTypeName(getHeader().e_machine, SymTable.sh_type) + + " section (expected SHT_SYMTAB/SHT_DYNSYM)"); uint64_t Syms = SymTable.sh_size / sizeof(Elf_Sym); if (V.size() != Syms) @@ -1134,33 +1134,33 @@ ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec, if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM) return createError( "invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM"); - Expected<const Elf_Shdr *> SectionOrErr = - object::getSection<ELFT>(Sections, Sec.sh_link); + Expected<const Elf_Shdr *> SectionOrErr = + object::getSection<ELFT>(Sections, Sec.sh_link); if (!SectionOrErr) return SectionOrErr.takeError(); - return getStringTable(**SectionOrErr); -} - -template <class ELFT> -Expected<StringRef> -ELFFile<ELFT>::getLinkAsStrtab(const typename ELFT::Shdr &Sec) const { - Expected<const typename ELFT::Shdr *> StrTabSecOrErr = - getSection(Sec.sh_link); - if (!StrTabSecOrErr) - return createError("invalid section linked to " + describe(*this, Sec) + - ": " + toString(StrTabSecOrErr.takeError())); - - Expected<StringRef> StrTabOrErr = getStringTable(**StrTabSecOrErr); - if (!StrTabOrErr) - return createError("invalid string table linked to " + - describe(*this, Sec) + ": " + - toString(StrTabOrErr.takeError())); - return *StrTabOrErr; + return getStringTable(**SectionOrErr); } template <class ELFT> Expected<StringRef> -ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section, +ELFFile<ELFT>::getLinkAsStrtab(const typename ELFT::Shdr &Sec) const { + Expected<const typename ELFT::Shdr *> StrTabSecOrErr = + getSection(Sec.sh_link); + if (!StrTabSecOrErr) + return createError("invalid section linked to " + describe(*this, Sec) + + ": " + toString(StrTabSecOrErr.takeError())); + + Expected<StringRef> StrTabOrErr = getStringTable(**StrTabSecOrErr); + if (!StrTabOrErr) + return createError("invalid string table linked to " + + describe(*this, Sec) + ": " + + toString(StrTabOrErr.takeError())); + return *StrTabOrErr; +} + +template <class ELFT> +Expected<StringRef> +ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section, WarningHandler WarnHandler) const { auto SectionsOrErr = sections(); if (!SectionsOrErr) @@ -1172,13 +1172,13 @@ ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section, } template <class ELFT> -Expected<StringRef> ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section, +Expected<StringRef> ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section, StringRef DotShstrtab) const { - uint32_t Offset = Section.sh_name; + uint32_t Offset = Section.sh_name; if (Offset == 0) return StringRef(); if (Offset >= DotShstrtab.size()) - return createError("a section " + getSecIndexForError(*this, Section) + + return createError("a section " + getSecIndexForError(*this, Section) + " has an invalid sh_name (0x" + Twine::utohexstr(Offset) + ") offset which goes past the end of the " |