diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:46:15 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-12-30 11:46:15 +0000 |
| commit | dd58ef019b700900793a1eb48b52123db01b654e (patch) | |
| tree | fcfbb4df56a744f4ddc6122c50521dd3f1c5e196 /include/llvm/Object | |
| parent | 2fe5752e3a7c345cdb59e869278d36af33c13fa4 (diff) | |
Notes
Diffstat (limited to 'include/llvm/Object')
| -rw-r--r-- | include/llvm/Object/Archive.h | 67 | ||||
| -rw-r--r-- | include/llvm/Object/ArchiveWriter.h | 13 | ||||
| -rw-r--r-- | include/llvm/Object/Binary.h | 10 | ||||
| -rw-r--r-- | include/llvm/Object/COFF.h | 4 | ||||
| -rw-r--r-- | include/llvm/Object/COFFImportFile.h | 74 | ||||
| -rw-r--r-- | include/llvm/Object/ELF.h | 871 | ||||
| -rw-r--r-- | include/llvm/Object/ELFObjectFile.h | 171 | ||||
| -rw-r--r-- | include/llvm/Object/ELFTypes.h | 37 | ||||
| -rw-r--r-- | include/llvm/Object/Error.h | 1 | ||||
| -rw-r--r-- | include/llvm/Object/FunctionIndexObjectFile.h | 110 | ||||
| -rw-r--r-- | include/llvm/Object/MachO.h | 26 | ||||
| -rw-r--r-- | include/llvm/Object/ObjectFile.h | 13 | ||||
| -rw-r--r-- | include/llvm/Object/SymbolicFile.h | 8 |
13 files changed, 584 insertions, 821 deletions
diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index 597f0d48c118..8dd042a2533f 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -37,7 +37,7 @@ struct ArchiveMemberHeader { llvm::StringRef getName() const; /// Members are not larger than 4GB. - uint32_t getSize() const; + ErrorOr<uint32_t> getSize() const; sys::fs::perms getAccessMode() const; sys::TimeValue getLastModified() const; @@ -52,6 +52,7 @@ class Archive : public Binary { virtual void anchor(); public: class Child { + friend Archive; const Archive *Parent; /// \brief Includes header but not padding byte. StringRef Data; @@ -62,19 +63,19 @@ public: return reinterpret_cast<const ArchiveMemberHeader *>(Data.data()); } + bool isThinMember() const; + public: - Child(const Archive *Parent, const char *Start); + Child(const Archive *Parent, const char *Start, std::error_code *EC); + Child(const Archive *Parent, StringRef Data, uint16_t StartOfFile); bool operator ==(const Child &other) const { assert(Parent == other.Parent); return Data.begin() == other.Data.begin(); } - bool operator <(const Child &other) const { - return Data.begin() < other.Data.begin(); - } - - Child getNext() const; + const Archive *getParent() const { return Parent; } + ErrorOr<Child> getNext() const; ErrorOr<StringRef> getName() const; StringRef getRawName() const { return getHeader()->getName(); } @@ -90,9 +91,9 @@ public: return getHeader()->getAccessMode(); } /// \return the size of the archive member without the header or padding. - uint64_t getSize() const; + ErrorOr<uint64_t> getSize() const; /// \return the size in the archive header for this member. - uint64_t getRawSize() const; + ErrorOr<uint64_t> getRawSize() const; ErrorOr<StringRef> getBuffer() const; uint64_t getChildOffset() const; @@ -104,28 +105,32 @@ public: }; class child_iterator { - Child child; + ErrorOr<Child> child; public: - child_iterator() : child(Child(nullptr, nullptr)) {} + child_iterator() : child(Child(nullptr, nullptr, nullptr)) {} child_iterator(const Child &c) : child(c) {} - const Child *operator->() const { return &child; } - const Child &operator*() const { return child; } + child_iterator(std::error_code EC) : child(EC) {} + const ErrorOr<Child> *operator->() const { return &child; } + const ErrorOr<Child> &operator*() const { return child; } bool operator==(const child_iterator &other) const { - return child == other.child; + // We ignore error states so that comparisions with end() work, which + // allows range loops. + if (child.getError() || other.child.getError()) + return false; + return *child == *other.child; } bool operator!=(const child_iterator &other) const { return !(*this == other); } - bool operator<(const child_iterator &other) const { - return child < other.child; - } - + // Code in loops with child_iterators must check for errors on each loop + // iteration. And if there is an error break out of the loop. child_iterator &operator++() { // Preincrement - child = child.getNext(); + assert(child && "Can't increment iterator with error"); + child = child->getNext(); return *this; } }; @@ -145,7 +150,7 @@ public: , SymbolIndex(symi) , StringIndex(stri) {} StringRef getName() const; - ErrorOr<child_iterator> getMember() const; + ErrorOr<Child> getMember() const; Symbol getNext() const; }; @@ -186,14 +191,13 @@ public: child_iterator child_begin(bool SkipInternal = true) const; child_iterator child_end() const; iterator_range<child_iterator> children(bool SkipInternal = true) const { - return iterator_range<child_iterator>(child_begin(SkipInternal), - child_end()); + return make_range(child_begin(SkipInternal), child_end()); } symbol_iterator symbol_begin() const; symbol_iterator symbol_end() const; iterator_range<symbol_iterator> symbols() const { - return iterator_range<symbol_iterator>(symbol_begin(), symbol_end()); + return make_range(symbol_begin(), symbol_end()); } // Cast methods. @@ -205,18 +209,17 @@ public: child_iterator findSym(StringRef name) const; bool hasSymbolTable() const; - child_iterator getSymbolTableChild() const { return SymbolTable; } - StringRef getSymbolTable() const { - // We know that the symbol table is not an external file, - // so we just assert there is no error. - return *SymbolTable->getBuffer(); - } + StringRef getSymbolTable() const { return SymbolTable; } uint32_t getNumberOfSymbols() const; private: - child_iterator SymbolTable; - child_iterator StringTable; - child_iterator FirstRegular; + StringRef SymbolTable; + StringRef StringTable; + + StringRef FirstRegularData; + uint16_t FirstRegularStartOfFile = -1; + void setFirstRegular(const Child &C); + unsigned Format : 2; unsigned IsThin : 1; mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers; diff --git a/include/llvm/Object/ArchiveWriter.h b/include/llvm/Object/ArchiveWriter.h index 3648d0c77fb5..b5d2ba358080 100644 --- a/include/llvm/Object/ArchiveWriter.h +++ b/include/llvm/Object/ArchiveWriter.h @@ -24,17 +24,15 @@ class NewArchiveIterator { bool IsNewMember; StringRef Name; - object::Archive::child_iterator OldI; - - StringRef NewFilename; + object::Archive::Child OldMember; public: - NewArchiveIterator(object::Archive::child_iterator I, StringRef Name); - NewArchiveIterator(StringRef I, StringRef Name); + NewArchiveIterator(const object::Archive::Child &OldMember, StringRef Name); + NewArchiveIterator(StringRef FileName); bool isNewMember() const; StringRef getName() const; - object::Archive::child_iterator getOld() const; + const object::Archive::Child &getOld() const; StringRef getNew() const; llvm::ErrorOr<int> getFD(sys::fs::file_status &NewStatus) const; @@ -43,7 +41,8 @@ public: std::pair<StringRef, std::error_code> writeArchive(StringRef ArcName, std::vector<NewArchiveIterator> &NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic); + bool WriteSymtab, object::Archive::Kind Kind, bool Deterministic, + bool Thin); } #endif diff --git a/include/llvm/Object/Binary.h b/include/llvm/Object/Binary.h index a3d6d0d4d428..a0d1127781f6 100644 --- a/include/llvm/Object/Binary.h +++ b/include/llvm/Object/Binary.h @@ -41,7 +41,9 @@ protected: enum { ID_Archive, ID_MachOUniversalBinary, - ID_IR, // LLVM IR + ID_COFFImportFile, + ID_IR, // LLVM IR + ID_FunctionIndex, // Function summary index // Object and children. ID_StartObjects, @@ -113,10 +115,16 @@ public: return TypeID == ID_COFF; } + bool isCOFFImportFile() const { + return TypeID == ID_COFFImportFile; + } + bool isIR() const { return TypeID == ID_IR; } + bool isFunctionIndex() const { return TypeID == ID_FunctionIndex; } + bool isLittleEndian() const { return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B || TypeID == ID_MachO32B || TypeID == ID_MachO64B); diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 025a9dbc6bc0..1b0e2e36bd5e 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -653,8 +653,7 @@ protected: uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; SymbolRef::Type getSymbolType(DataRefImpl Symb) const override; - std::error_code getSymbolSection(DataRefImpl Symb, - section_iterator &Res) const override; + ErrorOr<section_iterator> getSymbolSection(DataRefImpl Symb) const override; void moveSectionNext(DataRefImpl &Sec) const override; std::error_code getSectionName(DataRefImpl Sec, StringRef &Res) const override; @@ -774,6 +773,7 @@ public: std::error_code getSectionContents(const coff_section *Sec, ArrayRef<uint8_t> &Res) const; + uint64_t getImageBase() const; std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) const; std::error_code getRvaPtr(uint32_t Rva, uintptr_t &Res) const; std::error_code getHintName(uint32_t Rva, uint16_t &Hint, diff --git a/include/llvm/Object/COFFImportFile.h b/include/llvm/Object/COFFImportFile.h new file mode 100644 index 000000000000..b04a44ea60d2 --- /dev/null +++ b/include/llvm/Object/COFFImportFile.h @@ -0,0 +1,74 @@ +//===- COFFImportFile.h - COFF short import file implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// COFF short import file is a special kind of file which contains +// only symbol names for DLL-exported symbols. This class implements +// SymbolicFile interface for the file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_COFF_IMPORT_FILE_H +#define LLVM_OBJECT_COFF_IMPORT_FILE_H + +#include "llvm/Object/COFF.h" +#include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace object { + +class COFFImportFile : public SymbolicFile { +public: + COFFImportFile(MemoryBufferRef Source) + : SymbolicFile(ID_COFFImportFile, Source) {} + + static inline bool classof(Binary const *V) { return V->isCOFFImportFile(); } + + void moveSymbolNext(DataRefImpl &Symb) const override { ++Symb.p; } + + std::error_code printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const override { + if (Symb.p == 0) + OS << "__imp_"; + OS << StringRef(Data.getBufferStart() + sizeof(coff_import_header)); + return std::error_code(); + } + + uint32_t getSymbolFlags(DataRefImpl Symb) const override { + return SymbolRef::SF_Global; + } + + basic_symbol_iterator symbol_begin_impl() const override { + return BasicSymbolRef(DataRefImpl(), this); + } + + basic_symbol_iterator symbol_end_impl() const override { + DataRefImpl Symb; + Symb.p = isCode() ? 2 : 1; + return BasicSymbolRef(Symb, this); + } + + const coff_import_header *getCOFFImportHeader() const { + return reinterpret_cast<const object::coff_import_header *>( + Data.getBufferStart()); + } + +private: + bool isCode() const { + return getCOFFImportHeader()->getType() == COFF::IMPORT_CODE; + } +}; + +} // namespace object +} // namespace llvm + +#endif diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index cc271851e6b0..b0eaa3f5ed4d 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -14,25 +14,9 @@ #ifndef LLVM_OBJECT_ELF_H #define LLVM_OBJECT_ELF_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/IntervalMap.h" -#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Triple.h" #include "llvm/Object/ELFTypes.h" -#include "llvm/Object/Error.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/ELF.h" -#include "llvm/Support/Endian.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include <algorithm> -#include <limits> -#include <utility> namespace llvm { namespace object { @@ -56,78 +40,6 @@ public: typedef typename std::conditional<ELFT::Is64Bits, uint64_t, uint32_t>::type uintX_t; - /// \brief Iterate over constant sized entities. - template <class EntT> - class ELFEntityIterator { - public: - typedef ptrdiff_t difference_type; - typedef EntT value_type; - typedef std::forward_iterator_tag iterator_category; - typedef value_type &reference; - typedef value_type *pointer; - - /// \brief Default construct iterator. - ELFEntityIterator() : EntitySize(0), Current(nullptr) {} - ELFEntityIterator(uintX_t EntSize, const char *Start) - : EntitySize(EntSize), Current(Start) {} - - reference operator *() { - assert(Current && "Attempted to dereference an invalid iterator!"); - return *reinterpret_cast<pointer>(Current); - } - - pointer operator ->() { - assert(Current && "Attempted to dereference an invalid iterator!"); - return reinterpret_cast<pointer>(Current); - } - - bool operator ==(const ELFEntityIterator &Other) { - return Current == Other.Current; - } - - bool operator !=(const ELFEntityIterator &Other) { - return !(*this == Other); - } - - ELFEntityIterator &operator ++() { - assert(Current && "Attempted to increment an invalid iterator!"); - Current += EntitySize; - 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; - } - - difference_type operator -(const ELFEntityIterator &Other) const { - assert(EntitySize == Other.EntitySize && - "Subtracting iterators of different EntitySize!"); - return (Current - Other.Current) / EntitySize; - } - - const char *get() const { return Current; } - - uintX_t getEntSize() const { return EntitySize; } - - private: - uintX_t EntitySize; - const char *Current; - }; - typedef Elf_Ehdr_Impl<ELFT> Elf_Ehdr; typedef Elf_Shdr_Impl<ELFT> Elf_Shdr; typedef Elf_Sym_Impl<ELFT> Elf_Sym; @@ -141,98 +53,22 @@ public: typedef Elf_Vernaux_Impl<ELFT> Elf_Vernaux; typedef Elf_Versym_Impl<ELFT> Elf_Versym; typedef Elf_Hash_Impl<ELFT> Elf_Hash; - 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 Elf_GnuHash_Impl<ELFT> Elf_GnuHash; + typedef iterator_range<const Elf_Dyn *> Elf_Dyn_Range; typedef iterator_range<const Elf_Shdr *> Elf_Shdr_Range; - - /// \brief Archive files are 2 byte aligned, so we need this for - /// PointerIntPair to work. - template <typename T> - class ArchivePointerTypeTraits { - public: - static inline const void *getAsVoidPointer(T *P) { return P; } - static inline T *getFromVoidPointer(const void *P) { - return static_cast<T *>(P); - } - enum { NumLowBitsAvailable = 1 }; - }; - typedef iterator_range<const Elf_Sym *> Elf_Sym_Range; -private: - typedef SmallVector<const Elf_Shdr *, 2> Sections_t; - typedef DenseMap<unsigned, unsigned> IndexMap_t; - - StringRef Buf; - const uint8_t *base() const { return reinterpret_cast<const uint8_t *>(Buf.data()); } +private: + + StringRef Buf; + const Elf_Ehdr *Header; const Elf_Shdr *SectionHeaderTable = nullptr; StringRef DotShstrtab; // Section header string table. - StringRef DotStrtab; // Symbol header string table. - const Elf_Shdr *dot_symtab_sec = nullptr; // Symbol table section. - const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. - const Elf_Hash *HashTable = nullptr; - - const Elf_Shdr *SymbolTableSectionHeaderIndex = nullptr; - DenseMap<const Elf_Sym *, ELF::Elf64_Word> ExtendedSymbolTable; - - const Elf_Shdr *dot_gnu_version_sec = nullptr; // .gnu.version - const Elf_Shdr *dot_gnu_version_r_sec = nullptr; // .gnu.version_r - const Elf_Shdr *dot_gnu_version_d_sec = nullptr; // .gnu.version_d - - /// \brief Represents a region described by entries in the .dynamic table. - struct DynRegionInfo { - DynRegionInfo() : Addr(nullptr), Size(0), EntSize(0) {} - /// \brief Address in current address space. - const void *Addr; - /// \brief Size in bytes of the region. - uintX_t Size; - /// \brief Size of each entity in the region. - uintX_t EntSize; - }; - - DynRegionInfo DynamicRegion; - DynRegionInfo DynHashRegion; - DynRegionInfo DynStrRegion; - DynRegionInfo DynRelaRegion; - - // Pointer to SONAME entry in dynamic string table - // This is set the first time getLoadName is called. - mutable const char *dt_soname = nullptr; - - // Records for each version index the corresponding Verdef or Vernaux entry. - // This is filled the first time LoadVersionMap() is called. - class VersionMapEntry : public PointerIntPair<const void*, 1> { - 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>(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() == 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() : nullptr; - } - const Elf_Vernaux *getVernaux() const { - return isVernaux() ? (const Elf_Vernaux*)getPointer() : nullptr; - } - }; - mutable SmallVector<VersionMapEntry, 16> VersionMap; - void LoadVersionDefs(const Elf_Shdr *sec) const; - void LoadVersionNeeds(const Elf_Shdr *ec) const; - void LoadVersionMap() const; - - void scanDynamicTable(); public: template<typename T> @@ -240,25 +76,20 @@ public: template <typename T> const T *getEntry(const Elf_Shdr *Section, uint32_t Entry) const; - const Elf_Shdr *getDotSymtabSec() const { return dot_symtab_sec; } - const Elf_Shdr *getDotDynSymSec() const { return DotDynSymSec; } - const Elf_Hash *getHashTable() const { return HashTable; } - ErrorOr<StringRef> getStringTable(const Elf_Shdr *Section) const; - const char *getDynamicString(uintX_t Offset) const; - ErrorOr<StringRef> getSymbolVersion(const Elf_Shdr *section, - const Elf_Sym *Symb, - bool &IsDefault) const; + ErrorOr<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const; + + ErrorOr<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section) const; + void VerifyStrTab(const Elf_Shdr *sh) const; StringRef getRelocationTypeName(uint32_t Type) const; void getRelocationTypeName(uint32_t Type, SmallVectorImpl<char> &Result) const; - /// \brief Get the symbol table section and symbol for a given relocation. - template <class RelT> - std::pair<const Elf_Shdr *, const Elf_Sym *> - getRelocationSymbol(const Elf_Shdr *RelSec, const RelT *Rel) const; + /// \brief Get the symbol for a given relocation. + const Elf_Sym *getRelocationSymbol(const Elf_Rel *Rel, + const Elf_Shdr *SymTab) const; ELFFile(StringRef Object, std::error_code &EC); @@ -273,111 +104,116 @@ public: Header->getDataEncoding() == ELF::ELFDATA2LSB; } + ErrorOr<const Elf_Dyn *> dynamic_table_begin(const Elf_Phdr *Phdr) const; + ErrorOr<const Elf_Dyn *> dynamic_table_end(const Elf_Phdr *Phdr) const; + ErrorOr<Elf_Dyn_Range> dynamic_table(const Elf_Phdr *Phdr) const { + ErrorOr<const Elf_Dyn *> Begin = dynamic_table_begin(Phdr); + if (std::error_code EC = Begin.getError()) + return EC; + ErrorOr<const Elf_Dyn *> End = dynamic_table_end(Phdr); + if (std::error_code EC = End.getError()) + return EC; + return make_range(*Begin, *End); + } + const Elf_Shdr *section_begin() const; const Elf_Shdr *section_end() const; Elf_Shdr_Range sections() const { return make_range(section_begin(), section_end()); } - const Elf_Sym *symbol_begin() const; - const Elf_Sym *symbol_end() const; - Elf_Sym_Range symbols() const { - return make_range(symbol_begin(), symbol_end()); - } - - Elf_Dyn_Iter dynamic_table_begin() const; - /// \param NULLEnd use one past the first DT_NULL entry as the end instead of - /// the section size. - Elf_Dyn_Iter dynamic_table_end(bool NULLEnd = false) const; - Elf_Dyn_Range dynamic_table(bool NULLEnd = false) const { - return make_range(dynamic_table_begin(), dynamic_table_end(NULLEnd)); - } - - const Elf_Sym *dynamic_symbol_begin() const { - if (!DotDynSymSec) + const Elf_Sym *symbol_begin(const Elf_Shdr *Sec) const { + if (!Sec) return nullptr; - if (DotDynSymSec->sh_entsize != sizeof(Elf_Sym)) + if (Sec->sh_entsize != sizeof(Elf_Sym)) report_fatal_error("Invalid symbol size"); - return reinterpret_cast<const Elf_Sym *>(base() + DotDynSymSec->sh_offset); + return reinterpret_cast<const Elf_Sym *>(base() + Sec->sh_offset); } - - const Elf_Sym *dynamic_symbol_end() const { - if (!DotDynSymSec) + const Elf_Sym *symbol_end(const Elf_Shdr *Sec) const { + if (!Sec) return nullptr; - return reinterpret_cast<const Elf_Sym *>(base() + DotDynSymSec->sh_offset + - DotDynSymSec->sh_size); + uint64_t Size = Sec->sh_size; + if (Size % sizeof(Elf_Sym)) + report_fatal_error("Invalid symbol table size"); + return symbol_begin(Sec) + Size / sizeof(Elf_Sym); } - - Elf_Sym_Range dynamic_symbols() const { - return make_range(dynamic_symbol_begin(), dynamic_symbol_end()); + Elf_Sym_Range symbols(const Elf_Shdr *Sec) const { + return make_range(symbol_begin(Sec), symbol_end(Sec)); } - Elf_Rela_Iter dyn_rela_begin() const { - if (DynRelaRegion.Addr) - return Elf_Rela_Iter(DynRelaRegion.EntSize, - (const char *)DynRelaRegion.Addr); - return Elf_Rela_Iter(0, nullptr); + typedef iterator_range<const Elf_Rela *> Elf_Rela_Range; + + const Elf_Rela *rela_begin(const Elf_Shdr *sec) const { + if (sec->sh_entsize != sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast<const Elf_Rela *>(base() + sec->sh_offset); } - Elf_Rela_Iter dyn_rela_end() const { - if (DynRelaRegion.Addr) - return Elf_Rela_Iter( - DynRelaRegion.EntSize, - (const char *)DynRelaRegion.Addr + DynRelaRegion.Size); - return Elf_Rela_Iter(0, nullptr); + const Elf_Rela *rela_end(const Elf_Shdr *sec) const { + uint64_t Size = sec->sh_size; + if (Size % sizeof(Elf_Rela)) + report_fatal_error("Invalid relocation table size"); + return rela_begin(sec) + Size / sizeof(Elf_Rela); } - Elf_Rela_Iter rela_begin(const Elf_Shdr *sec) const { - return Elf_Rela_Iter(sec->sh_entsize, - (const char *)(base() + sec->sh_offset)); + Elf_Rela_Range relas(const Elf_Shdr *Sec) const { + return make_range(rela_begin(Sec), rela_end(Sec)); } - Elf_Rela_Iter rela_end(const Elf_Shdr *sec) const { - return Elf_Rela_Iter( - sec->sh_entsize, - (const char *)(base() + sec->sh_offset + sec->sh_size)); + const Elf_Rel *rel_begin(const Elf_Shdr *sec) const { + if (sec->sh_entsize != sizeof(Elf_Rel)) + report_fatal_error("Invalid relocation entry size"); + return reinterpret_cast<const Elf_Rel *>(base() + sec->sh_offset); } - Elf_Rel_Iter rel_begin(const Elf_Shdr *sec) const { - return Elf_Rel_Iter(sec->sh_entsize, - (const char *)(base() + sec->sh_offset)); + const Elf_Rel *rel_end(const Elf_Shdr *sec) const { + uint64_t Size = sec->sh_size; + if (Size % sizeof(Elf_Rel)) + report_fatal_error("Invalid relocation table size"); + return rel_begin(sec) + Size / sizeof(Elf_Rel); } - Elf_Rel_Iter rel_end(const Elf_Shdr *sec) const { - return Elf_Rel_Iter(sec->sh_entsize, - (const char *)(base() + sec->sh_offset + sec->sh_size)); + typedef iterator_range<const Elf_Rel *> Elf_Rel_Range; + Elf_Rel_Range rels(const Elf_Shdr *Sec) const { + return make_range(rel_begin(Sec), rel_end(Sec)); } /// \brief Iterate over program header table. - typedef ELFEntityIterator<const Elf_Phdr> Elf_Phdr_Iter; + const Elf_Phdr *program_header_begin() const { + if (Header->e_phnum && Header->e_phentsize != sizeof(Elf_Phdr)) + report_fatal_error("Invalid program header size"); + return reinterpret_cast<const Elf_Phdr *>(base() + Header->e_phoff); + } - Elf_Phdr_Iter program_header_begin() const { - return Elf_Phdr_Iter(Header->e_phentsize, - (const char*)base() + Header->e_phoff); + const Elf_Phdr *program_header_end() const { + return program_header_begin() + Header->e_phnum; } - Elf_Phdr_Iter program_header_end() const { - return Elf_Phdr_Iter(Header->e_phentsize, - (const char*)base() + - Header->e_phoff + - (Header->e_phnum * Header->e_phentsize)); + typedef iterator_range<const Elf_Phdr *> Elf_Phdr_Range; + + const Elf_Phdr_Range program_headers() const { + return make_range(program_header_begin(), program_header_end()); } uint64_t getNumSections() const; uintX_t getStringTableIndex() const; - ELF::Elf64_Word getExtendedSymbolTableIndex(const Elf_Sym *symb) const; + uint32_t getExtendedSymbolTableIndex(const Elf_Sym *Sym, + const Elf_Shdr *SymTab, + ArrayRef<Elf_Word> ShndxTable) const; const Elf_Ehdr *getHeader() const { return Header; } - ErrorOr<const Elf_Shdr *> getSection(const Elf_Sym *symb) const; + ErrorOr<const Elf_Shdr *> getSection(const Elf_Sym *Sym, + const Elf_Shdr *SymTab, + ArrayRef<Elf_Word> ShndxTable) const; ErrorOr<const Elf_Shdr *> getSection(uint32_t Index) const; - const Elf_Sym *getSymbol(uint32_t index) const; - ErrorOr<StringRef> getStaticSymbolName(const Elf_Sym *Symb) const; - ErrorOr<StringRef> getDynamicSymbolName(const Elf_Sym *Symb) const; - ErrorOr<StringRef> getSymbolName(const Elf_Sym *Symb, bool IsDynamic) const; + const Elf_Sym *getSymbol(const Elf_Shdr *Sec, uint32_t Index) const { + return &*(symbol_begin(Sec) + Index); + } ErrorOr<StringRef> getSectionName(const Elf_Shdr *Section) const; + template <typename T> + ErrorOr<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr *Sec) const; ErrorOr<ArrayRef<uint8_t> > getSectionContents(const Elf_Shdr *Sec) const; - StringRef getLoadName() const; }; typedef ELFFile<ELFType<support::little, false>> ELF32LEFile; @@ -385,118 +221,50 @@ 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>::LoadVersionDefs(const Elf_Shdr *sec) const { - unsigned vd_size = sec->sh_size; // Size of section in bytes - unsigned vd_count = sec->sh_info; // Number of Verdef entries - const char *sec_start = (const char*)base() + sec->sh_offset; - const char *sec_end = sec_start + vd_size; - // The first Verdef entry is at the start of the section. - const char *p = sec_start; - for (unsigned i = 0; i < vd_count; i++) { - if (p + sizeof(Elf_Verdef) > sec_end) - report_fatal_error("Section ended unexpectedly while scanning " - "version definitions."); - const Elf_Verdef *vd = reinterpret_cast<const Elf_Verdef *>(p); - if (vd->vd_version != ELF::VER_DEF_CURRENT) - report_fatal_error("Unexpected verdef version"); - size_t index = vd->vd_ndx & ELF::VERSYM_VERSION; - if (index >= VersionMap.size()) - VersionMap.resize(index + 1); - VersionMap[index] = VersionMapEntry(vd); - p += vd->vd_next; - } -} - -// Iterate through the versions needed section, and place each Elf_Vernaux -// in the VersionMap according to its index. template <class ELFT> -void ELFFile<ELFT>::LoadVersionNeeds(const Elf_Shdr *sec) const { - unsigned vn_size = sec->sh_size; // Size of section in bytes - unsigned vn_count = sec->sh_info; // Number of Verneed entries - const char *sec_start = (const char *)base() + sec->sh_offset; - const char *sec_end = sec_start + vn_size; - // The first Verneed entry is at the start of the section. - const char *p = sec_start; - for (unsigned i = 0; i < vn_count; i++) { - if (p + sizeof(Elf_Verneed) > sec_end) - report_fatal_error("Section ended unexpectedly while scanning " - "version needed records."); - const Elf_Verneed *vn = reinterpret_cast<const Elf_Verneed *>(p); - if (vn->vn_version != ELF::VER_NEED_CURRENT) - report_fatal_error("Unexpected verneed version"); - // Iterate through the Vernaux entries - const char *paux = p + vn->vn_aux; - for (unsigned j = 0; j < vn->vn_cnt; j++) { - if (paux + sizeof(Elf_Vernaux) > sec_end) - report_fatal_error("Section ended unexpected while scanning auxiliary " - "version needed records."); - const Elf_Vernaux *vna = reinterpret_cast<const Elf_Vernaux *>(paux); - size_t index = vna->vna_other & ELF::VERSYM_VERSION; - if (index >= VersionMap.size()) - VersionMap.resize(index + 1); - VersionMap[index] = VersionMapEntry(vna); - paux += vna->vna_next; - } - p += vn->vn_next; - } -} - -template <class ELFT> -void ELFFile<ELFT>::LoadVersionMap() const { - // If there is no dynamic symtab or version table, there is nothing to do. - if (!DotDynSymSec || !dot_gnu_version_sec) - return; - - // Has the VersionMap already been loaded? - if (VersionMap.size() > 0) - return; - - // The first two version indexes are reserved. - // Index 0 is LOCAL, index 1 is GLOBAL. - VersionMap.push_back(VersionMapEntry()); - VersionMap.push_back(VersionMapEntry()); - - if (dot_gnu_version_d_sec) - LoadVersionDefs(dot_gnu_version_d_sec); +uint32_t ELFFile<ELFT>::getExtendedSymbolTableIndex( + const Elf_Sym *Sym, const Elf_Shdr *SymTab, + ArrayRef<Elf_Word> ShndxTable) const { + assert(Sym->st_shndx == ELF::SHN_XINDEX); + unsigned Index = Sym - symbol_begin(SymTab); - if (dot_gnu_version_r_sec) - LoadVersionNeeds(dot_gnu_version_r_sec); -} - -template <class ELFT> -ELF::Elf64_Word -ELFFile<ELFT>::getExtendedSymbolTableIndex(const Elf_Sym *symb) const { - assert(symb->st_shndx == ELF::SHN_XINDEX); - return ExtendedSymbolTable.lookup(symb); + // The size of the table was checked in getSHNDXTable. + return ShndxTable[Index]; } template <class ELFT> ErrorOr<const typename ELFFile<ELFT>::Elf_Shdr *> -ELFFile<ELFT>::getSection(const Elf_Sym *symb) const { - uint32_t Index = symb->st_shndx; +ELFFile<ELFT>::getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, + ArrayRef<Elf_Word> ShndxTable) const { + uint32_t Index = Sym->st_shndx; if (Index == ELF::SHN_XINDEX) - return getSection(ExtendedSymbolTable.lookup(symb)); + return getSection(getExtendedSymbolTableIndex(Sym, SymTab, ShndxTable)); + if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE) return nullptr; - return getSection(symb->st_shndx); + return getSection(Sym->st_shndx); } template <class ELFT> -const typename ELFFile<ELFT>::Elf_Sym * -ELFFile<ELFT>::getSymbol(uint32_t Index) const { - return &*(symbol_begin() + Index); +template <typename T> +ErrorOr<ArrayRef<T>> +ELFFile<ELFT>::getSectionContentsAsArray(const Elf_Shdr *Sec) const { + uintX_t Offset = Sec->sh_offset; + uintX_t Size = Sec->sh_size; + + if (Size % sizeof(T)) + return object_error::parse_failed; + if (Offset + Size > Buf.size()) + return object_error::parse_failed; + + const T *Start = reinterpret_cast<const T *>(base() + Offset); + return makeArrayRef(Start, Size / sizeof(T)); } template <class ELFT> -ErrorOr<ArrayRef<uint8_t> > +ErrorOr<ArrayRef<uint8_t>> ELFFile<ELFT>::getSectionContents(const Elf_Shdr *Sec) const { - if (Sec->sh_offset + Sec->sh_size > Buf.size()) - return object_error::parse_failed; - const uint8_t *Start = base() + Sec->sh_offset; - return makeArrayRef(Start, Sec->sh_size); + return getSectionContentsAsArray<uint8_t>(Sec); } template <class ELFT> @@ -536,18 +304,13 @@ void ELFFile<ELFT>::getRelocationTypeName(uint32_t Type, } template <class ELFT> -template <class RelT> -std::pair<const typename ELFFile<ELFT>::Elf_Shdr *, - 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(nullptr, nullptr); - ErrorOr<const Elf_Shdr *> SymTableOrErr = getSection(Sec->sh_link); - if (std::error_code EC = SymTableOrErr.getError()) - report_fatal_error(EC.message()); - const Elf_Shdr *SymTable = *SymTableOrErr; - return std::make_pair( - SymTable, getEntry<Elf_Sym>(SymTable, Rel->getSymbol(isMips64EL()))); +const typename ELFFile<ELFT>::Elf_Sym * +ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel *Rel, + const Elf_Shdr *SymTab) const { + uint32_t Index = Rel->getSymbol(isMips64EL()); + if (Index == 0) + return nullptr; + return getEntry<Elf_Sym>(SymTab, Index); } template <class ELFT> @@ -584,10 +347,8 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC) Header = reinterpret_cast<const Elf_Ehdr *>(base()); - if (Header->e_shoff == 0) { - scanDynamicTable(); + if (Header->e_shoff == 0) return; - } const uint64_t SectionTableOffset = Header->e_shoff; @@ -608,185 +369,25 @@ ELFFile<ELFT>::ELFFile(StringRef Object, std::error_code &EC) return; } - // Scan sections for special sections. - - for (const Elf_Shdr &Sec : sections()) { - switch (Sec.sh_type) { - case ELF::SHT_HASH: - if (HashTable) { - EC = object_error::parse_failed; - return; - } - HashTable = reinterpret_cast<const Elf_Hash *>(base() + Sec.sh_offset); - break; - case ELF::SHT_SYMTAB_SHNDX: - if (SymbolTableSectionHeaderIndex) { - // More than one .symtab_shndx! - EC = object_error::parse_failed; - return; - } - SymbolTableSectionHeaderIndex = &Sec; - break; - case ELF::SHT_SYMTAB: { - if (dot_symtab_sec) { - // More than one .symtab! - EC = object_error::parse_failed; - return; - } - dot_symtab_sec = &Sec; - ErrorOr<const Elf_Shdr *> SectionOrErr = getSection(Sec.sh_link); - if ((EC = SectionOrErr.getError())) - return; - ErrorOr<StringRef> SymtabOrErr = getStringTable(*SectionOrErr); - if ((EC = SymtabOrErr.getError())) - return; - DotStrtab = *SymtabOrErr; - } break; - case ELF::SHT_DYNSYM: { - if (DotDynSymSec) { - // More than one .dynsym! - EC = object_error::parse_failed; - return; - } - DotDynSymSec = &Sec; - ErrorOr<const Elf_Shdr *> SectionOrErr = getSection(Sec.sh_link); - if ((EC = SectionOrErr.getError())) - return; - ErrorOr<StringRef> SymtabOrErr = getStringTable(*SectionOrErr); - if ((EC = SymtabOrErr.getError())) - return; - DynStrRegion.Addr = SymtabOrErr->data(); - DynStrRegion.Size = SymtabOrErr->size(); - DynStrRegion.EntSize = 1; - break; - } - case ELF::SHT_DYNAMIC: - if (DynamicRegion.Addr) { - // More than one .dynamic! - EC = object_error::parse_failed; - return; - } - DynamicRegion.Addr = base() + Sec.sh_offset; - DynamicRegion.Size = Sec.sh_size; - DynamicRegion.EntSize = Sec.sh_entsize; - break; - case ELF::SHT_GNU_versym: - if (dot_gnu_version_sec != nullptr) { - // More than one .gnu.version section! - EC = object_error::parse_failed; - return; - } - dot_gnu_version_sec = &Sec; - break; - case ELF::SHT_GNU_verdef: - 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 != nullptr) { - // More than one .gnu.version_r section! - EC = object_error::parse_failed; - return; - } - dot_gnu_version_r_sec = &Sec; - break; - } - } - // Get string table sections. - ErrorOr<const Elf_Shdr *> StrTabSecOrErr = getSection(getStringTableIndex()); - if ((EC = StrTabSecOrErr.getError())) - return; - - ErrorOr<StringRef> SymtabOrErr = getStringTable(*StrTabSecOrErr); - if ((EC = SymtabOrErr.getError())) - return; - DotShstrtab = *SymtabOrErr; + uintX_t StringTableIndex = getStringTableIndex(); + if (StringTableIndex) { + ErrorOr<const Elf_Shdr *> StrTabSecOrErr = getSection(StringTableIndex); + if ((EC = StrTabSecOrErr.getError())) + return; - // Build symbol name side-mapping if there is one. - if (SymbolTableSectionHeaderIndex) { - const Elf_Word *ShndxTable = reinterpret_cast<const Elf_Word*>(base() + - SymbolTableSectionHeaderIndex->sh_offset); - for (const Elf_Sym &S : symbols()) { - if (*ShndxTable != ELF::SHN_UNDEF) - ExtendedSymbolTable[&S] = *ShndxTable; - ++ShndxTable; - } + ErrorOr<StringRef> StringTableOrErr = getStringTable(*StrTabSecOrErr); + if ((EC = StringTableOrErr.getError())) + return; + DotShstrtab = *StringTableOrErr; } - scanDynamicTable(); - EC = std::error_code(); } template <class ELFT> -void ELFFile<ELFT>::scanDynamicTable() { - // Build load-address to file-offset map. - typedef IntervalMap< - uintX_t, uintptr_t, - IntervalMapImpl::NodeSizer<uintX_t, uintptr_t>::LeafSize, - IntervalMapHalfOpenInfo<uintX_t>> LoadMapT; - typename LoadMapT::Allocator Alloc; - // Allocate the IntervalMap on the heap to work around MSVC bug where the - // stack doesn't get realigned despite LoadMap having alignment 8 (PR24113). - std::unique_ptr<LoadMapT> LoadMap(new LoadMapT(Alloc)); - - for (Elf_Phdr_Iter PhdrI = program_header_begin(), - PhdrE = program_header_end(); - PhdrI != PhdrE; ++PhdrI) { - if (PhdrI->p_type == ELF::PT_DYNAMIC) { - DynamicRegion.Addr = base() + PhdrI->p_offset; - DynamicRegion.Size = PhdrI->p_filesz; - DynamicRegion.EntSize = sizeof(Elf_Dyn); - continue; - } - if (PhdrI->p_type != ELF::PT_LOAD) - continue; - if (PhdrI->p_filesz == 0) - continue; - LoadMap->insert(PhdrI->p_vaddr, PhdrI->p_vaddr + PhdrI->p_filesz, - PhdrI->p_offset); - } - - auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * { - auto I = LoadMap->find(VAddr); - if (I == LoadMap->end()) - return nullptr; - return this->base() + I.value() + (VAddr - I.start()); - }; - - for (Elf_Dyn_Iter DynI = dynamic_table_begin(), DynE = dynamic_table_end(); - DynI != DynE; ++DynI) { - switch (DynI->d_tag) { - case ELF::DT_HASH: - if (HashTable) - continue; - HashTable = - reinterpret_cast<const Elf_Hash *>(toMappedAddr(DynI->getPtr())); - break; - case ELF::DT_STRTAB: - if (!DynStrRegion.Addr) - DynStrRegion.Addr = toMappedAddr(DynI->getPtr()); - break; - case ELF::DT_STRSZ: - if (!DynStrRegion.Size) - DynStrRegion.Size = DynI->getVal(); - break; - case ELF::DT_RELA: - if (!DynRelaRegion.Addr) - DynRelaRegion.Addr = toMappedAddr(DynI->getPtr()); - break; - case ELF::DT_RELASZ: - DynRelaRegion.Size = DynI->getVal(); - break; - case ELF::DT_RELAENT: - DynRelaRegion.EntSize = DynI->getVal(); - } - } +static bool compareAddr(uint64_t VAddr, const Elf_Phdr_Impl<ELFT> *Phdr) { + return VAddr < Phdr->p_vaddr; } template <class ELFT> @@ -803,64 +404,31 @@ const typename ELFFile<ELFT>::Elf_Shdr *ELFFile<ELFT>::section_end() const { } template <class ELFT> -const typename ELFFile<ELFT>::Elf_Sym *ELFFile<ELFT>::symbol_begin() const { - if (!dot_symtab_sec) +ErrorOr<const typename ELFFile<ELFT>::Elf_Dyn *> +ELFFile<ELFT>::dynamic_table_begin(const Elf_Phdr *Phdr) const { + if (!Phdr) return nullptr; - if (dot_symtab_sec->sh_entsize != sizeof(Elf_Sym)) - report_fatal_error("Invalid symbol size"); - return reinterpret_cast<const Elf_Sym *>(base() + dot_symtab_sec->sh_offset); + assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header"); + uintX_t Offset = Phdr->p_offset; + if (Offset > Buf.size()) + return object_error::parse_failed; + return reinterpret_cast<const Elf_Dyn *>(base() + Offset); } template <class ELFT> -const typename ELFFile<ELFT>::Elf_Sym *ELFFile<ELFT>::symbol_end() const { - if (!dot_symtab_sec) +ErrorOr<const typename ELFFile<ELFT>::Elf_Dyn *> +ELFFile<ELFT>::dynamic_table_end(const Elf_Phdr *Phdr) const { + if (!Phdr) return nullptr; - return reinterpret_cast<const Elf_Sym *>(base() + dot_symtab_sec->sh_offset + - dot_symtab_sec->sh_size); -} - -template <class ELFT> -typename ELFFile<ELFT>::Elf_Dyn_Iter -ELFFile<ELFT>::dynamic_table_begin() const { - if (DynamicRegion.Addr) - return Elf_Dyn_Iter(DynamicRegion.EntSize, - (const char *)DynamicRegion.Addr); - return Elf_Dyn_Iter(0, nullptr); -} - -template <class ELFT> -typename ELFFile<ELFT>::Elf_Dyn_Iter -ELFFile<ELFT>::dynamic_table_end(bool NULLEnd) const { - if (!DynamicRegion.Addr) - return Elf_Dyn_Iter(0, nullptr); - Elf_Dyn_Iter Ret(DynamicRegion.EntSize, - (const char *)DynamicRegion.Addr + DynamicRegion.Size); - - if (NULLEnd) { - Elf_Dyn_Iter Start = dynamic_table_begin(); - while (Start != Ret && Start->getTag() != ELF::DT_NULL) - ++Start; - - // Include the DT_NULL. - if (Start != Ret) - ++Start; - Ret = Start; - } - return Ret; -} - -template <class ELFT> -StringRef ELFFile<ELFT>::getLoadName() const { - if (!dt_soname) { - dt_soname = ""; - // Find the DT_SONAME entry - for (const auto &Entry : dynamic_table()) - if (Entry.getTag() == ELF::DT_SONAME) { - dt_soname = getDynamicString(Entry.getVal()); - break; - } - } - return dt_soname; + assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header"); + uintX_t Size = Phdr->p_filesz; + if (Size % sizeof(Elf_Dyn)) + return object_error::elf_invalid_dynamic_table_size; + // FIKME: Check for overflow? + uintX_t End = Phdr->p_offset + Size; + if (End > Buf.size()) + return object_error::parse_failed; + return reinterpret_cast<const Elf_Dyn *>(base() + End); } template <class ELFT> @@ -908,127 +476,52 @@ ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section) const { } template <class ELFT> -const char *ELFFile<ELFT>::getDynamicString(uintX_t Offset) const { - if (Offset >= DynStrRegion.Size) - return nullptr; - return (const char *)DynStrRegion.Addr + Offset; -} - -template <class ELFT> -ErrorOr<StringRef> -ELFFile<ELFT>::getStaticSymbolName(const Elf_Sym *Symb) const { - return Symb->getName(DotStrtab); +ErrorOr<ArrayRef<typename ELFFile<ELFT>::Elf_Word>> +ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section) const { + assert(Section.sh_type == ELF::SHT_SYMTAB_SHNDX); + const Elf_Word *ShndxTableBegin = + reinterpret_cast<const Elf_Word *>(base() + Section.sh_offset); + uintX_t Size = Section.sh_size; + if (Size % sizeof(uint32_t)) + return object_error::parse_failed; + uintX_t NumSymbols = Size / sizeof(uint32_t); + const Elf_Word *ShndxTableEnd = ShndxTableBegin + NumSymbols; + if (reinterpret_cast<const char *>(ShndxTableEnd) > Buf.end()) + return object_error::parse_failed; + ErrorOr<const Elf_Shdr *> SymTableOrErr = getSection(Section.sh_link); + if (std::error_code EC = SymTableOrErr.getError()) + return EC; + const Elf_Shdr &SymTable = **SymTableOrErr; + if (SymTable.sh_type != ELF::SHT_SYMTAB && + SymTable.sh_type != ELF::SHT_DYNSYM) + return object_error::parse_failed; + if (NumSymbols != (SymTable.sh_size / sizeof(Elf_Sym))) + return object_error::parse_failed; + return makeArrayRef(ShndxTableBegin, ShndxTableEnd); } template <class ELFT> ErrorOr<StringRef> -ELFFile<ELFT>::getDynamicSymbolName(const Elf_Sym *Symb) const { - return StringRef(getDynamicString(Symb->st_name)); -} - -template <class ELFT> -ErrorOr<StringRef> ELFFile<ELFT>::getSymbolName(const Elf_Sym *Symb, - bool IsDynamic) const { - if (IsDynamic) - return getDynamicSymbolName(Symb); - return getStaticSymbolName(Symb); +ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec) const { + if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM) + return object_error::parse_failed; + ErrorOr<const Elf_Shdr *> SectionOrErr = getSection(Sec.sh_link); + if (std::error_code EC = SectionOrErr.getError()) + return EC; + return getStringTable(*SectionOrErr); } template <class ELFT> ErrorOr<StringRef> ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section) const { uint32_t Offset = Section->sh_name; + if (Offset == 0) + return StringRef(); if (Offset >= DotShstrtab.size()) return object_error::parse_failed; return StringRef(DotShstrtab.data() + Offset); } -template <class ELFT> -ErrorOr<StringRef> ELFFile<ELFT>::getSymbolVersion(const Elf_Shdr *section, - const Elf_Sym *symb, - bool &IsDefault) const { - StringRef StrTab; - if (section) { - ErrorOr<StringRef> StrTabOrErr = getStringTable(section); - if (std::error_code EC = StrTabOrErr.getError()) - return EC; - StrTab = *StrTabOrErr; - } - // Handle non-dynamic symbols. - if (section != DotDynSymSec && 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. - ErrorOr<StringRef> SymName = symb->getName(StrTab); - if (!SymName) - return SymName; - StringRef Name = *SymName; - size_t atpos = Name.find('@'); - if (atpos == StringRef::npos) { - IsDefault = false; - return StringRef(""); - } - ++atpos; - if (atpos < Name.size() && Name[atpos] == '@') { - IsDefault = true; - ++atpos; - } else { - IsDefault = false; - } - return Name.substr(atpos); - } - - // This is a dynamic symbol. Look in the GNU symbol version table. - if (!dot_gnu_version_sec) { - // No version table. - IsDefault = false; - return StringRef(""); - } - - // Determine the position in the symbol table of this entry. - size_t entry_index = - (reinterpret_cast<uintptr_t>(symb) - DotDynSymSec->sh_offset - - reinterpret_cast<uintptr_t>(base())) / - sizeof(Elf_Sym); - - // Get the corresponding version index entry - const Elf_Versym *vs = getEntry<Elf_Versym>(dot_gnu_version_sec, entry_index); - size_t version_index = vs->vs_index & ELF::VERSYM_VERSION; - - // Special markers for unversioned symbols. - if (version_index == ELF::VER_NDX_LOCAL || - version_index == ELF::VER_NDX_GLOBAL) { - IsDefault = false; - return StringRef(""); - } - - // Lookup this symbol in the version table - LoadVersionMap(); - if (version_index >= VersionMap.size() || VersionMap[version_index].isNull()) - return object_error::parse_failed; - const VersionMapEntry &entry = VersionMap[version_index]; - - // Get the version name string - size_t name_offset; - if (entry.isVerdef()) { - // The first Verdaux entry holds the name. - name_offset = entry.getVerdef()->getAux()->vda_name; - } else { - name_offset = entry.getVernaux()->vna_name; - } - - // Set IsDefault - if (entry.isVerdef()) { - IsDefault = !(vs->vs_index & ELF::VERSYM_HIDDEN); - } else { - IsDefault = false; - } - - if (name_offset >= DynStrRegion.Size) - return object_error::parse_failed; - return StringRef(getDynamicString(name_offset)); -} - /// This function returns the hash value for a symbol in the .dynsym section /// Name of the API remains consistent as specified in the libelf /// REF : http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#hash diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index 6e8ace427a20..5823848aaacb 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -189,11 +189,13 @@ public: typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela; typedef typename ELFFile<ELFT>::Elf_Dyn Elf_Dyn; - typedef typename ELFFile<ELFT>::Elf_Dyn_Iter Elf_Dyn_Iter; - protected: ELFFile<ELFT> EF; + const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. + const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section. + ArrayRef<Elf_Word> ShndxTable; + void moveSymbolNext(DataRefImpl &Symb) const override; ErrorOr<StringRef> getSymbolName(DataRefImpl Symb) const override; ErrorOr<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; @@ -204,9 +206,9 @@ protected: uint8_t getSymbolOther(DataRefImpl Symb) const override; uint8_t getSymbolELFType(DataRefImpl Symb) const override; SymbolRef::Type getSymbolType(DataRefImpl Symb) const override; - section_iterator getSymbolSection(const Elf_Sym *Symb) const; - std::error_code getSymbolSection(DataRefImpl Symb, - section_iterator &Res) const override; + ErrorOr<section_iterator> getSymbolSection(const Elf_Sym *Symb, + const Elf_Shdr *SymTab) const; + ErrorOr<section_iterator> getSymbolSection(DataRefImpl Symb) const override; void moveSectionNext(DataRefImpl &Sec) const override; std::error_code getSectionName(DataRefImpl Sec, @@ -240,10 +242,6 @@ protected: return *EF.getSection(Rel.d.a); } - const Elf_Sym *toELFSymIter(DataRefImpl Sym) const { - return EF.template getEntry<Elf_Sym>(Sym.d.a, Sym.d.b); - } - DataRefImpl toDRI(const Elf_Shdr *SymTable, unsigned SymbolNum) const { DataRefImpl DRI; if (!SymTable) { @@ -273,9 +271,9 @@ protected: return DRI; } - DataRefImpl toDRI(Elf_Dyn_Iter Dyn) const { + DataRefImpl toDRI(const Elf_Dyn *Dyn) const { DataRefImpl DRI; - DRI.p = reinterpret_cast<uintptr_t>(Dyn.get()); + DRI.p = reinterpret_cast<uintptr_t>(Dyn); return DRI; } @@ -304,7 +302,13 @@ public: const Elf_Rel *getRel(DataRefImpl Rel) const; const Elf_Rela *getRela(DataRefImpl Rela) const; - const Elf_Sym *getSymbol(DataRefImpl Symb) const; + const Elf_Sym *getSymbol(DataRefImpl Sym) const { + return EF.template getEntry<Elf_Sym>(Sym.d.a, Sym.d.b); + } + + const Elf_Shdr *getSection(DataRefImpl Sec) const { + return reinterpret_cast<const Elf_Shdr *>(Sec.p); + } basic_symbol_iterator symbol_begin_impl() const override; basic_symbol_iterator symbol_end_impl() const override; @@ -320,7 +324,6 @@ public: uint8_t getBytesInAddress() const override; StringRef getFileFormatName() const override; unsigned getArch() const override; - StringRef getLoadName() const; std::error_code getPlatformFlags(unsigned &Result) const override { Result = EF.getHeader()->e_flags; @@ -352,7 +355,7 @@ void ELFObjectFile<ELFT>::moveSymbolNext(DataRefImpl &Sym) const { template <class ELFT> ErrorOr<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { - const Elf_Sym *ESym = toELFSymIter(Sym); + const Elf_Sym *ESym = getSymbol(Sym); const Elf_Shdr *SymTableSec = *EF.getSection(Sym.d.a); const Elf_Shdr *StringTableSec = *EF.getSection(SymTableSec->sh_link); StringRef SymTable = *EF.getStringTable(StringTableSec); @@ -361,12 +364,12 @@ ErrorOr<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { template <class ELFT> uint64_t ELFObjectFile<ELFT>::getSectionFlags(DataRefImpl Sec) const { - return toELFShdrIter(Sec)->sh_flags; + return getSection(Sec)->sh_flags; } template <class ELFT> uint32_t ELFObjectFile<ELFT>::getSectionType(DataRefImpl Sec) const { - return toELFShdrIter(Sec)->sh_type; + return getSection(Sec)->sh_type; } template <class ELFT> @@ -398,9 +401,11 @@ ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const { } const Elf_Ehdr *Header = EF.getHeader(); + const Elf_Shdr *SymTab = *EF.getSection(Symb.d.a); if (Header->e_type == ELF::ET_REL) { - ErrorOr<const Elf_Shdr *> SectionOrErr = EF.getSection(ESym); + ErrorOr<const Elf_Shdr *> SectionOrErr = + EF.getSection(ESym, SymTab, ShndxTable); if (std::error_code EC = SectionOrErr.getError()) return EC; const Elf_Shdr *Section = *SectionOrErr; @@ -413,7 +418,7 @@ ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const { template <class ELFT> uint32_t ELFObjectFile<ELFT>::getSymbolAlignment(DataRefImpl Symb) const { - const Elf_Sym *Sym = toELFSymIter(Symb); + const Elf_Sym *Sym = getSymbol(Symb); if (Sym->st_shndx == ELF::SHN_COMMON) return Sym->st_value; return 0; @@ -421,22 +426,22 @@ uint32_t ELFObjectFile<ELFT>::getSymbolAlignment(DataRefImpl Symb) const { template <class ELFT> uint64_t ELFObjectFile<ELFT>::getSymbolSize(DataRefImpl Sym) const { - return toELFSymIter(Sym)->st_size; + return getSymbol(Sym)->st_size; } template <class ELFT> uint64_t ELFObjectFile<ELFT>::getCommonSymbolSizeImpl(DataRefImpl Symb) const { - return toELFSymIter(Symb)->st_size; + return getSymbol(Symb)->st_size; } template <class ELFT> uint8_t ELFObjectFile<ELFT>::getSymbolOther(DataRefImpl Symb) const { - return toELFSymIter(Symb)->st_other; + return getSymbol(Symb)->st_other; } template <class ELFT> uint8_t ELFObjectFile<ELFT>::getSymbolELFType(DataRefImpl Symb) const { - return toELFSymIter(Symb)->getType(); + return getSymbol(Symb)->getType(); } template <class ELFT> @@ -463,7 +468,7 @@ SymbolRef::Type ELFObjectFile<ELFT>::getSymbolType(DataRefImpl Symb) const { template <class ELFT> uint32_t ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const { - const Elf_Sym *ESym = toELFSymIter(Sym); + const Elf_Sym *ESym = getSymbol(Sym); uint32_t Result = SymbolRef::SF_None; @@ -477,7 +482,8 @@ uint32_t ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const { Result |= SymbolRef::SF_Absolute; if (ESym->getType() == ELF::STT_FILE || ESym->getType() == ELF::STT_SECTION || - ESym == EF.symbol_begin() || ESym == EF.dynamic_symbol_begin()) + ESym == EF.symbol_begin(DotSymtabSec) || + ESym == EF.symbol_begin(DotDynSymSec)) Result |= SymbolRef::SF_FormatSpecific; if (EF.getHeader()->e_machine == ELF::EM_ARM) { @@ -505,11 +511,12 @@ uint32_t ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const { } template <class ELFT> -section_iterator -ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym) const { - ErrorOr<const Elf_Shdr *> ESecOrErr = EF.getSection(ESym); +ErrorOr<section_iterator> +ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym, + const Elf_Shdr *SymTab) const { + ErrorOr<const Elf_Shdr *> ESecOrErr = EF.getSection(ESym, SymTab, ShndxTable); if (std::error_code EC = ESecOrErr.getError()) - report_fatal_error(EC.message()); + return EC; const Elf_Shdr *ESec = *ESecOrErr; if (!ESec) @@ -521,23 +528,23 @@ ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym) const { } template <class ELFT> -std::error_code -ELFObjectFile<ELFT>::getSymbolSection(DataRefImpl Symb, - section_iterator &Res) const { - Res = getSymbolSection(getSymbol(Symb)); - return std::error_code(); +ErrorOr<section_iterator> +ELFObjectFile<ELFT>::getSymbolSection(DataRefImpl Symb) const { + const Elf_Sym *Sym = getSymbol(Symb); + const Elf_Shdr *SymTab = *EF.getSection(Symb.d.a); + return getSymbolSection(Sym, SymTab); } template <class ELFT> void ELFObjectFile<ELFT>::moveSectionNext(DataRefImpl &Sec) const { - const Elf_Shdr *ESec = toELFShdrIter(Sec); + const Elf_Shdr *ESec = getSection(Sec); Sec = toDRI(++ESec); } template <class ELFT> std::error_code ELFObjectFile<ELFT>::getSectionName(DataRefImpl Sec, StringRef &Result) const { - ErrorOr<StringRef> Name = EF.getSectionName(&*toELFShdrIter(Sec)); + ErrorOr<StringRef> Name = EF.getSectionName(&*getSection(Sec)); if (!Name) return Name.getError(); Result = *Name; @@ -546,50 +553,50 @@ std::error_code ELFObjectFile<ELFT>::getSectionName(DataRefImpl Sec, template <class ELFT> uint64_t ELFObjectFile<ELFT>::getSectionAddress(DataRefImpl Sec) const { - return toELFShdrIter(Sec)->sh_addr; + return getSection(Sec)->sh_addr; } template <class ELFT> uint64_t ELFObjectFile<ELFT>::getSectionSize(DataRefImpl Sec) const { - return toELFShdrIter(Sec)->sh_size; + return getSection(Sec)->sh_size; } template <class ELFT> std::error_code ELFObjectFile<ELFT>::getSectionContents(DataRefImpl Sec, StringRef &Result) const { - const Elf_Shdr *EShdr = toELFShdrIter(Sec); + const Elf_Shdr *EShdr = getSection(Sec); Result = StringRef((const char *)base() + EShdr->sh_offset, EShdr->sh_size); return std::error_code(); } template <class ELFT> uint64_t ELFObjectFile<ELFT>::getSectionAlignment(DataRefImpl Sec) const { - return toELFShdrIter(Sec)->sh_addralign; + return getSection(Sec)->sh_addralign; } template <class ELFT> bool ELFObjectFile<ELFT>::isSectionText(DataRefImpl Sec) const { - return toELFShdrIter(Sec)->sh_flags & ELF::SHF_EXECINSTR; + return getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR; } template <class ELFT> bool ELFObjectFile<ELFT>::isSectionData(DataRefImpl Sec) const { - const Elf_Shdr *EShdr = toELFShdrIter(Sec); + const Elf_Shdr *EShdr = getSection(Sec); return EShdr->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) && EShdr->sh_type == ELF::SHT_PROGBITS; } template <class ELFT> bool ELFObjectFile<ELFT>::isSectionBSS(DataRefImpl Sec) const { - const Elf_Shdr *EShdr = toELFShdrIter(Sec); + const Elf_Shdr *EShdr = getSection(Sec); return EShdr->sh_flags & (ELF::SHF_ALLOC | ELF::SHF_WRITE) && EShdr->sh_type == ELF::SHT_NOBITS; } template <class ELFT> bool ELFObjectFile<ELFT>::isSectionVirtual(DataRefImpl Sec) const { - return toELFShdrIter(Sec)->sh_type == ELF::SHT_NOBITS; + return getSection(Sec)->sh_type == ELF::SHT_NOBITS; } template <class ELFT> @@ -636,7 +643,7 @@ ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const { if (EF.getHeader()->e_type != ELF::ET_REL) return section_end(); - const Elf_Shdr *EShdr = toELFShdrIter(Sec); + const Elf_Shdr *EShdr = getSection(Sec); uintX_t Type = EShdr->sh_type; if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA) return section_end(); @@ -668,9 +675,9 @@ ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const { bool IsDyn = Rel.d.b & 1; DataRefImpl SymbolData; if (IsDyn) - SymbolData = toDRI(EF.getDotDynSymSec(), symbolIdx); + SymbolData = toDRI(DotDynSymSec, symbolIdx); else - SymbolData = toDRI(EF.getDotSymtabSec(), symbolIdx); + SymbolData = toDRI(DotSymtabSec, symbolIdx); return symbol_iterator(SymbolRef(SymbolData, this)); } @@ -715,12 +722,6 @@ ELFObjectFile<ELFT>::getRelocationAddend(DataRefImpl Rel) const { } template <class ELFT> -const typename ELFFile<ELFT>::Elf_Sym * -ELFObjectFile<ELFT>::getSymbol(DataRefImpl Symb) const { - return &*toELFSymIter(Symb); -} - -template <class ELFT> const typename ELFObjectFile<ELFT>::Elf_Rel * ELFObjectFile<ELFT>::getRel(DataRefImpl Rel) const { assert(getRelSection(Rel)->sh_type == ELF::SHT_REL); @@ -737,21 +738,51 @@ ELFObjectFile<ELFT>::getRela(DataRefImpl Rela) const { template <class ELFT> ELFObjectFile<ELFT>::ELFObjectFile(MemoryBufferRef Object, std::error_code &EC) : ELFObjectFileBase( - getELFType(static_cast<endianness>(ELFT::TargetEndianness) == - support::little, - ELFT::Is64Bits), + getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits), Object), - EF(Data.getBuffer(), EC) {} + EF(Data.getBuffer(), EC) { + if (EC) + return; + for (const Elf_Shdr &Sec : EF.sections()) { + switch (Sec.sh_type) { + case ELF::SHT_DYNSYM: { + if (DotDynSymSec) { + // More than one .dynsym! + EC = object_error::parse_failed; + return; + } + DotDynSymSec = &Sec; + break; + } + case ELF::SHT_SYMTAB: { + if (DotSymtabSec) { + // More than one .dynsym! + EC = object_error::parse_failed; + return; + } + DotSymtabSec = &Sec; + break; + } + case ELF::SHT_SYMTAB_SHNDX: { + ErrorOr<ArrayRef<Elf_Word>> TableOrErr = EF.getSHNDXTable(Sec); + if ((EC = TableOrErr.getError())) + return; + ShndxTable = *TableOrErr; + break; + } + } + } +} template <class ELFT> basic_symbol_iterator ELFObjectFile<ELFT>::symbol_begin_impl() const { - DataRefImpl Sym = toDRI(EF.getDotSymtabSec(), 0); + DataRefImpl Sym = toDRI(DotSymtabSec, 0); return basic_symbol_iterator(SymbolRef(Sym, this)); } template <class ELFT> basic_symbol_iterator ELFObjectFile<ELFT>::symbol_end_impl() const { - const Elf_Shdr *SymTab = EF.getDotSymtabSec(); + const Elf_Shdr *SymTab = DotSymtabSec; if (!SymTab) return symbol_begin_impl(); DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym)); @@ -760,13 +791,13 @@ basic_symbol_iterator ELFObjectFile<ELFT>::symbol_end_impl() const { template <class ELFT> elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_begin() const { - DataRefImpl Sym = toDRI(EF.getDotDynSymSec(), 0); + DataRefImpl Sym = toDRI(DotDynSymSec, 0); return symbol_iterator(SymbolRef(Sym, this)); } template <class ELFT> elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_end() const { - const Elf_Shdr *SymTab = EF.getDotDynSymSec(); + const Elf_Shdr *SymTab = DotDynSymSec; DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym)); return basic_symbol_iterator(SymbolRef(Sym, this)); } @@ -782,19 +813,6 @@ section_iterator ELFObjectFile<ELFT>::section_end() const { } template <class ELFT> -StringRef ELFObjectFile<ELFT>::getLoadName() const { - Elf_Dyn_Iter DI = EF.dynamic_table_begin(); - Elf_Dyn_Iter DE = EF.dynamic_table_end(); - - while (DI != DE && DI->getTag() != ELF::DT_SONAME) - ++DI; - - if (DI != DE) - return EF.getDynamicString(DI->getVal()); - return ""; -} - -template <class ELFT> uint8_t ELFObjectFile<ELFT>::getBytesInAddress() const { return ELFT::Is64Bits ? 8 : 4; } @@ -807,10 +825,14 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const { switch (EF.getHeader()->e_machine) { case ELF::EM_386: return "ELF32-i386"; + case ELF::EM_IAMCU: + return "ELF32-iamcu"; case ELF::EM_X86_64: return "ELF32-x86-64"; case ELF::EM_ARM: return (IsLittleEndian ? "ELF32-arm-little" : "ELF32-arm-big"); + case ELF::EM_AVR: + return "ELF32-avr"; case ELF::EM_HEXAGON: return "ELF32-hexagon"; case ELF::EM_MIPS: @@ -853,6 +875,7 @@ unsigned ELFObjectFile<ELFT>::getArch() const { bool IsLittleEndian = ELFT::TargetEndianness == support::little; switch (EF.getHeader()->e_machine) { case ELF::EM_386: + case ELF::EM_IAMCU: return Triple::x86; case ELF::EM_X86_64: return Triple::x86_64; @@ -860,6 +883,8 @@ unsigned ELFObjectFile<ELFT>::getArch() const { return Triple::aarch64; case ELF::EM_ARM: return Triple::arm; + case ELF::EM_AVR: + return Triple::avr; case ELF::EM_HEXAGON: return Triple::hexagon; case ELF::EM_MIPS: diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index 27e987ba2852..07b312a7d77c 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -12,7 +12,6 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Object/Error.h" -#include "llvm/Support/DataTypes.h" #include "llvm/Support/ELF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/ErrorOr.h" @@ -307,14 +306,18 @@ struct Elf_Dyn_Base<ELFType<TargetEndianness, true>> { } d_un; }; -/// Elf_Dyn_Impl: This inherits from Elf_Dyn_Base, adding getters and setters. +/// Elf_Dyn_Impl: This inherits from Elf_Dyn_Base, adding getters. template <class ELFT> struct Elf_Dyn_Impl : Elf_Dyn_Base<ELFT> { using Elf_Dyn_Base<ELFT>::d_tag; using Elf_Dyn_Base<ELFT>::d_un; - int64_t getTag() const { return d_tag; } - uint64_t getVal() const { return d_un.d_val; } - uint64_t getPtr() const { return d_un.d_ptr; } + typedef typename std::conditional<ELFT::Is64Bits, + int64_t, int32_t>::type intX_t; + typedef typename std::conditional<ELFT::Is64Bits, + uint64_t, uint32_t>::type uintX_t; + intX_t getTag() const { return d_tag; } + uintX_t getVal() const { return d_un.d_val; } + uintX_t getPtr() const { return d_un.d_ptr; } }; // Elf_Rel: Elf Relocation @@ -481,6 +484,30 @@ struct Elf_Hash_Impl { } }; +// .gnu.hash section +template <class ELFT> +struct Elf_GnuHash_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word nbuckets; + Elf_Word symndx; + Elf_Word maskwords; + Elf_Word shift2; + + ArrayRef<Elf_Off> filter() const { + return ArrayRef<Elf_Off>(reinterpret_cast<const Elf_Off *>(&shift2 + 1), + maskwords); + } + + ArrayRef<Elf_Word> buckets() const { + return ArrayRef<Elf_Word>( + reinterpret_cast<const Elf_Word *>(filter().end()), nbuckets); + } + + ArrayRef<Elf_Word> values(unsigned DynamicSymCount) const { + return ArrayRef<Elf_Word>(buckets().end(), DynamicSymCount - symndx); + } +}; + // MIPS .reginfo section template <class ELFT> struct Elf_Mips_RegInfo; diff --git a/include/llvm/Object/Error.h b/include/llvm/Object/Error.h index aa320bb51a46..0f79a6ed0dd8 100644 --- a/include/llvm/Object/Error.h +++ b/include/llvm/Object/Error.h @@ -30,6 +30,7 @@ enum class object_error { string_table_non_null_end, invalid_section_index, bitcode_section_not_found, + elf_invalid_dynamic_table_size, macho_small_load_command, macho_load_segment_too_many_sections, macho_load_segment_too_small, diff --git a/include/llvm/Object/FunctionIndexObjectFile.h b/include/llvm/Object/FunctionIndexObjectFile.h new file mode 100644 index 000000000000..74b461dc7cc7 --- /dev/null +++ b/include/llvm/Object/FunctionIndexObjectFile.h @@ -0,0 +1,110 @@ +//===- FunctionIndexObjectFile.h - Function index file implementation -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file declares the FunctionIndexObjectFile template class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_FUNCTIONINDEXOBJECTFILE_H +#define LLVM_OBJECT_FUNCTIONINDEXOBJECTFILE_H + +#include "llvm/IR/DiagnosticInfo.h" +#include "llvm/Object/SymbolicFile.h" + +namespace llvm { +class FunctionInfoIndex; +class Module; + +namespace object { +class ObjectFile; + +/// This class is used to read just the function summary index related +/// sections out of the given object (which may contain a single module's +/// bitcode or be a combined index bitcode file). It builds a FunctionInfoIndex +/// object. +class FunctionIndexObjectFile : public SymbolicFile { + std::unique_ptr<FunctionInfoIndex> Index; + +public: + FunctionIndexObjectFile(MemoryBufferRef Object, + std::unique_ptr<FunctionInfoIndex> I); + ~FunctionIndexObjectFile() override; + + // TODO: Walk through FunctionMap entries for function symbols. + // However, currently these interfaces are not used by any consumers. + void moveSymbolNext(DataRefImpl &Symb) const override { + llvm_unreachable("not implemented"); + } + std::error_code printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const override { + llvm_unreachable("not implemented"); + return std::error_code(); + } + uint32_t getSymbolFlags(DataRefImpl Symb) const override { + llvm_unreachable("not implemented"); + return 0; + } + basic_symbol_iterator symbol_begin_impl() const override { + llvm_unreachable("not implemented"); + return basic_symbol_iterator(BasicSymbolRef()); + } + basic_symbol_iterator symbol_end_impl() const override { + llvm_unreachable("not implemented"); + return basic_symbol_iterator(BasicSymbolRef()); + } + + const FunctionInfoIndex &getIndex() const { + return const_cast<FunctionIndexObjectFile *>(this)->getIndex(); + } + FunctionInfoIndex &getIndex() { return *Index; } + std::unique_ptr<FunctionInfoIndex> takeIndex(); + + static inline bool classof(const Binary *v) { return v->isFunctionIndex(); } + + /// \brief Finds and returns bitcode embedded in the given object file, or an + /// error code if not found. + static ErrorOr<MemoryBufferRef> findBitcodeInObject(const ObjectFile &Obj); + + /// \brief Finds and returns bitcode in the given memory buffer (which may + /// be either a bitcode file or a native object file with embedded bitcode), + /// or an error code if not found. + static ErrorOr<MemoryBufferRef> + findBitcodeInMemBuffer(MemoryBufferRef Object); + + /// \brief Looks for function summary in the given memory buffer, + /// returns true if found, else false. + static bool + hasFunctionSummaryInMemBuffer(MemoryBufferRef Object, + DiagnosticHandlerFunction DiagnosticHandler); + + /// \brief Parse function index in the given memory buffer. + /// Return new FunctionIndexObjectFile instance containing parsed function + /// summary/index. + static ErrorOr<std::unique_ptr<FunctionIndexObjectFile>> + create(MemoryBufferRef Object, DiagnosticHandlerFunction DiagnosticHandler, + bool IsLazy = false); + + /// \brief Parse the function summary information for function with the + /// given name out of the given buffer. Parsed information is + /// stored on the index object saved in this object. + std::error_code + findFunctionSummaryInMemBuffer(MemoryBufferRef Object, + DiagnosticHandlerFunction DiagnosticHandler, + StringRef FunctionName); +}; +} + +/// Parse the function index out of an IR file and return the function +/// index object if found, or nullptr if not. +ErrorOr<std::unique_ptr<FunctionInfoIndex>> +getFunctionIndexForFile(StringRef Path, + DiagnosticHandlerFunction DiagnosticHandler); +} + +#endif diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 489ecef5c996..e02ce3b21416 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -100,7 +100,7 @@ private: }; typedef content_iterator<ExportEntry> export_iterator; -/// MachORebaseEntry encapsulates the current state in the decompression of +/// MachORebaseEntry encapsulates the current state in the decompression of /// rebasing opcodes. This allows you to iterate through the compressed table of /// rebasing using: /// for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable()) { @@ -116,7 +116,7 @@ public: bool operator==(const MachORebaseEntry &) const; void moveNext(); - + private: friend class MachOObjectFile; void moveToFirst(); @@ -210,8 +210,7 @@ public: uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; SymbolRef::Type getSymbolType(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; - std::error_code getSymbolSection(DataRefImpl Symb, - section_iterator &Res) const override; + ErrorOr<section_iterator> getSymbolSection(DataRefImpl Symb) const override; unsigned getSymbolSectionID(SymbolRef Symb) const; unsigned getSectionID(SectionRef Sec) const; @@ -423,6 +422,24 @@ public: return v->isMachO(); } + static uint32_t + getVersionMinMajor(MachO::version_min_command &C, bool SDK) { + uint32_t VersionOrSDK = (SDK) ? C.sdk : C.version; + return (VersionOrSDK >> 16) & 0xffff; + } + + static uint32_t + getVersionMinMinor(MachO::version_min_command &C, bool SDK) { + uint32_t VersionOrSDK = (SDK) ? C.sdk : C.version; + return (VersionOrSDK >> 8) & 0xff; + } + + static uint32_t + getVersionMinUpdate(MachO::version_min_command &C, bool SDK) { + uint32_t VersionOrSDK = (SDK) ? C.sdk : C.version; + return VersionOrSDK & 0xff; + } + private: uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; @@ -504,4 +521,3 @@ inline const ObjectFile *DiceRef::getObjectFile() const { } #endif - diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 8dd525626218..ce0c891ee0c2 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -100,8 +100,7 @@ public: relocation_iterator relocation_begin() const; relocation_iterator relocation_end() const; iterator_range<relocation_iterator> relocations() const { - return iterator_range<relocation_iterator>(relocation_begin(), - relocation_end()); + return make_range(relocation_begin(), relocation_end()); } section_iterator getRelocatedSection() const; @@ -147,7 +146,7 @@ public: /// @brief Get section this symbol is defined in reference to. Result is /// end_sections() if it is undefined or is an absolute symbol. - std::error_code getSection(section_iterator &Result) const; + ErrorOr<section_iterator> getSection() const; const ObjectFile *getObject() const; }; @@ -202,8 +201,8 @@ protected: virtual uint32_t getSymbolAlignment(DataRefImpl Symb) const; virtual uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const = 0; virtual SymbolRef::Type getSymbolType(DataRefImpl Symb) const = 0; - virtual std::error_code getSymbolSection(DataRefImpl Symb, - section_iterator &Res) const = 0; + virtual ErrorOr<section_iterator> + getSymbolSection(DataRefImpl Symb) const = 0; // Same as above for SectionRef. friend class SectionRef; @@ -323,8 +322,8 @@ inline uint64_t SymbolRef::getCommonSize() const { return getObject()->getCommonSymbolSize(getRawDataRefImpl()); } -inline std::error_code SymbolRef::getSection(section_iterator &Result) const { - return getObject()->getSymbolSection(getRawDataRefImpl(), Result); +inline ErrorOr<section_iterator> SymbolRef::getSection() const { + return getObject()->getSymbolSection(getRawDataRefImpl()); } inline SymbolRef::Type SymbolRef::getType() const { diff --git a/include/llvm/Object/SymbolicFile.h b/include/llvm/Object/SymbolicFile.h index 537997ac6318..0c5b38111a9c 100644 --- a/include/llvm/Object/SymbolicFile.h +++ b/include/llvm/Object/SymbolicFile.h @@ -15,6 +15,7 @@ #define LLVM_OBJECT_SYMBOLICFILE_H #include "llvm/Object/Binary.h" +#include "llvm/Support/Format.h" namespace llvm { namespace object { @@ -29,6 +30,12 @@ union DataRefImpl { DataRefImpl() { std::memset(this, 0, sizeof(DataRefImpl)); } }; +template <typename OStream> +OStream& operator<<(OStream &OS, const DataRefImpl &D) { + OS << "(" << format("0x%x8", D.p) << " (" << format("0x%x8", D.d.a) << ", " << format("0x%x8", D.d.b) << "))"; + return OS; +} + inline bool operator==(const DataRefImpl &a, const DataRefImpl &b) { // Check bitwise identical. This is the only legal way to compare a union w/o // knowing which member is in use. @@ -94,6 +101,7 @@ public: // (e.g. section symbols) SF_Thumb = 1U << 8, // Thumb symbol in a 32-bit ARM binary SF_Hidden = 1U << 9, // Symbol has hidden visibility + SF_Const = 1U << 10, // Symbol value is constant }; BasicSymbolRef() : OwningObject(nullptr) { } |
