diff options
author | Alon Zakai <azakai@google.com> | 2019-12-19 09:04:08 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-12-19 09:04:08 -0800 |
commit | 4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6 (patch) | |
tree | 91bffc2d47b1fe4bba01e7ada77006ef340bd138 /third_party/llvm-project/include/llvm/Object | |
parent | 0048f5b004ddf50e750aa335d0be314a73852058 (diff) | |
download | binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.gz binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.tar.bz2 binaryen-4d28d3f32e7f213e300b24bc61c3f0ac9d6e1ab6.zip |
DWARF parsing and writing support using LLVM (#2520)
This imports LLVM code for DWARF handling. That code has the
Apache 2 license like us. It's also the same code used to
emit DWARF in the common toolchain, so it seems like a safe choice.
This adds two passes: --dwarfdump which runs the same code LLVM
runs for llvm-dwarfdump. This shows we can parse it ok, and will
be useful for debugging. And --dwarfupdate writes out the DWARF
sections (unchanged from what we read, so it just roundtrips - for
updating we need #2515).
This puts LLVM in thirdparty which is added here.
All the LLVM code is behind USE_LLVM_DWARF, which is on
by default, but off in JS for now, as it increases code size by 20%.
This current approach imports the LLVM files directly. This is not
how they are intended to be used, so it required a bunch of
local changes - more than I expected actually, for the platform-specific
stuff. For now this seems to work, so it may be good enough, but
in the long term we may want to switch to linking against libllvm.
A downside to doing that is that binaryen users would need to
have an LLVM build, and even in the waterfall builds we'd have a
problem - while we ship LLVM there anyhow, we constantly update
it, which means that binaryen would need to be on latest llvm all
the time too (which otherwise, given DWARF is quite stable, we
might not need to constantly update).
An even larger issue is that as I did this work I learned about how
DWARF works in LLVM, and while the reading code is easy to
reuse, the writing code is trickier. The main code path is heavily
integrated with the MC layer, which we don't have - we might want
to create a "fake MC layer" for that, but it sounds hard. Instead,
there is the YAML path which is used mostly for testing, and which
can convert DWARF to and from YAML and from binary. Using
the non-YAML parts there, we can convert binary DWARF to
the YAML layer's nice Info data, then convert that to binary. This
works, however, this is not the path LLVM uses normally, and it
supports only some basic DWARF sections - I had to add ranges
support, in fact. So if we need more complex things, we may end
up needing to use the MC layer approach, or consider some other
DWARF library. However, hopefully that should not affect the core
binaryen code which just calls a library for DWARF stuff.
Helps #2400
Diffstat (limited to 'third_party/llvm-project/include/llvm/Object')
15 files changed, 6848 insertions, 0 deletions
diff --git a/third_party/llvm-project/include/llvm/Object/Archive.h b/third_party/llvm-project/include/llvm/Object/Archive.h new file mode 100644 index 000000000..c3f36bdd9 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/Archive.h @@ -0,0 +1,286 @@ +//===- Archive.h - ar archive file format -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the ar archive file format class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ARCHIVE_H +#define LLVM_OBJECT_ARCHIVE_H + +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/fallible_iterator.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/Binary.h" +#include "llvm/Support/Chrono.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <memory> +#include <string> +#include <vector> + +namespace llvm { +namespace object { + +class Archive; + +class ArchiveMemberHeader { +public: + friend class Archive; + + ArchiveMemberHeader(Archive const *Parent, const char *RawHeaderPtr, + uint64_t Size, Error *Err); + // ArchiveMemberHeader() = default; + + /// Get the name without looking up long names. + Expected<StringRef> getRawName() const; + + /// Get the name looking up long names. + Expected<StringRef> getName(uint64_t Size) const; + + Expected<uint64_t> getSize() const; + + Expected<sys::fs::perms> getAccessMode() const; + Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const; + + StringRef getRawLastModified() const { + return StringRef(ArMemHdr->LastModified, + sizeof(ArMemHdr->LastModified)).rtrim(' '); + } + + Expected<unsigned> getUID() const; + Expected<unsigned> getGID() const; + + // This returns the size of the private struct ArMemHdrType + uint64_t getSizeOf() const { + return sizeof(ArMemHdrType); + } + +private: + struct ArMemHdrType { + char Name[16]; + char LastModified[12]; + char UID[6]; + char GID[6]; + char AccessMode[8]; + char Size[10]; ///< Size of data, not including header or padding. + char Terminator[2]; + }; + Archive const *Parent; + ArMemHdrType const *ArMemHdr; +}; + +class Archive : public Binary { + virtual void anchor(); + +public: + class Child { + friend Archive; + friend ArchiveMemberHeader; + + const Archive *Parent; + ArchiveMemberHeader Header; + /// Includes header but not padding byte. + StringRef Data; + /// Offset from Data to the start of the file. + uint16_t StartOfFile; + + Expected<bool> isThinMember() const; + + public: + Child(const Archive *Parent, const char *Start, Error *Err); + Child(const Archive *Parent, StringRef Data, uint16_t StartOfFile); + + bool operator ==(const Child &other) const { + assert(!Parent || !other.Parent || Parent == other.Parent); + return Data.begin() == other.Data.begin(); + } + + const Archive *getParent() const { return Parent; } + Expected<Child> getNext() const; + + Expected<StringRef> getName() const; + Expected<std::string> getFullName() const; + Expected<StringRef> getRawName() const { return Header.getRawName(); } + + Expected<sys::TimePoint<std::chrono::seconds>> getLastModified() const { + return Header.getLastModified(); + } + + StringRef getRawLastModified() const { + return Header.getRawLastModified(); + } + + Expected<unsigned> getUID() const { return Header.getUID(); } + Expected<unsigned> getGID() const { return Header.getGID(); } + + Expected<sys::fs::perms> getAccessMode() const { + return Header.getAccessMode(); + } + + /// \return the size of the archive member without the header or padding. + Expected<uint64_t> getSize() const; + /// \return the size in the archive header for this member. + Expected<uint64_t> getRawSize() const; + + Expected<StringRef> getBuffer() const; + uint64_t getChildOffset() const; + uint64_t getDataOffset() const { return getChildOffset() + StartOfFile; } + + Expected<MemoryBufferRef> getMemoryBufferRef() const; + + Expected<std::unique_ptr<Binary>> + getAsBinary(LLVMContext *Context = nullptr) const; + }; + + class ChildFallibleIterator { + Child C; + + public: + ChildFallibleIterator() : C(Child(nullptr, nullptr, nullptr)) {} + ChildFallibleIterator(const Child &C) : C(C) {} + + const Child *operator->() const { return &C; } + const Child &operator*() const { return C; } + + bool operator==(const ChildFallibleIterator &other) const { + // Ignore errors here: If an error occurred during increment then getNext + // will have been set to child_end(), and the following comparison should + // do the right thing. + return C == other.C; + } + + bool operator!=(const ChildFallibleIterator &other) const { + return !(*this == other); + } + + Error inc() { + auto NextChild = C.getNext(); + if (!NextChild) + return NextChild.takeError(); + C = std::move(*NextChild); + return Error::success(); + } + }; + + using child_iterator = fallible_iterator<ChildFallibleIterator>; + + class Symbol { + const Archive *Parent; + uint32_t SymbolIndex; + uint32_t StringIndex; // Extra index to the string. + + public: + Symbol(const Archive *p, uint32_t symi, uint32_t stri) + : Parent(p) + , SymbolIndex(symi) + , StringIndex(stri) {} + + bool operator ==(const Symbol &other) const { + return (Parent == other.Parent) && (SymbolIndex == other.SymbolIndex); + } + + StringRef getName() const; + Expected<Child> getMember() const; + Symbol getNext() const; + }; + + class symbol_iterator { + Symbol symbol; + + public: + symbol_iterator(const Symbol &s) : symbol(s) {} + + const Symbol *operator->() const { return &symbol; } + const Symbol &operator*() const { return symbol; } + + bool operator==(const symbol_iterator &other) const { + return symbol == other.symbol; + } + + bool operator!=(const symbol_iterator &other) const { + return !(*this == other); + } + + symbol_iterator& operator++() { // Preincrement + symbol = symbol.getNext(); + return *this; + } + }; + + Archive(MemoryBufferRef Source, Error &Err); + static Expected<std::unique_ptr<Archive>> create(MemoryBufferRef Source); + + /// Size field is 10 decimal digits long + static const uint64_t MaxMemberSize = 9999999999; + + enum Kind { + K_GNU, + K_GNU64, + K_BSD, + K_DARWIN, + K_DARWIN64, + K_COFF + }; + + Kind kind() const { return (Kind)Format; } + bool isThin() const { return IsThin; } + + child_iterator child_begin(Error &Err, bool SkipInternal = true) const; + child_iterator child_end() const; + iterator_range<child_iterator> children(Error &Err, + bool SkipInternal = true) const { + return make_range(child_begin(Err, SkipInternal), child_end()); + } + + symbol_iterator symbol_begin() const; + symbol_iterator symbol_end() const; + iterator_range<symbol_iterator> symbols() const { + return make_range(symbol_begin(), symbol_end()); + } + + // Cast methods. + static bool classof(Binary const *v) { + return v->isArchive(); + } + + // check if a symbol is in the archive + Expected<Optional<Child>> findSym(StringRef name) const; + + bool isEmpty() const; + bool hasSymbolTable() const; + StringRef getSymbolTable() const { return SymbolTable; } + StringRef getStringTable() const { return StringTable; } + uint32_t getNumberOfSymbols() const; + + std::vector<std::unique_ptr<MemoryBuffer>> takeThinBuffers() { + return std::move(ThinBuffers); + } + +private: + StringRef SymbolTable; + StringRef StringTable; + + StringRef FirstRegularData; + uint16_t FirstRegularStartOfFile = -1; + void setFirstRegular(const Child &C); + + unsigned Format : 3; + unsigned IsThin : 1; + mutable std::vector<std::unique_ptr<MemoryBuffer>> ThinBuffers; +}; + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_ARCHIVE_H diff --git a/third_party/llvm-project/include/llvm/Object/Binary.h b/third_party/llvm-project/include/llvm/Object/Binary.h new file mode 100644 index 000000000..aa5e718f5 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/Binary.h @@ -0,0 +1,237 @@ +//===- Binary.h - A generic binary file -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the Binary class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_BINARY_H +#define LLVM_OBJECT_BINARY_H + +#include "llvm-c/Types.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#include <algorithm> +#include <memory> +#include <utility> + +namespace llvm { + +class LLVMContext; +class StringRef; + +namespace object { + +class Binary { +private: + unsigned int TypeID; + +protected: + MemoryBufferRef Data; + + Binary(unsigned int Type, MemoryBufferRef Source); + + enum { + ID_Archive, + ID_MachOUniversalBinary, + ID_COFFImportFile, + ID_IR, // LLVM IR + ID_TapiUniversal, // Text-based Dynamic Library Stub file. + ID_TapiFile, // Text-based Dynamic Library Stub file. + + ID_Minidump, + + ID_WinRes, // Windows resource (.res) file. + + // Object and children. + ID_StartObjects, + ID_COFF, + + ID_XCOFF32, // AIX XCOFF 32-bit + ID_XCOFF64, // AIX XCOFF 64-bit + + ID_ELF32L, // ELF 32-bit, little endian + ID_ELF32B, // ELF 32-bit, big endian + ID_ELF64L, // ELF 64-bit, little endian + ID_ELF64B, // ELF 64-bit, big endian + + ID_MachO32L, // MachO 32-bit, little endian + ID_MachO32B, // MachO 32-bit, big endian + ID_MachO64L, // MachO 64-bit, little endian + ID_MachO64B, // MachO 64-bit, big endian + + ID_Wasm, + + ID_EndObjects + }; + + static inline unsigned int getELFType(bool isLE, bool is64Bits) { + if (isLE) + return is64Bits ? ID_ELF64L : ID_ELF32L; + else + return is64Bits ? ID_ELF64B : ID_ELF32B; + } + + static unsigned int getMachOType(bool isLE, bool is64Bits) { + if (isLE) + return is64Bits ? ID_MachO64L : ID_MachO32L; + else + return is64Bits ? ID_MachO64B : ID_MachO32B; + } + +public: + Binary() = delete; + Binary(const Binary &other) = delete; + virtual ~Binary(); + + StringRef getData() const; + StringRef getFileName() const; + MemoryBufferRef getMemoryBufferRef() const; + + // Cast methods. + unsigned int getType() const { return TypeID; } + + // Convenience methods + bool isObject() const { + return TypeID > ID_StartObjects && TypeID < ID_EndObjects; + } + + bool isSymbolic() const { + return isIR() || isObject() || isCOFFImportFile() || isTapiFile(); + } + + bool isArchive() const { return TypeID == ID_Archive; } + + bool isMachOUniversalBinary() const { + return TypeID == ID_MachOUniversalBinary; + } + + bool isTapiUniversal() const { return TypeID == ID_TapiUniversal; } + + bool isELF() const { + return TypeID >= ID_ELF32L && TypeID <= ID_ELF64B; + } + + bool isMachO() const { + return TypeID >= ID_MachO32L && TypeID <= ID_MachO64B; + } + + bool isCOFF() const { + return TypeID == ID_COFF; + } + + bool isXCOFF() const { return TypeID == ID_XCOFF32 || TypeID == ID_XCOFF64; } + + bool isWasm() const { return TypeID == ID_Wasm; } + + bool isCOFFImportFile() const { + return TypeID == ID_COFFImportFile; + } + + bool isIR() const { + return TypeID == ID_IR; + } + + bool isMinidump() const { return TypeID == ID_Minidump; } + + bool isTapiFile() const { return TypeID == ID_TapiFile; } + + bool isLittleEndian() const { + return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B || + TypeID == ID_MachO32B || TypeID == ID_MachO64B); + } + + bool isWinRes() const { return TypeID == ID_WinRes; } + + Triple::ObjectFormatType getTripleObjectFormat() const { + if (isCOFF()) + return Triple::COFF; + if (isMachO()) + return Triple::MachO; + if (isELF()) + return Triple::ELF; + return Triple::UnknownObjectFormat; + } + + static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, + const uint64_t Size) { + if (Addr + Size < Addr || Addr + Size < Size || + Addr + Size > uintptr_t(M.getBufferEnd()) || + Addr < uintptr_t(M.getBufferStart())) { + return object_error::unexpected_eof; + } + return std::error_code(); + } +}; + +// Create wrappers for C Binding types (see CBindingWrapping.h). +DEFINE_ISA_CONVERSION_FUNCTIONS(Binary, LLVMBinaryRef) + +/// Create a Binary from Source, autodetecting the file type. +/// +/// @param Source The data to create the Binary from. +Expected<std::unique_ptr<Binary>> createBinary(MemoryBufferRef Source, + LLVMContext *Context = nullptr); + +template <typename T> class OwningBinary { + std::unique_ptr<T> Bin; + std::unique_ptr<MemoryBuffer> Buf; + +public: + OwningBinary(); + OwningBinary(std::unique_ptr<T> Bin, std::unique_ptr<MemoryBuffer> Buf); + OwningBinary(OwningBinary<T>&& Other); + OwningBinary<T> &operator=(OwningBinary<T> &&Other); + + std::pair<std::unique_ptr<T>, std::unique_ptr<MemoryBuffer>> takeBinary(); + + T* getBinary(); + const T* getBinary() const; +}; + +template <typename T> +OwningBinary<T>::OwningBinary(std::unique_ptr<T> Bin, + std::unique_ptr<MemoryBuffer> Buf) + : Bin(std::move(Bin)), Buf(std::move(Buf)) {} + +template <typename T> OwningBinary<T>::OwningBinary() = default; + +template <typename T> +OwningBinary<T>::OwningBinary(OwningBinary &&Other) + : Bin(std::move(Other.Bin)), Buf(std::move(Other.Buf)) {} + +template <typename T> +OwningBinary<T> &OwningBinary<T>::operator=(OwningBinary &&Other) { + Bin = std::move(Other.Bin); + Buf = std::move(Other.Buf); + return *this; +} + +template <typename T> +std::pair<std::unique_ptr<T>, std::unique_ptr<MemoryBuffer>> +OwningBinary<T>::takeBinary() { + return std::make_pair(std::move(Bin), std::move(Buf)); +} + +template <typename T> T* OwningBinary<T>::getBinary() { + return Bin.get(); +} + +template <typename T> const T* OwningBinary<T>::getBinary() const { + return Bin.get(); +} + +Expected<OwningBinary<Binary>> createBinary(StringRef Path); + +} // end namespace object + +} // end namespace llvm + +#endif // LLVM_OBJECT_BINARY_H diff --git a/third_party/llvm-project/include/llvm/Object/COFF.h b/third_party/llvm-project/include/llvm/Object/COFF.h new file mode 100644 index 000000000..b91ee5887 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/COFF.h @@ -0,0 +1,1269 @@ +//===- COFF.h - COFF object file implementation -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the COFFObjectFile class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_COFF_H +#define LLVM_OBJECT_COFF_H + +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/CVDebugRecord.h" +#include "llvm/Object/Error.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <system_error> + +namespace llvm { + +template <typename T> class ArrayRef; + +namespace object { + +class BaseRelocRef; +class DelayImportDirectoryEntryRef; +class ExportDirectoryEntryRef; +class ImportDirectoryEntryRef; +class ImportedSymbolRef; +class ResourceSectionRef; + +using import_directory_iterator = content_iterator<ImportDirectoryEntryRef>; +using delay_import_directory_iterator = + content_iterator<DelayImportDirectoryEntryRef>; +using export_directory_iterator = content_iterator<ExportDirectoryEntryRef>; +using imported_symbol_iterator = content_iterator<ImportedSymbolRef>; +using base_reloc_iterator = content_iterator<BaseRelocRef>; + +/// The DOS compatible header at the front of all PE/COFF executables. +struct dos_header { + char Magic[2]; + support::ulittle16_t UsedBytesInTheLastPage; + support::ulittle16_t FileSizeInPages; + support::ulittle16_t NumberOfRelocationItems; + support::ulittle16_t HeaderSizeInParagraphs; + support::ulittle16_t MinimumExtraParagraphs; + support::ulittle16_t MaximumExtraParagraphs; + support::ulittle16_t InitialRelativeSS; + support::ulittle16_t InitialSP; + support::ulittle16_t Checksum; + support::ulittle16_t InitialIP; + support::ulittle16_t InitialRelativeCS; + support::ulittle16_t AddressOfRelocationTable; + support::ulittle16_t OverlayNumber; + support::ulittle16_t Reserved[4]; + support::ulittle16_t OEMid; + support::ulittle16_t OEMinfo; + support::ulittle16_t Reserved2[10]; + support::ulittle32_t AddressOfNewExeHeader; +}; + +struct coff_file_header { + support::ulittle16_t Machine; + support::ulittle16_t NumberOfSections; + support::ulittle32_t TimeDateStamp; + support::ulittle32_t PointerToSymbolTable; + support::ulittle32_t NumberOfSymbols; + support::ulittle16_t SizeOfOptionalHeader; + support::ulittle16_t Characteristics; + + bool isImportLibrary() const { return NumberOfSections == 0xffff; } +}; + +struct coff_bigobj_file_header { + support::ulittle16_t Sig1; + support::ulittle16_t Sig2; + support::ulittle16_t Version; + support::ulittle16_t Machine; + support::ulittle32_t TimeDateStamp; + uint8_t UUID[16]; + support::ulittle32_t unused1; + support::ulittle32_t unused2; + support::ulittle32_t unused3; + support::ulittle32_t unused4; + support::ulittle32_t NumberOfSections; + support::ulittle32_t PointerToSymbolTable; + support::ulittle32_t NumberOfSymbols; +}; + +/// The 32-bit PE header that follows the COFF header. +struct pe32_header { + support::ulittle16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + support::ulittle32_t SizeOfCode; + support::ulittle32_t SizeOfInitializedData; + support::ulittle32_t SizeOfUninitializedData; + support::ulittle32_t AddressOfEntryPoint; + support::ulittle32_t BaseOfCode; + support::ulittle32_t BaseOfData; + support::ulittle32_t ImageBase; + support::ulittle32_t SectionAlignment; + support::ulittle32_t FileAlignment; + support::ulittle16_t MajorOperatingSystemVersion; + support::ulittle16_t MinorOperatingSystemVersion; + support::ulittle16_t MajorImageVersion; + support::ulittle16_t MinorImageVersion; + support::ulittle16_t MajorSubsystemVersion; + support::ulittle16_t MinorSubsystemVersion; + support::ulittle32_t Win32VersionValue; + support::ulittle32_t SizeOfImage; + support::ulittle32_t SizeOfHeaders; + support::ulittle32_t CheckSum; + support::ulittle16_t Subsystem; + // FIXME: This should be DllCharacteristics. + support::ulittle16_t DLLCharacteristics; + support::ulittle32_t SizeOfStackReserve; + support::ulittle32_t SizeOfStackCommit; + support::ulittle32_t SizeOfHeapReserve; + support::ulittle32_t SizeOfHeapCommit; + support::ulittle32_t LoaderFlags; + // FIXME: This should be NumberOfRvaAndSizes. + support::ulittle32_t NumberOfRvaAndSize; +}; + +/// The 64-bit PE header that follows the COFF header. +struct pe32plus_header { + support::ulittle16_t Magic; + uint8_t MajorLinkerVersion; + uint8_t MinorLinkerVersion; + support::ulittle32_t SizeOfCode; + support::ulittle32_t SizeOfInitializedData; + support::ulittle32_t SizeOfUninitializedData; + support::ulittle32_t AddressOfEntryPoint; + support::ulittle32_t BaseOfCode; + support::ulittle64_t ImageBase; + support::ulittle32_t SectionAlignment; + support::ulittle32_t FileAlignment; + support::ulittle16_t MajorOperatingSystemVersion; + support::ulittle16_t MinorOperatingSystemVersion; + support::ulittle16_t MajorImageVersion; + support::ulittle16_t MinorImageVersion; + support::ulittle16_t MajorSubsystemVersion; + support::ulittle16_t MinorSubsystemVersion; + support::ulittle32_t Win32VersionValue; + support::ulittle32_t SizeOfImage; + support::ulittle32_t SizeOfHeaders; + support::ulittle32_t CheckSum; + support::ulittle16_t Subsystem; + support::ulittle16_t DLLCharacteristics; + support::ulittle64_t SizeOfStackReserve; + support::ulittle64_t SizeOfStackCommit; + support::ulittle64_t SizeOfHeapReserve; + support::ulittle64_t SizeOfHeapCommit; + support::ulittle32_t LoaderFlags; + support::ulittle32_t NumberOfRvaAndSize; +}; + +struct data_directory { + support::ulittle32_t RelativeVirtualAddress; + support::ulittle32_t Size; +}; + +struct debug_directory { + support::ulittle32_t Characteristics; + support::ulittle32_t TimeDateStamp; + support::ulittle16_t MajorVersion; + support::ulittle16_t MinorVersion; + support::ulittle32_t Type; + support::ulittle32_t SizeOfData; + support::ulittle32_t AddressOfRawData; + support::ulittle32_t PointerToRawData; +}; + +template <typename IntTy> +struct import_lookup_table_entry { + IntTy Data; + + bool isOrdinal() const { return Data < 0; } + + uint16_t getOrdinal() const { + assert(isOrdinal() && "ILT entry is not an ordinal!"); + return Data & 0xFFFF; + } + + uint32_t getHintNameRVA() const { + assert(!isOrdinal() && "ILT entry is not a Hint/Name RVA!"); + return Data & 0xFFFFFFFF; + } +}; + +using import_lookup_table_entry32 = + import_lookup_table_entry<support::little32_t>; +using import_lookup_table_entry64 = + import_lookup_table_entry<support::little64_t>; + +struct delay_import_directory_table_entry { + // dumpbin reports this field as "Characteristics" instead of "Attributes". + support::ulittle32_t Attributes; + support::ulittle32_t Name; + support::ulittle32_t ModuleHandle; + support::ulittle32_t DelayImportAddressTable; + support::ulittle32_t DelayImportNameTable; + support::ulittle32_t BoundDelayImportTable; + support::ulittle32_t UnloadDelayImportTable; + support::ulittle32_t TimeStamp; +}; + +struct export_directory_table_entry { + support::ulittle32_t ExportFlags; + support::ulittle32_t TimeDateStamp; + support::ulittle16_t MajorVersion; + support::ulittle16_t MinorVersion; + support::ulittle32_t NameRVA; + support::ulittle32_t OrdinalBase; + support::ulittle32_t AddressTableEntries; + support::ulittle32_t NumberOfNamePointers; + support::ulittle32_t ExportAddressTableRVA; + support::ulittle32_t NamePointerRVA; + support::ulittle32_t OrdinalTableRVA; +}; + +union export_address_table_entry { + support::ulittle32_t ExportRVA; + support::ulittle32_t ForwarderRVA; +}; + +using export_name_pointer_table_entry = support::ulittle32_t; +using export_ordinal_table_entry = support::ulittle16_t; + +struct StringTableOffset { + support::ulittle32_t Zeroes; + support::ulittle32_t Offset; +}; + +template <typename SectionNumberType> +struct coff_symbol { + union { + char ShortName[COFF::NameSize]; + StringTableOffset Offset; + } Name; + + support::ulittle32_t Value; + SectionNumberType SectionNumber; + + support::ulittle16_t Type; + + uint8_t StorageClass; + uint8_t NumberOfAuxSymbols; +}; + +using coff_symbol16 = coff_symbol<support::ulittle16_t>; +using coff_symbol32 = coff_symbol<support::ulittle32_t>; + +// Contains only common parts of coff_symbol16 and coff_symbol32. +struct coff_symbol_generic { + union { + char ShortName[COFF::NameSize]; + StringTableOffset Offset; + } Name; + support::ulittle32_t Value; +}; + +struct coff_aux_section_definition; +struct coff_aux_weak_external; + +class COFFSymbolRef { +public: + COFFSymbolRef() = default; + COFFSymbolRef(const coff_symbol16 *CS) : CS16(CS) {} + COFFSymbolRef(const coff_symbol32 *CS) : CS32(CS) {} + + const void *getRawPtr() const { + return CS16 ? static_cast<const void *>(CS16) : CS32; + } + + const coff_symbol_generic *getGeneric() const { + if (CS16) + return reinterpret_cast<const coff_symbol_generic *>(CS16); + return reinterpret_cast<const coff_symbol_generic *>(CS32); + } + + friend bool operator<(COFFSymbolRef A, COFFSymbolRef B) { + return A.getRawPtr() < B.getRawPtr(); + } + + bool isBigObj() const { + if (CS16) + return false; + if (CS32) + return true; + llvm_unreachable("COFFSymbolRef points to nothing!"); + } + + const char *getShortName() const { + return CS16 ? CS16->Name.ShortName : CS32->Name.ShortName; + } + + const StringTableOffset &getStringTableOffset() const { + assert(isSet() && "COFFSymbolRef points to nothing!"); + return CS16 ? CS16->Name.Offset : CS32->Name.Offset; + } + + uint32_t getValue() const { + assert(isSet() && "COFFSymbolRef points to nothing!"); + return CS16 ? CS16->Value : CS32->Value; + } + + int32_t getSectionNumber() const { + assert(isSet() && "COFFSymbolRef points to nothing!"); + if (CS16) { + // Reserved sections are returned as negative numbers. + if (CS16->SectionNumber <= COFF::MaxNumberOfSections16) + return CS16->SectionNumber; + return static_cast<int16_t>(CS16->SectionNumber); + } + return static_cast<int32_t>(CS32->SectionNumber); + } + + uint16_t getType() const { + assert(isSet() && "COFFSymbolRef points to nothing!"); + return CS16 ? CS16->Type : CS32->Type; + } + + uint8_t getStorageClass() const { + assert(isSet() && "COFFSymbolRef points to nothing!"); + return CS16 ? CS16->StorageClass : CS32->StorageClass; + } + + uint8_t getNumberOfAuxSymbols() const { + assert(isSet() && "COFFSymbolRef points to nothing!"); + return CS16 ? CS16->NumberOfAuxSymbols : CS32->NumberOfAuxSymbols; + } + + uint8_t getBaseType() const { return getType() & 0x0F; } + + uint8_t getComplexType() const { + return (getType() & 0xF0) >> COFF::SCT_COMPLEX_TYPE_SHIFT; + } + + template <typename T> const T *getAux() const { + return CS16 ? reinterpret_cast<const T *>(CS16 + 1) + : reinterpret_cast<const T *>(CS32 + 1); + } + + const coff_aux_section_definition *getSectionDefinition() const { + if (!getNumberOfAuxSymbols() || + getStorageClass() != COFF::IMAGE_SYM_CLASS_STATIC) + return nullptr; + return getAux<coff_aux_section_definition>(); + } + + const coff_aux_weak_external *getWeakExternal() const { + if (!getNumberOfAuxSymbols() || + getStorageClass() != COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL) + return nullptr; + return getAux<coff_aux_weak_external>(); + } + + bool isAbsolute() const { + return getSectionNumber() == -1; + } + + bool isExternal() const { + return getStorageClass() == COFF::IMAGE_SYM_CLASS_EXTERNAL; + } + + bool isCommon() const { + return isExternal() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED && + getValue() != 0; + } + + bool isUndefined() const { + return isExternal() && getSectionNumber() == COFF::IMAGE_SYM_UNDEFINED && + getValue() == 0; + } + + bool isWeakExternal() const { + return getStorageClass() == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL; + } + + bool isFunctionDefinition() const { + return isExternal() && getBaseType() == COFF::IMAGE_SYM_TYPE_NULL && + getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION && + !COFF::isReservedSectionNumber(getSectionNumber()); + } + + bool isFunctionLineInfo() const { + return getStorageClass() == COFF::IMAGE_SYM_CLASS_FUNCTION; + } + + bool isAnyUndefined() const { + return isUndefined() || isWeakExternal(); + } + + bool isFileRecord() const { + return getStorageClass() == COFF::IMAGE_SYM_CLASS_FILE; + } + + bool isSection() const { + return getStorageClass() == COFF::IMAGE_SYM_CLASS_SECTION; + } + + bool isSectionDefinition() const { + // C++/CLI creates external ABS symbols for non-const appdomain globals. + // These are also followed by an auxiliary section definition. + bool isAppdomainGlobal = + getStorageClass() == COFF::IMAGE_SYM_CLASS_EXTERNAL && + getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE; + bool isOrdinarySection = getStorageClass() == COFF::IMAGE_SYM_CLASS_STATIC; + if (!getNumberOfAuxSymbols()) + return false; + return isAppdomainGlobal || isOrdinarySection; + } + + bool isCLRToken() const { + return getStorageClass() == COFF::IMAGE_SYM_CLASS_CLR_TOKEN; + } + +private: + bool isSet() const { return CS16 || CS32; } + + const coff_symbol16 *CS16 = nullptr; + const coff_symbol32 *CS32 = nullptr; +}; + +struct coff_section { + char Name[COFF::NameSize]; + support::ulittle32_t VirtualSize; + support::ulittle32_t VirtualAddress; + support::ulittle32_t SizeOfRawData; + support::ulittle32_t PointerToRawData; + support::ulittle32_t PointerToRelocations; + support::ulittle32_t PointerToLinenumbers; + support::ulittle16_t NumberOfRelocations; + support::ulittle16_t NumberOfLinenumbers; + support::ulittle32_t Characteristics; + + // Returns true if the actual number of relocations is stored in + // VirtualAddress field of the first relocation table entry. + bool hasExtendedRelocations() const { + return (Characteristics & COFF::IMAGE_SCN_LNK_NRELOC_OVFL) && + NumberOfRelocations == UINT16_MAX; + } + + uint32_t getAlignment() const { + // The IMAGE_SCN_TYPE_NO_PAD bit is a legacy way of getting to + // IMAGE_SCN_ALIGN_1BYTES. + if (Characteristics & COFF::IMAGE_SCN_TYPE_NO_PAD) + return 1; + + // Bit [20:24] contains section alignment. 0 means use a default alignment + // of 16. + uint32_t Shift = (Characteristics >> 20) & 0xF; + if (Shift > 0) + return 1U << (Shift - 1); + return 16; + } +}; + +struct coff_relocation { + support::ulittle32_t VirtualAddress; + support::ulittle32_t SymbolTableIndex; + support::ulittle16_t Type; +}; + +struct coff_aux_function_definition { + support::ulittle32_t TagIndex; + support::ulittle32_t TotalSize; + support::ulittle32_t PointerToLinenumber; + support::ulittle32_t PointerToNextFunction; + char Unused1[2]; +}; + +static_assert(sizeof(coff_aux_function_definition) == 18, + "auxiliary entry must be 18 bytes"); + +struct coff_aux_bf_and_ef_symbol { + char Unused1[4]; + support::ulittle16_t Linenumber; + char Unused2[6]; + support::ulittle32_t PointerToNextFunction; + char Unused3[2]; +}; + +static_assert(sizeof(coff_aux_bf_and_ef_symbol) == 18, + "auxiliary entry must be 18 bytes"); + +struct coff_aux_weak_external { + support::ulittle32_t TagIndex; + support::ulittle32_t Characteristics; + char Unused1[10]; +}; + +static_assert(sizeof(coff_aux_weak_external) == 18, + "auxiliary entry must be 18 bytes"); + +struct coff_aux_section_definition { + support::ulittle32_t Length; + support::ulittle16_t NumberOfRelocations; + support::ulittle16_t NumberOfLinenumbers; + support::ulittle32_t CheckSum; + support::ulittle16_t NumberLowPart; + uint8_t Selection; + uint8_t Unused; + support::ulittle16_t NumberHighPart; + int32_t getNumber(bool IsBigObj) const { + uint32_t Number = static_cast<uint32_t>(NumberLowPart); + if (IsBigObj) + Number |= static_cast<uint32_t>(NumberHighPart) << 16; + return static_cast<int32_t>(Number); + } +}; + +static_assert(sizeof(coff_aux_section_definition) == 18, + "auxiliary entry must be 18 bytes"); + +struct coff_aux_clr_token { + uint8_t AuxType; + uint8_t Reserved; + support::ulittle32_t SymbolTableIndex; + char MBZ[12]; +}; + +static_assert(sizeof(coff_aux_clr_token) == 18, + "auxiliary entry must be 18 bytes"); + +struct coff_import_header { + support::ulittle16_t Sig1; + support::ulittle16_t Sig2; + support::ulittle16_t Version; + support::ulittle16_t Machine; + support::ulittle32_t TimeDateStamp; + support::ulittle32_t SizeOfData; + support::ulittle16_t OrdinalHint; + support::ulittle16_t TypeInfo; + + int getType() const { return TypeInfo & 0x3; } + int getNameType() const { return (TypeInfo >> 2) & 0x7; } +}; + +struct coff_import_directory_table_entry { + support::ulittle32_t ImportLookupTableRVA; + support::ulittle32_t TimeDateStamp; + support::ulittle32_t ForwarderChain; + support::ulittle32_t NameRVA; + support::ulittle32_t ImportAddressTableRVA; + + bool isNull() const { + return ImportLookupTableRVA == 0 && TimeDateStamp == 0 && + ForwarderChain == 0 && NameRVA == 0 && ImportAddressTableRVA == 0; + } +}; + +template <typename IntTy> +struct coff_tls_directory { + IntTy StartAddressOfRawData; + IntTy EndAddressOfRawData; + IntTy AddressOfIndex; + IntTy AddressOfCallBacks; + support::ulittle32_t SizeOfZeroFill; + support::ulittle32_t Characteristics; + + uint32_t getAlignment() const { + // Bit [20:24] contains section alignment. + uint32_t Shift = (Characteristics & 0x00F00000) >> 20; + if (Shift > 0) + return 1U << (Shift - 1); + return 0; + } +}; + +using coff_tls_directory32 = coff_tls_directory<support::little32_t>; +using coff_tls_directory64 = coff_tls_directory<support::little64_t>; + +/// Bits in control flow guard flags as we understand them. +enum class coff_guard_flags : uint32_t { + CFInstrumented = 0x00000100, + HasFidTable = 0x00000400, + ProtectDelayLoadIAT = 0x00001000, + DelayLoadIATSection = 0x00002000, // Delay load in separate section + HasLongJmpTable = 0x00010000, + FidTableHasFlags = 0x10000000, // Indicates that fid tables are 5 bytes +}; + +enum class frame_type : uint16_t { Fpo = 0, Trap = 1, Tss = 2, NonFpo = 3 }; + +struct coff_load_config_code_integrity { + support::ulittle16_t Flags; + support::ulittle16_t Catalog; + support::ulittle32_t CatalogOffset; + support::ulittle32_t Reserved; +}; + +/// 32-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY32) +struct coff_load_configuration32 { + support::ulittle32_t Size; + support::ulittle32_t TimeDateStamp; + support::ulittle16_t MajorVersion; + support::ulittle16_t MinorVersion; + support::ulittle32_t GlobalFlagsClear; + support::ulittle32_t GlobalFlagsSet; + support::ulittle32_t CriticalSectionDefaultTimeout; + support::ulittle32_t DeCommitFreeBlockThreshold; + support::ulittle32_t DeCommitTotalFreeThreshold; + support::ulittle32_t LockPrefixTable; + support::ulittle32_t MaximumAllocationSize; + support::ulittle32_t VirtualMemoryThreshold; + support::ulittle32_t ProcessAffinityMask; + support::ulittle32_t ProcessHeapFlags; + support::ulittle16_t CSDVersion; + support::ulittle16_t DependentLoadFlags; + support::ulittle32_t EditList; + support::ulittle32_t SecurityCookie; + support::ulittle32_t SEHandlerTable; + support::ulittle32_t SEHandlerCount; + + // Added in MSVC 2015 for /guard:cf. + support::ulittle32_t GuardCFCheckFunction; + support::ulittle32_t GuardCFCheckDispatch; + support::ulittle32_t GuardCFFunctionTable; + support::ulittle32_t GuardCFFunctionCount; + support::ulittle32_t GuardFlags; // coff_guard_flags + + // Added in MSVC 2017 + coff_load_config_code_integrity CodeIntegrity; + support::ulittle32_t GuardAddressTakenIatEntryTable; + support::ulittle32_t GuardAddressTakenIatEntryCount; + support::ulittle32_t GuardLongJumpTargetTable; + support::ulittle32_t GuardLongJumpTargetCount; + support::ulittle32_t DynamicValueRelocTable; + support::ulittle32_t CHPEMetadataPointer; + support::ulittle32_t GuardRFFailureRoutine; + support::ulittle32_t GuardRFFailureRoutineFunctionPointer; + support::ulittle32_t DynamicValueRelocTableOffset; + support::ulittle16_t DynamicValueRelocTableSection; + support::ulittle16_t Reserved2; + support::ulittle32_t GuardRFVerifyStackPointerFunctionPointer; + support::ulittle32_t HotPatchTableOffset; +}; + +/// 64-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY64) +struct coff_load_configuration64 { + support::ulittle32_t Size; + support::ulittle32_t TimeDateStamp; + support::ulittle16_t MajorVersion; + support::ulittle16_t MinorVersion; + support::ulittle32_t GlobalFlagsClear; + support::ulittle32_t GlobalFlagsSet; + support::ulittle32_t CriticalSectionDefaultTimeout; + support::ulittle64_t DeCommitFreeBlockThreshold; + support::ulittle64_t DeCommitTotalFreeThreshold; + support::ulittle64_t LockPrefixTable; + support::ulittle64_t MaximumAllocationSize; + support::ulittle64_t VirtualMemoryThreshold; + support::ulittle64_t ProcessAffinityMask; + support::ulittle32_t ProcessHeapFlags; + support::ulittle16_t CSDVersion; + support::ulittle16_t DependentLoadFlags; + support::ulittle64_t EditList; + support::ulittle64_t SecurityCookie; + support::ulittle64_t SEHandlerTable; + support::ulittle64_t SEHandlerCount; + + // Added in MSVC 2015 for /guard:cf. + support::ulittle64_t GuardCFCheckFunction; + support::ulittle64_t GuardCFCheckDispatch; + support::ulittle64_t GuardCFFunctionTable; + support::ulittle64_t GuardCFFunctionCount; + support::ulittle32_t GuardFlags; + + // Added in MSVC 2017 + coff_load_config_code_integrity CodeIntegrity; + support::ulittle64_t GuardAddressTakenIatEntryTable; + support::ulittle64_t GuardAddressTakenIatEntryCount; + support::ulittle64_t GuardLongJumpTargetTable; + support::ulittle64_t GuardLongJumpTargetCount; + support::ulittle64_t DynamicValueRelocTable; + support::ulittle64_t CHPEMetadataPointer; + support::ulittle64_t GuardRFFailureRoutine; + support::ulittle64_t GuardRFFailureRoutineFunctionPointer; + support::ulittle32_t DynamicValueRelocTableOffset; + support::ulittle16_t DynamicValueRelocTableSection; + support::ulittle16_t Reserved2; + support::ulittle64_t GuardRFVerifyStackPointerFunctionPointer; + support::ulittle32_t HotPatchTableOffset; +}; + +struct coff_runtime_function_x64 { + support::ulittle32_t BeginAddress; + support::ulittle32_t EndAddress; + support::ulittle32_t UnwindInformation; +}; + +struct coff_base_reloc_block_header { + support::ulittle32_t PageRVA; + support::ulittle32_t BlockSize; +}; + +struct coff_base_reloc_block_entry { + support::ulittle16_t Data; + + int getType() const { return Data >> 12; } + int getOffset() const { return Data & ((1 << 12) - 1); } +}; + +struct coff_resource_dir_entry { + union { + support::ulittle32_t NameOffset; + support::ulittle32_t ID; + uint32_t getNameOffset() const { + return maskTrailingOnes<uint32_t>(31) & NameOffset; + } + // Even though the PE/COFF spec doesn't mention this, the high bit of a name + // offset is set. + void setNameOffset(uint32_t Offset) { NameOffset = Offset | (1 << 31); } + } Identifier; + union { + support::ulittle32_t DataEntryOffset; + support::ulittle32_t SubdirOffset; + + bool isSubDir() const { return SubdirOffset >> 31; } + uint32_t value() const { + return maskTrailingOnes<uint32_t>(31) & SubdirOffset; + } + + } Offset; +}; + +struct coff_resource_data_entry { + support::ulittle32_t DataRVA; + support::ulittle32_t DataSize; + support::ulittle32_t Codepage; + support::ulittle32_t Reserved; +}; + +struct coff_resource_dir_table { + support::ulittle32_t Characteristics; + support::ulittle32_t TimeDateStamp; + support::ulittle16_t MajorVersion; + support::ulittle16_t MinorVersion; + support::ulittle16_t NumberOfNameEntries; + support::ulittle16_t NumberOfIDEntries; +}; + +struct debug_h_header { + support::ulittle32_t Magic; + support::ulittle16_t Version; + support::ulittle16_t HashAlgorithm; +}; + +class COFFObjectFile : public ObjectFile { +private: + friend class ImportDirectoryEntryRef; + friend class ExportDirectoryEntryRef; + const coff_file_header *COFFHeader; + const coff_bigobj_file_header *COFFBigObjHeader; + const pe32_header *PE32Header; + const pe32plus_header *PE32PlusHeader; + const data_directory *DataDirectory; + const coff_section *SectionTable; + const coff_symbol16 *SymbolTable16; + const coff_symbol32 *SymbolTable32; + const char *StringTable; + uint32_t StringTableSize; + const coff_import_directory_table_entry *ImportDirectory; + const delay_import_directory_table_entry *DelayImportDirectory; + uint32_t NumberOfDelayImportDirectory; + const export_directory_table_entry *ExportDirectory; + const coff_base_reloc_block_header *BaseRelocHeader; + const coff_base_reloc_block_header *BaseRelocEnd; + const debug_directory *DebugDirectoryBegin; + const debug_directory *DebugDirectoryEnd; + // Either coff_load_configuration32 or coff_load_configuration64. + const void *LoadConfig = nullptr; + + std::error_code getString(uint32_t offset, StringRef &Res) const; + + template <typename coff_symbol_type> + const coff_symbol_type *toSymb(DataRefImpl Symb) const; + const coff_section *toSec(DataRefImpl Sec) const; + const coff_relocation *toRel(DataRefImpl Rel) const; + + std::error_code initSymbolTablePtr(); + std::error_code initImportTablePtr(); + std::error_code initDelayImportTablePtr(); + std::error_code initExportTablePtr(); + std::error_code initBaseRelocPtr(); + std::error_code initDebugDirectoryPtr(); + std::error_code initLoadConfigPtr(); + +public: + uintptr_t getSymbolTable() const { + if (SymbolTable16) + return reinterpret_cast<uintptr_t>(SymbolTable16); + if (SymbolTable32) + return reinterpret_cast<uintptr_t>(SymbolTable32); + return uintptr_t(0); + } + + uint16_t getMachine() const { + if (COFFHeader) + return COFFHeader->Machine; + if (COFFBigObjHeader) + return COFFBigObjHeader->Machine; + llvm_unreachable("no COFF header!"); + } + + uint16_t getSizeOfOptionalHeader() const { + if (COFFHeader) + return COFFHeader->isImportLibrary() ? 0 + : COFFHeader->SizeOfOptionalHeader; + // bigobj doesn't have this field. + if (COFFBigObjHeader) + return 0; + llvm_unreachable("no COFF header!"); + } + + uint16_t getCharacteristics() const { + if (COFFHeader) + return COFFHeader->isImportLibrary() ? 0 : COFFHeader->Characteristics; + // bigobj doesn't have characteristics to speak of, + // editbin will silently lie to you if you attempt to set any. + if (COFFBigObjHeader) + return 0; + llvm_unreachable("no COFF header!"); + } + + uint32_t getTimeDateStamp() const { + if (COFFHeader) + return COFFHeader->TimeDateStamp; + if (COFFBigObjHeader) + return COFFBigObjHeader->TimeDateStamp; + llvm_unreachable("no COFF header!"); + } + + uint32_t getNumberOfSections() const { + if (COFFHeader) + return COFFHeader->isImportLibrary() ? 0 : COFFHeader->NumberOfSections; + if (COFFBigObjHeader) + return COFFBigObjHeader->NumberOfSections; + llvm_unreachable("no COFF header!"); + } + + uint32_t getPointerToSymbolTable() const { + if (COFFHeader) + return COFFHeader->isImportLibrary() ? 0 + : COFFHeader->PointerToSymbolTable; + if (COFFBigObjHeader) + return COFFBigObjHeader->PointerToSymbolTable; + llvm_unreachable("no COFF header!"); + } + + uint32_t getRawNumberOfSymbols() const { + if (COFFHeader) + return COFFHeader->isImportLibrary() ? 0 : COFFHeader->NumberOfSymbols; + if (COFFBigObjHeader) + return COFFBigObjHeader->NumberOfSymbols; + llvm_unreachable("no COFF header!"); + } + + uint32_t getNumberOfSymbols() const { + if (!SymbolTable16 && !SymbolTable32) + return 0; + return getRawNumberOfSymbols(); + } + + const coff_load_configuration32 *getLoadConfig32() const { + assert(!is64()); + return reinterpret_cast<const coff_load_configuration32 *>(LoadConfig); + } + + const coff_load_configuration64 *getLoadConfig64() const { + assert(is64()); + return reinterpret_cast<const coff_load_configuration64 *>(LoadConfig); + } + StringRef getRelocationTypeName(uint16_t Type) const; + +protected: + void moveSymbolNext(DataRefImpl &Symb) const override; + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + uint32_t getSymbolAlignment(DataRefImpl Symb) const override; + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; + uint32_t getSymbolFlags(DataRefImpl Symb) const override; + Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; + Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; + void moveSectionNext(DataRefImpl &Sec) const override; + Expected<StringRef> getSectionName(DataRefImpl Sec) const override; + uint64_t getSectionAddress(DataRefImpl Sec) const override; + uint64_t getSectionIndex(DataRefImpl Sec) const override; + uint64_t getSectionSize(DataRefImpl Sec) const override; + Expected<ArrayRef<uint8_t>> + getSectionContents(DataRefImpl Sec) const override; + uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; + bool isSectionText(DataRefImpl Sec) const override; + bool isSectionData(DataRefImpl Sec) const override; + bool isSectionBSS(DataRefImpl Sec) const override; + bool isSectionVirtual(DataRefImpl Sec) const override; + relocation_iterator section_rel_begin(DataRefImpl Sec) const override; + relocation_iterator section_rel_end(DataRefImpl Sec) const override; + + void moveRelocationNext(DataRefImpl &Rel) const override; + uint64_t getRelocationOffset(DataRefImpl Rel) const override; + symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; + uint64_t getRelocationType(DataRefImpl Rel) const override; + void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const override; + +public: + COFFObjectFile(MemoryBufferRef Object, std::error_code &EC); + + basic_symbol_iterator symbol_begin() const override; + basic_symbol_iterator symbol_end() const override; + section_iterator section_begin() const override; + section_iterator section_end() const override; + + const coff_section *getCOFFSection(const SectionRef &Section) const; + COFFSymbolRef getCOFFSymbol(const DataRefImpl &Ref) const; + COFFSymbolRef getCOFFSymbol(const SymbolRef &Symbol) const; + const coff_relocation *getCOFFRelocation(const RelocationRef &Reloc) const; + unsigned getSectionID(SectionRef Sec) const; + unsigned getSymbolSectionID(SymbolRef Sym) const; + + uint8_t getBytesInAddress() const override; + StringRef getFileFormatName() const override; + Triple::ArchType getArch() const override; + Expected<uint64_t> getStartAddress() const override; + SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } + + import_directory_iterator import_directory_begin() const; + import_directory_iterator import_directory_end() const; + delay_import_directory_iterator delay_import_directory_begin() const; + delay_import_directory_iterator delay_import_directory_end() const; + export_directory_iterator export_directory_begin() const; + export_directory_iterator export_directory_end() const; + base_reloc_iterator base_reloc_begin() const; + base_reloc_iterator base_reloc_end() const; + const debug_directory *debug_directory_begin() const { + return DebugDirectoryBegin; + } + const debug_directory *debug_directory_end() const { + return DebugDirectoryEnd; + } + + iterator_range<import_directory_iterator> import_directories() const; + iterator_range<delay_import_directory_iterator> + delay_import_directories() const; + iterator_range<export_directory_iterator> export_directories() const; + iterator_range<base_reloc_iterator> base_relocs() const; + iterator_range<const debug_directory *> debug_directories() const { + return make_range(debug_directory_begin(), debug_directory_end()); + } + + const dos_header *getDOSHeader() const { + if (!PE32Header && !PE32PlusHeader) + return nullptr; + return reinterpret_cast<const dos_header *>(base()); + } + + const coff_file_header *getCOFFHeader() const { return COFFHeader; } + const coff_bigobj_file_header *getCOFFBigObjHeader() const { + return COFFBigObjHeader; + } + const pe32_header *getPE32Header() const { return PE32Header; } + const pe32plus_header *getPE32PlusHeader() const { return PE32PlusHeader; } + + std::error_code getDataDirectory(uint32_t index, + const data_directory *&Res) const; + std::error_code getSection(int32_t index, const coff_section *&Res) const; + std::error_code getSection(StringRef SectionName, + const coff_section *&Res) const; + + template <typename coff_symbol_type> + std::error_code getSymbol(uint32_t Index, + const coff_symbol_type *&Res) const { + if (Index >= getNumberOfSymbols()) + return object_error::parse_failed; + + Res = reinterpret_cast<coff_symbol_type *>(getSymbolTable()) + Index; + return std::error_code(); + } + Expected<COFFSymbolRef> getSymbol(uint32_t index) const { + if (SymbolTable16) { + const coff_symbol16 *Symb = nullptr; + if (std::error_code EC = getSymbol(index, Symb)) + return errorCodeToError(EC); + return COFFSymbolRef(Symb); + } + if (SymbolTable32) { + const coff_symbol32 *Symb = nullptr; + if (std::error_code EC = getSymbol(index, Symb)) + return errorCodeToError(EC); + return COFFSymbolRef(Symb); + } + return errorCodeToError(object_error::parse_failed); + } + + template <typename T> + std::error_code getAuxSymbol(uint32_t index, const T *&Res) const { + Expected<COFFSymbolRef> S = getSymbol(index); + if (Error E = S.takeError()) + return errorToErrorCode(std::move(E)); + Res = reinterpret_cast<const T *>(S->getRawPtr()); + return std::error_code(); + } + + std::error_code getSymbolName(COFFSymbolRef Symbol, StringRef &Res) const; + std::error_code getSymbolName(const coff_symbol_generic *Symbol, + StringRef &Res) const; + + ArrayRef<uint8_t> getSymbolAuxData(COFFSymbolRef Symbol) const; + + uint32_t getSymbolIndex(COFFSymbolRef Symbol) const; + + size_t getSymbolTableEntrySize() const { + if (COFFHeader) + return sizeof(coff_symbol16); + if (COFFBigObjHeader) + return sizeof(coff_symbol32); + llvm_unreachable("null symbol table pointer!"); + } + + ArrayRef<coff_relocation> getRelocations(const coff_section *Sec) const; + + Expected<StringRef> getSectionName(const coff_section *Sec) const; + uint64_t getSectionSize(const coff_section *Sec) const; + Error 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; + + /// Given an RVA base and size, returns a valid array of bytes or an error + /// code if the RVA and size is not contained completely within a valid + /// section. + std::error_code getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size, + ArrayRef<uint8_t> &Contents) const; + + std::error_code getHintName(uint32_t Rva, uint16_t &Hint, + StringRef &Name) const; + + /// Get PDB information out of a codeview debug directory entry. + std::error_code getDebugPDBInfo(const debug_directory *DebugDir, + const codeview::DebugInfo *&Info, + StringRef &PDBFileName) const; + + /// Get PDB information from an executable. If the information is not present, + /// Info will be set to nullptr and PDBFileName will be empty. An error is + /// returned only on corrupt object files. Convenience accessor that can be + /// used if the debug directory is not already handy. + std::error_code getDebugPDBInfo(const codeview::DebugInfo *&Info, + StringRef &PDBFileName) const; + + bool isRelocatableObject() const override; + bool is64() const { return PE32PlusHeader; } + + StringRef mapDebugSectionName(StringRef Name) const override; + + static bool classof(const Binary *v) { return v->isCOFF(); } +}; + +// The iterator for the import directory table. +class ImportDirectoryEntryRef { +public: + ImportDirectoryEntryRef() = default; + ImportDirectoryEntryRef(const coff_import_directory_table_entry *Table, + uint32_t I, const COFFObjectFile *Owner) + : ImportTable(Table), Index(I), OwningObject(Owner) {} + + bool operator==(const ImportDirectoryEntryRef &Other) const; + void moveNext(); + + imported_symbol_iterator imported_symbol_begin() const; + imported_symbol_iterator imported_symbol_end() const; + iterator_range<imported_symbol_iterator> imported_symbols() const; + + imported_symbol_iterator lookup_table_begin() const; + imported_symbol_iterator lookup_table_end() const; + iterator_range<imported_symbol_iterator> lookup_table_symbols() const; + + std::error_code getName(StringRef &Result) const; + std::error_code getImportLookupTableRVA(uint32_t &Result) const; + std::error_code getImportAddressTableRVA(uint32_t &Result) const; + + std::error_code + getImportTableEntry(const coff_import_directory_table_entry *&Result) const; + +private: + const coff_import_directory_table_entry *ImportTable; + uint32_t Index; + const COFFObjectFile *OwningObject = nullptr; +}; + +class DelayImportDirectoryEntryRef { +public: + DelayImportDirectoryEntryRef() = default; + DelayImportDirectoryEntryRef(const delay_import_directory_table_entry *T, + uint32_t I, const COFFObjectFile *Owner) + : Table(T), Index(I), OwningObject(Owner) {} + + bool operator==(const DelayImportDirectoryEntryRef &Other) const; + void moveNext(); + + imported_symbol_iterator imported_symbol_begin() const; + imported_symbol_iterator imported_symbol_end() const; + iterator_range<imported_symbol_iterator> imported_symbols() const; + + std::error_code getName(StringRef &Result) const; + std::error_code getDelayImportTable( + const delay_import_directory_table_entry *&Result) const; + std::error_code getImportAddress(int AddrIndex, uint64_t &Result) const; + +private: + const delay_import_directory_table_entry *Table; + uint32_t Index; + const COFFObjectFile *OwningObject = nullptr; +}; + +// The iterator for the export directory table entry. +class ExportDirectoryEntryRef { +public: + ExportDirectoryEntryRef() = default; + ExportDirectoryEntryRef(const export_directory_table_entry *Table, uint32_t I, + const COFFObjectFile *Owner) + : ExportTable(Table), Index(I), OwningObject(Owner) {} + + bool operator==(const ExportDirectoryEntryRef &Other) const; + void moveNext(); + + std::error_code getDllName(StringRef &Result) const; + std::error_code getOrdinalBase(uint32_t &Result) const; + std::error_code getOrdinal(uint32_t &Result) const; + std::error_code getExportRVA(uint32_t &Result) const; + std::error_code getSymbolName(StringRef &Result) const; + + std::error_code isForwarder(bool &Result) const; + std::error_code getForwardTo(StringRef &Result) const; + +private: + const export_directory_table_entry *ExportTable; + uint32_t Index; + const COFFObjectFile *OwningObject = nullptr; +}; + +class ImportedSymbolRef { +public: + ImportedSymbolRef() = default; + ImportedSymbolRef(const import_lookup_table_entry32 *Entry, uint32_t I, + const COFFObjectFile *Owner) + : Entry32(Entry), Entry64(nullptr), Index(I), OwningObject(Owner) {} + ImportedSymbolRef(const import_lookup_table_entry64 *Entry, uint32_t I, + const COFFObjectFile *Owner) + : Entry32(nullptr), Entry64(Entry), Index(I), OwningObject(Owner) {} + + bool operator==(const ImportedSymbolRef &Other) const; + void moveNext(); + + std::error_code getSymbolName(StringRef &Result) const; + std::error_code isOrdinal(bool &Result) const; + std::error_code getOrdinal(uint16_t &Result) const; + std::error_code getHintNameRVA(uint32_t &Result) const; + +private: + const import_lookup_table_entry32 *Entry32; + const import_lookup_table_entry64 *Entry64; + uint32_t Index; + const COFFObjectFile *OwningObject = nullptr; +}; + +class BaseRelocRef { +public: + BaseRelocRef() = default; + BaseRelocRef(const coff_base_reloc_block_header *Header, + const COFFObjectFile *Owner) + : Header(Header), Index(0) {} + + bool operator==(const BaseRelocRef &Other) const; + void moveNext(); + + std::error_code getType(uint8_t &Type) const; + std::error_code getRVA(uint32_t &Result) const; + +private: + const coff_base_reloc_block_header *Header; + uint32_t Index; +}; + +class ResourceSectionRef { +public: + ResourceSectionRef() = default; + explicit ResourceSectionRef(StringRef Ref) : BBS(Ref, support::little) {} + + Error load(const COFFObjectFile *O); + Error load(const COFFObjectFile *O, const SectionRef &S); + + Expected<ArrayRef<UTF16>> + getEntryNameString(const coff_resource_dir_entry &Entry); + Expected<const coff_resource_dir_table &> + getEntrySubDir(const coff_resource_dir_entry &Entry); + Expected<const coff_resource_data_entry &> + getEntryData(const coff_resource_dir_entry &Entry); + Expected<const coff_resource_dir_table &> getBaseTable(); + Expected<const coff_resource_dir_entry &> + getTableEntry(const coff_resource_dir_table &Table, uint32_t Index); + + Expected<StringRef> getContents(const coff_resource_data_entry &Entry); + +private: + BinaryByteStream BBS; + + SectionRef Section; + const COFFObjectFile *Obj; + + std::vector<const coff_relocation *> Relocs; + + Expected<const coff_resource_dir_table &> getTableAtOffset(uint32_t Offset); + Expected<const coff_resource_dir_entry &> + getTableEntryAtOffset(uint32_t Offset); + Expected<const coff_resource_data_entry &> + getDataEntryAtOffset(uint32_t Offset); + Expected<ArrayRef<UTF16>> getDirStringAtOffset(uint32_t Offset); +}; + +// Corresponds to `_FPO_DATA` structure in the PE/COFF spec. +struct FpoData { + support::ulittle32_t Offset; // ulOffStart: Offset 1st byte of function code + support::ulittle32_t Size; // cbProcSize: # bytes in function + support::ulittle32_t NumLocals; // cdwLocals: # bytes in locals/4 + support::ulittle16_t NumParams; // cdwParams: # bytes in params/4 + support::ulittle16_t Attributes; + + // cbProlog: # bytes in prolog + int getPrologSize() const { return Attributes & 0xF; } + + // cbRegs: # regs saved + int getNumSavedRegs() const { return (Attributes >> 8) & 0x7; } + + // fHasSEH: true if seh is func + bool hasSEH() const { return (Attributes >> 9) & 1; } + + // fUseBP: true if EBP has been allocated + bool useBP() const { return (Attributes >> 10) & 1; } + + // cbFrame: frame pointer + frame_type getFP() const { return static_cast<frame_type>(Attributes >> 14); } +}; + +} // end namespace object + +} // end namespace llvm + +#endif // LLVM_OBJECT_COFF_H diff --git a/third_party/llvm-project/include/llvm/Object/CVDebugRecord.h b/third_party/llvm-project/include/llvm/Object/CVDebugRecord.h new file mode 100644 index 000000000..d41c7391f --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/CVDebugRecord.h @@ -0,0 +1,54 @@ +//===- CVDebugRecord.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_CVDEBUGRECORD_H +#define LLVM_OBJECT_CVDEBUGRECORD_H + +#include "llvm/Support/Endian.h" + +namespace llvm { +namespace OMF { +struct Signature { + enum ID : uint32_t { + PDB70 = 0x53445352, // RSDS + PDB20 = 0x3031424e, // NB10 + CV50 = 0x3131424e, // NB11 + CV41 = 0x3930424e, // NB09 + }; + + support::ulittle32_t CVSignature; + support::ulittle32_t Offset; +}; +} + +namespace codeview { +struct PDB70DebugInfo { + support::ulittle32_t CVSignature; + uint8_t Signature[16]; + support::ulittle32_t Age; + // char PDBFileName[]; +}; + +struct PDB20DebugInfo { + support::ulittle32_t CVSignature; + support::ulittle32_t Offset; + support::ulittle32_t Signature; + support::ulittle32_t Age; + // char PDBFileName[]; +}; + +union DebugInfo { + struct OMF::Signature Signature; + struct PDB20DebugInfo PDB20; + struct PDB70DebugInfo PDB70; +}; +} +} + +#endif + diff --git a/third_party/llvm-project/include/llvm/Object/Decompressor.h b/third_party/llvm-project/include/llvm/Object/Decompressor.h new file mode 100644 index 000000000..cc918481b --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/Decompressor.h @@ -0,0 +1,66 @@ +//===-- Decompressor.h ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===/ + +#ifndef LLVM_OBJECT_DECOMPRESSOR_H +#define LLVM_OBJECT_DECOMPRESSOR_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Object/ObjectFile.h" + +namespace llvm { +namespace object { + +/// Decompressor helps to handle decompression of compressed sections. +class Decompressor { +public: + /// Create decompressor object. + /// @param Name Section name. + /// @param Data Section content. + /// @param IsLE Flag determines if Data is in little endian form. + /// @param Is64Bit Flag determines if object is 64 bit. + static Expected<Decompressor> create(StringRef Name, StringRef Data, + bool IsLE, bool Is64Bit); + + /// Resize the buffer and uncompress section data into it. + /// @param Out Destination buffer. + template <class T> Error resizeAndDecompress(T &Out) { + Out.resize(DecompressedSize); + return decompress({Out.data(), (size_t)DecompressedSize}); + } + + /// Uncompress section data to raw buffer provided. + /// @param Buffer Destination buffer. + Error decompress(MutableArrayRef<char> Buffer); + + /// Return memory buffer size required for decompression. + uint64_t getDecompressedSize() { return DecompressedSize; } + + /// Return true if section is compressed, including gnu-styled case. + static bool isCompressed(const object::SectionRef &Section); + + /// Return true if section is a ELF compressed one. + static bool isCompressedELFSection(uint64_t Flags, StringRef Name); + + /// Return true if section name matches gnu style compressed one. + static bool isGnuStyle(StringRef Name); + +private: + Decompressor(StringRef Data); + + Error consumeCompressedGnuHeader(); + Error consumeCompressedZLibHeader(bool Is64Bit, bool IsLittleEndian); + + StringRef SectionData; + uint64_t DecompressedSize; +}; + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_DECOMPRESSOR_H diff --git a/third_party/llvm-project/include/llvm/Object/ELF.h b/third_party/llvm-project/include/llvm/Object/ELF.h new file mode 100644 index 000000000..0d5482ae8 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/ELF.h @@ -0,0 +1,723 @@ +//===- ELF.h - ELF object file implementation -------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the ELFFile template class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ELF_H +#define LLVM_OBJECT_ELF_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <limits> +#include <utility> + +namespace llvm { +namespace object { + +StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type); +uint32_t getELFRelativeRelocationType(uint32_t Machine); +StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type); + +// Subclasses of ELFFile may need this for template instantiation +inline std::pair<unsigned char, unsigned char> +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]); +} + +static inline Error createError(const Twine &Err) { + return make_error<StringError>(Err, object_error::parse_failed); +} + +template <class ELFT> class ELFFile; + +template <class ELFT> +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()) + "]"; + // 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 + // failure. + llvm::consumeError(TableOrErr.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(); } + + size_t getBufSize() const { return Buf.size(); } + +private: + StringRef Buf; + + ELFFile(StringRef Object); + +public: + 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<StringRef> + getStringTable(const Elf_Shdr *Section, + WarningHandler WarnHandler = &defaultWarningHandler) const; + Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const; + Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section, + Elf_Shdr_Range Sections) const; + + Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section) const; + Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section, + Elf_Shdr_Range Sections) const; + + StringRef getRelocationTypeName(uint32_t Type) const; + void getRelocationTypeName(uint32_t Type, + SmallVectorImpl<char> &Result) const; + uint32_t getRelativeRelocationType() const; + + std::string getDynamicTagAsString(unsigned Arch, uint64_t Type) const; + std::string getDynamicTagAsString(uint64_t Type) const; + + /// Get the symbol for a given relocation. + Expected<const Elf_Sym *> getRelocationSymbol(const Elf_Rel *Rel, + const Elf_Shdr *SymTab) const; + + static Expected<ELFFile> create(StringRef Object); + + bool isLE() const { + return 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<Elf_Sym_Range> symbols(const Elf_Shdr *Sec) const { + if (!Sec) + return makeArrayRef<Elf_Sym>(nullptr, nullptr); + return getSectionContentsAsArray<Elf_Sym>(Sec); + } + + 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 { + return getSectionContentsAsArray<Elf_Rel>(Sec); + } + + 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; + + 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)) + return createError("invalid e_phentsize: " + + Twine(getHeader()->e_phentsize)); + if (getHeader()->e_phoff + + (getHeader()->e_phnum * getHeader()->e_phentsize) > + 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); + } + + /// Get an iterator over notes in a program header. + /// + /// The program header must be of type \c PT_NOTE. + /// + /// \param Phdr the program header to iterate over. + /// \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 { + assert(Phdr.p_type == ELF::PT_NOTE && "Phdr is not of type PT_NOTE"); + ErrorAsOutParameter ErrAsOutParam(&Err); + if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) { + Err = createError("PT_NOTE header has 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); + } + + /// Get an iterator over notes in a section. + /// + /// The section must be of type \c SHT_NOTE. + /// + /// \param Shdr the section to iterate over. + /// \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 { + assert(Shdr.sh_type == ELF::SHT_NOTE && "Shdr is not of type SHT_NOTE"); + ErrorAsOutParameter ErrAsOutParam(&Err); + if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) { + Err = createError("SHT_NOTE section " + getSecIndexForError(this, &Shdr) + + " has 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); + } + + /// Get the end iterator for notes. + Elf_Note_Iterator notes_end() const { + return Elf_Note_Iterator(); + } + + /// Get an iterator range over notes of a program header. + /// + /// The program header must be of type \c PT_NOTE. + /// + /// \param Phdr the program header to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + iterator_range<Elf_Note_Iterator> notes(const Elf_Phdr &Phdr, + Error &Err) const { + return make_range(notes_begin(Phdr, Err), notes_end()); + } + + /// Get an iterator range over notes of a section. + /// + /// The section must be of type \c SHT_NOTE. + /// + /// \param Shdr the section to iterate over. + /// \param Err [out] an error to support fallible iteration, which should + /// be checked after iteration ends. + iterator_range<Elf_Note_Iterator> notes(const Elf_Shdr &Shdr, + Error &Err) const { + return make_range(notes_begin(Shdr, Err), notes_end()); + } + + Expected<StringRef> getSectionStringTable( + Elf_Shdr_Range Sections, + WarningHandler WarnHandler = &defaultWarningHandler) 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, + const Elf_Shdr *SymTab, + ArrayRef<Elf_Word> ShndxTable) const; + Expected<const Elf_Shdr *> getSection(const Elf_Sym *Sym, + Elf_Sym_Range Symtab, + ArrayRef<Elf_Word> ShndxTable) const; + Expected<const Elf_Shdr *> getSection(uint32_t Index) const; + + Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec, + uint32_t Index) const; + + Expected<StringRef> + getSectionName(const Elf_Shdr *Section, + 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; +}; + +using ELF32LEFile = ELFFile<ELF32LE>; +using ELF64LEFile = ELFFile<ELF64LE>; +using ELF32BEFile = ELFFile<ELF32BE>; +using ELF64BEFile = ELFFile<ELF64BE>; + +template <class ELFT> +inline Expected<const typename ELFT::Shdr *> +getSection(typename ELFT::ShdrRange Sections, uint32_t Index) { + if (Index >= Sections.size()) + return createError("invalid section index: " + Twine(Index)); + return &Sections[Index]; +} + +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()) + return createError( + "extended symbol index (" + Twine(Index) + + ") is past the end of the SHT_SYMTAB_SHNDX section of size " + + Twine(ShndxTable.size())); + + // The size of the table was checked in getSHNDXTable. + return ShndxTable[Index]; +} + +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; + if (Index == ELF::SHN_XINDEX) { + auto ErrorOrIndex = getExtendedSymbolTableIndex<ELFT>( + Sym, Syms.begin(), ShndxTable); + if (!ErrorOrIndex) + return ErrorOrIndex.takeError(); + return *ErrorOrIndex; + } + if (Index == ELF::SHN_UNDEF || Index >= ELF::SHN_LORESERVE) + return 0; + return Index; +} + +template <class ELFT> +Expected<const typename ELFT::Shdr *> +ELFFile<ELFT>::getSection(const Elf_Sym *Sym, const Elf_Shdr *SymTab, + ArrayRef<Elf_Word> ShndxTable) const { + auto SymsOrErr = symbols(SymTab); + if (!SymsOrErr) + return SymsOrErr.takeError(); + return getSection(Sym, *SymsOrErr, ShndxTable); +} + +template <class ELFT> +Expected<const typename ELFT::Shdr *> +ELFFile<ELFT>::getSection(const Elf_Sym *Sym, Elf_Sym_Range Symbols, + ArrayRef<Elf_Word> ShndxTable) const { + auto IndexOrErr = getSectionIndex(Sym, Symbols, ShndxTable); + if (!IndexOrErr) + return IndexOrErr.takeError(); + uint32_t Index = *IndexOrErr; + if (Index == 0) + return nullptr; + return getSection(Index); +} + +template <class ELFT> +Expected<const typename ELFT::Sym *> +ELFFile<ELFT>::getSymbol(const Elf_Shdr *Sec, uint32_t Index) const { + 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)); + + uintX_t Offset = Sec->sh_offset; + uintX_t Size = Sec->sh_size; + + if (Size % sizeof(T)) + 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) + + " has a sh_offset (0x" + Twine::utohexstr(Offset) + + ") + sh_size (0x" + Twine(Size) + + ") that cannot be represented"); + + if (Offset % alignof(T)) + // TODO: this error is untested. + return createError("unaligned data"); + + const T *Start = reinterpret_cast<const T *>(base() + Offset); + return makeArrayRef(Start, Size / sizeof(T)); +} + +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); +} + +template <class ELFT> +void ELFFile<ELFT>::getRelocationTypeName(uint32_t Type, + SmallVectorImpl<char> &Result) const { + 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; + + // Concat all three relocation type names. + StringRef Name = getRelocationTypeName(Type1); + Result.append(Name.begin(), Name.end()); + + Name = getRelocationTypeName(Type2); + Result.append(1, '/'); + Result.append(Name.begin(), Name.end()); + + Name = getRelocationTypeName(Type3); + Result.append(1, '/'); + Result.append(Name.begin(), Name.end()); + } +} + +template <class ELFT> +uint32_t ELFFile<ELFT>::getRelativeRelocationType() const { + return getELFRelativeRelocationType(getHeader()->e_machine); +} + +template <class ELFT> +Expected<const typename ELFT::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> +Expected<StringRef> +ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections, + WarningHandler WarnHandler) const { + uint32_t Index = getHeader()->e_shstrndx; + if (Index == ELF::SHN_XINDEX) + Index = Sections[0].sh_link; + + if (!Index) // no section string table. + return ""; + if (Index >= Sections.size()) + 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) {} + +template <class ELFT> +Expected<ELFFile<ELFT>> ELFFile<ELFT>::create(StringRef Object) { + if (sizeof(Elf_Ehdr) > Object.size()) + return createError("invalid buffer: the size (" + Twine(Object.size()) + + ") is smaller than an ELF header (" + + Twine(sizeof(Elf_Ehdr)) + ")"); + return ELFFile(Object); +} + +template <class ELFT> +Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const { + const uintX_t SectionTableOffset = getHeader()->e_shoff; + if (SectionTableOffset == 0) + return ArrayRef<Elf_Shdr>(); + + if (getHeader()->e_shentsize != sizeof(Elf_Shdr)) + return createError("invalid e_shentsize in ELF header: " + + Twine(getHeader()->e_shentsize)); + + const uint64_t FileSize = Buf.size(); + 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)); + + // Invalid address alignment of section headers + if (SectionTableOffset & (alignof(Elf_Shdr) - 1)) + // TODO: this error is untested. + return createError("invalid alignment of section headers"); + + const Elf_Shdr *First = + reinterpret_cast<const Elf_Shdr *>(base() + SectionTableOffset); + + uintX_t NumSections = getHeader()->e_shnum; + if (NumSections == 0) + NumSections = First->sh_size; + + if (NumSections > UINT64_MAX / sizeof(Elf_Shdr)) + 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); +} + +template <class ELFT> +template <typename T> +Expected<const T *> ELFFile<ELFT>::getEntry(uint32_t Section, + uint32_t Entry) const { + auto SecOrErr = getSection(Section); + if (!SecOrErr) + return SecOrErr.takeError(); + return getEntry<T>(*SecOrErr, Entry); +} + +template <class ELFT> +template <typename T> +Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr *Section, + uint32_t Entry) const { + if (sizeof(T) != Section->sh_entsize) + return createError("section " + getSecIndexForError(this, Section) + + " has invalid sh_entsize: expected " + Twine(sizeof(T)) + + ", but got " + Twine(Section->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); +} + +template <class ELFT> +Expected<const typename ELFT::Shdr *> +ELFFile<ELFT>::getSection(uint32_t Index) const { + auto TableOrErr = sections(); + if (!TableOrErr) + return TableOrErr.takeError(); + return object::getSection<ELFT>(*TableOrErr, Index); +} + +template <class ELFT> +Expected<StringRef> +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()) + return createError("SHT_STRTAB string table section " + + getSecIndexForError(this, Section) + " is empty"); + if (Data.back() != '\0') + return createError("SHT_STRTAB string table section " + + getSecIndexForError(this, Section) + + " is non-null terminated"); + return StringRef(Data.begin(), Data.size()); +} + +template <class ELFT> +Expected<ArrayRef<typename ELFT::Word>> +ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section) const { + auto SectionsOrErr = sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + return getSHNDXTable(Section, *SectionsOrErr); +} + +template <class ELFT> +Expected<ArrayRef<typename ELFT::Word>> +ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section, + Elf_Shdr_Range Sections) const { + assert(Section.sh_type == ELF::SHT_SYMTAB_SHNDX); + auto VOrErr = getSectionContentsAsArray<Elf_Word>(&Section); + if (!VOrErr) + return VOrErr.takeError(); + ArrayRef<Elf_Word> V = *VOrErr; + auto SymTableOrErr = object::getSection<ELFT>(Sections, Section.sh_link); + if (!SymTableOrErr) + return SymTableOrErr.takeError(); + const Elf_Shdr &SymTable = **SymTableOrErr; + if (SymTable.sh_type != ELF::SHT_SYMTAB && + SymTable.sh_type != ELF::SHT_DYNSYM) + return createError("SHT_SYMTAB_SHNDX section is linked with " + + object::getELFSectionTypeName(getHeader()->e_machine, + SymTable.sh_type) + + " section (expected SHT_SYMTAB/SHT_DYNSYM)"); + + 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; +} + +template <class ELFT> +Expected<StringRef> +ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec) const { + auto SectionsOrErr = sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + return getStringTableForSymtab(Sec, *SectionsOrErr); +} + +template <class ELFT> +Expected<StringRef> +ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec, + 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); + if (!SectionOrErr) + return SectionOrErr.takeError(); + return getStringTable(*SectionOrErr); +} + +template <class ELFT> +Expected<StringRef> +ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section, + WarningHandler WarnHandler) const { + auto SectionsOrErr = sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + 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, + StringRef DotShstrtab) const { + uint32_t Offset = Section->sh_name; + if (Offset == 0) + return StringRef(); + if (Offset >= DotShstrtab.size()) + return createError("a section " + getSecIndexForError(this, Section) + + " has an invalid sh_name (0x" + + Twine::utohexstr(Offset) + + ") offset which goes past the end of the " + "section name string table"); + return StringRef(DotShstrtab.data() + 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 +inline unsigned hashSysV(StringRef SymbolName) { + unsigned h = 0, g; + for (char C : SymbolName) { + h = (h << 4) + C; + g = h & 0xf0000000L; + if (g != 0) + h ^= g >> 24; + h &= ~g; + } + return h; +} + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_ELF_H diff --git a/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h b/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h new file mode 100644 index 000000000..8a68e4947 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/ELFObjectFile.h @@ -0,0 +1,1214 @@ +//===- ELFObjectFile.h - ELF object file implementation ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the ELFObjectFile template class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ELFOBJECTFILE_H +#define LLVM_OBJECT_ELFOBJECTFILE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ELF.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/Error.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/ARMAttributeParser.h" +#include "llvm/Support/ARMBuildAttributes.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cassert> +#include <cstdint> +#include <system_error> + +namespace llvm { +namespace object { + +constexpr int NumElfSymbolTypes = 16; +extern const llvm::EnumEntry<unsigned> ElfSymbolTypes[NumElfSymbolTypes]; + +class elf_symbol_iterator; + +class ELFObjectFileBase : public ObjectFile { + friend class ELFRelocationRef; + friend class ELFSectionRef; + friend class ELFSymbolRef; + +protected: + ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source); + + virtual uint64_t getSymbolSize(DataRefImpl Symb) const = 0; + virtual uint8_t getSymbolBinding(DataRefImpl Symb) const = 0; + virtual uint8_t getSymbolOther(DataRefImpl Symb) const = 0; + virtual uint8_t getSymbolELFType(DataRefImpl Symb) const = 0; + + virtual uint32_t getSectionType(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionFlags(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0; + + virtual Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0; + virtual Error getBuildAttributes(ARMAttributeParser &Attributes) const = 0; + +public: + using elf_symbol_iterator_range = iterator_range<elf_symbol_iterator>; + + virtual elf_symbol_iterator_range getDynamicSymbolIterators() const = 0; + + /// Returns platform-specific object flags, if any. + virtual unsigned getPlatformFlags() const = 0; + + elf_symbol_iterator_range symbols() const; + + static bool classof(const Binary *v) { return v->isELF(); } + + SubtargetFeatures getFeatures() const override; + + SubtargetFeatures getMIPSFeatures() const; + + SubtargetFeatures getARMFeatures() const; + + SubtargetFeatures getRISCVFeatures() const; + + void setARMSubArch(Triple &TheTriple) const override; + + virtual uint16_t getEType() const = 0; + + virtual uint16_t getEMachine() const = 0; + + std::vector<std::pair<DataRefImpl, uint64_t>> getPltAddresses() const; +}; + +class ELFSectionRef : public SectionRef { +public: + ELFSectionRef(const SectionRef &B) : SectionRef(B) { + assert(isa<ELFObjectFileBase>(SectionRef::getObject())); + } + + const ELFObjectFileBase *getObject() const { + return cast<ELFObjectFileBase>(SectionRef::getObject()); + } + + uint32_t getType() const { + return getObject()->getSectionType(getRawDataRefImpl()); + } + + uint64_t getFlags() const { + return getObject()->getSectionFlags(getRawDataRefImpl()); + } + + uint64_t getOffset() const { + return getObject()->getSectionOffset(getRawDataRefImpl()); + } +}; + +class elf_section_iterator : public section_iterator { +public: + elf_section_iterator(const section_iterator &B) : section_iterator(B) { + assert(isa<ELFObjectFileBase>(B->getObject())); + } + + const ELFSectionRef *operator->() const { + return static_cast<const ELFSectionRef *>(section_iterator::operator->()); + } + + const ELFSectionRef &operator*() const { + return static_cast<const ELFSectionRef &>(section_iterator::operator*()); + } +}; + +class ELFSymbolRef : public SymbolRef { +public: + ELFSymbolRef(const SymbolRef &B) : SymbolRef(B) { + assert(isa<ELFObjectFileBase>(SymbolRef::getObject())); + } + + const ELFObjectFileBase *getObject() const { + return cast<ELFObjectFileBase>(BasicSymbolRef::getObject()); + } + + uint64_t getSize() const { + return getObject()->getSymbolSize(getRawDataRefImpl()); + } + + uint8_t getBinding() const { + return getObject()->getSymbolBinding(getRawDataRefImpl()); + } + + uint8_t getOther() const { + return getObject()->getSymbolOther(getRawDataRefImpl()); + } + + uint8_t getELFType() const { + return getObject()->getSymbolELFType(getRawDataRefImpl()); + } + + StringRef getELFTypeName() const { + uint8_t Type = getELFType(); + for (auto &EE : ElfSymbolTypes) { + if (EE.Value == Type) { + return EE.AltName; + } + } + return ""; + } +}; + +class elf_symbol_iterator : public symbol_iterator { +public: + elf_symbol_iterator(const basic_symbol_iterator &B) + : symbol_iterator(SymbolRef(B->getRawDataRefImpl(), + cast<ELFObjectFileBase>(B->getObject()))) {} + + const ELFSymbolRef *operator->() const { + return static_cast<const ELFSymbolRef *>(symbol_iterator::operator->()); + } + + const ELFSymbolRef &operator*() const { + return static_cast<const ELFSymbolRef &>(symbol_iterator::operator*()); + } +}; + +class ELFRelocationRef : public RelocationRef { +public: + ELFRelocationRef(const RelocationRef &B) : RelocationRef(B) { + assert(isa<ELFObjectFileBase>(RelocationRef::getObject())); + } + + const ELFObjectFileBase *getObject() const { + return cast<ELFObjectFileBase>(RelocationRef::getObject()); + } + + Expected<int64_t> getAddend() const { + return getObject()->getRelocationAddend(getRawDataRefImpl()); + } +}; + +class elf_relocation_iterator : public relocation_iterator { +public: + elf_relocation_iterator(const relocation_iterator &B) + : relocation_iterator(RelocationRef( + B->getRawDataRefImpl(), cast<ELFObjectFileBase>(B->getObject()))) {} + + const ELFRelocationRef *operator->() const { + return static_cast<const ELFRelocationRef *>( + relocation_iterator::operator->()); + } + + const ELFRelocationRef &operator*() const { + return static_cast<const ELFRelocationRef &>( + relocation_iterator::operator*()); + } +}; + +inline ELFObjectFileBase::elf_symbol_iterator_range +ELFObjectFileBase::symbols() const { + return elf_symbol_iterator_range(symbol_begin(), symbol_end()); +} + +template <class ELFT> class ELFObjectFile : public ELFObjectFileBase { + uint16_t getEMachine() const override; + uint16_t getEType() const override; + uint64_t getSymbolSize(DataRefImpl Sym) const override; + +public: + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + + using uintX_t = typename ELFT::uint; + + using Elf_Sym = typename ELFT::Sym; + using Elf_Shdr = typename ELFT::Shdr; + using Elf_Ehdr = typename ELFT::Ehdr; + using Elf_Rel = typename ELFT::Rel; + using Elf_Rela = typename ELFT::Rela; + using Elf_Dyn = typename ELFT::Dyn; + + SectionRef toSectionRef(const Elf_Shdr *Sec) const { + return SectionRef(toDRI(Sec), this); + } + +private: + ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF, + const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, + ArrayRef<Elf_Word> ShndxTable); + +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; + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + uint32_t getSymbolAlignment(DataRefImpl Symb) const override; + uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; + uint32_t getSymbolFlags(DataRefImpl Symb) const override; + uint8_t getSymbolBinding(DataRefImpl Symb) const override; + uint8_t getSymbolOther(DataRefImpl Symb) const override; + uint8_t getSymbolELFType(DataRefImpl Symb) const override; + Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; + Expected<section_iterator> getSymbolSection(const Elf_Sym *Symb, + const Elf_Shdr *SymTab) const; + Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; + + void moveSectionNext(DataRefImpl &Sec) const override; + Expected<StringRef> getSectionName(DataRefImpl Sec) const override; + uint64_t getSectionAddress(DataRefImpl Sec) const override; + uint64_t getSectionIndex(DataRefImpl Sec) const override; + uint64_t getSectionSize(DataRefImpl Sec) const override; + Expected<ArrayRef<uint8_t>> + getSectionContents(DataRefImpl Sec) const override; + uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; + bool isSectionText(DataRefImpl Sec) const override; + bool isSectionData(DataRefImpl Sec) const override; + bool isSectionBSS(DataRefImpl Sec) const override; + bool isSectionVirtual(DataRefImpl Sec) const override; + bool isBerkeleyText(DataRefImpl Sec) const override; + bool isBerkeleyData(DataRefImpl Sec) const override; + relocation_iterator section_rel_begin(DataRefImpl Sec) const override; + relocation_iterator section_rel_end(DataRefImpl Sec) const override; + std::vector<SectionRef> dynamic_relocation_sections() const override; + Expected<section_iterator> + getRelocatedSection(DataRefImpl Sec) const override; + + void moveRelocationNext(DataRefImpl &Rel) const override; + uint64_t getRelocationOffset(DataRefImpl Rel) const override; + symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; + uint64_t getRelocationType(DataRefImpl Rel) const override; + void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const override; + + uint32_t getSectionType(DataRefImpl Sec) const override; + uint64_t getSectionFlags(DataRefImpl Sec) const override; + uint64_t getSectionOffset(DataRefImpl Sec) const override; + StringRef getRelocationTypeName(uint32_t Type) const; + + /// Get the relocation section that contains \a Rel. + const Elf_Shdr *getRelSection(DataRefImpl Rel) const { + auto RelSecOrErr = EF.getSection(Rel.d.a); + if (!RelSecOrErr) + report_fatal_error(errorToErrorCode(RelSecOrErr.takeError()).message()); + return *RelSecOrErr; + } + + DataRefImpl toDRI(const Elf_Shdr *SymTable, unsigned SymbolNum) const { + DataRefImpl DRI; + if (!SymTable) { + DRI.d.a = 0; + DRI.d.b = 0; + return DRI; + } + assert(SymTable->sh_type == ELF::SHT_SYMTAB || + SymTable->sh_type == ELF::SHT_DYNSYM); + + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) { + DRI.d.a = 0; + DRI.d.b = 0; + return DRI; + } + uintptr_t SHT = reinterpret_cast<uintptr_t>((*SectionsOrErr).begin()); + unsigned SymTableIndex = + (reinterpret_cast<uintptr_t>(SymTable) - SHT) / sizeof(Elf_Shdr); + + DRI.d.a = SymTableIndex; + DRI.d.b = SymbolNum; + return DRI; + } + + const Elf_Shdr *toELFShdrIter(DataRefImpl Sec) const { + return reinterpret_cast<const Elf_Shdr *>(Sec.p); + } + + DataRefImpl toDRI(const Elf_Shdr *Sec) const { + DataRefImpl DRI; + DRI.p = reinterpret_cast<uintptr_t>(Sec); + return DRI; + } + + DataRefImpl toDRI(const Elf_Dyn *Dyn) const { + DataRefImpl DRI; + DRI.p = reinterpret_cast<uintptr_t>(Dyn); + return DRI; + } + + bool isExportedToOtherDSO(const Elf_Sym *ESym) const { + unsigned char Binding = ESym->getBinding(); + unsigned char Visibility = ESym->getVisibility(); + + // A symbol is exported if its binding is either GLOBAL or WEAK, and its + // visibility is either DEFAULT or PROTECTED. All other symbols are not + // exported. + return ( + (Binding == ELF::STB_GLOBAL || Binding == ELF::STB_WEAK || + Binding == ELF::STB_GNU_UNIQUE) && + (Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_PROTECTED)); + } + + Error getBuildAttributes(ARMAttributeParser &Attributes) const override { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) { + auto ErrorOrContents = EF.getSectionContents(&Sec); + if (!ErrorOrContents) + return ErrorOrContents.takeError(); + + auto Contents = ErrorOrContents.get(); + if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1) + return Error::success(); + + Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); + break; + } + } + return Error::success(); + } + + // This flag is used for classof, to distinguish ELFObjectFile from + // its subclass. If more subclasses will be created, this flag will + // have to become an enum. + bool isDyldELFObject; + +public: + ELFObjectFile(ELFObjectFile<ELFT> &&Other); + static Expected<ELFObjectFile<ELFT>> create(MemoryBufferRef Object); + + const Elf_Rel *getRel(DataRefImpl Rel) const; + const Elf_Rela *getRela(DataRefImpl Rela) const; + + const Elf_Sym *getSymbol(DataRefImpl Sym) const { + auto Ret = EF.template getEntry<Elf_Sym>(Sym.d.a, Sym.d.b); + if (!Ret) + report_fatal_error(errorToErrorCode(Ret.takeError()).message()); + return *Ret; + } + + const Elf_Shdr *getSection(DataRefImpl Sec) const { + return reinterpret_cast<const Elf_Shdr *>(Sec.p); + } + + basic_symbol_iterator symbol_begin() const override; + basic_symbol_iterator symbol_end() const override; + + elf_symbol_iterator dynamic_symbol_begin() const; + elf_symbol_iterator dynamic_symbol_end() const; + + section_iterator section_begin() const override; + section_iterator section_end() const override; + + Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const override; + + uint8_t getBytesInAddress() const override; + StringRef getFileFormatName() const override; + Triple::ArchType getArch() const override; + Expected<uint64_t> getStartAddress() const override; + + unsigned getPlatformFlags() const override { return EF.getHeader()->e_flags; } + + const ELFFile<ELFT> *getELFFile() const { return &EF; } + + bool isDyldType() const { return isDyldELFObject; } + static bool classof(const Binary *v) { + return v->getType() == getELFType(ELFT::TargetEndianness == support::little, + ELFT::Is64Bits); + } + + elf_symbol_iterator_range getDynamicSymbolIterators() const override; + + bool isRelocatableObject() const override; +}; + +using ELF32LEObjectFile = ELFObjectFile<ELF32LE>; +using ELF64LEObjectFile = ELFObjectFile<ELF64LE>; +using ELF32BEObjectFile = ELFObjectFile<ELF32BE>; +using ELF64BEObjectFile = ELFObjectFile<ELF64BE>; + +template <class ELFT> +void ELFObjectFile<ELFT>::moveSymbolNext(DataRefImpl &Sym) const { + ++Sym.d.b; +} + +template <class ELFT> +Expected<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { + const Elf_Sym *ESym = getSymbol(Sym); + auto SymTabOrErr = EF.getSection(Sym.d.a); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + const Elf_Shdr *SymTableSec = *SymTabOrErr; + auto StrTabOrErr = EF.getSection(SymTableSec->sh_link); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + const Elf_Shdr *StringTableSec = *StrTabOrErr; + auto SymStrTabOrErr = EF.getStringTable(StringTableSec); + if (!SymStrTabOrErr) + return SymStrTabOrErr.takeError(); + Expected<StringRef> Name = ESym->getName(*SymStrTabOrErr); + if (Name && !Name->empty()) + return Name; + + // If the symbol name is empty use the section name. + if (ESym->getType() == ELF::STT_SECTION) { + if (Expected<section_iterator> SecOrErr = getSymbolSection(Sym)) { + consumeError(Name.takeError()); + return (*SecOrErr)->getName(); + } + } + return Name; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionFlags(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags; +} + +template <class ELFT> +uint32_t ELFObjectFile<ELFT>::getSectionType(DataRefImpl Sec) const { + return getSection(Sec)->sh_type; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionOffset(DataRefImpl Sec) const { + return getSection(Sec)->sh_offset; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSymbolValueImpl(DataRefImpl Symb) const { + const Elf_Sym *ESym = getSymbol(Symb); + uint64_t Ret = ESym->st_value; + if (ESym->st_shndx == ELF::SHN_ABS) + return Ret; + + const Elf_Ehdr *Header = EF.getHeader(); + // Clear the ARM/Thumb or microMIPS indicator flag. + if ((Header->e_machine == ELF::EM_ARM || Header->e_machine == ELF::EM_MIPS) && + ESym->getType() == ELF::STT_FUNC) + Ret &= ~1; + + return Ret; +} + +template <class ELFT> +Expected<uint64_t> +ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const { + uint64_t Result = getSymbolValue(Symb); + const Elf_Sym *ESym = getSymbol(Symb); + switch (ESym->st_shndx) { + case ELF::SHN_COMMON: + case ELF::SHN_UNDEF: + case ELF::SHN_ABS: + return Result; + } + + const Elf_Ehdr *Header = EF.getHeader(); + auto SymTabOrErr = EF.getSection(Symb.d.a); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + const Elf_Shdr *SymTab = *SymTabOrErr; + + if (Header->e_type == ELF::ET_REL) { + auto SectionOrErr = EF.getSection(ESym, SymTab, ShndxTable); + if (!SectionOrErr) + return SectionOrErr.takeError(); + const Elf_Shdr *Section = *SectionOrErr; + if (Section) + Result += Section->sh_addr; + } + + return Result; +} + +template <class ELFT> +uint32_t ELFObjectFile<ELFT>::getSymbolAlignment(DataRefImpl Symb) const { + const Elf_Sym *Sym = getSymbol(Symb); + if (Sym->st_shndx == ELF::SHN_COMMON) + return Sym->st_value; + return 0; +} + +template <class ELFT> +uint16_t ELFObjectFile<ELFT>::getEMachine() const { + return EF.getHeader()->e_machine; +} + +template <class ELFT> uint16_t ELFObjectFile<ELFT>::getEType() const { + return EF.getHeader()->e_type; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSymbolSize(DataRefImpl Sym) const { + return getSymbol(Sym)->st_size; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getCommonSymbolSizeImpl(DataRefImpl Symb) const { + return getSymbol(Symb)->st_size; +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolBinding(DataRefImpl Symb) const { + return getSymbol(Symb)->getBinding(); +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolOther(DataRefImpl Symb) const { + return getSymbol(Symb)->st_other; +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolELFType(DataRefImpl Symb) const { + return getSymbol(Symb)->getType(); +} + +template <class ELFT> +Expected<SymbolRef::Type> +ELFObjectFile<ELFT>::getSymbolType(DataRefImpl Symb) const { + const Elf_Sym *ESym = getSymbol(Symb); + + switch (ESym->getType()) { + case ELF::STT_NOTYPE: + return SymbolRef::ST_Unknown; + case ELF::STT_SECTION: + return SymbolRef::ST_Debug; + case ELF::STT_FILE: + return SymbolRef::ST_File; + case ELF::STT_FUNC: + return SymbolRef::ST_Function; + case ELF::STT_OBJECT: + case ELF::STT_COMMON: + case ELF::STT_TLS: + return SymbolRef::ST_Data; + default: + return SymbolRef::ST_Other; + } +} + +template <class ELFT> +uint32_t ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const { + const Elf_Sym *ESym = getSymbol(Sym); + + uint32_t Result = SymbolRef::SF_None; + + if (ESym->getBinding() != ELF::STB_LOCAL) + Result |= SymbolRef::SF_Global; + + if (ESym->getBinding() == ELF::STB_WEAK) + Result |= SymbolRef::SF_Weak; + + if (ESym->st_shndx == ELF::SHN_ABS) + Result |= SymbolRef::SF_Absolute; + + if (ESym->getType() == ELF::STT_FILE || ESym->getType() == ELF::STT_SECTION) + Result |= SymbolRef::SF_FormatSpecific; + + auto DotSymtabSecSyms = EF.symbols(DotSymtabSec); + if (DotSymtabSecSyms && ESym == (*DotSymtabSecSyms).begin()) + Result |= SymbolRef::SF_FormatSpecific; + auto DotDynSymSecSyms = EF.symbols(DotDynSymSec); + if (DotDynSymSecSyms && ESym == (*DotDynSymSecSyms).begin()) + Result |= SymbolRef::SF_FormatSpecific; + + if (EF.getHeader()->e_machine == ELF::EM_ARM) { + if (Expected<StringRef> NameOrErr = getSymbolName(Sym)) { + StringRef Name = *NameOrErr; + if (Name.startswith("$d") || Name.startswith("$t") || + Name.startswith("$a")) + Result |= SymbolRef::SF_FormatSpecific; + } else { + // TODO: Actually report errors helpfully. + consumeError(NameOrErr.takeError()); + } + if (ESym->getType() == ELF::STT_FUNC && (ESym->st_value & 1) == 1) + Result |= SymbolRef::SF_Thumb; + } + + if (ESym->st_shndx == ELF::SHN_UNDEF) + Result |= SymbolRef::SF_Undefined; + + if (ESym->getType() == ELF::STT_COMMON || ESym->st_shndx == ELF::SHN_COMMON) + Result |= SymbolRef::SF_Common; + + if (isExportedToOtherDSO(ESym)) + Result |= SymbolRef::SF_Exported; + + if (ESym->getVisibility() == ELF::STV_HIDDEN) + Result |= SymbolRef::SF_Hidden; + + return Result; +} + +template <class ELFT> +Expected<section_iterator> +ELFObjectFile<ELFT>::getSymbolSection(const Elf_Sym *ESym, + const Elf_Shdr *SymTab) const { + auto ESecOrErr = EF.getSection(ESym, SymTab, ShndxTable); + if (!ESecOrErr) + return ESecOrErr.takeError(); + + const Elf_Shdr *ESec = *ESecOrErr; + if (!ESec) + return section_end(); + + DataRefImpl Sec; + Sec.p = reinterpret_cast<intptr_t>(ESec); + return section_iterator(SectionRef(Sec, this)); +} + +template <class ELFT> +Expected<section_iterator> +ELFObjectFile<ELFT>::getSymbolSection(DataRefImpl Symb) const { + const Elf_Sym *Sym = getSymbol(Symb); + auto SymTabOrErr = EF.getSection(Symb.d.a); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + const Elf_Shdr *SymTab = *SymTabOrErr; + return getSymbolSection(Sym, SymTab); +} + +template <class ELFT> +void ELFObjectFile<ELFT>::moveSectionNext(DataRefImpl &Sec) const { + const Elf_Shdr *ESec = getSection(Sec); + Sec = toDRI(++ESec); +} + +template <class ELFT> +Expected<StringRef> ELFObjectFile<ELFT>::getSectionName(DataRefImpl Sec) const { + return EF.getSectionName(&*getSection(Sec)); +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionAddress(DataRefImpl Sec) const { + return getSection(Sec)->sh_addr; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionIndex(DataRefImpl Sec) const { + auto SectionsOrErr = EF.sections(); + handleAllErrors(std::move(SectionsOrErr.takeError()), + [](const ErrorInfoBase &) { + llvm_unreachable("unable to get section index"); + }); + const Elf_Shdr *First = SectionsOrErr->begin(); + return getSection(Sec) - First; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionSize(DataRefImpl Sec) const { + return getSection(Sec)->sh_size; +} + +template <class ELFT> +Expected<ArrayRef<uint8_t>> +ELFObjectFile<ELFT>::getSectionContents(DataRefImpl Sec) const { + const Elf_Shdr *EShdr = getSection(Sec); + if (EShdr->sh_type == ELF::SHT_NOBITS) + return makeArrayRef((const uint8_t *)base(), 0); + if (std::error_code EC = + checkOffset(getMemoryBufferRef(), + (uintptr_t)base() + EShdr->sh_offset, EShdr->sh_size)) + return errorCodeToError(EC); + return makeArrayRef((const uint8_t *)base() + EShdr->sh_offset, + EShdr->sh_size); +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getSectionAlignment(DataRefImpl Sec) const { + return getSection(Sec)->sh_addralign; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionCompressed(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_COMPRESSED; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionText(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionData(DataRefImpl Sec) const { + const Elf_Shdr *EShdr = getSection(Sec); + return EShdr->sh_type == ELF::SHT_PROGBITS && + EShdr->sh_flags & ELF::SHF_ALLOC && + !(EShdr->sh_flags & ELF::SHF_EXECINSTR); +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionBSS(DataRefImpl Sec) const { + 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> +std::vector<SectionRef> +ELFObjectFile<ELFT>::dynamic_relocation_sections() const { + std::vector<SectionRef> Res; + std::vector<uintptr_t> Offsets; + + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return Res; + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type != ELF::SHT_DYNAMIC) + continue; + Elf_Dyn *Dynamic = + reinterpret_cast<Elf_Dyn *>((uintptr_t)base() + Sec.sh_offset); + for (; Dynamic->d_tag != ELF::DT_NULL; Dynamic++) { + if (Dynamic->d_tag == ELF::DT_REL || Dynamic->d_tag == ELF::DT_RELA || + Dynamic->d_tag == ELF::DT_JMPREL) { + Offsets.push_back(Dynamic->d_un.d_val); + } + } + } + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (is_contained(Offsets, Sec.sh_addr)) + Res.emplace_back(toDRI(&Sec), this); + } + return Res; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isSectionVirtual(DataRefImpl Sec) const { + return getSection(Sec)->sh_type == ELF::SHT_NOBITS; +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isBerkeleyText(DataRefImpl Sec) const { + return getSection(Sec)->sh_flags & ELF::SHF_ALLOC && + (getSection(Sec)->sh_flags & ELF::SHF_EXECINSTR || + !(getSection(Sec)->sh_flags & ELF::SHF_WRITE)); +} + +template <class ELFT> +bool ELFObjectFile<ELFT>::isBerkeleyData(DataRefImpl Sec) const { + const Elf_Shdr *EShdr = getSection(Sec); + return !isBerkeleyText(Sec) && EShdr->sh_type != ELF::SHT_NOBITS && + EShdr->sh_flags & ELF::SHF_ALLOC; +} + +template <class ELFT> +relocation_iterator +ELFObjectFile<ELFT>::section_rel_begin(DataRefImpl Sec) const { + DataRefImpl RelData; + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return relocation_iterator(RelocationRef()); + uintptr_t SHT = reinterpret_cast<uintptr_t>((*SectionsOrErr).begin()); + RelData.d.a = (Sec.p - SHT) / EF.getHeader()->e_shentsize; + RelData.d.b = 0; + return relocation_iterator(RelocationRef(RelData, this)); +} + +template <class ELFT> +relocation_iterator +ELFObjectFile<ELFT>::section_rel_end(DataRefImpl Sec) const { + const Elf_Shdr *S = reinterpret_cast<const Elf_Shdr *>(Sec.p); + relocation_iterator Begin = section_rel_begin(Sec); + if (S->sh_type != ELF::SHT_RELA && S->sh_type != ELF::SHT_REL) + return Begin; + DataRefImpl RelData = Begin->getRawDataRefImpl(); + const Elf_Shdr *RelSec = getRelSection(RelData); + + // Error check sh_link here so that getRelocationSymbol can just use it. + auto SymSecOrErr = EF.getSection(RelSec->sh_link); + if (!SymSecOrErr) + report_fatal_error(errorToErrorCode(SymSecOrErr.takeError()).message()); + + RelData.d.b += S->sh_size / S->sh_entsize; + return relocation_iterator(RelocationRef(RelData, this)); +} + +template <class ELFT> +Expected<section_iterator> +ELFObjectFile<ELFT>::getRelocatedSection(DataRefImpl Sec) const { + if (EF.getHeader()->e_type != ELF::ET_REL) + return section_end(); + + const Elf_Shdr *EShdr = getSection(Sec); + uintX_t Type = EShdr->sh_type; + if (Type != ELF::SHT_REL && Type != ELF::SHT_RELA) + return section_end(); + + Expected<const Elf_Shdr *> SecOrErr = EF.getSection(EShdr->sh_info); + if (!SecOrErr) + return SecOrErr.takeError(); + return section_iterator(SectionRef(toDRI(*SecOrErr), this)); +} + +// Relocations +template <class ELFT> +void ELFObjectFile<ELFT>::moveRelocationNext(DataRefImpl &Rel) const { + ++Rel.d.b; +} + +template <class ELFT> +symbol_iterator +ELFObjectFile<ELFT>::getRelocationSymbol(DataRefImpl Rel) const { + uint32_t symbolIdx; + const Elf_Shdr *sec = getRelSection(Rel); + if (sec->sh_type == ELF::SHT_REL) + symbolIdx = getRel(Rel)->getSymbol(EF.isMips64EL()); + else + symbolIdx = getRela(Rel)->getSymbol(EF.isMips64EL()); + if (!symbolIdx) + return symbol_end(); + + // FIXME: error check symbolIdx + DataRefImpl SymbolData; + SymbolData.d.a = sec->sh_link; + SymbolData.d.b = symbolIdx; + return symbol_iterator(SymbolRef(SymbolData, this)); +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getRelocationOffset(DataRefImpl Rel) const { + const Elf_Shdr *sec = getRelSection(Rel); + if (sec->sh_type == ELF::SHT_REL) + return getRel(Rel)->r_offset; + + return getRela(Rel)->r_offset; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getRelocationType(DataRefImpl Rel) const { + const Elf_Shdr *sec = getRelSection(Rel); + if (sec->sh_type == ELF::SHT_REL) + return getRel(Rel)->getType(EF.isMips64EL()); + else + return getRela(Rel)->getType(EF.isMips64EL()); +} + +template <class ELFT> +StringRef ELFObjectFile<ELFT>::getRelocationTypeName(uint32_t Type) const { + return getELFRelocationTypeName(EF.getHeader()->e_machine, Type); +} + +template <class ELFT> +void ELFObjectFile<ELFT>::getRelocationTypeName( + DataRefImpl Rel, SmallVectorImpl<char> &Result) const { + uint32_t type = getRelocationType(Rel); + EF.getRelocationTypeName(type, Result); +} + +template <class ELFT> +Expected<int64_t> +ELFObjectFile<ELFT>::getRelocationAddend(DataRefImpl Rel) const { + if (getRelSection(Rel)->sh_type != ELF::SHT_RELA) + return createError("Section is not SHT_RELA"); + return (int64_t)getRela(Rel)->r_addend; +} + +template <class ELFT> +const typename ELFObjectFile<ELFT>::Elf_Rel * +ELFObjectFile<ELFT>::getRel(DataRefImpl Rel) const { + assert(getRelSection(Rel)->sh_type == ELF::SHT_REL); + auto Ret = EF.template getEntry<Elf_Rel>(Rel.d.a, Rel.d.b); + if (!Ret) + report_fatal_error(errorToErrorCode(Ret.takeError()).message()); + return *Ret; +} + +template <class ELFT> +const typename ELFObjectFile<ELFT>::Elf_Rela * +ELFObjectFile<ELFT>::getRela(DataRefImpl Rela) const { + assert(getRelSection(Rela)->sh_type == ELF::SHT_RELA); + auto Ret = EF.template getEntry<Elf_Rela>(Rela.d.a, Rela.d.b); + if (!Ret) + report_fatal_error(errorToErrorCode(Ret.takeError()).message()); + return *Ret; +} + +template <class ELFT> +Expected<ELFObjectFile<ELFT>> +ELFObjectFile<ELFT>::create(MemoryBufferRef Object) { + auto EFOrErr = ELFFile<ELFT>::create(Object.getBuffer()); + if (Error E = EFOrErr.takeError()) + return std::move(E); + auto EF = std::move(*EFOrErr); + + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + + const Elf_Shdr *DotDynSymSec = nullptr; + const Elf_Shdr *DotSymtabSec = nullptr; + ArrayRef<Elf_Word> ShndxTable; + for (const Elf_Shdr &Sec : *SectionsOrErr) { + switch (Sec.sh_type) { + case ELF::SHT_DYNSYM: { + if (!DotDynSymSec) + DotDynSymSec = &Sec; + break; + } + case ELF::SHT_SYMTAB: { + if (!DotSymtabSec) + DotSymtabSec = &Sec; + break; + } + case ELF::SHT_SYMTAB_SHNDX: { + auto TableOrErr = EF.getSHNDXTable(Sec); + if (!TableOrErr) + return TableOrErr.takeError(); + ShndxTable = *TableOrErr; + break; + } + } + } + return ELFObjectFile<ELFT>(Object, EF, DotDynSymSec, DotSymtabSec, + ShndxTable); +} + +template <class ELFT> +ELFObjectFile<ELFT>::ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF, + const Elf_Shdr *DotDynSymSec, + const Elf_Shdr *DotSymtabSec, + ArrayRef<Elf_Word> ShndxTable) + : ELFObjectFileBase( + getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits), + Object), + EF(EF), DotDynSymSec(DotDynSymSec), DotSymtabSec(DotSymtabSec), + ShndxTable(ShndxTable) {} + +template <class ELFT> +ELFObjectFile<ELFT>::ELFObjectFile(ELFObjectFile<ELFT> &&Other) + : ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec, + Other.DotSymtabSec, Other.ShndxTable) {} + +template <class ELFT> +basic_symbol_iterator ELFObjectFile<ELFT>::symbol_begin() const { + DataRefImpl Sym = + toDRI(DotSymtabSec, + DotSymtabSec && DotSymtabSec->sh_size >= sizeof(Elf_Sym) ? 1 : 0); + return basic_symbol_iterator(SymbolRef(Sym, this)); +} + +template <class ELFT> +basic_symbol_iterator ELFObjectFile<ELFT>::symbol_end() const { + const Elf_Shdr *SymTab = DotSymtabSec; + if (!SymTab) + return symbol_begin(); + DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym)); + return basic_symbol_iterator(SymbolRef(Sym, this)); +} + +template <class ELFT> +elf_symbol_iterator ELFObjectFile<ELFT>::dynamic_symbol_begin() const { + 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 = DotDynSymSec; + if (!SymTab) + return dynamic_symbol_begin(); + DataRefImpl Sym = toDRI(SymTab, SymTab->sh_size / sizeof(Elf_Sym)); + return basic_symbol_iterator(SymbolRef(Sym, this)); +} + +template <class ELFT> +section_iterator ELFObjectFile<ELFT>::section_begin() const { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return section_iterator(SectionRef()); + return section_iterator(SectionRef(toDRI((*SectionsOrErr).begin()), this)); +} + +template <class ELFT> +section_iterator ELFObjectFile<ELFT>::section_end() const { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return section_iterator(SectionRef()); + return section_iterator(SectionRef(toDRI((*SectionsOrErr).end()), this)); +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getBytesInAddress() const { + return ELFT::Is64Bits ? 8 : 4; +} + +template <class ELFT> +StringRef ELFObjectFile<ELFT>::getFileFormatName() const { + bool IsLittleEndian = ELFT::TargetEndianness == support::little; + switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + case ELF::ELFCLASS32: + 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_LANAI: + return "ELF32-lanai"; + case ELF::EM_MIPS: + return "ELF32-mips"; + case ELF::EM_MSP430: + return "ELF32-msp430"; + case ELF::EM_PPC: + return "ELF32-ppc"; + case ELF::EM_RISCV: + return "ELF32-riscv"; + case ELF::EM_SPARC: + case ELF::EM_SPARC32PLUS: + return "ELF32-sparc"; + case ELF::EM_AMDGPU: + return "ELF32-amdgpu"; + default: + return "ELF32-unknown"; + } + case ELF::ELFCLASS64: + switch (EF.getHeader()->e_machine) { + case ELF::EM_386: + return "ELF64-i386"; + case ELF::EM_X86_64: + return "ELF64-x86-64"; + case ELF::EM_AARCH64: + return (IsLittleEndian ? "ELF64-aarch64-little" : "ELF64-aarch64-big"); + case ELF::EM_PPC64: + return "ELF64-ppc64"; + case ELF::EM_RISCV: + return "ELF64-riscv"; + case ELF::EM_S390: + return "ELF64-s390"; + case ELF::EM_SPARCV9: + return "ELF64-sparc"; + case ELF::EM_MIPS: + return "ELF64-mips"; + case ELF::EM_AMDGPU: + return "ELF64-amdgpu"; + case ELF::EM_BPF: + return "ELF64-BPF"; + default: + return "ELF64-unknown"; + } + default: + // FIXME: Proper error handling. + report_fatal_error("Invalid ELFCLASS!"); + } +} + +template <class ELFT> Triple::ArchType 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; + case ELF::EM_AARCH64: + return IsLittleEndian ? Triple::aarch64 : Triple::aarch64_be; + case ELF::EM_ARM: + return Triple::arm; + case ELF::EM_AVR: + return Triple::avr; + case ELF::EM_HEXAGON: + return Triple::hexagon; + case ELF::EM_LANAI: + return Triple::lanai; + case ELF::EM_MIPS: + switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + case ELF::ELFCLASS32: + return IsLittleEndian ? Triple::mipsel : Triple::mips; + case ELF::ELFCLASS64: + return IsLittleEndian ? Triple::mips64el : Triple::mips64; + default: + report_fatal_error("Invalid ELFCLASS!"); + } + case ELF::EM_MSP430: + return Triple::msp430; + case ELF::EM_PPC: + return Triple::ppc; + case ELF::EM_PPC64: + return IsLittleEndian ? Triple::ppc64le : Triple::ppc64; + case ELF::EM_RISCV: + switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { + case ELF::ELFCLASS32: + return Triple::riscv32; + case ELF::ELFCLASS64: + return Triple::riscv64; + default: + report_fatal_error("Invalid ELFCLASS!"); + } + case ELF::EM_S390: + return Triple::systemz; + + case ELF::EM_SPARC: + case ELF::EM_SPARC32PLUS: + return IsLittleEndian ? Triple::sparcel : Triple::sparc; + case ELF::EM_SPARCV9: + return Triple::sparcv9; + + case ELF::EM_AMDGPU: { + if (!IsLittleEndian) + return Triple::UnknownArch; + + unsigned MACH = EF.getHeader()->e_flags & ELF::EF_AMDGPU_MACH; + if (MACH >= ELF::EF_AMDGPU_MACH_R600_FIRST && + MACH <= ELF::EF_AMDGPU_MACH_R600_LAST) + return Triple::r600; + if (MACH >= ELF::EF_AMDGPU_MACH_AMDGCN_FIRST && + MACH <= ELF::EF_AMDGPU_MACH_AMDGCN_LAST) + return Triple::amdgcn; + + return Triple::UnknownArch; + } + + case ELF::EM_BPF: + return IsLittleEndian ? Triple::bpfel : Triple::bpfeb; + + default: + return Triple::UnknownArch; + } +} + +template <class ELFT> +Expected<uint64_t> ELFObjectFile<ELFT>::getStartAddress() const { + return EF.getHeader()->e_entry; +} + +template <class ELFT> +ELFObjectFileBase::elf_symbol_iterator_range +ELFObjectFile<ELFT>::getDynamicSymbolIterators() const { + return make_range(dynamic_symbol_begin(), dynamic_symbol_end()); +} + +template <class ELFT> bool ELFObjectFile<ELFT>::isRelocatableObject() const { + return EF.getHeader()->e_type == ELF::ET_REL; +} + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_ELFOBJECTFILE_H diff --git a/third_party/llvm-project/include/llvm/Object/ELFTypes.h b/third_party/llvm-project/include/llvm/Object/ELFTypes.h new file mode 100644 index 000000000..7d1ade4d5 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/ELFTypes.h @@ -0,0 +1,763 @@ +//===- ELFTypes.h - Endian specific types for ELF ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ELFTYPES_H +#define LLVM_OBJECT_ELFTYPES_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cassert> +#include <cstdint> +#include <cstring> +#include <type_traits> + +namespace llvm { +namespace object { + +using support::endianness; + +template <class ELFT> struct Elf_Ehdr_Impl; +template <class ELFT> struct Elf_Shdr_Impl; +template <class ELFT> struct Elf_Sym_Impl; +template <class ELFT> struct Elf_Dyn_Impl; +template <class ELFT> struct Elf_Phdr_Impl; +template <class ELFT, bool isRela> struct Elf_Rel_Impl; +template <class ELFT> struct Elf_Verdef_Impl; +template <class ELFT> struct Elf_Verdaux_Impl; +template <class ELFT> struct Elf_Verneed_Impl; +template <class ELFT> struct Elf_Vernaux_Impl; +template <class ELFT> struct Elf_Versym_Impl; +template <class ELFT> struct Elf_Hash_Impl; +template <class ELFT> struct Elf_GnuHash_Impl; +template <class ELFT> struct Elf_Chdr_Impl; +template <class ELFT> struct Elf_Nhdr_Impl; +template <class ELFT> class Elf_Note_Impl; +template <class ELFT> class Elf_Note_Iterator_Impl; +template <class ELFT> struct Elf_CGProfile_Impl; + +template <endianness E, bool Is64> struct ELFType { +private: + template <typename Ty> + using packed = support::detail::packed_endian_specific_integral<Ty, E, 1>; + +public: + static const endianness TargetEndianness = E; + static const bool Is64Bits = Is64; + + using uint = typename std::conditional<Is64, uint64_t, uint32_t>::type; + using Ehdr = Elf_Ehdr_Impl<ELFType<E, Is64>>; + using Shdr = Elf_Shdr_Impl<ELFType<E, Is64>>; + using Sym = Elf_Sym_Impl<ELFType<E, Is64>>; + using Dyn = Elf_Dyn_Impl<ELFType<E, Is64>>; + using Phdr = Elf_Phdr_Impl<ELFType<E, Is64>>; + using Rel = Elf_Rel_Impl<ELFType<E, Is64>, false>; + using Rela = Elf_Rel_Impl<ELFType<E, Is64>, true>; + using Relr = packed<uint>; + using Verdef = Elf_Verdef_Impl<ELFType<E, Is64>>; + using Verdaux = Elf_Verdaux_Impl<ELFType<E, Is64>>; + using Verneed = Elf_Verneed_Impl<ELFType<E, Is64>>; + using Vernaux = Elf_Vernaux_Impl<ELFType<E, Is64>>; + using Versym = Elf_Versym_Impl<ELFType<E, Is64>>; + using Hash = Elf_Hash_Impl<ELFType<E, Is64>>; + using GnuHash = Elf_GnuHash_Impl<ELFType<E, Is64>>; + using Chdr = Elf_Chdr_Impl<ELFType<E, Is64>>; + using Nhdr = Elf_Nhdr_Impl<ELFType<E, Is64>>; + using Note = Elf_Note_Impl<ELFType<E, Is64>>; + using NoteIterator = Elf_Note_Iterator_Impl<ELFType<E, Is64>>; + using CGProfile = Elf_CGProfile_Impl<ELFType<E, Is64>>; + using DynRange = ArrayRef<Dyn>; + using ShdrRange = ArrayRef<Shdr>; + using SymRange = ArrayRef<Sym>; + using RelRange = ArrayRef<Rel>; + using RelaRange = ArrayRef<Rela>; + using RelrRange = ArrayRef<Relr>; + using PhdrRange = ArrayRef<Phdr>; + + using Half = packed<uint16_t>; + using Word = packed<uint32_t>; + using Sword = packed<int32_t>; + using Xword = packed<uint64_t>; + using Sxword = packed<int64_t>; + using Addr = packed<uint>; + using Off = packed<uint>; +}; + +using ELF32LE = ELFType<support::little, false>; +using ELF32BE = ELFType<support::big, false>; +using ELF64LE = ELFType<support::little, true>; +using ELF64BE = ELFType<support::big, true>; + +// Use an alignment of 2 for the typedefs since that is the worst case for +// ELF files in archives. + +// I really don't like doing this, but the alternative is copypasta. +#define LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) \ + using Elf_Addr = typename ELFT::Addr; \ + using Elf_Off = typename ELFT::Off; \ + using Elf_Half = typename ELFT::Half; \ + using Elf_Word = typename ELFT::Word; \ + using Elf_Sword = typename ELFT::Sword; \ + using Elf_Xword = typename ELFT::Xword; \ + using Elf_Sxword = typename ELFT::Sxword; + +#define LLVM_ELF_COMMA , +#define LLVM_ELF_IMPORT_TYPES(E, W) \ + LLVM_ELF_IMPORT_TYPES_ELFT(ELFType<E LLVM_ELF_COMMA W>) + +// Section header. +template <class ELFT> struct Elf_Shdr_Base; + +template <endianness TargetEndianness> +struct Elf_Shdr_Base<ELFType<TargetEndianness, false>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + Elf_Word sh_name; // Section name (index into string table) + Elf_Word sh_type; // Section type (SHT_*) + Elf_Word sh_flags; // Section flags (SHF_*) + Elf_Addr sh_addr; // Address where section is to be loaded + Elf_Off sh_offset; // File offset of section data, in bytes + Elf_Word sh_size; // Size of section, in bytes + Elf_Word sh_link; // Section type-specific header table index link + Elf_Word sh_info; // Section type-specific extra information + Elf_Word sh_addralign; // Section address alignment + Elf_Word sh_entsize; // Size of records contained within the section +}; + +template <endianness TargetEndianness> +struct Elf_Shdr_Base<ELFType<TargetEndianness, true>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + Elf_Word sh_name; // Section name (index into string table) + Elf_Word sh_type; // Section type (SHT_*) + Elf_Xword sh_flags; // Section flags (SHF_*) + Elf_Addr sh_addr; // Address where section is to be loaded + Elf_Off sh_offset; // File offset of section data, in bytes + Elf_Xword sh_size; // Size of section, in bytes + Elf_Word sh_link; // Section type-specific header table index link + Elf_Word sh_info; // Section type-specific extra information + Elf_Xword sh_addralign; // Section address alignment + Elf_Xword sh_entsize; // Size of records contained within the section +}; + +template <class ELFT> +struct Elf_Shdr_Impl : Elf_Shdr_Base<ELFT> { + using Elf_Shdr_Base<ELFT>::sh_entsize; + using Elf_Shdr_Base<ELFT>::sh_size; + + /// Get the number of entities this section contains if it has any. + unsigned getEntityCount() const { + if (sh_entsize == 0) + return 0; + return sh_size / sh_entsize; + } +}; + +template <class ELFT> struct Elf_Sym_Base; + +template <endianness TargetEndianness> +struct Elf_Sym_Base<ELFType<TargetEndianness, false>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + Elf_Word st_name; // Symbol name (index into string table) + Elf_Addr st_value; // Value or address associated with the symbol + Elf_Word st_size; // Size of the symbol + unsigned char st_info; // Symbol's type and binding attributes + unsigned char st_other; // Must be zero; reserved + Elf_Half st_shndx; // Which section (header table index) it's defined in +}; + +template <endianness TargetEndianness> +struct Elf_Sym_Base<ELFType<TargetEndianness, true>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + Elf_Word st_name; // Symbol name (index into string table) + unsigned char st_info; // Symbol's type and binding attributes + unsigned char st_other; // Must be zero; reserved + Elf_Half st_shndx; // Which section (header table index) it's defined in + Elf_Addr st_value; // Value or address associated with the symbol + Elf_Xword st_size; // Size of the symbol +}; + +template <class ELFT> +struct Elf_Sym_Impl : Elf_Sym_Base<ELFT> { + using Elf_Sym_Base<ELFT>::st_info; + using Elf_Sym_Base<ELFT>::st_shndx; + using Elf_Sym_Base<ELFT>::st_other; + using Elf_Sym_Base<ELFT>::st_value; + + // These accessors and mutators correspond to the ELF32_ST_BIND, + // ELF32_ST_TYPE, and ELF32_ST_INFO macros defined in the ELF specification: + unsigned char getBinding() const { return st_info >> 4; } + unsigned char getType() const { return st_info & 0x0f; } + uint64_t getValue() const { return st_value; } + void setBinding(unsigned char b) { setBindingAndType(b, getType()); } + void setType(unsigned char t) { setBindingAndType(getBinding(), t); } + + void setBindingAndType(unsigned char b, unsigned char t) { + st_info = (b << 4) + (t & 0x0f); + } + + /// Access to the STV_xxx flag stored in the first two bits of st_other. + /// STV_DEFAULT: 0 + /// STV_INTERNAL: 1 + /// STV_HIDDEN: 2 + /// STV_PROTECTED: 3 + unsigned char getVisibility() const { return st_other & 0x3; } + void setVisibility(unsigned char v) { + assert(v < 4 && "Invalid value for visibility"); + st_other = (st_other & ~0x3) | v; + } + + bool isAbsolute() const { return st_shndx == ELF::SHN_ABS; } + + bool isCommon() const { + return getType() == ELF::STT_COMMON || st_shndx == ELF::SHN_COMMON; + } + + bool isDefined() const { return !isUndefined(); } + + bool isProcessorSpecific() const { + return st_shndx >= ELF::SHN_LOPROC && st_shndx <= ELF::SHN_HIPROC; + } + + bool isOSSpecific() const { + return st_shndx >= ELF::SHN_LOOS && st_shndx <= ELF::SHN_HIOS; + } + + bool isReserved() const { + // ELF::SHN_HIRESERVE is 0xffff so st_shndx <= ELF::SHN_HIRESERVE is always + // true and some compilers warn about it. + return st_shndx >= ELF::SHN_LORESERVE; + } + + bool isUndefined() const { return st_shndx == ELF::SHN_UNDEF; } + + bool isExternal() const { + return getBinding() != ELF::STB_LOCAL; + } + + Expected<StringRef> getName(StringRef StrTab) const; +}; + +template <class ELFT> +Expected<StringRef> Elf_Sym_Impl<ELFT>::getName(StringRef StrTab) const { + uint32_t Offset = this->st_name; + if (Offset >= StrTab.size()) + return createStringError(object_error::parse_failed, + "st_name (0x%" PRIx32 + ") is past the end of the string table" + " of size 0x%zx", + Offset, StrTab.size()); + return StringRef(StrTab.data() + Offset); +} + +/// Elf_Versym: This is the structure of entries in the SHT_GNU_versym section +/// (.gnu.version). This structure is identical for ELF32 and ELF64. +template <class ELFT> +struct Elf_Versym_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Half vs_index; // Version index with flags (e.g. VERSYM_HIDDEN) +}; + +/// Elf_Verdef: This is the structure of entries in the SHT_GNU_verdef section +/// (.gnu.version_d). This structure is identical for ELF32 and ELF64. +template <class ELFT> +struct Elf_Verdef_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + using Elf_Verdaux = Elf_Verdaux_Impl<ELFT>; + Elf_Half vd_version; // Version of this structure (e.g. VER_DEF_CURRENT) + Elf_Half vd_flags; // Bitwise flags (VER_DEF_*) + Elf_Half vd_ndx; // Version index, used in .gnu.version entries + Elf_Half vd_cnt; // Number of Verdaux entries + Elf_Word vd_hash; // Hash of name + Elf_Word vd_aux; // Offset to the first Verdaux entry (in bytes) + Elf_Word vd_next; // Offset to the next Verdef entry (in bytes) + + /// Get the first Verdaux entry for this Verdef. + const Elf_Verdaux *getAux() const { + return reinterpret_cast<const Elf_Verdaux *>((const char *)this + vd_aux); + } +}; + +/// Elf_Verdaux: This is the structure of auxiliary data in the SHT_GNU_verdef +/// section (.gnu.version_d). This structure is identical for ELF32 and ELF64. +template <class ELFT> +struct Elf_Verdaux_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word vda_name; // Version name (offset in string table) + Elf_Word vda_next; // Offset to next Verdaux entry (in bytes) +}; + +/// Elf_Verneed: This is the structure of entries in the SHT_GNU_verneed +/// section (.gnu.version_r). This structure is identical for ELF32 and ELF64. +template <class ELFT> +struct Elf_Verneed_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Half vn_version; // Version of this structure (e.g. VER_NEED_CURRENT) + Elf_Half vn_cnt; // Number of associated Vernaux entries + Elf_Word vn_file; // Library name (string table offset) + Elf_Word vn_aux; // Offset to first Vernaux entry (in bytes) + Elf_Word vn_next; // Offset to next Verneed entry (in bytes) +}; + +/// Elf_Vernaux: This is the structure of auxiliary data in SHT_GNU_verneed +/// section (.gnu.version_r). This structure is identical for ELF32 and ELF64. +template <class ELFT> +struct Elf_Vernaux_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word vna_hash; // Hash of dependency name + Elf_Half vna_flags; // Bitwise Flags (VER_FLAG_*) + Elf_Half vna_other; // Version index, used in .gnu.version entries + Elf_Word vna_name; // Dependency name + Elf_Word vna_next; // Offset to next Vernaux entry (in bytes) +}; + +/// Elf_Dyn_Base: This structure matches the form of entries in the dynamic +/// table section (.dynamic) look like. +template <class ELFT> struct Elf_Dyn_Base; + +template <endianness TargetEndianness> +struct Elf_Dyn_Base<ELFType<TargetEndianness, false>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + Elf_Sword d_tag; + union { + Elf_Word d_val; + Elf_Addr d_ptr; + } d_un; +}; + +template <endianness TargetEndianness> +struct Elf_Dyn_Base<ELFType<TargetEndianness, true>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + Elf_Sxword d_tag; + union { + Elf_Xword d_val; + Elf_Addr d_ptr; + } d_un; +}; + +/// 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; + using intX_t = typename std::conditional<ELFT::Is64Bits, + int64_t, int32_t>::type; + using uintX_t = typename std::conditional<ELFT::Is64Bits, + uint64_t, uint32_t>::type; + 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; } +}; + +template <endianness TargetEndianness> +struct Elf_Rel_Impl<ELFType<TargetEndianness, false>, false> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + static const bool IsRela = false; + Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf_Word r_info; // Symbol table index and type of relocation to apply + + uint32_t getRInfo(bool isMips64EL) const { + assert(!isMips64EL); + return r_info; + } + void setRInfo(uint32_t R, bool IsMips64EL) { + assert(!IsMips64EL); + r_info = R; + } + + // These accessors and mutators correspond to the ELF32_R_SYM, ELF32_R_TYPE, + // and ELF32_R_INFO macros defined in the ELF specification: + uint32_t getSymbol(bool isMips64EL) const { + return this->getRInfo(isMips64EL) >> 8; + } + unsigned char getType(bool isMips64EL) const { + return (unsigned char)(this->getRInfo(isMips64EL) & 0x0ff); + } + void setSymbol(uint32_t s, bool IsMips64EL) { + setSymbolAndType(s, getType(IsMips64EL), IsMips64EL); + } + void setType(unsigned char t, bool IsMips64EL) { + setSymbolAndType(getSymbol(IsMips64EL), t, IsMips64EL); + } + void setSymbolAndType(uint32_t s, unsigned char t, bool IsMips64EL) { + this->setRInfo((s << 8) + t, IsMips64EL); + } +}; + +template <endianness TargetEndianness> +struct Elf_Rel_Impl<ELFType<TargetEndianness, false>, true> + : public Elf_Rel_Impl<ELFType<TargetEndianness, false>, false> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + static const bool IsRela = true; + Elf_Sword r_addend; // Compute value for relocatable field by adding this +}; + +template <endianness TargetEndianness> +struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + static const bool IsRela = false; + Elf_Addr r_offset; // Location (file byte offset, or program virtual addr) + Elf_Xword r_info; // Symbol table index and type of relocation to apply + + uint64_t getRInfo(bool isMips64EL) const { + uint64_t t = r_info; + if (!isMips64EL) + return t; + // Mips64 little endian has a "special" encoding of r_info. Instead of one + // 64 bit little endian number, it is a little endian 32 bit number followed + // by a 32 bit big endian number. + return (t << 32) | ((t >> 8) & 0xff000000) | ((t >> 24) & 0x00ff0000) | + ((t >> 40) & 0x0000ff00) | ((t >> 56) & 0x000000ff); + } + + void setRInfo(uint64_t R, bool IsMips64EL) { + if (IsMips64EL) + r_info = (R >> 32) | ((R & 0xff000000) << 8) | ((R & 0x00ff0000) << 24) | + ((R & 0x0000ff00) << 40) | ((R & 0x000000ff) << 56); + else + r_info = R; + } + + // These accessors and mutators correspond to the ELF64_R_SYM, ELF64_R_TYPE, + // and ELF64_R_INFO macros defined in the ELF specification: + uint32_t getSymbol(bool isMips64EL) const { + return (uint32_t)(this->getRInfo(isMips64EL) >> 32); + } + uint32_t getType(bool isMips64EL) const { + return (uint32_t)(this->getRInfo(isMips64EL) & 0xffffffffL); + } + void setSymbol(uint32_t s, bool IsMips64EL) { + setSymbolAndType(s, getType(IsMips64EL), IsMips64EL); + } + void setType(uint32_t t, bool IsMips64EL) { + setSymbolAndType(getSymbol(IsMips64EL), t, IsMips64EL); + } + void setSymbolAndType(uint32_t s, uint32_t t, bool IsMips64EL) { + this->setRInfo(((uint64_t)s << 32) + (t & 0xffffffffL), IsMips64EL); + } +}; + +template <endianness TargetEndianness> +struct Elf_Rel_Impl<ELFType<TargetEndianness, true>, true> + : public Elf_Rel_Impl<ELFType<TargetEndianness, true>, false> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + static const bool IsRela = true; + Elf_Sxword r_addend; // Compute value for relocatable field by adding this. +}; + +template <class ELFT> +struct Elf_Ehdr_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + unsigned char e_ident[ELF::EI_NIDENT]; // ELF Identification bytes + Elf_Half e_type; // Type of file (see ET_*) + Elf_Half e_machine; // Required architecture for this file (see EM_*) + Elf_Word e_version; // Must be equal to 1 + Elf_Addr e_entry; // Address to jump to in order to start program + Elf_Off e_phoff; // Program header table's file offset, in bytes + Elf_Off e_shoff; // Section header table's file offset, in bytes + Elf_Word e_flags; // Processor-specific flags + Elf_Half e_ehsize; // Size of ELF header, in bytes + Elf_Half e_phentsize; // Size of an entry in the program header table + Elf_Half e_phnum; // Number of entries in the program header table + Elf_Half e_shentsize; // Size of an entry in the section header table + Elf_Half e_shnum; // Number of entries in the section header table + Elf_Half e_shstrndx; // Section header table index of section name + // string table + + bool checkMagic() const { + return (memcmp(e_ident, ELF::ElfMagic, strlen(ELF::ElfMagic))) == 0; + } + + unsigned char getFileClass() const { return e_ident[ELF::EI_CLASS]; } + unsigned char getDataEncoding() const { return e_ident[ELF::EI_DATA]; } +}; + +template <endianness TargetEndianness> +struct Elf_Phdr_Impl<ELFType<TargetEndianness, false>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + Elf_Word p_type; // Type of segment + Elf_Off p_offset; // FileOffset where segment is located, in bytes + Elf_Addr p_vaddr; // Virtual Address of beginning of segment + Elf_Addr p_paddr; // Physical address of beginning of segment (OS-specific) + Elf_Word p_filesz; // Num. of bytes in file image of segment (may be zero) + Elf_Word p_memsz; // Num. of bytes in mem image of segment (may be zero) + Elf_Word p_flags; // Segment flags + Elf_Word p_align; // Segment alignment constraint +}; + +template <endianness TargetEndianness> +struct Elf_Phdr_Impl<ELFType<TargetEndianness, true>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + Elf_Word p_type; // Type of segment + Elf_Word p_flags; // Segment flags + Elf_Off p_offset; // FileOffset where segment is located, in bytes + Elf_Addr p_vaddr; // Virtual Address of beginning of segment + Elf_Addr p_paddr; // Physical address of beginning of segment (OS-specific) + Elf_Xword p_filesz; // Num. of bytes in file image of segment (may be zero) + Elf_Xword p_memsz; // Num. of bytes in mem image of segment (may be zero) + Elf_Xword p_align; // Segment alignment constraint +}; + +// ELFT needed for endianness. +template <class ELFT> +struct Elf_Hash_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word nbucket; + Elf_Word nchain; + + ArrayRef<Elf_Word> buckets() const { + return ArrayRef<Elf_Word>(&nbucket + 2, &nbucket + 2 + nbucket); + } + + ArrayRef<Elf_Word> chains() const { + return ArrayRef<Elf_Word>(&nbucket + 2 + nbucket, + &nbucket + 2 + nbucket + nchain); + } +}; + +// .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); + } +}; + +// Compressed section headers. +// http://www.sco.com/developers/gabi/latest/ch4.sheader.html#compression_header +template <endianness TargetEndianness> +struct Elf_Chdr_Impl<ELFType<TargetEndianness, false>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + Elf_Word ch_type; + Elf_Word ch_size; + Elf_Word ch_addralign; +}; + +template <endianness TargetEndianness> +struct Elf_Chdr_Impl<ELFType<TargetEndianness, true>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + Elf_Word ch_type; + Elf_Word ch_reserved; + Elf_Xword ch_size; + Elf_Xword ch_addralign; +}; + +/// Note header +template <class ELFT> +struct Elf_Nhdr_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word n_namesz; + Elf_Word n_descsz; + Elf_Word n_type; + + /// The alignment of the name and descriptor. + /// + /// Implementations differ from the specification here: in practice all + /// variants align both the name and descriptor to 4-bytes. + static const unsigned int Align = 4; + + /// Get the size of the note, including name, descriptor, and padding. + size_t getSize() const { + return sizeof(*this) + alignTo<Align>(n_namesz) + alignTo<Align>(n_descsz); + } +}; + +/// An ELF note. +/// +/// Wraps a note header, providing methods for accessing the name and +/// descriptor safely. +template <class ELFT> +class Elf_Note_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + + const Elf_Nhdr_Impl<ELFT> &Nhdr; + + template <class NoteIteratorELFT> friend class Elf_Note_Iterator_Impl; + +public: + Elf_Note_Impl(const Elf_Nhdr_Impl<ELFT> &Nhdr) : Nhdr(Nhdr) {} + + /// Get the note's name, excluding the terminating null byte. + StringRef getName() const { + if (!Nhdr.n_namesz) + return StringRef(); + return StringRef(reinterpret_cast<const char *>(&Nhdr) + sizeof(Nhdr), + Nhdr.n_namesz - 1); + } + + /// Get the note's descriptor. + ArrayRef<uint8_t> getDesc() const { + if (!Nhdr.n_descsz) + return ArrayRef<uint8_t>(); + return ArrayRef<uint8_t>( + reinterpret_cast<const uint8_t *>(&Nhdr) + sizeof(Nhdr) + + alignTo<Elf_Nhdr_Impl<ELFT>::Align>(Nhdr.n_namesz), + Nhdr.n_descsz); + } + + /// Get the note's type. + Elf_Word getType() const { return Nhdr.n_type; } +}; + +template <class ELFT> +class Elf_Note_Iterator_Impl + : std::iterator<std::forward_iterator_tag, Elf_Note_Impl<ELFT>> { + // Nhdr being a nullptr marks the end of iteration. + const Elf_Nhdr_Impl<ELFT> *Nhdr = nullptr; + size_t RemainingSize = 0u; + Error *Err = nullptr; + + template <class ELFFileELFT> friend class ELFFile; + + // Stop iteration and indicate an overflow. + void stopWithOverflowError() { + Nhdr = nullptr; + *Err = make_error<StringError>("ELF note overflows container", + object_error::parse_failed); + } + + // Advance Nhdr by NoteSize bytes, starting from NhdrPos. + // + // Assumes NoteSize <= RemainingSize. Ensures Nhdr->getSize() <= RemainingSize + // upon returning. Handles stopping iteration when reaching the end of the + // container, either cleanly or with an overflow error. + void advanceNhdr(const uint8_t *NhdrPos, size_t NoteSize) { + RemainingSize -= NoteSize; + if (RemainingSize == 0u) { + // Ensure that if the iterator walks to the end, the error is checked + // afterwards. + *Err = Error::success(); + Nhdr = nullptr; + } else if (sizeof(*Nhdr) > RemainingSize) + stopWithOverflowError(); + else { + Nhdr = reinterpret_cast<const Elf_Nhdr_Impl<ELFT> *>(NhdrPos + NoteSize); + if (Nhdr->getSize() > RemainingSize) + stopWithOverflowError(); + else + *Err = Error::success(); + } + } + + Elf_Note_Iterator_Impl() {} + explicit Elf_Note_Iterator_Impl(Error &Err) : Err(&Err) {} + Elf_Note_Iterator_Impl(const uint8_t *Start, size_t Size, Error &Err) + : RemainingSize(Size), Err(&Err) { + consumeError(std::move(Err)); + assert(Start && "ELF note iterator starting at NULL"); + advanceNhdr(Start, 0u); + } + +public: + Elf_Note_Iterator_Impl &operator++() { + assert(Nhdr && "incremented ELF note end iterator"); + const uint8_t *NhdrPos = reinterpret_cast<const uint8_t *>(Nhdr); + size_t NoteSize = Nhdr->getSize(); + advanceNhdr(NhdrPos, NoteSize); + return *this; + } + bool operator==(Elf_Note_Iterator_Impl Other) const { + if (!Nhdr && Other.Err) + (void)(bool)(*Other.Err); + if (!Other.Nhdr && Err) + (void)(bool)(*Err); + return Nhdr == Other.Nhdr; + } + bool operator!=(Elf_Note_Iterator_Impl Other) const { + return !(*this == Other); + } + Elf_Note_Impl<ELFT> operator*() const { + assert(Nhdr && "dereferenced ELF note end iterator"); + return Elf_Note_Impl<ELFT>(*Nhdr); + } +}; + +template <class ELFT> struct Elf_CGProfile_Impl { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Word cgp_from; + Elf_Word cgp_to; + Elf_Xword cgp_weight; +}; + +// MIPS .reginfo section +template <class ELFT> +struct Elf_Mips_RegInfo; + +template <support::endianness TargetEndianness> +struct Elf_Mips_RegInfo<ELFType<TargetEndianness, false>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, false) + Elf_Word ri_gprmask; // bit-mask of used general registers + Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers + Elf_Addr ri_gp_value; // gp register value +}; + +template <support::endianness TargetEndianness> +struct Elf_Mips_RegInfo<ELFType<TargetEndianness, true>> { + LLVM_ELF_IMPORT_TYPES(TargetEndianness, true) + Elf_Word ri_gprmask; // bit-mask of used general registers + Elf_Word ri_pad; // unused padding field + Elf_Word ri_cprmask[4]; // bit-mask of used co-processor registers + Elf_Addr ri_gp_value; // gp register value +}; + +// .MIPS.options section +template <class ELFT> struct Elf_Mips_Options { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + uint8_t kind; // Determines interpretation of variable part of descriptor + uint8_t size; // Byte size of descriptor, including this header + Elf_Half section; // Section header index of section affected, + // or 0 for global options + Elf_Word info; // Kind-specific information + + Elf_Mips_RegInfo<ELFT> &getRegInfo() { + assert(kind == ELF::ODK_REGINFO); + return *reinterpret_cast<Elf_Mips_RegInfo<ELFT> *>( + (uint8_t *)this + sizeof(Elf_Mips_Options)); + } + const Elf_Mips_RegInfo<ELFT> &getRegInfo() const { + return const_cast<Elf_Mips_Options *>(this)->getRegInfo(); + } +}; + +// .MIPS.abiflags section content +template <class ELFT> struct Elf_Mips_ABIFlags { + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + Elf_Half version; // Version of the structure + uint8_t isa_level; // ISA level: 1-5, 32, and 64 + uint8_t isa_rev; // ISA revision (0 for MIPS I - MIPS V) + uint8_t gpr_size; // General purpose registers size + uint8_t cpr1_size; // Co-processor 1 registers size + uint8_t cpr2_size; // Co-processor 2 registers size + uint8_t fp_abi; // Floating-point ABI flag + Elf_Word isa_ext; // Processor-specific extension + Elf_Word ases; // ASEs flags + Elf_Word flags1; // General flags + Elf_Word flags2; // General flags +}; + +} // end namespace object. +} // end namespace llvm. + +#endif // LLVM_OBJECT_ELFTYPES_H diff --git a/third_party/llvm-project/include/llvm/Object/Error.h b/third_party/llvm-project/include/llvm/Object/Error.h new file mode 100644 index 000000000..b7bbf06fc --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/Error.h @@ -0,0 +1,92 @@ +//===- Error.h - system_error extensions for Object -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This declares a new error_category for the Object library. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ERROR_H +#define LLVM_OBJECT_ERROR_H + +#include "llvm/ADT/Twine.h" +#include "llvm/Support/Error.h" +#include <system_error> + +namespace llvm { +namespace object { + +class Binary; + +const std::error_category &object_category(); + +enum class object_error { + // Error code 0 is absent. Use std::error_code() instead. + arch_not_found = 1, + invalid_file_type, + parse_failed, + unexpected_eof, + string_table_non_null_end, + invalid_section_index, + bitcode_section_not_found, + invalid_symbol_index, +}; + +inline std::error_code make_error_code(object_error e) { + return std::error_code(static_cast<int>(e), object_category()); +} + +/// Base class for all errors indicating malformed binary files. +/// +/// Having a subclass for all malformed binary files allows archive-walking +/// code to skip malformed files without having to understand every possible +/// way that a binary file might be malformed. +/// +/// Currently inherits from ECError for easy interoperability with +/// std::error_code, but this will be removed in the future. +class BinaryError : public ErrorInfo<BinaryError, ECError> { + virtual void anchor(); +public: + static char ID; + BinaryError() { + // Default to parse_failed, can be overridden with setErrorCode. + setErrorCode(make_error_code(object_error::parse_failed)); + } +}; + +/// Generic binary error. +/// +/// For errors that don't require their own specific sub-error (most errors) +/// this class can be used to describe the error via a string message. +class GenericBinaryError : public ErrorInfo<GenericBinaryError, BinaryError> { +public: + static char ID; + GenericBinaryError(Twine Msg); + GenericBinaryError(Twine Msg, object_error ECOverride); + const std::string &getMessage() const { return Msg; } + void log(raw_ostream &OS) const override; +private: + std::string Msg; +}; + +/// isNotObjectErrorInvalidFileType() is used when looping through the children +/// of an archive after calling getAsBinary() on the child and it returns an +/// llvm::Error. In the cases we want to loop through the children and ignore the +/// non-objects in the archive this is used to test the error to see if an +/// error() function needs to called on the llvm::Error. +Error isNotObjectErrorInvalidFileType(llvm::Error Err); + +} // end namespace object. + +} // end namespace llvm. + +namespace std { +template <> +struct is_error_code_enum<llvm::object::object_error> : std::true_type {}; +} + +#endif diff --git a/third_party/llvm-project/include/llvm/Object/MachO.h b/third_party/llvm-project/include/llvm/Object/MachO.h new file mode 100644 index 000000000..76be8049a --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/MachO.h @@ -0,0 +1,737 @@ +//===- MachO.h - MachO object file implementation ---------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the MachOObjectFile class, which implement the ObjectFile +// interface for MachO files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_MACHO_H +#define LLVM_OBJECT_MACHO_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" +#include <cstdint> +#include <memory> +#include <string> +#include <system_error> + +namespace llvm { +namespace object { + +/// DiceRef - This is a value type class that represents a single +/// data in code entry in the table in a Mach-O object file. +class DiceRef { + DataRefImpl DicePimpl; + const ObjectFile *OwningObject = nullptr; + +public: + DiceRef() = default; + DiceRef(DataRefImpl DiceP, const ObjectFile *Owner); + + bool operator==(const DiceRef &Other) const; + bool operator<(const DiceRef &Other) const; + + void moveNext(); + + std::error_code getOffset(uint32_t &Result) const; + std::error_code getLength(uint16_t &Result) const; + std::error_code getKind(uint16_t &Result) const; + + DataRefImpl getRawDataRefImpl() const; + const ObjectFile *getObjectFile() const; +}; +using dice_iterator = content_iterator<DiceRef>; + +/// ExportEntry encapsulates the current-state-of-the-walk used when doing a +/// non-recursive walk of the trie data structure. This allows you to iterate +/// across all exported symbols using: +/// Error Err; +/// for (const llvm::object::ExportEntry &AnExport : Obj->exports(&Err)) { +/// } +/// if (Err) { report error ... +class ExportEntry { +public: + ExportEntry(Error *Err, const MachOObjectFile *O, ArrayRef<uint8_t> Trie); + + StringRef name() const; + uint64_t flags() const; + uint64_t address() const; + uint64_t other() const; + StringRef otherName() const; + uint32_t nodeOffset() const; + + bool operator==(const ExportEntry &) const; + + void moveNext(); + +private: + friend class MachOObjectFile; + + void moveToFirst(); + void moveToEnd(); + uint64_t readULEB128(const uint8_t *&p, const char **error); + void pushDownUntilBottom(); + void pushNode(uint64_t Offset); + + // Represents a node in the mach-o exports trie. + struct NodeState { + NodeState(const uint8_t *Ptr); + + const uint8_t *Start; + const uint8_t *Current; + uint64_t Flags = 0; + uint64_t Address = 0; + uint64_t Other = 0; + const char *ImportName = nullptr; + unsigned ChildCount = 0; + unsigned NextChildIndex = 0; + unsigned ParentStringLength = 0; + bool IsExportNode = false; + }; + using NodeList = SmallVector<NodeState, 16>; + using node_iterator = NodeList::const_iterator; + + Error *E; + const MachOObjectFile *O; + ArrayRef<uint8_t> Trie; + SmallString<256> CumulativeString; + NodeList Stack; + bool Done = false; + + iterator_range<node_iterator> nodes() const { + return make_range(Stack.begin(), Stack.end()); + } +}; +using export_iterator = content_iterator<ExportEntry>; + +// Segment info so SegIndex/SegOffset pairs in a Mach-O Bind or Rebase entry +// can be checked and translated. Only the SegIndex/SegOffset pairs from +// checked entries are to be used with the segmentName(), sectionName() and +// address() methods below. +class BindRebaseSegInfo { +public: + BindRebaseSegInfo(const MachOObjectFile *Obj); + + // Used to check a Mach-O Bind or Rebase entry for errors when iterating. + const char* checkSegAndOffsets(int32_t SegIndex, uint64_t SegOffset, + uint8_t PointerSize, uint32_t Count=1, + uint32_t Skip=0); + // Used with valid SegIndex/SegOffset values from checked entries. + StringRef segmentName(int32_t SegIndex); + StringRef sectionName(int32_t SegIndex, uint64_t SegOffset); + uint64_t address(uint32_t SegIndex, uint64_t SegOffset); + +private: + struct SectionInfo { + uint64_t Address; + uint64_t Size; + StringRef SectionName; + StringRef SegmentName; + uint64_t OffsetInSegment; + uint64_t SegmentStartAddress; + int32_t SegmentIndex; + }; + const SectionInfo &findSection(int32_t SegIndex, uint64_t SegOffset); + + SmallVector<SectionInfo, 32> Sections; + int32_t MaxSegIndex; +}; + +/// MachORebaseEntry encapsulates the current state in the decompression of +/// rebasing opcodes. This allows you to iterate through the compressed table of +/// rebasing using: +/// Error Err; +/// for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable(&Err)) { +/// } +/// if (Err) { report error ... +class MachORebaseEntry { +public: + MachORebaseEntry(Error *Err, const MachOObjectFile *O, + ArrayRef<uint8_t> opcodes, bool is64Bit); + + int32_t segmentIndex() const; + uint64_t segmentOffset() const; + StringRef typeName() const; + StringRef segmentName() const; + StringRef sectionName() const; + uint64_t address() const; + + bool operator==(const MachORebaseEntry &) const; + + void moveNext(); + +private: + friend class MachOObjectFile; + + void moveToFirst(); + void moveToEnd(); + uint64_t readULEB128(const char **error); + + Error *E; + const MachOObjectFile *O; + ArrayRef<uint8_t> Opcodes; + const uint8_t *Ptr; + uint64_t SegmentOffset = 0; + int32_t SegmentIndex = -1; + uint64_t RemainingLoopCount = 0; + uint64_t AdvanceAmount = 0; + uint8_t RebaseType = 0; + uint8_t PointerSize; + bool Done = false; +}; +using rebase_iterator = content_iterator<MachORebaseEntry>; + +/// MachOBindEntry encapsulates the current state in the decompression of +/// binding opcodes. This allows you to iterate through the compressed table of +/// bindings using: +/// Error Err; +/// for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable(&Err)) { +/// } +/// if (Err) { report error ... +class MachOBindEntry { +public: + enum class Kind { Regular, Lazy, Weak }; + + MachOBindEntry(Error *Err, const MachOObjectFile *O, + ArrayRef<uint8_t> Opcodes, bool is64Bit, MachOBindEntry::Kind); + + int32_t segmentIndex() const; + uint64_t segmentOffset() const; + StringRef typeName() const; + StringRef symbolName() const; + uint32_t flags() const; + int64_t addend() const; + int ordinal() const; + + StringRef segmentName() const; + StringRef sectionName() const; + uint64_t address() const; + + bool operator==(const MachOBindEntry &) const; + + void moveNext(); + +private: + friend class MachOObjectFile; + + void moveToFirst(); + void moveToEnd(); + uint64_t readULEB128(const char **error); + int64_t readSLEB128(const char **error); + + Error *E; + const MachOObjectFile *O; + ArrayRef<uint8_t> Opcodes; + const uint8_t *Ptr; + uint64_t SegmentOffset = 0; + int32_t SegmentIndex = -1; + StringRef SymbolName; + bool LibraryOrdinalSet = false; + int Ordinal = 0; + uint32_t Flags = 0; + int64_t Addend = 0; + uint64_t RemainingLoopCount = 0; + uint64_t AdvanceAmount = 0; + uint8_t BindType = 0; + uint8_t PointerSize; + Kind TableKind; + bool Done = false; +}; +using bind_iterator = content_iterator<MachOBindEntry>; + +class MachOObjectFile : public ObjectFile { +public: + struct LoadCommandInfo { + const char *Ptr; // Where in memory the load command is. + MachO::load_command C; // The command itself. + }; + using LoadCommandList = SmallVector<LoadCommandInfo, 4>; + using load_command_iterator = LoadCommandList::const_iterator; + + static Expected<std::unique_ptr<MachOObjectFile>> + create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, + uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0); + + void moveSymbolNext(DataRefImpl &Symb) const override; + + uint64_t getNValue(DataRefImpl Sym) const; + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; + + // MachO specific. + Error checkSymbolTable() const; + + std::error_code getIndirectName(DataRefImpl Symb, StringRef &Res) const; + unsigned getSectionType(SectionRef Sec) const; + + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + uint32_t getSymbolAlignment(DataRefImpl Symb) const override; + uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; + Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; + uint32_t getSymbolFlags(DataRefImpl Symb) const override; + Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; + unsigned getSymbolSectionID(SymbolRef Symb) const; + unsigned getSectionID(SectionRef Sec) const; + + void moveSectionNext(DataRefImpl &Sec) const override; + Expected<StringRef> getSectionName(DataRefImpl Sec) const override; + uint64_t getSectionAddress(DataRefImpl Sec) const override; + uint64_t getSectionIndex(DataRefImpl Sec) const override; + uint64_t getSectionSize(DataRefImpl Sec) const override; + ArrayRef<uint8_t> getSectionContents(uint32_t Offset, uint64_t Size) const; + Expected<ArrayRef<uint8_t>> + getSectionContents(DataRefImpl Sec) const override; + uint64_t getSectionAlignment(DataRefImpl Sec) const override; + Expected<SectionRef> getSection(unsigned SectionIndex) const; + Expected<SectionRef> getSection(StringRef SectionName) const; + bool isSectionCompressed(DataRefImpl Sec) const override; + bool isSectionText(DataRefImpl Sec) const override; + bool isSectionData(DataRefImpl Sec) const override; + bool isSectionBSS(DataRefImpl Sec) const override; + bool isSectionVirtual(DataRefImpl Sec) const override; + bool isSectionBitcode(DataRefImpl Sec) const override; + + /// When dsymutil generates the companion file, it strips all unnecessary + /// sections (e.g. everything in the _TEXT segment) by omitting their body + /// and setting the offset in their corresponding load command to zero. + /// + /// While the load command itself is valid, reading the section corresponds + /// to reading the number of bytes specified in the load command, starting + /// from offset 0 (i.e. the Mach-O header at the beginning of the file). + bool isSectionStripped(DataRefImpl Sec) const override; + + relocation_iterator section_rel_begin(DataRefImpl Sec) const override; + relocation_iterator section_rel_end(DataRefImpl Sec) const override; + + relocation_iterator extrel_begin() const; + relocation_iterator extrel_end() const; + iterator_range<relocation_iterator> external_relocations() const { + return make_range(extrel_begin(), extrel_end()); + } + + relocation_iterator locrel_begin() const; + relocation_iterator locrel_end() const; + + void moveRelocationNext(DataRefImpl &Rel) const override; + uint64_t getRelocationOffset(DataRefImpl Rel) const override; + symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; + section_iterator getRelocationSection(DataRefImpl Rel) const; + uint64_t getRelocationType(DataRefImpl Rel) const override; + void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const override; + uint8_t getRelocationLength(DataRefImpl Rel) const; + + // MachO specific. + std::error_code getLibraryShortNameByIndex(unsigned Index, StringRef &) const; + uint32_t getLibraryCount() const; + + section_iterator getRelocationRelocatedSection(relocation_iterator Rel) const; + + // TODO: Would be useful to have an iterator based version + // of the load command interface too. + + basic_symbol_iterator symbol_begin() const override; + basic_symbol_iterator symbol_end() const override; + + // MachO specific. + symbol_iterator getSymbolByIndex(unsigned Index) const; + uint64_t getSymbolIndex(DataRefImpl Symb) const; + + section_iterator section_begin() const override; + section_iterator section_end() const override; + + uint8_t getBytesInAddress() const override; + + StringRef getFileFormatName() const override; + Triple::ArchType getArch() const override; + SubtargetFeatures getFeatures() const override { return SubtargetFeatures(); } + Triple getArchTriple(const char **McpuDefault = nullptr) const; + + relocation_iterator section_rel_begin(unsigned Index) const; + relocation_iterator section_rel_end(unsigned Index) const; + + dice_iterator begin_dices() const; + dice_iterator end_dices() const; + + load_command_iterator begin_load_commands() const; + load_command_iterator end_load_commands() const; + iterator_range<load_command_iterator> load_commands() const; + + /// For use iterating over all exported symbols. + iterator_range<export_iterator> exports(Error &Err) const; + + /// For use examining a trie not in a MachOObjectFile. + static iterator_range<export_iterator> exports(Error &Err, + ArrayRef<uint8_t> Trie, + const MachOObjectFile *O = + nullptr); + + /// For use iterating over all rebase table entries. + iterator_range<rebase_iterator> rebaseTable(Error &Err); + + /// For use examining rebase opcodes in a MachOObjectFile. + static iterator_range<rebase_iterator> rebaseTable(Error &Err, + MachOObjectFile *O, + ArrayRef<uint8_t> Opcodes, + bool is64); + + /// For use iterating over all bind table entries. + iterator_range<bind_iterator> bindTable(Error &Err); + + /// For use iterating over all lazy bind table entries. + iterator_range<bind_iterator> lazyBindTable(Error &Err); + + /// For use iterating over all weak bind table entries. + iterator_range<bind_iterator> weakBindTable(Error &Err); + + /// For use examining bind opcodes in a MachOObjectFile. + static iterator_range<bind_iterator> bindTable(Error &Err, + MachOObjectFile *O, + ArrayRef<uint8_t> Opcodes, + bool is64, + MachOBindEntry::Kind); + + // Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists + // that fully contains a pointer at that location. Multiple fixups in a bind + // (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can + // be tested via the Count and Skip parameters. + // + // This is used by MachOBindEntry::moveNext() to validate a MachOBindEntry. + const char *BindEntryCheckSegAndOffsets(int32_t SegIndex, uint64_t SegOffset, + uint8_t PointerSize, uint32_t Count=1, + uint32_t Skip=0) const { + return BindRebaseSectionTable->checkSegAndOffsets(SegIndex, SegOffset, + PointerSize, Count, Skip); + } + + // Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists + // that fully contains a pointer at that location. Multiple fixups in a rebase + // (such as with the REBASE_OPCODE_DO_*_TIMES* opcodes) can be tested via the + // Count and Skip parameters. + // + // This is used by MachORebaseEntry::moveNext() to validate a MachORebaseEntry + const char *RebaseEntryCheckSegAndOffsets(int32_t SegIndex, + uint64_t SegOffset, + uint8_t PointerSize, + uint32_t Count=1, + uint32_t Skip=0) const { + return BindRebaseSectionTable->checkSegAndOffsets(SegIndex, SegOffset, + PointerSize, Count, Skip); + } + + /// For use with the SegIndex of a checked Mach-O Bind or Rebase entry to + /// get the segment name. + StringRef BindRebaseSegmentName(int32_t SegIndex) const { + return BindRebaseSectionTable->segmentName(SegIndex); + } + + /// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or + /// Rebase entry to get the section name. + StringRef BindRebaseSectionName(uint32_t SegIndex, uint64_t SegOffset) const { + return BindRebaseSectionTable->sectionName(SegIndex, SegOffset); + } + + /// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or + /// Rebase entry to get the address. + uint64_t BindRebaseAddress(uint32_t SegIndex, uint64_t SegOffset) const { + return BindRebaseSectionTable->address(SegIndex, SegOffset); + } + + // In a MachO file, sections have a segment name. This is used in the .o + // files. They have a single segment, but this field specifies which segment + // a section should be put in the final object. + StringRef getSectionFinalSegmentName(DataRefImpl Sec) const; + + // Names are stored as 16 bytes. These returns the raw 16 bytes without + // interpreting them as a C string. + ArrayRef<char> getSectionRawName(DataRefImpl Sec) const; + ArrayRef<char> getSectionRawFinalSegmentName(DataRefImpl Sec) const; + + // MachO specific Info about relocations. + bool isRelocationScattered(const MachO::any_relocation_info &RE) const; + unsigned getPlainRelocationSymbolNum( + const MachO::any_relocation_info &RE) const; + bool getPlainRelocationExternal(const MachO::any_relocation_info &RE) const; + bool getScatteredRelocationScattered( + const MachO::any_relocation_info &RE) const; + uint32_t getScatteredRelocationValue( + const MachO::any_relocation_info &RE) const; + uint32_t getScatteredRelocationType( + const MachO::any_relocation_info &RE) const; + unsigned getAnyRelocationAddress(const MachO::any_relocation_info &RE) const; + unsigned getAnyRelocationPCRel(const MachO::any_relocation_info &RE) const; + unsigned getAnyRelocationLength(const MachO::any_relocation_info &RE) const; + unsigned getAnyRelocationType(const MachO::any_relocation_info &RE) const; + SectionRef getAnyRelocationSection(const MachO::any_relocation_info &RE) const; + + // MachO specific structures. + MachO::section getSection(DataRefImpl DRI) const; + MachO::section_64 getSection64(DataRefImpl DRI) const; + MachO::section getSection(const LoadCommandInfo &L, unsigned Index) const; + MachO::section_64 getSection64(const LoadCommandInfo &L,unsigned Index) const; + MachO::nlist getSymbolTableEntry(DataRefImpl DRI) const; + MachO::nlist_64 getSymbol64TableEntry(DataRefImpl DRI) const; + + MachO::linkedit_data_command + getLinkeditDataLoadCommand(const LoadCommandInfo &L) const; + MachO::segment_command + getSegmentLoadCommand(const LoadCommandInfo &L) const; + MachO::segment_command_64 + getSegment64LoadCommand(const LoadCommandInfo &L) const; + MachO::linker_option_command + getLinkerOptionLoadCommand(const LoadCommandInfo &L) const; + MachO::version_min_command + getVersionMinLoadCommand(const LoadCommandInfo &L) const; + MachO::note_command + getNoteLoadCommand(const LoadCommandInfo &L) const; + MachO::build_version_command + getBuildVersionLoadCommand(const LoadCommandInfo &L) const; + MachO::build_tool_version + getBuildToolVersion(unsigned index) const; + MachO::dylib_command + getDylibIDLoadCommand(const LoadCommandInfo &L) const; + MachO::dyld_info_command + getDyldInfoLoadCommand(const LoadCommandInfo &L) const; + MachO::dylinker_command + getDylinkerCommand(const LoadCommandInfo &L) const; + MachO::uuid_command + getUuidCommand(const LoadCommandInfo &L) const; + MachO::rpath_command + getRpathCommand(const LoadCommandInfo &L) const; + MachO::source_version_command + getSourceVersionCommand(const LoadCommandInfo &L) const; + MachO::entry_point_command + getEntryPointCommand(const LoadCommandInfo &L) const; + MachO::encryption_info_command + getEncryptionInfoCommand(const LoadCommandInfo &L) const; + MachO::encryption_info_command_64 + getEncryptionInfoCommand64(const LoadCommandInfo &L) const; + MachO::sub_framework_command + getSubFrameworkCommand(const LoadCommandInfo &L) const; + MachO::sub_umbrella_command + getSubUmbrellaCommand(const LoadCommandInfo &L) const; + MachO::sub_library_command + getSubLibraryCommand(const LoadCommandInfo &L) const; + MachO::sub_client_command + getSubClientCommand(const LoadCommandInfo &L) const; + MachO::routines_command + getRoutinesCommand(const LoadCommandInfo &L) const; + MachO::routines_command_64 + getRoutinesCommand64(const LoadCommandInfo &L) const; + MachO::thread_command + getThreadCommand(const LoadCommandInfo &L) const; + + MachO::any_relocation_info getRelocation(DataRefImpl Rel) const; + MachO::data_in_code_entry getDice(DataRefImpl Rel) const; + const MachO::mach_header &getHeader() const; + const MachO::mach_header_64 &getHeader64() const; + uint32_t + getIndirectSymbolTableEntry(const MachO::dysymtab_command &DLC, + unsigned Index) const; + MachO::data_in_code_entry getDataInCodeTableEntry(uint32_t DataOffset, + unsigned Index) const; + MachO::symtab_command getSymtabLoadCommand() const; + MachO::dysymtab_command getDysymtabLoadCommand() const; + MachO::linkedit_data_command getDataInCodeLoadCommand() const; + MachO::linkedit_data_command getLinkOptHintsLoadCommand() const; + ArrayRef<uint8_t> getDyldInfoRebaseOpcodes() const; + ArrayRef<uint8_t> getDyldInfoBindOpcodes() const; + ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const; + ArrayRef<uint8_t> getDyldInfoLazyBindOpcodes() const; + ArrayRef<uint8_t> getDyldInfoExportsTrie() const; + ArrayRef<uint8_t> getUuid() const; + + StringRef getStringTableData() const; + bool is64Bit() const; + void ReadULEB128s(uint64_t Index, SmallVectorImpl<uint64_t> &Out) const; + + static StringRef guessLibraryShortName(StringRef Name, bool &isFramework, + StringRef &Suffix); + + static Triple::ArchType getArch(uint32_t CPUType); + static Triple getArchTriple(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault = nullptr, + const char **ArchFlag = nullptr); + static bool isValidArch(StringRef ArchFlag); + static ArrayRef<StringRef> getValidArchs(); + static Triple getHostArch(); + + bool isRelocatableObject() const override; + + StringRef mapDebugSectionName(StringRef Name) const override; + + bool hasPageZeroSegment() const { return HasPageZeroSegment; } + + static bool classof(const Binary *v) { + 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; + } + + static std::string getBuildPlatform(uint32_t platform) { + switch (platform) { + case MachO::PLATFORM_MACOS: return "macos"; + case MachO::PLATFORM_IOS: return "ios"; + case MachO::PLATFORM_TVOS: return "tvos"; + case MachO::PLATFORM_WATCHOS: return "watchos"; + case MachO::PLATFORM_BRIDGEOS: return "bridgeos"; + case MachO::PLATFORM_MACCATALYST: return "macCatalyst"; + case MachO::PLATFORM_IOSSIMULATOR: return "iossimulator"; + case MachO::PLATFORM_TVOSSIMULATOR: return "tvossimulator"; + case MachO::PLATFORM_WATCHOSSIMULATOR: return "watchossimulator"; + default: + std::string ret; + raw_string_ostream ss(ret); + ss << format_hex(platform, 8, true); + return ss.str(); + } + } + + static std::string getBuildTool(uint32_t tools) { + switch (tools) { + case MachO::TOOL_CLANG: return "clang"; + case MachO::TOOL_SWIFT: return "swift"; + case MachO::TOOL_LD: return "ld"; + default: + std::string ret; + raw_string_ostream ss(ret); + ss << format_hex(tools, 8, true); + return ss.str(); + } + } + + static std::string getVersionString(uint32_t version) { + uint32_t major = (version >> 16) & 0xffff; + uint32_t minor = (version >> 8) & 0xff; + uint32_t update = version & 0xff; + + SmallString<32> Version; + Version = utostr(major) + "." + utostr(minor); + if (update != 0) + Version += "." + utostr(update); + return Version.str(); + } + +private: + MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, + Error &Err, uint32_t UniversalCputype = 0, + uint32_t UniversalIndex = 0); + + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + + union { + MachO::mach_header_64 Header64; + MachO::mach_header Header; + }; + using SectionList = SmallVector<const char*, 1>; + SectionList Sections; + using LibraryList = SmallVector<const char*, 1>; + LibraryList Libraries; + LoadCommandList LoadCommands; + using LibraryShortName = SmallVector<StringRef, 1>; + using BuildToolList = SmallVector<const char*, 1>; + BuildToolList BuildTools; + mutable LibraryShortName LibrariesShortNames; + std::unique_ptr<BindRebaseSegInfo> BindRebaseSectionTable; + const char *SymtabLoadCmd = nullptr; + const char *DysymtabLoadCmd = nullptr; + const char *DataInCodeLoadCmd = nullptr; + const char *LinkOptHintsLoadCmd = nullptr; + const char *DyldInfoLoadCmd = nullptr; + const char *UuidLoadCmd = nullptr; + bool HasPageZeroSegment = false; +}; + +/// DiceRef +inline DiceRef::DiceRef(DataRefImpl DiceP, const ObjectFile *Owner) + : DicePimpl(DiceP) , OwningObject(Owner) {} + +inline bool DiceRef::operator==(const DiceRef &Other) const { + return DicePimpl == Other.DicePimpl; +} + +inline bool DiceRef::operator<(const DiceRef &Other) const { + return DicePimpl < Other.DicePimpl; +} + +inline void DiceRef::moveNext() { + const MachO::data_in_code_entry *P = + reinterpret_cast<const MachO::data_in_code_entry *>(DicePimpl.p); + DicePimpl.p = reinterpret_cast<uintptr_t>(P + 1); +} + +// Since a Mach-O data in code reference, a DiceRef, can only be created when +// the OwningObject ObjectFile is a MachOObjectFile a static_cast<> is used for +// the methods that get the values of the fields of the reference. + +inline std::error_code DiceRef::getOffset(uint32_t &Result) const { + const MachOObjectFile *MachOOF = + static_cast<const MachOObjectFile *>(OwningObject); + MachO::data_in_code_entry Dice = MachOOF->getDice(DicePimpl); + Result = Dice.offset; + return std::error_code(); +} + +inline std::error_code DiceRef::getLength(uint16_t &Result) const { + const MachOObjectFile *MachOOF = + static_cast<const MachOObjectFile *>(OwningObject); + MachO::data_in_code_entry Dice = MachOOF->getDice(DicePimpl); + Result = Dice.length; + return std::error_code(); +} + +inline std::error_code DiceRef::getKind(uint16_t &Result) const { + const MachOObjectFile *MachOOF = + static_cast<const MachOObjectFile *>(OwningObject); + MachO::data_in_code_entry Dice = MachOOF->getDice(DicePimpl); + Result = Dice.kind; + return std::error_code(); +} + +inline DataRefImpl DiceRef::getRawDataRefImpl() const { + return DicePimpl; +} + +inline const ObjectFile *DiceRef::getObjectFile() const { + return OwningObject; +} + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_MACHO_H diff --git a/third_party/llvm-project/include/llvm/Object/Minidump.h b/third_party/llvm-project/include/llvm/Object/Minidump.h new file mode 100644 index 000000000..4429493af --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/Minidump.h @@ -0,0 +1,216 @@ +//===- Minidump.h - Minidump object file implementation ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_MINIDUMP_H +#define LLVM_OBJECT_MINIDUMP_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/iterator.h" +#include "llvm/BinaryFormat/Minidump.h" +#include "llvm/Object/Binary.h" +#include "llvm/Support/Error.h" + +namespace llvm { +namespace object { + +/// A class providing access to the contents of a minidump file. +class MinidumpFile : public Binary { +public: + /// Construct a new MinidumpFile object from the given memory buffer. Returns + /// an error if this file cannot be identified as a minidump file, or if its + /// contents are badly corrupted (i.e. we cannot read the stream directory). + static Expected<std::unique_ptr<MinidumpFile>> create(MemoryBufferRef Source); + + static bool classof(const Binary *B) { return B->isMinidump(); } + + /// Returns the contents of the minidump header. + const minidump::Header &header() const { return Header; } + + /// Returns the list of streams (stream directory entries) in this file. + ArrayRef<minidump::Directory> streams() const { return Streams; } + + /// Returns the raw contents of the stream given by the directory entry. + ArrayRef<uint8_t> getRawStream(const minidump::Directory &Stream) const { + return getData().slice(Stream.Location.RVA, Stream.Location.DataSize); + } + + /// Returns the raw contents of the stream of the given type, or None if the + /// file does not contain a stream of this type. + Optional<ArrayRef<uint8_t>> getRawStream(minidump::StreamType Type) const; + + /// Returns the raw contents of an object given by the LocationDescriptor. An + /// error is returned if the descriptor points outside of the minidump file. + Expected<ArrayRef<uint8_t>> + getRawData(minidump::LocationDescriptor Desc) const { + return getDataSlice(getData(), Desc.RVA, Desc.DataSize); + } + + /// Returns the minidump string at the given offset. An error is returned if + /// we fail to parse the string, or the string is invalid UTF16. + Expected<std::string> getString(size_t Offset) const; + + /// Returns the contents of the SystemInfo stream, cast to the appropriate + /// type. An error is returned if the file does not contain this stream, or + /// the stream is smaller than the size of the SystemInfo structure. The + /// internal consistency of the stream is not checked in any way. + Expected<const minidump::SystemInfo &> getSystemInfo() const { + return getStream<minidump::SystemInfo>(minidump::StreamType::SystemInfo); + } + + /// Returns the module list embedded in the ModuleList stream. An error is + /// returned if the file does not contain this stream, or if the stream is + /// not large enough to contain the number of modules declared in the stream + /// header. The consistency of the Module entries themselves is not checked in + /// any way. + Expected<ArrayRef<minidump::Module>> getModuleList() const { + return getListStream<minidump::Module>(minidump::StreamType::ModuleList); + } + + /// Returns the thread list embedded in the ThreadList stream. An error is + /// returned if the file does not contain this stream, or if the stream is + /// not large enough to contain the number of threads declared in the stream + /// header. The consistency of the Thread entries themselves is not checked in + /// any way. + Expected<ArrayRef<minidump::Thread>> getThreadList() const { + return getListStream<minidump::Thread>(minidump::StreamType::ThreadList); + } + + /// Returns the contents of the Exception stream. An error is returned if the + /// file does not contain this stream, or the stream is smaller than the size + /// of the ExceptionStream structure. The internal consistency of the stream + /// is not checked in any way. + Expected<const minidump::ExceptionStream &> getExceptionStream() const { + return getStream<minidump::ExceptionStream>( + minidump::StreamType::Exception); + } + + /// Returns the list of descriptors embedded in the MemoryList stream. The + /// descriptors provide the content of interesting regions of memory at the + /// time the minidump was taken. An error is returned if the file does not + /// contain this stream, or if the stream is not large enough to contain the + /// number of memory descriptors declared in the stream header. The + /// consistency of the MemoryDescriptor entries themselves is not checked in + /// any way. + Expected<ArrayRef<minidump::MemoryDescriptor>> getMemoryList() const { + return getListStream<minidump::MemoryDescriptor>( + minidump::StreamType::MemoryList); + } + + class MemoryInfoIterator + : public iterator_facade_base<MemoryInfoIterator, + std::forward_iterator_tag, + minidump::MemoryInfo> { + public: + MemoryInfoIterator(ArrayRef<uint8_t> Storage, size_t Stride) + : Storage(Storage), Stride(Stride) { + assert(Storage.size() % Stride == 0); + } + + bool operator==(const MemoryInfoIterator &R) const { + return Storage.size() == R.Storage.size(); + } + + const minidump::MemoryInfo &operator*() const { + assert(Storage.size() >= sizeof(minidump::MemoryInfo)); + return *reinterpret_cast<const minidump::MemoryInfo *>(Storage.data()); + } + + MemoryInfoIterator &operator++() { + Storage = Storage.drop_front(Stride); + return *this; + } + + private: + ArrayRef<uint8_t> Storage; + size_t Stride; + }; + + /// Returns the list of descriptors embedded in the MemoryInfoList stream. The + /// descriptors provide properties (e.g. permissions) of interesting regions + /// of memory at the time the minidump was taken. An error is returned if the + /// file does not contain this stream, or if the stream is not large enough to + /// contain the number of memory descriptors declared in the stream header. + /// The consistency of the MemoryInfoList entries themselves is not checked + /// in any way. + Expected<iterator_range<MemoryInfoIterator>> getMemoryInfoList() const; + +private: + static Error createError(StringRef Str) { + return make_error<GenericBinaryError>(Str, object_error::parse_failed); + } + + static Error createEOFError() { + return make_error<GenericBinaryError>("Unexpected EOF", + object_error::unexpected_eof); + } + + /// Return a slice of the given data array, with bounds checking. + static Expected<ArrayRef<uint8_t>> getDataSlice(ArrayRef<uint8_t> Data, + size_t Offset, size_t Size); + + /// Return the slice of the given data array as an array of objects of the + /// given type. The function checks that the input array is large enough to + /// contain the correct number of objects of the given type. + template <typename T> + static Expected<ArrayRef<T>> getDataSliceAs(ArrayRef<uint8_t> Data, + size_t Offset, size_t Count); + + MinidumpFile(MemoryBufferRef Source, const minidump::Header &Header, + ArrayRef<minidump::Directory> Streams, + DenseMap<minidump::StreamType, std::size_t> StreamMap) + : Binary(ID_Minidump, Source), Header(Header), Streams(Streams), + StreamMap(std::move(StreamMap)) {} + + ArrayRef<uint8_t> getData() const { + return arrayRefFromStringRef(Data.getBuffer()); + } + + /// Return the stream of the given type, cast to the appropriate type. Checks + /// that the stream is large enough to hold an object of this type. + template <typename T> + Expected<const T &> getStream(minidump::StreamType Stream) const; + + /// Return the contents of a stream which contains a list of fixed-size items, + /// prefixed by the list size. + template <typename T> + Expected<ArrayRef<T>> getListStream(minidump::StreamType Stream) const; + + const minidump::Header &Header; + ArrayRef<minidump::Directory> Streams; + DenseMap<minidump::StreamType, std::size_t> StreamMap; +}; + +template <typename T> +Expected<const T &> MinidumpFile::getStream(minidump::StreamType Type) const { + if (Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type)) { + if (Stream->size() >= sizeof(T)) + return *reinterpret_cast<const T *>(Stream->data()); + return createEOFError(); + } + return createError("No such stream"); +} + +template <typename T> +Expected<ArrayRef<T>> MinidumpFile::getDataSliceAs(ArrayRef<uint8_t> Data, + size_t Offset, + size_t Count) { + // Check for overflow. + if (Count > std::numeric_limits<size_t>::max() / sizeof(T)) + return createEOFError(); + Expected<ArrayRef<uint8_t>> Slice = + getDataSlice(Data, Offset, sizeof(T) * Count); + if (!Slice) + return Slice.takeError(); + return ArrayRef<T>(reinterpret_cast<const T *>(Slice->data()), Count); +} + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_MINIDUMP_H diff --git a/third_party/llvm-project/include/llvm/Object/ObjectFile.h b/third_party/llvm-project/include/llvm/Object/ObjectFile.h new file mode 100644 index 000000000..d53c9b49c --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/ObjectFile.h @@ -0,0 +1,579 @@ +//===- ObjectFile.h - File format independent object file -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares a file format independent ObjectFile class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_OBJECTFILE_H +#define LLVM_OBJECT_OBJECTFILE_H + +#include "llvm/ADT/DenseMapInfo.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/Error.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <system_error> + +namespace llvm { + +class ARMAttributeParser; + +namespace object { + +class COFFObjectFile; +class MachOObjectFile; +class ObjectFile; +class SectionRef; +class SymbolRef; +class symbol_iterator; +class WasmObjectFile; + +using section_iterator = content_iterator<SectionRef>; + +/// This is a value type class that represents a single relocation in the list +/// of relocations in the object file. +class RelocationRef { + DataRefImpl RelocationPimpl; + const ObjectFile *OwningObject = nullptr; + +public: + RelocationRef() = default; + RelocationRef(DataRefImpl RelocationP, const ObjectFile *Owner); + + bool operator==(const RelocationRef &Other) const; + + void moveNext(); + + uint64_t getOffset() const; + symbol_iterator getSymbol() const; + uint64_t getType() const; + + /// Get a string that represents the type of this relocation. + /// + /// This is for display purposes only. + void getTypeName(SmallVectorImpl<char> &Result) const; + + DataRefImpl getRawDataRefImpl() const; + const ObjectFile *getObject() const; +}; + +using relocation_iterator = content_iterator<RelocationRef>; + +/// This is a value type class that represents a single section in the list of +/// sections in the object file. +class SectionRef { + friend class SymbolRef; + + DataRefImpl SectionPimpl; + const ObjectFile *OwningObject = nullptr; + +public: + SectionRef() = default; + SectionRef(DataRefImpl SectionP, const ObjectFile *Owner); + + bool operator==(const SectionRef &Other) const; + bool operator!=(const SectionRef &Other) const; + bool operator<(const SectionRef &Other) const; + + void moveNext(); + + Expected<StringRef> getName() const; + uint64_t getAddress() const; + uint64_t getIndex() const; + uint64_t getSize() const; + Expected<StringRef> getContents() const; + + /// Get the alignment of this section as the actual value (not log 2). + uint64_t getAlignment() const; + + bool isCompressed() const; + /// Whether this section contains instructions. + bool isText() const; + /// Whether this section contains data, not instructions. + bool isData() const; + /// Whether this section contains BSS uninitialized data. + bool isBSS() const; + bool isVirtual() const; + bool isBitcode() const; + bool isStripped() const; + + /// Whether this section will be placed in the text segment, according to the + /// Berkeley size format. This is true if the section is allocatable, and + /// contains either code or readonly data. + bool isBerkeleyText() const; + /// Whether this section will be placed in the data segment, according to the + /// Berkeley size format. This is true if the section is allocatable and + /// contains data (e.g. PROGBITS), but is not text. + bool isBerkeleyData() const; + + bool containsSymbol(SymbolRef S) const; + + relocation_iterator relocation_begin() const; + relocation_iterator relocation_end() const; + iterator_range<relocation_iterator> relocations() const { + return make_range(relocation_begin(), relocation_end()); + } + Expected<section_iterator> getRelocatedSection() const; + + DataRefImpl getRawDataRefImpl() const; + const ObjectFile *getObject() const; +}; + +struct SectionedAddress { + const static uint64_t UndefSection = UINT64_MAX; + + uint64_t Address = 0; + uint64_t SectionIndex = UndefSection; +}; + +inline bool operator<(const SectionedAddress &LHS, + const SectionedAddress &RHS) { + return std::tie(LHS.SectionIndex, LHS.Address) < + std::tie(RHS.SectionIndex, RHS.Address); +} + +inline bool operator==(const SectionedAddress &LHS, + const SectionedAddress &RHS) { + return std::tie(LHS.SectionIndex, LHS.Address) == + std::tie(RHS.SectionIndex, RHS.Address); +} + +/// This is a value type class that represents a single symbol in the list of +/// symbols in the object file. +class SymbolRef : public BasicSymbolRef { + friend class SectionRef; + +public: + enum Type { + ST_Unknown, // Type not specified + ST_Data, + ST_Debug, + ST_File, + ST_Function, + ST_Other + }; + + SymbolRef() = default; + SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner); + SymbolRef(const BasicSymbolRef &B) : BasicSymbolRef(B) { + assert(isa<ObjectFile>(BasicSymbolRef::getObject())); + } + + Expected<StringRef> getName() const; + /// Returns the symbol virtual address (i.e. address at which it will be + /// mapped). + Expected<uint64_t> getAddress() const; + + /// Return the value of the symbol depending on the object this can be an + /// offset or a virtual address. + uint64_t getValue() const; + + /// Get the alignment of this symbol as the actual value (not log 2). + uint32_t getAlignment() const; + uint64_t getCommonSize() const; + Expected<SymbolRef::Type> getType() const; + + /// Get section this symbol is defined in reference to. Result is + /// end_sections() if it is undefined or is an absolute symbol. + Expected<section_iterator> getSection() const; + + const ObjectFile *getObject() const; +}; + +class symbol_iterator : public basic_symbol_iterator { +public: + symbol_iterator(SymbolRef Sym) : basic_symbol_iterator(Sym) {} + symbol_iterator(const basic_symbol_iterator &B) + : basic_symbol_iterator(SymbolRef(B->getRawDataRefImpl(), + cast<ObjectFile>(B->getObject()))) {} + + const SymbolRef *operator->() const { + const BasicSymbolRef &P = basic_symbol_iterator::operator *(); + return static_cast<const SymbolRef*>(&P); + } + + const SymbolRef &operator*() const { + const BasicSymbolRef &P = basic_symbol_iterator::operator *(); + return static_cast<const SymbolRef&>(P); + } +}; + +/// This class is the base class for all object file types. Concrete instances +/// of this object are created by createObjectFile, which figures out which type +/// to create. +class ObjectFile : public SymbolicFile { + virtual void anchor(); + +protected: + ObjectFile(unsigned int Type, MemoryBufferRef Source); + + const uint8_t *base() const { + return reinterpret_cast<const uint8_t *>(Data.getBufferStart()); + } + + // These functions are for SymbolRef to call internally. The main goal of + // this is to allow SymbolRef::SymbolPimpl to point directly to the symbol + // entry in the memory mapped object file. SymbolPimpl cannot contain any + // virtual functions because then it could not point into the memory mapped + // file. + // + // Implementations assume that the DataRefImpl is valid and has not been + // modified externally. It's UB otherwise. + friend class SymbolRef; + + virtual Expected<StringRef> getSymbolName(DataRefImpl Symb) const = 0; + Error printSymbolName(raw_ostream &OS, + DataRefImpl Symb) const override; + virtual Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const = 0; + virtual uint64_t getSymbolValueImpl(DataRefImpl Symb) const = 0; + virtual uint32_t getSymbolAlignment(DataRefImpl Symb) const; + virtual uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const = 0; + virtual Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const = 0; + virtual Expected<section_iterator> + getSymbolSection(DataRefImpl Symb) const = 0; + + // Same as above for SectionRef. + friend class SectionRef; + + virtual void moveSectionNext(DataRefImpl &Sec) const = 0; + virtual Expected<StringRef> getSectionName(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionAddress(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionIndex(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionSize(DataRefImpl Sec) const = 0; + virtual Expected<ArrayRef<uint8_t>> + getSectionContents(DataRefImpl Sec) const = 0; + virtual uint64_t getSectionAlignment(DataRefImpl Sec) const = 0; + virtual bool isSectionCompressed(DataRefImpl Sec) const = 0; + virtual bool isSectionText(DataRefImpl Sec) const = 0; + virtual bool isSectionData(DataRefImpl Sec) const = 0; + virtual bool isSectionBSS(DataRefImpl Sec) const = 0; + // A section is 'virtual' if its contents aren't present in the object image. + virtual bool isSectionVirtual(DataRefImpl Sec) const = 0; + virtual bool isSectionBitcode(DataRefImpl Sec) const; + virtual bool isSectionStripped(DataRefImpl Sec) const; + virtual bool isBerkeleyText(DataRefImpl Sec) const; + virtual bool isBerkeleyData(DataRefImpl Sec) const; + virtual relocation_iterator section_rel_begin(DataRefImpl Sec) const = 0; + virtual relocation_iterator section_rel_end(DataRefImpl Sec) const = 0; + virtual Expected<section_iterator> getRelocatedSection(DataRefImpl Sec) const; + + // Same as above for RelocationRef. + friend class RelocationRef; + virtual void moveRelocationNext(DataRefImpl &Rel) const = 0; + virtual uint64_t getRelocationOffset(DataRefImpl Rel) const = 0; + virtual symbol_iterator getRelocationSymbol(DataRefImpl Rel) const = 0; + virtual uint64_t getRelocationType(DataRefImpl Rel) const = 0; + virtual void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const = 0; + + uint64_t getSymbolValue(DataRefImpl Symb) const; + +public: + ObjectFile() = delete; + ObjectFile(const ObjectFile &other) = delete; + + uint64_t getCommonSymbolSize(DataRefImpl Symb) const { + assert(getSymbolFlags(Symb) & SymbolRef::SF_Common); + return getCommonSymbolSizeImpl(Symb); + } + + virtual std::vector<SectionRef> dynamic_relocation_sections() const { + return std::vector<SectionRef>(); + } + + using symbol_iterator_range = iterator_range<symbol_iterator>; + symbol_iterator_range symbols() const { + return symbol_iterator_range(symbol_begin(), symbol_end()); + } + + virtual section_iterator section_begin() const = 0; + virtual section_iterator section_end() const = 0; + + using section_iterator_range = iterator_range<section_iterator>; + section_iterator_range sections() const { + return section_iterator_range(section_begin(), section_end()); + } + + /// The number of bytes used to represent an address in this object + /// file format. + virtual uint8_t getBytesInAddress() const = 0; + + virtual StringRef getFileFormatName() const = 0; + virtual Triple::ArchType getArch() const = 0; + virtual SubtargetFeatures getFeatures() const = 0; + virtual void setARMSubArch(Triple &TheTriple) const { } + virtual Expected<uint64_t> getStartAddress() const { + // XXX BINARYEN + llvm_unreachable("getStartAddress"); + //return errorCodeToError(object_error::parse_failed); + }; + + /// Create a triple from the data in this object file. + Triple makeTriple() const; + + /// Maps a debug section name to a standard DWARF section name. + virtual StringRef mapDebugSectionName(StringRef Name) const { return Name; } + + /// True if this is a relocatable object (.o/.obj). + virtual bool isRelocatableObject() const = 0; + + /// @returns Pointer to ObjectFile subclass to handle this type of object. + /// @param ObjectPath The path to the object file. ObjectPath.isObject must + /// return true. + /// Create ObjectFile from path. + static Expected<OwningBinary<ObjectFile>> + createObjectFile(StringRef ObjectPath); + + static Expected<std::unique_ptr<ObjectFile>> + createObjectFile(MemoryBufferRef Object, llvm::file_magic Type); + static Expected<std::unique_ptr<ObjectFile>> + createObjectFile(MemoryBufferRef Object) { + return createObjectFile(Object, llvm::file_magic::unknown); + } + + static bool classof(const Binary *v) { + return v->isObject(); + } + + static Expected<std::unique_ptr<COFFObjectFile>> + createCOFFObjectFile(MemoryBufferRef Object); + + static Expected<std::unique_ptr<ObjectFile>> + createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); + + static Expected<std::unique_ptr<ObjectFile>> + createELFObjectFile(MemoryBufferRef Object); + + static Expected<std::unique_ptr<MachOObjectFile>> + createMachOObjectFile(MemoryBufferRef Object, + uint32_t UniversalCputype = 0, + uint32_t UniversalIndex = 0); + + static Expected<std::unique_ptr<WasmObjectFile>> + createWasmObjectFile(MemoryBufferRef Object); +}; + +// Inline function definitions. +inline SymbolRef::SymbolRef(DataRefImpl SymbolP, const ObjectFile *Owner) + : BasicSymbolRef(SymbolP, Owner) {} + +inline Expected<StringRef> SymbolRef::getName() const { + return getObject()->getSymbolName(getRawDataRefImpl()); +} + +inline Expected<uint64_t> SymbolRef::getAddress() const { + return getObject()->getSymbolAddress(getRawDataRefImpl()); +} + +inline uint64_t SymbolRef::getValue() const { + return getObject()->getSymbolValue(getRawDataRefImpl()); +} + +inline uint32_t SymbolRef::getAlignment() const { + return getObject()->getSymbolAlignment(getRawDataRefImpl()); +} + +inline uint64_t SymbolRef::getCommonSize() const { + return getObject()->getCommonSymbolSize(getRawDataRefImpl()); +} + +inline Expected<section_iterator> SymbolRef::getSection() const { + return getObject()->getSymbolSection(getRawDataRefImpl()); +} + +inline Expected<SymbolRef::Type> SymbolRef::getType() const { + return getObject()->getSymbolType(getRawDataRefImpl()); +} + +inline const ObjectFile *SymbolRef::getObject() const { + const SymbolicFile *O = BasicSymbolRef::getObject(); + return cast<ObjectFile>(O); +} + +/// SectionRef +inline SectionRef::SectionRef(DataRefImpl SectionP, + const ObjectFile *Owner) + : SectionPimpl(SectionP) + , OwningObject(Owner) {} + +inline bool SectionRef::operator==(const SectionRef &Other) const { + return OwningObject == Other.OwningObject && + SectionPimpl == Other.SectionPimpl; +} + +inline bool SectionRef::operator!=(const SectionRef &Other) const { + return !(*this == Other); +} + +inline bool SectionRef::operator<(const SectionRef &Other) const { + assert(OwningObject == Other.OwningObject); + return SectionPimpl < Other.SectionPimpl; +} + +inline void SectionRef::moveNext() { + return OwningObject->moveSectionNext(SectionPimpl); +} + +inline Expected<StringRef> SectionRef::getName() const { + return OwningObject->getSectionName(SectionPimpl); +} + +inline uint64_t SectionRef::getAddress() const { + return OwningObject->getSectionAddress(SectionPimpl); +} + +inline uint64_t SectionRef::getIndex() const { + return OwningObject->getSectionIndex(SectionPimpl); +} + +inline uint64_t SectionRef::getSize() const { + return OwningObject->getSectionSize(SectionPimpl); +} + +inline Expected<StringRef> SectionRef::getContents() const { + Expected<ArrayRef<uint8_t>> Res = + OwningObject->getSectionContents(SectionPimpl); + if (!Res) + return Res.takeError(); + return StringRef(reinterpret_cast<const char *>(Res->data()), Res->size()); +} + +inline uint64_t SectionRef::getAlignment() const { + return OwningObject->getSectionAlignment(SectionPimpl); +} + +inline bool SectionRef::isCompressed() const { + return OwningObject->isSectionCompressed(SectionPimpl); +} + +inline bool SectionRef::isText() const { + return OwningObject->isSectionText(SectionPimpl); +} + +inline bool SectionRef::isData() const { + return OwningObject->isSectionData(SectionPimpl); +} + +inline bool SectionRef::isBSS() const { + return OwningObject->isSectionBSS(SectionPimpl); +} + +inline bool SectionRef::isVirtual() const { + return OwningObject->isSectionVirtual(SectionPimpl); +} + +inline bool SectionRef::isBitcode() const { + return OwningObject->isSectionBitcode(SectionPimpl); +} + +inline bool SectionRef::isStripped() const { + return OwningObject->isSectionStripped(SectionPimpl); +} + +inline bool SectionRef::isBerkeleyText() const { + return OwningObject->isBerkeleyText(SectionPimpl); +} + +inline bool SectionRef::isBerkeleyData() const { + return OwningObject->isBerkeleyData(SectionPimpl); +} + +inline relocation_iterator SectionRef::relocation_begin() const { + return OwningObject->section_rel_begin(SectionPimpl); +} + +inline relocation_iterator SectionRef::relocation_end() const { + return OwningObject->section_rel_end(SectionPimpl); +} + +inline Expected<section_iterator> SectionRef::getRelocatedSection() const { + return OwningObject->getRelocatedSection(SectionPimpl); +} + +inline DataRefImpl SectionRef::getRawDataRefImpl() const { + return SectionPimpl; +} + +inline const ObjectFile *SectionRef::getObject() const { + return OwningObject; +} + +/// RelocationRef +inline RelocationRef::RelocationRef(DataRefImpl RelocationP, + const ObjectFile *Owner) + : RelocationPimpl(RelocationP) + , OwningObject(Owner) {} + +inline bool RelocationRef::operator==(const RelocationRef &Other) const { + return RelocationPimpl == Other.RelocationPimpl; +} + +inline void RelocationRef::moveNext() { + return OwningObject->moveRelocationNext(RelocationPimpl); +} + +inline uint64_t RelocationRef::getOffset() const { + return OwningObject->getRelocationOffset(RelocationPimpl); +} + +inline symbol_iterator RelocationRef::getSymbol() const { + return OwningObject->getRelocationSymbol(RelocationPimpl); +} + +inline uint64_t RelocationRef::getType() const { + return OwningObject->getRelocationType(RelocationPimpl); +} + +inline void RelocationRef::getTypeName(SmallVectorImpl<char> &Result) const { + return OwningObject->getRelocationTypeName(RelocationPimpl, Result); +} + +inline DataRefImpl RelocationRef::getRawDataRefImpl() const { + return RelocationPimpl; +} + +inline const ObjectFile *RelocationRef::getObject() const { + return OwningObject; +} + +} // end namespace object + +template <> struct DenseMapInfo<object::SectionRef> { + static bool isEqual(const object::SectionRef &A, + const object::SectionRef &B) { + return A == B; + } + static object::SectionRef getEmptyKey() { + return object::SectionRef({}, nullptr); + } + static object::SectionRef getTombstoneKey() { + object::DataRefImpl TS; + TS.p = (uintptr_t)-1; + return object::SectionRef(TS, nullptr); + } + static unsigned getHashValue(const object::SectionRef &Sec) { + object::DataRefImpl Raw = Sec.getRawDataRefImpl(); + return hash_combine(Raw.p, Raw.d.a, Raw.d.b); + } +}; + +} // end namespace llvm + +#endif // LLVM_OBJECT_OBJECTFILE_H diff --git a/third_party/llvm-project/include/llvm/Object/RelocationResolver.h b/third_party/llvm-project/include/llvm/Object/RelocationResolver.h new file mode 100644 index 000000000..1246dcc5e --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/RelocationResolver.h @@ -0,0 +1,42 @@ +//===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides a wrapper around all the different types of relocations +// in different file formats, such that a client can handle them in a unified +// manner by only implementing a minimal number of functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_RELOCVISITOR_H +#define LLVM_OBJECT_RELOCVISITOR_H + +#include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <cstdint> +#include <system_error> + +namespace llvm { +namespace object { + +using RelocationResolver = uint64_t (*)(RelocationRef R, uint64_t S, uint64_t A); + +std::pair<bool (*)(uint64_t), RelocationResolver> +getRelocationResolver(const ObjectFile &Obj); + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_RELOCVISITOR_H diff --git a/third_party/llvm-project/include/llvm/Object/SymbolicFile.h b/third_party/llvm-project/include/llvm/Object/SymbolicFile.h new file mode 100644 index 000000000..1398fa134 --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/SymbolicFile.h @@ -0,0 +1,214 @@ +//===- SymbolicFile.h - Interface that only provides symbols ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the SymbolicFile interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_SYMBOLICFILE_H +#define LLVM_OBJECT_SYMBOLICFILE_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/Object/Binary.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cinttypes> +#include <cstdint> +#include <cstring> +#include <iterator> +#include <memory> +#include <system_error> + +namespace llvm { +namespace object { + +union DataRefImpl { + // This entire union should probably be a + // char[max(8, sizeof(uintptr_t))] and require the impl to cast. + struct { + uint32_t a, b; + } d; + uintptr_t p; + + DataRefImpl() { std::memset(this, 0, sizeof(DataRefImpl)); } +}; + +template <typename OStream> +OStream& operator<<(OStream &OS, const DataRefImpl &D) { + OS << "(" << format("0x%08" PRIxPTR, D.p) << " (" << format("0x%08x", D.d.a) + << ", " << format("0x%08x", 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. + return std::memcmp(&a, &b, sizeof(DataRefImpl)) == 0; +} + +inline bool operator!=(const DataRefImpl &a, const DataRefImpl &b) { + return !operator==(a, b); +} + +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. + return std::memcmp(&a, &b, sizeof(DataRefImpl)) < 0; +} + +template <class content_type> +class content_iterator + : public std::iterator<std::forward_iterator_tag, content_type> { + content_type Current; + +public: + content_iterator(content_type symb) : Current(std::move(symb)) {} + + const content_type *operator->() const { return &Current; } + + const content_type &operator*() const { return Current; } + + bool operator==(const content_iterator &other) const { + return Current == other.Current; + } + + bool operator!=(const content_iterator &other) const { + return !(*this == other); + } + + content_iterator &operator++() { // preincrement + Current.moveNext(); + return *this; + } +}; + +class SymbolicFile; + +/// This is a value type class that represents a single symbol in the list of +/// symbols in the object file. +class BasicSymbolRef { + DataRefImpl SymbolPimpl; + const SymbolicFile *OwningObject = nullptr; + +public: + enum Flags : unsigned { + SF_None = 0, + SF_Undefined = 1U << 0, // Symbol is defined in another object file + SF_Global = 1U << 1, // Global symbol + SF_Weak = 1U << 2, // Weak symbol + SF_Absolute = 1U << 3, // Absolute symbol + SF_Common = 1U << 4, // Symbol has common linkage + SF_Indirect = 1U << 5, // Symbol is an alias to another symbol + SF_Exported = 1U << 6, // Symbol is visible to other DSOs + SF_FormatSpecific = 1U << 7, // Specific to the object file format + // (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 + SF_Executable = 1U << 11, // Symbol points to an executable section + // (IR only) + }; + + BasicSymbolRef() = default; + BasicSymbolRef(DataRefImpl SymbolP, const SymbolicFile *Owner); + + bool operator==(const BasicSymbolRef &Other) const; + bool operator<(const BasicSymbolRef &Other) const; + + void moveNext(); + + Error printName(raw_ostream &OS) const; + + /// Get symbol flags (bitwise OR of SymbolRef::Flags) + uint32_t getFlags() const; + + DataRefImpl getRawDataRefImpl() const; + const SymbolicFile *getObject() const; +}; + +using basic_symbol_iterator = content_iterator<BasicSymbolRef>; + +class SymbolicFile : public Binary { +public: + SymbolicFile(unsigned int Type, MemoryBufferRef Source); + ~SymbolicFile() override; + + // virtual interface. + virtual void moveSymbolNext(DataRefImpl &Symb) const = 0; + + virtual Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const = 0; + + virtual uint32_t getSymbolFlags(DataRefImpl Symb) const = 0; + + virtual basic_symbol_iterator symbol_begin() const = 0; + + virtual basic_symbol_iterator symbol_end() const = 0; + + // convenience wrappers. + using basic_symbol_iterator_range = iterator_range<basic_symbol_iterator>; + basic_symbol_iterator_range symbols() const { + return basic_symbol_iterator_range(symbol_begin(), symbol_end()); + } + + // construction aux. + static Expected<std::unique_ptr<SymbolicFile>> + createSymbolicFile(MemoryBufferRef Object, llvm::file_magic Type, + LLVMContext *Context); + + static Expected<std::unique_ptr<SymbolicFile>> + createSymbolicFile(MemoryBufferRef Object) { + return createSymbolicFile(Object, llvm::file_magic::unknown, nullptr); + } + static Expected<OwningBinary<SymbolicFile>> + createSymbolicFile(StringRef ObjectPath); + + static bool classof(const Binary *v) { + return v->isSymbolic(); + } +}; + +inline BasicSymbolRef::BasicSymbolRef(DataRefImpl SymbolP, + const SymbolicFile *Owner) + : SymbolPimpl(SymbolP), OwningObject(Owner) {} + +inline bool BasicSymbolRef::operator==(const BasicSymbolRef &Other) const { + return SymbolPimpl == Other.SymbolPimpl; +} + +inline bool BasicSymbolRef::operator<(const BasicSymbolRef &Other) const { + return SymbolPimpl < Other.SymbolPimpl; +} + +inline void BasicSymbolRef::moveNext() { + return OwningObject->moveSymbolNext(SymbolPimpl); +} + +inline Error BasicSymbolRef::printName(raw_ostream &OS) const { + return OwningObject->printSymbolName(OS, SymbolPimpl); +} + +inline uint32_t BasicSymbolRef::getFlags() const { + return OwningObject->getSymbolFlags(SymbolPimpl); +} + +inline DataRefImpl BasicSymbolRef::getRawDataRefImpl() const { + return SymbolPimpl; +} + +inline const SymbolicFile *BasicSymbolRef::getObject() const { + return OwningObject; +} + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_SYMBOLICFILE_H diff --git a/third_party/llvm-project/include/llvm/Object/Wasm.h b/third_party/llvm-project/include/llvm/Object/Wasm.h new file mode 100644 index 000000000..e130ea32e --- /dev/null +++ b/third_party/llvm-project/include/llvm/Object/Wasm.h @@ -0,0 +1,356 @@ +//===- Wasm.h - Wasm object file implementation -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file declares the WasmObjectFile class, which implements the ObjectFile +// interface for Wasm files. +// +// See: https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_WASM_H +#define LLVM_OBJECT_WASM_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/Config/llvm-config.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cstddef> +#include <cstdint> +#include <vector> + +namespace llvm { +namespace object { + +class WasmSymbol { +public: + WasmSymbol(const wasm::WasmSymbolInfo &Info, + const wasm::WasmGlobalType *GlobalType, + const wasm::WasmEventType *EventType, + const wasm::WasmSignature *Signature) + : Info(Info), GlobalType(GlobalType), EventType(EventType), + Signature(Signature) {} + + const wasm::WasmSymbolInfo &Info; + const wasm::WasmGlobalType *GlobalType; + const wasm::WasmEventType *EventType; + const wasm::WasmSignature *Signature; + + bool isTypeFunction() const { + return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION; + } + + bool isTypeData() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_DATA; } + + bool isTypeGlobal() const { + return Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL; + } + + bool isTypeSection() const { + return Info.Kind == wasm::WASM_SYMBOL_TYPE_SECTION; + } + + bool isTypeEvent() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_EVENT; } + + bool isDefined() const { return !isUndefined(); } + + bool isUndefined() const { + return (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) != 0; + } + + bool isBindingWeak() const { + return getBinding() == wasm::WASM_SYMBOL_BINDING_WEAK; + } + + bool isBindingGlobal() const { + return getBinding() == wasm::WASM_SYMBOL_BINDING_GLOBAL; + } + + bool isBindingLocal() const { + return getBinding() == wasm::WASM_SYMBOL_BINDING_LOCAL; + } + + unsigned getBinding() const { + return Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK; + } + + bool isHidden() const { + return getVisibility() == wasm::WASM_SYMBOL_VISIBILITY_HIDDEN; + } + + unsigned getVisibility() const { + return Info.Flags & wasm::WASM_SYMBOL_VISIBILITY_MASK; + } + + void print(raw_ostream &Out) const; + +#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) + LLVM_DUMP_METHOD void dump() const; +#endif +}; + +struct WasmSection { + WasmSection() = default; + + uint32_t Type = 0; // Section type (See below) + uint32_t Offset = 0; // Offset with in the file + StringRef Name; // Section name (User-defined sections only) + ArrayRef<uint8_t> Content; // Section content + std::vector<wasm::WasmRelocation> Relocations; // Relocations for this section +}; + +struct WasmSegment { + uint32_t SectionOffset; + wasm::WasmDataSegment Data; +}; + +class WasmObjectFile : public ObjectFile { + +public: + WasmObjectFile(MemoryBufferRef Object, Error &Err); + + const wasm::WasmObjectHeader &getHeader() const; + const WasmSymbol &getWasmSymbol(const DataRefImpl &Symb) const; + const WasmSymbol &getWasmSymbol(const SymbolRef &Symbol) const; + const WasmSection &getWasmSection(const SectionRef &Section) const; + const wasm::WasmRelocation &getWasmRelocation(const RelocationRef &Ref) const; + + static bool classof(const Binary *v) { return v->isWasm(); } + + const wasm::WasmDylinkInfo &dylinkInfo() const { return DylinkInfo; } + const wasm::WasmProducerInfo &getProducerInfo() const { return ProducerInfo; } + ArrayRef<wasm::WasmFeatureEntry> getTargetFeatures() const { + return TargetFeatures; + } + ArrayRef<wasm::WasmSignature> types() const { return Signatures; } + ArrayRef<uint32_t> functionTypes() const { return FunctionTypes; } + ArrayRef<wasm::WasmImport> imports() const { return Imports; } + ArrayRef<wasm::WasmTable> tables() const { return Tables; } + ArrayRef<wasm::WasmLimits> memories() const { return Memories; } + ArrayRef<wasm::WasmGlobal> globals() const { return Globals; } + ArrayRef<wasm::WasmEvent> events() const { return Events; } + ArrayRef<wasm::WasmExport> exports() const { return Exports; } + ArrayRef<WasmSymbol> syms() const { return Symbols; } + const wasm::WasmLinkingData &linkingData() const { return LinkingData; } + uint32_t getNumberOfSymbols() const { return Symbols.size(); } + ArrayRef<wasm::WasmElemSegment> elements() const { return ElemSegments; } + ArrayRef<WasmSegment> dataSegments() const { return DataSegments; } + ArrayRef<wasm::WasmFunction> functions() const { return Functions; } + ArrayRef<wasm::WasmFunctionName> debugNames() const { return DebugNames; } + uint32_t startFunction() const { return StartFunction; } + uint32_t getNumImportedGlobals() const { return NumImportedGlobals; } + uint32_t getNumImportedFunctions() const { return NumImportedFunctions; } + uint32_t getNumImportedEvents() const { return NumImportedEvents; } + void moveSymbolNext(DataRefImpl &Symb) const override; + + uint32_t getSymbolFlags(DataRefImpl Symb) const override; + + basic_symbol_iterator symbol_begin() const override; + + basic_symbol_iterator symbol_end() const override; + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; + + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + uint64_t getWasmSymbolValue(const WasmSymbol &Sym) const; + uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; + uint32_t getSymbolAlignment(DataRefImpl Symb) const override; + uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; + Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; + Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; + + // Overrides from SectionRef. + void moveSectionNext(DataRefImpl &Sec) const override; + Expected<StringRef> getSectionName(DataRefImpl Sec) const override; + uint64_t getSectionAddress(DataRefImpl Sec) const override; + uint64_t getSectionIndex(DataRefImpl Sec) const override; + uint64_t getSectionSize(DataRefImpl Sec) const override; + Expected<ArrayRef<uint8_t>> + getSectionContents(DataRefImpl Sec) const override; + uint64_t getSectionAlignment(DataRefImpl Sec) const override; + bool isSectionCompressed(DataRefImpl Sec) const override; + bool isSectionText(DataRefImpl Sec) const override; + bool isSectionData(DataRefImpl Sec) const override; + bool isSectionBSS(DataRefImpl Sec) const override; + bool isSectionVirtual(DataRefImpl Sec) const override; + bool isSectionBitcode(DataRefImpl Sec) const override; + relocation_iterator section_rel_begin(DataRefImpl Sec) const override; + relocation_iterator section_rel_end(DataRefImpl Sec) const override; + + // Overrides from RelocationRef. + void moveRelocationNext(DataRefImpl &Rel) const override; + uint64_t getRelocationOffset(DataRefImpl Rel) const override; + symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override; + uint64_t getRelocationType(DataRefImpl Rel) const override; + void getRelocationTypeName(DataRefImpl Rel, + SmallVectorImpl<char> &Result) const override; + + section_iterator section_begin() const override; + section_iterator section_end() const override; + uint8_t getBytesInAddress() const override; + StringRef getFileFormatName() const override; + Triple::ArchType getArch() const override; + SubtargetFeatures getFeatures() const override; + bool isRelocatableObject() const override; + bool isSharedObject() const; + + struct ReadContext { + const uint8_t *Start; + const uint8_t *Ptr; + const uint8_t *End; + }; + +private: + bool isValidFunctionIndex(uint32_t Index) const; + bool isDefinedFunctionIndex(uint32_t Index) const; + bool isValidGlobalIndex(uint32_t Index) const; + bool isDefinedGlobalIndex(uint32_t Index) const; + bool isValidEventIndex(uint32_t Index) const; + bool isDefinedEventIndex(uint32_t Index) const; + bool isValidFunctionSymbol(uint32_t Index) const; + bool isValidGlobalSymbol(uint32_t Index) const; + bool isValidEventSymbol(uint32_t Index) const; + bool isValidDataSymbol(uint32_t Index) const; + bool isValidSectionSymbol(uint32_t Index) const; + wasm::WasmFunction &getDefinedFunction(uint32_t Index); + const wasm::WasmFunction &getDefinedFunction(uint32_t Index) const; + wasm::WasmGlobal &getDefinedGlobal(uint32_t Index); + wasm::WasmEvent &getDefinedEvent(uint32_t Index); + + const WasmSection &getWasmSection(DataRefImpl Ref) const; + const wasm::WasmRelocation &getWasmRelocation(DataRefImpl Ref) const; + + Error parseSection(WasmSection &Sec); + Error parseCustomSection(WasmSection &Sec, ReadContext &Ctx); + + // Standard section types + Error parseTypeSection(ReadContext &Ctx); + Error parseImportSection(ReadContext &Ctx); + Error parseFunctionSection(ReadContext &Ctx); + Error parseTableSection(ReadContext &Ctx); + Error parseMemorySection(ReadContext &Ctx); + Error parseGlobalSection(ReadContext &Ctx); + Error parseEventSection(ReadContext &Ctx); + Error parseExportSection(ReadContext &Ctx); + Error parseStartSection(ReadContext &Ctx); + Error parseElemSection(ReadContext &Ctx); + Error parseCodeSection(ReadContext &Ctx); + Error parseDataSection(ReadContext &Ctx); + Error parseDataCountSection(ReadContext &Ctx); + + // Custom section types + Error parseDylinkSection(ReadContext &Ctx); + Error parseNameSection(ReadContext &Ctx); + Error parseLinkingSection(ReadContext &Ctx); + Error parseLinkingSectionSymtab(ReadContext &Ctx); + Error parseLinkingSectionComdat(ReadContext &Ctx); + Error parseProducersSection(ReadContext &Ctx); + Error parseTargetFeaturesSection(ReadContext &Ctx); + Error parseRelocSection(StringRef Name, ReadContext &Ctx); + + wasm::WasmObjectHeader Header; + std::vector<WasmSection> Sections; + wasm::WasmDylinkInfo DylinkInfo; + wasm::WasmProducerInfo ProducerInfo; + std::vector<wasm::WasmFeatureEntry> TargetFeatures; + std::vector<wasm::WasmSignature> Signatures; + std::vector<uint32_t> FunctionTypes; + std::vector<wasm::WasmTable> Tables; + std::vector<wasm::WasmLimits> Memories; + std::vector<wasm::WasmGlobal> Globals; + std::vector<wasm::WasmEvent> Events; + std::vector<wasm::WasmImport> Imports; + std::vector<wasm::WasmExport> Exports; + std::vector<wasm::WasmElemSegment> ElemSegments; + std::vector<WasmSegment> DataSegments; + llvm::Optional<size_t> DataCount; + std::vector<wasm::WasmFunction> Functions; + std::vector<WasmSymbol> Symbols; + std::vector<wasm::WasmFunctionName> DebugNames; + uint32_t StartFunction = -1; + bool HasLinkingSection = false; + bool HasDylinkSection = false; + wasm::WasmLinkingData LinkingData; + uint32_t NumImportedGlobals = 0; + uint32_t NumImportedFunctions = 0; + uint32_t NumImportedEvents = 0; + uint32_t CodeSection = 0; + uint32_t DataSection = 0; + uint32_t GlobalSection = 0; + uint32_t EventSection = 0; +}; + +class WasmSectionOrderChecker { +public: + // We define orders for all core wasm sections and known custom sections. + enum : int { + // Sentinel, must be zero + WASM_SEC_ORDER_NONE = 0, + + // Core sections + WASM_SEC_ORDER_TYPE, + WASM_SEC_ORDER_IMPORT, + WASM_SEC_ORDER_FUNCTION, + WASM_SEC_ORDER_TABLE, + WASM_SEC_ORDER_MEMORY, + WASM_SEC_ORDER_GLOBAL, + WASM_SEC_ORDER_EVENT, + WASM_SEC_ORDER_EXPORT, + WASM_SEC_ORDER_START, + WASM_SEC_ORDER_ELEM, + WASM_SEC_ORDER_DATACOUNT, + WASM_SEC_ORDER_CODE, + WASM_SEC_ORDER_DATA, + + // Custom sections + // "dylink" should be the very first section in the module + WASM_SEC_ORDER_DYLINK, + // "linking" section requires DATA section in order to validate data symbols + WASM_SEC_ORDER_LINKING, + // Must come after "linking" section in order to validate reloc indexes. + WASM_SEC_ORDER_RELOC, + // "name" section must appear after DATA. Comes after "linking" to allow + // symbol table to set default function name. + WASM_SEC_ORDER_NAME, + // "producers" section must appear after "name" section. + WASM_SEC_ORDER_PRODUCERS, + // "target_features" section must appear after producers section + WASM_SEC_ORDER_TARGET_FEATURES, + + // Must be last + WASM_NUM_SEC_ORDERS + + }; + + // Sections that may or may not be present, but cannot be predecessors + static int DisallowedPredecessors[WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS]; + + bool isValidSectionOrder(unsigned ID, StringRef CustomSectionName = ""); + +private: + bool Seen[WASM_NUM_SEC_ORDERS] = {}; // Sections that have been seen already + + // Returns -1 for unknown sections. + int getSectionOrder(unsigned ID, StringRef CustomSectionName = ""); +}; + +} // end namespace object + +inline raw_ostream &operator<<(raw_ostream &OS, const object::WasmSymbol &Sym) { + Sym.print(OS); + return OS; +} + +} // end namespace llvm + +#endif // LLVM_OBJECT_WASM_H |