Update prebuilt Clang to r416183b from Android.
https://android.googlesource.com/platform/prebuilts/clang/host/
linux-x86/+/06a71ddac05c22edb2d10b590e1769b3f8619bef
clang 12.0.5 (based on r416183b) from build 7284624.
Change-Id: I277a316abcf47307562d8b748b84870f31a72866
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/linux-x64/clang/include/llvm/Object/ELF.h b/linux-x64/clang/include/llvm/Object/ELF.h
index cab2974..86359ff 100644
--- a/linux-x64/clang/include/llvm/Object/ELF.h
+++ b/linux-x64/clang/include/llvm/Object/ELF.h
@@ -48,14 +48,51 @@
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,
+};
+
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 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
@@ -65,37 +102,34 @@
}
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();
+ // See comment in the getSecIndexForError() above.
+ llvm::consumeError(Headers.takeError());
+ return "[unknown index]";
+}
+
+static inline Error defaultWarningHandler(const Twine &Msg) {
+ return createError(Msg);
+}
+
+template <class ELFT>
class ELFFile {
public:
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
- using uintX_t = typename ELFT::uint;
- using Elf_Ehdr = typename ELFT::Ehdr;
- using Elf_Shdr = typename ELFT::Shdr;
- using Elf_Sym = typename ELFT::Sym;
- using Elf_Dyn = typename ELFT::Dyn;
- using Elf_Phdr = typename ELFT::Phdr;
- using Elf_Rel = typename ELFT::Rel;
- using Elf_Rela = typename ELFT::Rela;
- using Elf_Relr = typename ELFT::Relr;
- using Elf_Verdef = typename ELFT::Verdef;
- using Elf_Verdaux = typename ELFT::Verdaux;
- using Elf_Verneed = typename ELFT::Verneed;
- using Elf_Vernaux = typename ELFT::Vernaux;
- using Elf_Versym = typename ELFT::Versym;
- using Elf_Hash = typename ELFT::Hash;
- using Elf_GnuHash = typename ELFT::GnuHash;
- using Elf_Nhdr = typename ELFT::Nhdr;
- using Elf_Note = typename ELFT::Note;
- using Elf_Note_Iterator = typename ELFT::NoteIterator;
- using Elf_Dyn_Range = typename ELFT::DynRange;
- using Elf_Shdr_Range = typename ELFT::ShdrRange;
- using Elf_Sym_Range = typename ELFT::SymRange;
- using Elf_Rel_Range = typename ELFT::RelRange;
- using Elf_Rela_Range = typename ELFT::RelaRange;
- using Elf_Relr_Range = typename ELFT::RelrRange;
- using Elf_Phdr_Range = typename ELFT::PhdrRange;
+
+ // This is a callback that can be passed to a number of functions.
+ // It can be used to ignore non-critical errors (warnings), which is
+ // useful for dumpers, like llvm-readobj.
+ // It accepts a warning message string and returns a success
+ // when the warning should be ignored or an error otherwise.
+ 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(); }
size_t getBufSize() const { return Buf.size(); }
@@ -105,16 +139,18 @@
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<StringRef> getStringTable(const Elf_Shdr *Section) 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;
@@ -132,65 +168,70 @@
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;
static Expected<ELFFile> create(StringRef Object);
- bool isMipsELF64() const {
- return getHeader()->e_machine == ELF::EM_MIPS &&
- getHeader()->getFileClass() == ELF::ELFCLASS64;
+ bool isLE() const {
+ return getHeader().getDataEncoding() == ELF::ELFDATA2LSB;
}
- bool isMips64EL() const {
- return isMipsELF64() &&
- getHeader()->getDataEncoding() == ELF::ELFDATA2LSB;
+ bool isMipsELF64() const {
+ return getHeader().e_machine == ELF::EM_MIPS &&
+ getHeader().getFileClass() == ELF::ELFCLASS64;
}
+ bool isMips64EL() const { return isMipsELF64() && isLE(); }
+
Expected<Elf_Shdr_Range> sections() const;
Expected<Elf_Dyn_Range> dynamicEntries() const;
- Expected<const uint8_t *> toMappedAddr(uint64_t VAddr) 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);
}
- Expected<std::vector<Elf_Rela>> 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));
- if (getHeader()->e_phoff +
- (getHeader()->e_phnum * getHeader()->e_phentsize) >
- getBufSize())
+ Twine(getHeader().e_phentsize));
+
+ uint64_t HeadersSize =
+ (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));
- auto *Begin =
- reinterpret_cast<const Elf_Phdr *>(base() + getHeader()->e_phoff);
- return makeArrayRef(Begin, Begin + getHeader()->e_phnum);
+ 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);
}
/// Get an iterator over notes in a program header.
@@ -201,14 +242,12 @@
/// \param Err [out] an error to support fallible iteration, which should
/// be checked after iteration ends.
Elf_Note_Iterator notes_begin(const Elf_Phdr &Phdr, Error &Err) const {
- if (Phdr.p_type != ELF::PT_NOTE) {
- // TODO: this error is untested.
- Err = createError("attempt to iterate notes of non-note program header");
- return Elf_Note_Iterator(Err);
- }
+ 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()) {
- // TODO: this error is untested.
- Err = createError("invalid program header offset/size");
+ 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);
@@ -222,14 +261,12 @@
/// \param Err [out] an error to support fallible iteration, which should
/// be checked after iteration ends.
Elf_Note_Iterator notes_begin(const Elf_Shdr &Shdr, Error &Err) const {
- if (Shdr.sh_type != ELF::SHT_NOTE) {
- // TODO: this error is untested.
- Err = createError("attempt to iterate notes of non-note section");
- return Elf_Note_Iterator(Err);
- }
+ 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()) {
- // TODO: this error is untested.
- Err = createError("invalid section offset/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);
@@ -264,27 +301,31 @@
return make_range(notes_begin(Shdr, Err), notes_end());
}
- Expected<StringRef> getSectionStringTable(Elf_Shdr_Range Sections) const;
- Expected<uint32_t> getSectionIndex(const Elf_Sym *Sym, Elf_Sym_Range Syms,
- ArrayRef<Elf_Word> ShndxTable) const;
- Expected<const Elf_Shdr *> getSection(const Elf_Sym *Sym,
+ 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,
const Elf_Shdr *SymTab,
- ArrayRef<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,
- ArrayRef<Elf_Word> ShndxTable) const;
+ DataRegion<Elf_Word> ShndxTable) const;
Expected<const Elf_Shdr *> getSection(uint32_t Index) const;
- Expected<const Elf_Shdr *> getSection(const StringRef SectionName) const;
Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec,
uint32_t Index) const;
- Expected<StringRef> getSectionName(const Elf_Shdr *Section) const;
- Expected<StringRef> getSectionName(const Elf_Shdr *Section,
+ Expected<StringRef>
+ getSectionName(const Elf_Shdr &Section,
+ WarningHandler WarnHandler = &defaultWarningHandler) const;
+ 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<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>;
@@ -302,29 +343,30 @@
template <class ELFT>
inline Expected<uint32_t>
-getExtendedSymbolTableIndex(const typename ELFT::Sym *Sym,
- const typename ELFT::Sym *FirstSym,
- ArrayRef<typename ELFT::Word> ShndxTable) {
- assert(Sym->st_shndx == ELF::SHN_XINDEX);
- unsigned Index = Sym - FirstSym;
- if (Index >= ShndxTable.size())
+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(
- "extended symbol index (" + Twine(Index) +
- ") is past the end of the SHT_SYMTAB_SHNDX section of size " +
- Twine(ShndxTable.size()));
+ "found an extended symbol index (" + Twine(SymIndex) +
+ "), but unable to locate the extended symbol index table");
- // The size of the table was checked in getSHNDXTable.
- return ShndxTable[Index];
+ 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,
- ArrayRef<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) {
- auto ErrorOrIndex = getExtendedSymbolTableIndex<ELFT>(
- Sym, Syms.begin(), ShndxTable);
+ Expected<uint32_t> ErrorOrIndex =
+ getExtendedSymbolTableIndex<ELFT>(Sym, &Sym - Syms.begin(), ShndxTable);
if (!ErrorOrIndex)
return ErrorOrIndex.takeError();
return *ErrorOrIndex;
@@ -336,8 +378,8 @@
template <class ELFT>
Expected<const typename ELFT::Shdr *>
-ELFFile<ELFT>::getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab,
- ArrayRef<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();
@@ -346,8 +388,8 @@
template <class ELFT>
Expected<const typename ELFT::Shdr *>
-ELFFile<ELFT>::getSection(const Elf_Sym *Sym, Elf_Sym_Range Symbols,
- ArrayRef<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();
@@ -358,45 +400,48 @@
}
template <class ELFT>
-inline Expected<const typename ELFT::Sym *>
-getSymbol(typename ELFT::SymRange Symbols, uint32_t Index) {
- if (Index >= Symbols.size())
- // TODO: this error is untested.
- return createError("invalid symbol index");
- return &Symbols[Index];
-}
-
-template <class ELFT>
Expected<const typename ELFT::Sym *>
ELFFile<ELFT>::getSymbol(const Elf_Shdr *Sec, uint32_t Index) const {
- auto SymtabOrErr = symbols(Sec);
- if (!SymtabOrErr)
- return SymtabOrErr.takeError();
- return object::getSymbol<ELFT>(*SymtabOrErr, Index);
+ auto SymsOrErr = symbols(Sec);
+ if (!SymsOrErr)
+ return SymsOrErr.takeError();
+
+ Elf_Sym_Range Symbols = *SymsOrErr;
+ if (Index >= Symbols.size())
+ return createError("unable to get symbol from section " +
+ getSecIndexForError(*this, *Sec) +
+ ": invalid symbol index (" + Twine(Index) + ")");
+ return &Symbols[Index];
}
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 an invalid sh_entsize: " + 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) + ")");
- if ((std::numeric_limits<uintX_t>::max() - Offset < Size) ||
- Offset + Size > Buf.size())
- return createError("section " + getSecIndexForError(this, Sec) +
+ Twine(Sec.sh_entsize) + ")");
+ if (std::numeric_limits<uintX_t>::max() - Offset < Size)
+ return createError("section " + getSecIndexForError(*this, Sec) +
" has a sh_offset (0x" + Twine::utohexstr(Offset) +
- ") + sh_size (0x" + Twine(Size) +
+ ") + sh_size (0x" + Twine::utohexstr(Size) +
") that cannot be represented");
+ if (Offset + Size > Buf.size())
+ 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" +
+ Twine::utohexstr(Buf.size()) + ")");
if (Offset % alignof(T))
// TODO: this error is untested.
@@ -408,13 +453,33 @@
template <class ELFT>
Expected<ArrayRef<uint8_t>>
-ELFFile<ELFT>::getSectionContents(const Elf_Shdr *Sec) const {
+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) +
+ " 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) +
+ " has a p_offset (0x" + Twine::utohexstr(Offset) +
+ ") + p_filesz (0x" + Twine::utohexstr(Size) +
+ ") that is greater than the file size (0x" +
+ Twine::utohexstr(Buf.size()) + ")");
+ return makeArrayRef(base() + Offset, Size);
+}
+
+template <class ELFT>
+Expected<ArrayRef<uint8_t>>
+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>
@@ -450,32 +515,42 @@
template <class ELFT>
uint32_t ELFFile<ELFT>::getRelativeRelocationType() const {
- return getELFRelativeRelocationType(getHeader()->e_machine);
+ return getELFRelativeRelocationType(getHeader().e_machine);
}
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) const {
- uint32_t Index = getHeader()->e_shstrndx;
- if (Index == ELF::SHN_XINDEX)
+ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections,
+ WarningHandler WarnHandler) const {
+ 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
+ // string table section is contained in the sh_link field of the section
+ // header at index 0.
+ if (Sections.empty())
+ return createError(
+ "e_shstrndx == SHN_XINDEX, but the section header table is empty");
+
Index = Sections[0].sh_link;
+ }
if (!Index) // no section string table.
return "";
if (Index >= Sections.size())
- // TODO: this error is untested.
- return createError("invalid section index");
- return getStringTable(&Sections[Index]);
+ return createError("section header string table index " + Twine(Index) +
+ " does not exist");
+ return getStringTable(Sections[Index], WarnHandler);
}
template <class ELFT> ELFFile<ELFT>::ELFFile(StringRef Object) : Buf(Object) {}
@@ -491,16 +566,17 @@
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)
+ if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize ||
+ SectionTableOffset + (uintX_t)sizeof(Elf_Shdr) < SectionTableOffset)
return createError(
"section header table goes past the end of the file: e_shoff = 0x" +
Twine::utohexstr(SectionTableOffset));
@@ -513,20 +589,27 @@
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;
if (NumSections > UINT64_MAX / sizeof(Elf_Shdr))
- // TODO: this error is untested.
- return createError("section table goes past the end of file");
+ return createError("invalid number of sections specified in the NULL "
+ "section's sh_size field (" +
+ Twine(NumSections) + ")");
const uint64_t SectionTableSize = NumSections * sizeof(Elf_Shdr);
+ if (SectionTableOffset + SectionTableSize < SectionTableOffset)
+ return createError(
+ "invalid section header table offset (e_shoff = 0x" +
+ Twine::utohexstr(SectionTableOffset) +
+ ") or invalid number of sections specified in the first section "
+ "header's sh_size field (0x" +
+ Twine::utohexstr(NumSections) + ")");
// Section table goes past end of file!
if (SectionTableOffset + SectionTableSize > FileSize)
return createError("section table goes past the end of file");
-
return makeArrayRef(First, NumSections);
}
@@ -537,23 +620,25 @@
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 {
- if (sizeof(T) != Section->sh_entsize)
- // TODO: this error is untested.
- return createError("invalid sh_entsize");
- size_t Pos = Section->sh_offset + Entry * sizeof(T);
- if (Pos + sizeof(T) > Buf.size())
- return createError("unable to access section " +
- getSecIndexForError(this, Section) + " data at 0x" +
- Twine::utohexstr(Pos) +
- ": offset goes past the end of file");
- return reinterpret_cast<const T *>(base() + Pos);
+ 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 <class ELFT>
@@ -566,43 +651,27 @@
}
template <class ELFT>
-Expected<const typename ELFT::Shdr *>
-ELFFile<ELFT>::getSection(const StringRef SectionName) const {
- auto TableOrErr = sections();
- if (!TableOrErr)
- return TableOrErr.takeError();
- for (auto &Sec : *TableOrErr) {
- auto SecNameOrErr = getSectionName(&Sec);
- if (!SecNameOrErr)
- return SecNameOrErr.takeError();
- if (*SecNameOrErr == SectionName)
- return &Sec;
- }
- // TODO: this error is untested.
- return createError("invalid section name");
-}
-
-template <class ELFT>
Expected<StringRef>
-ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section) const {
- if (Section->sh_type != ELF::SHT_STRTAB)
- return createError("invalid sh_type for string table section " +
- getSecIndexForError(this, Section) +
- ": expected SHT_STRTAB, but got " +
- object::getELFSectionTypeName(getHeader()->e_machine,
- Section->sh_type));
+ELFFile<ELFT>::getStringTable(const Elf_Shdr &Section,
+ WarningHandler WarnHandler) const {
+ if (Section.sh_type != ELF::SHT_STRTAB)
+ if (Error E = WarnHandler("invalid sh_type for string table section " +
+ getSecIndexForError(*this, Section) +
+ ": expected SHT_STRTAB, but got " +
+ object::getELFSectionTypeName(
+ getHeader().e_machine, Section.sh_type)))
+ return std::move(E);
+
auto V = getSectionContentsAsArray<char>(Section);
if (!V)
return V.takeError();
ArrayRef<char> Data = *V;
if (Data.empty())
- // TODO: this error is untested.
- return createError("empty string table");
+ return createError("SHT_STRTAB string table section " +
+ getSecIndexForError(*this, Section) + " is empty");
if (Data.back() != '\0')
- return createError(object::getELFSectionTypeName(getHeader()->e_machine,
- Section->sh_type) +
- " string table section " +
- getSecIndexForError(this, Section) +
+ return createError("SHT_STRTAB string table section " +
+ getSecIndexForError(*this, Section) +
" is non-null terminated");
return StringRef(Data.begin(), Data.size());
}
@@ -621,7 +690,7 @@
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;
@@ -631,13 +700,17 @@
const Elf_Shdr &SymTable = **SymTableOrErr;
if (SymTable.sh_type != ELF::SHT_SYMTAB &&
SymTable.sh_type != ELF::SHT_DYNSYM)
- // TODO: this error is untested.
- return createError("invalid sh_type");
- if (V.size() != (SymTable.sh_size / sizeof(Elf_Sym)))
- return createError("SHT_SYMTAB_SHNDX section has sh_size (" +
- Twine(SymTable.sh_size) +
- ") which is not equal to the number of symbols (" +
- Twine(V.size()) + ")");
+ 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)
+ return createError("SHT_SYMTAB_SHNDX has " + Twine(V.size()) +
+ " entries, but the symbol table associated has " +
+ Twine(Syms));
+
return V;
}
@@ -656,35 +729,36 @@
Elf_Shdr_Range Sections) const {
if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM)
- // TODO: this error is untested.
return createError(
"invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM");
- auto 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);
+ return getStringTable(**SectionOrErr);
}
template <class ELFT>
Expected<StringRef>
-ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section) const {
+ELFFile<ELFT>::getSectionName(const Elf_Shdr &Section,
+ WarningHandler WarnHandler) const {
auto SectionsOrErr = sections();
if (!SectionsOrErr)
return SectionsOrErr.takeError();
- auto Table = getSectionStringTable(*SectionsOrErr);
+ auto Table = getSectionStringTable(*SectionsOrErr, WarnHandler);
if (!Table)
return Table.takeError();
return getSectionName(Section, *Table);
}
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 "