// Subclasses of ELFFile may need this for template instantiation
inline std::pair<unsigned char, unsigned char>
-getElfArchType(MemoryBuffer *Object) {
- if (Object->getBufferSize() < ELF::EI_NIDENT)
- return std::make_pair((uint8_t)ELF::ELFCLASSNONE,(uint8_t)ELF::ELFDATANONE);
- return std::make_pair((uint8_t) Object->getBufferStart()[ELF::EI_CLASS],
- (uint8_t) Object->getBufferStart()[ELF::EI_DATA]);
+getElfArchType(StringRef Object) {
+ if (Object.size() < ELF::EI_NIDENT)
+ return std::make_pair((uint8_t)ELF::ELFCLASSNONE,
+ (uint8_t)ELF::ELFDATANONE);
+ return std::make_pair((uint8_t)Object[ELF::EI_CLASS],
+ (uint8_t)Object[ELF::EI_DATA]);
}
template <class ELFT>
class ELFFile {
public:
LLVM_ELF_IMPORT_TYPES_ELFT(ELFT)
- typedef typename conditional<ELFT::Is64Bits,
- uint64_t, uint32_t>::type uintX_t;
+ typedef typename std::conditional<ELFT::Is64Bits,
+ uint64_t, uint32_t>::type uintX_t;
/// \brief Iterate over constant sized entities.
template <class EntT>
public:
typedef ptrdiff_t difference_type;
typedef EntT value_type;
- typedef std::random_access_iterator_tag iterator_category;
+ typedef std::forward_iterator_tag iterator_category;
typedef value_type &reference;
typedef value_type *pointer;
/// \brief Default construct iterator.
- ELFEntityIterator() : EntitySize(0), Current(0) {}
+ ELFEntityIterator() : EntitySize(0), Current(nullptr) {}
ELFEntityIterator(uintX_t EntSize, const char *Start)
: EntitySize(EntSize), Current(Start) {}
return *this;
}
+ ELFEntityIterator &operator+(difference_type n) {
+ assert(Current && "Attempted to increment an invalid iterator!");
+ Current += (n * EntitySize);
+ return *this;
+ }
+
+ ELFEntityIterator &operator-(difference_type n) {
+ assert(Current && "Attempted to subtract an invalid iterator!");
+ Current -= (n * EntitySize);
+ return *this;
+ }
+
ELFEntityIterator operator ++(int) {
ELFEntityIterator Tmp = *this;
++*this;
return Tmp;
}
- ELFEntityIterator &operator =(const ELFEntityIterator &Other) {
- EntitySize = Other.EntitySize;
- Current = Other.Current;
- return *this;
- }
-
difference_type operator -(const ELFEntityIterator &Other) const {
assert(EntitySize == Other.EntitySize &&
"Subtracting iterators of different EntitySize!");
typedef Elf_Vernaux_Impl<ELFT> Elf_Vernaux;
typedef Elf_Versym_Impl<ELFT> Elf_Versym;
typedef ELFEntityIterator<const Elf_Dyn> Elf_Dyn_Iter;
+ typedef iterator_range<Elf_Dyn_Iter> Elf_Dyn_Range;
typedef ELFEntityIterator<const Elf_Rela> Elf_Rela_Iter;
typedef ELFEntityIterator<const Elf_Rel> Elf_Rel_Iter;
typedef ELFEntityIterator<const Elf_Shdr> Elf_Shdr_Iter;
+ typedef iterator_range<Elf_Shdr_Iter> Elf_Shdr_Range;
/// \brief Archive files are 2 byte aligned, so we need this for
/// PointerIntPair to work.
return *this;
}
- Elf_Sym_Iter &operator=(const Elf_Sym_Iter &Other) {
- EntitySize = Other.EntitySize;
- Current = Other.Current;
- return *this;
- }
-
difference_type operator-(const Elf_Sym_Iter &Other) const {
assert(EntitySize == Other.EntitySize &&
"Subtracting iterators of different EntitySize!");
typedef SmallVector<const Elf_Shdr *, 2> Sections_t;
typedef DenseMap<unsigned, unsigned> IndexMap_t;
- MemoryBuffer *Buf;
+ StringRef Buf;
const uint8_t *base() const {
- return reinterpret_cast<const uint8_t *>(Buf->getBufferStart());
+ return reinterpret_cast<const uint8_t *>(Buf.data());
}
const Elf_Ehdr *Header;
/// \brief Represents a region described by entries in the .dynamic table.
struct DynRegionInfo {
- DynRegionInfo() : Addr(0), Size(0), EntSize(0) {}
+ DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {}
/// \brief Address in current address space.
const void *Addr;
/// \brief Size in bytes of the region.
public:
// If the integer is 0, this is an Elf_Verdef*.
// If the integer is 1, this is an Elf_Vernaux*.
- VersionMapEntry() : PointerIntPair<const void*, 1>(NULL, 0) { }
+ VersionMapEntry() : PointerIntPair<const void*, 1>(nullptr, 0) { }
VersionMapEntry(const Elf_Verdef *verdef)
: PointerIntPair<const void*, 1>(verdef, 0) { }
VersionMapEntry(const Elf_Vernaux *vernaux)
: PointerIntPair<const void*, 1>(vernaux, 1) { }
- bool isNull() const { return getPointer() == NULL; }
+ bool isNull() const { return getPointer() == nullptr; }
bool isVerdef() const { return !isNull() && getInt() == 0; }
bool isVernaux() const { return !isNull() && getInt() == 1; }
const Elf_Verdef *getVerdef() const {
- return isVerdef() ? (const Elf_Verdef*)getPointer() : NULL;
+ return isVerdef() ? (const Elf_Verdef*)getPointer() : nullptr;
}
const Elf_Vernaux *getVernaux() const {
- return isVernaux() ? (const Elf_Vernaux*)getPointer() : NULL;
+ return isVernaux() ? (const Elf_Vernaux*)getPointer() : nullptr;
}
};
mutable SmallVector<VersionMapEntry, 16> VersionMap;
std::pair<const Elf_Shdr *, const Elf_Sym *>
getRelocationSymbol(const Elf_Shdr *RelSec, const RelT *Rel) const;
- ELFFile(MemoryBuffer *Object, error_code &ec);
+ ELFFile(StringRef Object, std::error_code &EC);
+
+ bool isMipsELF64() const {
+ return Header->e_machine == ELF::EM_MIPS &&
+ Header->getFileClass() == ELF::ELFCLASS64;
+ }
bool isMips64EL() const {
return Header->e_machine == ELF::EM_MIPS &&
Elf_Shdr_Iter begin_sections() const;
Elf_Shdr_Iter end_sections() const;
+ Elf_Shdr_Range sections() const {
+ return make_range(begin_sections(), end_sections());
+ }
Elf_Sym_Iter begin_symbols() const;
Elf_Sym_Iter end_symbols() const;
/// \param NULLEnd use one past the first DT_NULL entry as the end instead of
/// the section size.
Elf_Dyn_Iter end_dynamic_table(bool NULLEnd = false) const;
+ Elf_Dyn_Range dynamic_table(bool NULLEnd = false) const {
+ return make_range(begin_dynamic_table(), end_dynamic_table(NULLEnd));
+ }
Elf_Sym_Iter begin_dynamic_symbols() const {
if (DynSymRegion.Addr)
return Elf_Sym_Iter(DynSymRegion.EntSize, (const char *)DynSymRegion.Addr,
true);
- return Elf_Sym_Iter(0, 0, true);
+ return Elf_Sym_Iter(0, nullptr, true);
}
Elf_Sym_Iter end_dynamic_symbols() const {
return Elf_Sym_Iter(DynSymRegion.EntSize,
(const char *)DynSymRegion.Addr + DynSymRegion.Size,
true);
- return Elf_Sym_Iter(0, 0, true);
+ return Elf_Sym_Iter(0, nullptr, true);
}
Elf_Rela_Iter begin_rela(const Elf_Shdr *sec) const {
StringRef getLoadName() const;
};
-// Use an alignment of 2 for the typedefs since that is the worst case for
-// ELF files in archives.
-typedef ELFFile<ELFType<support::little, 2, false> > ELF32LEFile;
-typedef ELFFile<ELFType<support::little, 2, true> > ELF64LEFile;
-typedef ELFFile<ELFType<support::big, 2, false> > ELF32BEFile;
-typedef ELFFile<ELFType<support::big, 2, true> > ELF64BEFile;
+typedef ELFFile<ELFType<support::little, false>> ELF32LEFile;
+typedef ELFFile<ELFType<support::little, true>> ELF64LEFile;
+typedef ELFFile<ELFType<support::big, false>> ELF32BEFile;
+typedef ELFFile<ELFType<support::big, true>> ELF64BEFile;
// Iterate through the version definitions, and place each Elf_Verdef
// in the VersionMap according to its index.
template <class ELFT>
void ELFFile<ELFT>::LoadVersionMap() const {
// If there is no dynamic symtab or version table, there is nothing to do.
- if (DynSymRegion.Addr == NULL || dot_gnu_version_sec == NULL)
+ if (!DynSymRegion.Addr || !dot_gnu_version_sec)
return;
// Has the VersionMap already been loaded?
if (symb->st_shndx == ELF::SHN_XINDEX)
return getSection(ExtendedSymbolTable.lookup(symb));
if (symb->st_shndx >= ELF::SHN_LORESERVE)
- return 0;
+ return nullptr;
return getSection(symb->st_shndx);
}
template <class ELFT>
ErrorOr<ArrayRef<uint8_t> >
ELFFile<ELFT>::getSectionContents(const Elf_Shdr *Sec) const {
- if (Sec->sh_offset + Sec->sh_size > Buf->getBufferSize())
+ if (Sec->sh_offset + Sec->sh_size > Buf.size())
return object_error::parse_failed;
const uint8_t *Start = base() + Sec->sh_offset;
- return ArrayRef<uint8_t>(Start, Sec->sh_size);
+ return makeArrayRef(Start, Sec->sh_size);
}
template <class ELFT>
template <class ELFT>
void ELFFile<ELFT>::getRelocationTypeName(uint32_t Type,
SmallVectorImpl<char> &Result) const {
- if (!isMips64EL()) {
+ if (!isMipsELF64()) {
StringRef Name = getRelocationTypeName(Type);
Result.append(Name.begin(), Name.end());
} else {
+ // The Mips N64 ABI allows up to three operations to be specified per
+ // relocation record. Unfortunately there's no easy way to test for the
+ // presence of N64 ELFs as they have no special flag that identifies them
+ // as being N64. We can safely assume at the moment that all Mips
+ // ELFCLASS64 ELFs are N64. New Mips64 ABIs should provide enough
+ // information to disambiguate between old vs new ABIs.
uint8_t Type1 = (Type >> 0) & 0xFF;
uint8_t Type2 = (Type >> 8) & 0xFF;
uint8_t Type3 = (Type >> 16) & 0xFF;
const typename ELFFile<ELFT>::Elf_Sym *>
ELFFile<ELFT>::getRelocationSymbol(const Elf_Shdr *Sec, const RelT *Rel) const {
if (!Sec->sh_link)
- return std::make_pair((const Elf_Shdr *)0, (const Elf_Sym *)0);
+ return std::make_pair(nullptr, nullptr);
const Elf_Shdr *SymTable = getSection(Sec->sh_link);
return std::make_pair(
SymTable, getEntry<Elf_Sym>(SymTable, Rel->getSymbol(isMips64EL())));
template <class ELFT>
uint64_t ELFFile<ELFT>::getNumSections() const {
assert(Header && "Header not initialized!");
- if (Header->e_shnum == ELF::SHN_UNDEF) {
+ if (Header->e_shnum == ELF::SHN_UNDEF && Header->e_shoff > 0) {
assert(SectionHeaderTable && "SectionHeaderTable not initialized!");
return SectionHeaderTable->sh_size;
}
}
template <class ELFT>
-ELFFile<ELFT>::ELFFile(MemoryBuffer *Object, error_code &ec)
- : Buf(Object),
- SectionHeaderTable(0),
- dot_shstrtab_sec(0),
- dot_strtab_sec(0),
- dot_symtab_sec(0),
- SymbolTableSectionHeaderIndex(0),
- dot_gnu_version_sec(0),
- dot_gnu_version_r_sec(0),
- dot_gnu_version_d_sec(0),
- dt_soname(0) {
- const uint64_t FileSize = Buf->getBufferSize();
-
- if (sizeof(Elf_Ehdr) > FileSize)
- // FIXME: Proper error handling.
- report_fatal_error("File too short!");
+ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC)
+ : Buf(Object), SectionHeaderTable(nullptr), dot_shstrtab_sec(nullptr),
+ dot_strtab_sec(nullptr), dot_symtab_sec(nullptr),
+ SymbolTableSectionHeaderIndex(nullptr), dot_gnu_version_sec(nullptr),
+ dot_gnu_version_r_sec(nullptr), dot_gnu_version_d_sec(nullptr),
+ dt_soname(nullptr) {
+ const uint64_t FileSize = Buf.size();
+
+ if (sizeof(Elf_Ehdr) > FileSize) {
+ // File too short!
+ EC = object_error::parse_failed;
+ return;
+ }
Header = reinterpret_cast<const Elf_Ehdr *>(base());
const uint64_t SectionTableOffset = Header->e_shoff;
- if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize)
- // FIXME: Proper error handling.
- report_fatal_error("Section header table goes past end of file!");
+ if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) {
+ // Section header table goes past end of file!
+ EC = object_error::parse_failed;
+ return;
+ }
// The getNumSections() call below depends on SectionHeaderTable being set.
SectionHeaderTable =
reinterpret_cast<const Elf_Shdr *>(base() + SectionTableOffset);
const uint64_t SectionTableSize = getNumSections() * Header->e_shentsize;
- if (SectionTableOffset + SectionTableSize > FileSize)
- // FIXME: Proper error handling.
- report_fatal_error("Section table goes past end of file!");
+ if (SectionTableOffset + SectionTableSize > FileSize) {
+ // Section table goes past end of file!
+ EC = object_error::parse_failed;
+ return;
+ }
// Scan sections for special sections.
- for (Elf_Shdr_Iter SecI = begin_sections(), SecE = end_sections();
- SecI != SecE; ++SecI) {
- switch (SecI->sh_type) {
+ for (const Elf_Shdr &Sec : sections()) {
+ switch (Sec.sh_type) {
case ELF::SHT_SYMTAB_SHNDX:
- if (SymbolTableSectionHeaderIndex)
- // FIXME: Proper error handling.
- report_fatal_error("More than one .symtab_shndx!");
- SymbolTableSectionHeaderIndex = &*SecI;
+ if (SymbolTableSectionHeaderIndex) {
+ // More than one .symtab_shndx!
+ EC = object_error::parse_failed;
+ return;
+ }
+ SymbolTableSectionHeaderIndex = &Sec;
break;
case ELF::SHT_SYMTAB:
- if (dot_symtab_sec)
- // FIXME: Proper error handling.
- report_fatal_error("More than one .symtab!");
- dot_symtab_sec = &*SecI;
- dot_strtab_sec = getSection(SecI->sh_link);
+ if (dot_symtab_sec) {
+ // More than one .symtab!
+ EC = object_error::parse_failed;
+ return;
+ }
+ dot_symtab_sec = &Sec;
+ dot_strtab_sec = getSection(Sec.sh_link);
break;
case ELF::SHT_DYNSYM: {
- if (DynSymRegion.Addr)
- // FIXME: Proper error handling.
- report_fatal_error("More than one .dynsym!");
- DynSymRegion.Addr = base() + SecI->sh_offset;
- DynSymRegion.Size = SecI->sh_size;
- DynSymRegion.EntSize = SecI->sh_entsize;
- const Elf_Shdr *DynStr = getSection(SecI->sh_link);
+ if (DynSymRegion.Addr) {
+ // More than one .dynsym!
+ EC = object_error::parse_failed;
+ return;
+ }
+ DynSymRegion.Addr = base() + Sec.sh_offset;
+ DynSymRegion.Size = Sec.sh_size;
+ DynSymRegion.EntSize = Sec.sh_entsize;
+ const Elf_Shdr *DynStr = getSection(Sec.sh_link);
DynStrRegion.Addr = base() + DynStr->sh_offset;
DynStrRegion.Size = DynStr->sh_size;
DynStrRegion.EntSize = DynStr->sh_entsize;
break;
}
case ELF::SHT_DYNAMIC:
- if (DynamicRegion.Addr)
- // FIXME: Proper error handling.
- report_fatal_error("More than one .dynamic!");
- DynamicRegion.Addr = base() + SecI->sh_offset;
- DynamicRegion.Size = SecI->sh_size;
- DynamicRegion.EntSize = SecI->sh_entsize;
+ 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 != NULL)
- // FIXME: Proper error handling.
- report_fatal_error("More than one .gnu.version section!");
- dot_gnu_version_sec = &*SecI;
+ if (dot_gnu_version_sec != nullptr) {
+ // More than one .gnu.version section!
+ EC = object_error::parse_failed;
+ return;
+ }
+ dot_gnu_version_sec = &Sec;
break;
case ELF::SHT_GNU_verdef:
- if (dot_gnu_version_d_sec != NULL)
- // FIXME: Proper error handling.
- report_fatal_error("More than one .gnu.version_d section!");
- dot_gnu_version_d_sec = &*SecI;
+ if (dot_gnu_version_d_sec != nullptr) {
+ // More than one .gnu.version_d section!
+ EC = object_error::parse_failed;
+ return;
+ }
+ dot_gnu_version_d_sec = &Sec;
break;
case ELF::SHT_GNU_verneed:
- if (dot_gnu_version_r_sec != NULL)
- // FIXME: Proper error handling.
- report_fatal_error("More than one .gnu.version_r section!");
- dot_gnu_version_r_sec = &*SecI;
+ if (dot_gnu_version_r_sec != nullptr) {
+ // More than one .gnu.version_r section!
+ EC = object_error::parse_failed;
+ return;
+ }
+ dot_gnu_version_r_sec = &Sec;
break;
}
}
}
}
- ec = error_code::success();
+ EC = std::error_code();
}
// Get the symbol table index in the symtab section given a symbol
template <class ELFT>
typename ELFFile<ELFT>::Elf_Sym_Iter ELFFile<ELFT>::begin_symbols() const {
if (!dot_symtab_sec)
- return Elf_Sym_Iter(0, 0, false);
+ return Elf_Sym_Iter(0, nullptr, false);
return Elf_Sym_Iter(dot_symtab_sec->sh_entsize,
(const char *)base() + dot_symtab_sec->sh_offset, false);
}
template <class ELFT>
typename ELFFile<ELFT>::Elf_Sym_Iter ELFFile<ELFT>::end_symbols() const {
if (!dot_symtab_sec)
- return Elf_Sym_Iter(0, 0, false);
+ return Elf_Sym_Iter(0, nullptr, false);
return Elf_Sym_Iter(dot_symtab_sec->sh_entsize,
(const char *)base() + dot_symtab_sec->sh_offset +
dot_symtab_sec->sh_size,
if (DynamicRegion.Addr)
return Elf_Dyn_Iter(DynamicRegion.EntSize,
(const char *)DynamicRegion.Addr);
- return Elf_Dyn_Iter(0, 0);
+ return Elf_Dyn_Iter(0, nullptr);
}
template <class ELFT>
typename ELFFile<ELFT>::Elf_Dyn_Iter
ELFFile<ELFT>::end_dynamic_table(bool NULLEnd) const {
if (!DynamicRegion.Addr)
- return Elf_Dyn_Iter(0, 0);
+ return Elf_Dyn_Iter(0, nullptr);
Elf_Dyn_Iter Ret(DynamicRegion.EntSize,
(const char *)DynamicRegion.Addr + DynamicRegion.Size);
template <class ELFT>
StringRef ELFFile<ELFT>::getLoadName() const {
if (!dt_soname) {
+ dt_soname = "";
// Find the DT_SONAME entry
- Elf_Dyn_Iter it = begin_dynamic_table();
- Elf_Dyn_Iter ie = end_dynamic_table();
- while (it != ie && it->getTag() != ELF::DT_SONAME)
- ++it;
-
- if (it != ie) {
- dt_soname = getDynamicString(it->getVal());
- } else {
- dt_soname = "";
- }
+ for (const auto &Entry : dynamic_table())
+ if (Entry.getTag() == ELF::DT_SONAME) {
+ dt_soname = getDynamicString(Entry.getVal());
+ break;
+ }
}
return dt_soname;
}
const typename ELFFile<ELFT>::Elf_Shdr *
ELFFile<ELFT>::getSection(uint32_t index) const {
if (index == 0)
- return 0;
+ return nullptr;
if (!SectionHeaderTable || index >= getNumSections())
// FIXME: Proper error handling.
report_fatal_error("Invalid section index!");
template <class ELFT>
const char *ELFFile<ELFT>::getDynamicString(uintX_t Offset) const {
if (!DynStrRegion.Addr || Offset >= DynStrRegion.Size)
- return 0;
+ return nullptr;
return (const char *)DynStrRegion.Addr + Offset;
}
template <class ELFT>
ErrorOr<StringRef> ELFFile<ELFT>::getSymbolName(const Elf_Shdr *Section,
const Elf_Sym *Symb) const {
- if (Symb->st_name == 0) {
- const Elf_Shdr *ContainingSec = getSection(Symb);
- if (ContainingSec)
- return getSectionName(ContainingSec);
- }
+ if (Symb->st_name == 0)
+ return StringRef("");
const Elf_Shdr *StrTab = getSection(Section->sh_link);
if (Symb->st_name >= StrTab->sh_size)
const Elf_Sym *symb,
bool &IsDefault) const {
// Handle non-dynamic symbols.
- if (section != DynSymRegion.Addr && section != 0) {
+ if (section != DynSymRegion.Addr && section != nullptr) {
// Non-dynamic symbols can have versions in their names
// A name of the form 'foo@V1' indicates version 'V1', non-default.
// A name of the form 'foo@@V2' indicates version 'V2', default version.
}
// This is a dynamic symbol. Look in the GNU symbol version table.
- if (dot_gnu_version_sec == NULL) {
+ if (!dot_gnu_version_sec) {
// No version table.
IsDefault = false;
return StringRef("");