diff options
| author | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
|---|---|---|
| committer | Devtools Arcadia <[email protected]> | 2022-02-07 18:08:42 +0300 |
| commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
| tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /contrib/libs/llvm12/include/llvm/Object | |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'contrib/libs/llvm12/include/llvm/Object')
30 files changed, 10342 insertions, 0 deletions
diff --git a/contrib/libs/llvm12/include/llvm/Object/Archive.h b/contrib/libs/llvm12/include/llvm/Object/Archive.h new file mode 100644 index 00000000000..b6b1a126ac3 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/Archive.h @@ -0,0 +1,297 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/ArchiveWriter.h b/contrib/libs/llvm12/include/llvm/Object/ArchiveWriter.h new file mode 100644 index 00000000000..a2c582c4804 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/ArchiveWriter.h @@ -0,0 +1,61 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- ArchiveWriter.h - ar archive file format writer ----------*- 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 +// +//===----------------------------------------------------------------------===// +// +// Declares the writeArchive function for writing an archive file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_ARCHIVEWRITER_H +#define LLVM_OBJECT_ARCHIVEWRITER_H + +#include "llvm/Object/Archive.h" + +namespace llvm { + +struct NewArchiveMember { + std::unique_ptr<MemoryBuffer> Buf; + StringRef MemberName; + sys::TimePoint<std::chrono::seconds> ModTime; + unsigned UID = 0, GID = 0, Perms = 0644; + + NewArchiveMember() = default; + NewArchiveMember(MemoryBufferRef BufRef); + + static Expected<NewArchiveMember> + getOldMember(const object::Archive::Child &OldMember, bool Deterministic); + + static Expected<NewArchiveMember> getFile(StringRef FileName, + bool Deterministic); +}; + +Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To); + +Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, + bool WriteSymtab, object::Archive::Kind Kind, + bool Deterministic, bool Thin, + std::unique_ptr<MemoryBuffer> OldArchiveBuf = nullptr); + +// writeArchiveToBuffer is similar to writeArchive but returns the Archive in a +// buffer instead of writing it out to a file. +Expected<std::unique_ptr<MemoryBuffer>> +writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab, + object::Archive::Kind Kind, bool Deterministic, bool Thin); +} + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/Binary.h b/contrib/libs/llvm12/include/llvm/Object/Binary.h new file mode 100644 index 00000000000..0b1ee8456bb --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/Binary.h @@ -0,0 +1,253 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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(); + + virtual Error initContent() { return Error::success(); }; + + 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 Error checkOffset(MemoryBufferRef M, uintptr_t Addr, + const uint64_t Size) { + if (Addr + Size < Addr || Addr + Size < Size || + Addr + Size > reinterpret_cast<uintptr_t>(M.getBufferEnd()) || + Addr < reinterpret_cast<uintptr_t>(M.getBufferStart())) { + return errorCodeToError(object_error::unexpected_eof); + } + return Error::success(); + } +}; + +// 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, + bool InitContent = true); + +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, + LLVMContext *Context = nullptr, + bool InitContent = true); + +} // end namespace object + +} // end namespace llvm + +#endif // LLVM_OBJECT_BINARY_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/COFF.h b/contrib/libs/llvm12/include/llvm/Object/COFF.h new file mode 100644 index 00000000000..816a078cfcd --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/COFF.h @@ -0,0 +1,1291 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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 & COFF::IMAGE_SCN_ALIGN_MASK) >> 20; + if (Shift > 0) + return 1U << (Shift - 1); + return 0; + } + + void setAlignment(uint32_t Align) { + uint32_t AlignBits = 0; + if (Align) { + assert(llvm::isPowerOf2_32(Align) && "alignment is not a power of 2"); + assert(llvm::Log2_32(Align) <= 13 && "alignment requested is too large"); + AlignBits = (llvm::Log2_32(Align) + 1) << 20; + } + Characteristics = + (Characteristics & ~COFF::IMAGE_SCN_ALIGN_MASK) | AlignBits; + } +}; + +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: + COFFObjectFile(MemoryBufferRef Object); + + 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; + const coff_tls_directory32 *TLSDirectory32; + const coff_tls_directory64 *TLSDirectory64; + // Either coff_load_configuration32 or coff_load_configuration64. + const void *LoadConfig = nullptr; + + Expected<StringRef> getString(uint32_t offset) 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; + + // Finish initializing the object and return success or an error. + Error initialize(); + + Error initSymbolTablePtr(); + Error initImportTablePtr(); + Error initDelayImportTablePtr(); + Error initExportTablePtr(); + Error initBaseRelocPtr(); + Error initDebugDirectoryPtr(); + Error initTLSDirectoryPtr(); + Error initLoadConfigPtr(); + +public: + static Expected<std::unique_ptr<COFFObjectFile>> + create(MemoryBufferRef Object); + + 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(); + } + + uint32_t getStringTableSize() const { return StringTableSize; } + + 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; + Expected<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; + bool isDebugSection(StringRef SectionName) 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: + 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 coff_tls_directory32 *getTLSDirectory32() const { + return TLSDirectory32; + } + const coff_tls_directory64 *getTLSDirectory64() const { + return TLSDirectory64; + } + + 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; } + + const data_directory *getDataDirectory(uint32_t index) const; + Expected<const coff_section *> getSection(int32_t index) const; + + Expected<COFFSymbolRef> getSymbol(uint32_t index) const { + if (index >= getNumberOfSymbols()) + return errorCodeToError(object_error::parse_failed); + if (SymbolTable16) + return COFFSymbolRef(SymbolTable16 + index); + if (SymbolTable32) + return COFFSymbolRef(SymbolTable32 + index); + return errorCodeToError(object_error::parse_failed); + } + + template <typename T> + Error getAuxSymbol(uint32_t index, const T *&Res) const { + Expected<COFFSymbolRef> S = getSymbol(index); + if (Error E = S.takeError()) + return E; + Res = reinterpret_cast<const T *>(S->getRawPtr()); + return Error::success(); + } + + Expected<StringRef> getSymbolName(COFFSymbolRef Symbol) const; + Expected<StringRef> getSymbolName(const coff_symbol_generic *Symbol) 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; + Error getVaPtr(uint64_t VA, uintptr_t &Res) const; + Error 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. + Error getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size, + ArrayRef<uint8_t> &Contents) const; + + Error getHintName(uint32_t Rva, uint16_t &Hint, + StringRef &Name) const; + + /// Get PDB information out of a codeview debug directory entry. + Error 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. + Error 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; + + Error getName(StringRef &Result) const; + Error getImportLookupTableRVA(uint32_t &Result) const; + Error getImportAddressTableRVA(uint32_t &Result) const; + + Error + 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; + + Error getName(StringRef &Result) const; + Error getDelayImportTable( + const delay_import_directory_table_entry *&Result) const; + Error 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(); + + Error getDllName(StringRef &Result) const; + Error getOrdinalBase(uint32_t &Result) const; + Error getOrdinal(uint32_t &Result) const; + Error getExportRVA(uint32_t &Result) const; + Error getSymbolName(StringRef &Result) const; + + Error isForwarder(bool &Result) const; + Error 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(); + + Error getSymbolName(StringRef &Result) const; + Error isOrdinal(bool &Result) const; + Error getOrdinal(uint16_t &Result) const; + Error 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(); + + Error getType(uint8_t &Type) const; + Error 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/COFFImportFile.h b/contrib/libs/llvm12/include/llvm/Object/COFFImportFile.h new file mode 100644 index 00000000000..d5d5a369dff --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/COFFImportFile.h @@ -0,0 +1,124 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- COFFImportFile.h - COFF short import 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 +// +//===----------------------------------------------------------------------===// +// +// COFF short import file is a special kind of file which contains +// only symbol names for DLL-exported symbols. This class implements +// exporting of Symbols to create libraries and a SymbolicFile +// interface for the file type. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_COFF_IMPORT_FILE_H +#define LLVM_OBJECT_COFF_IMPORT_FILE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace object { + +class COFFImportFile : public SymbolicFile { +public: + COFFImportFile(MemoryBufferRef Source) + : SymbolicFile(ID_COFFImportFile, Source) {} + + static bool classof(Binary const *V) { return V->isCOFFImportFile(); } + + void moveSymbolNext(DataRefImpl &Symb) const override { ++Symb.p; } + + Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override { + if (Symb.p == 0) + OS << "__imp_"; + OS << StringRef(Data.getBufferStart() + sizeof(coff_import_header)); + return Error::success(); + } + + Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override { + return SymbolRef::SF_Global; + } + + basic_symbol_iterator symbol_begin() const override { + return BasicSymbolRef(DataRefImpl(), this); + } + + basic_symbol_iterator symbol_end() const override { + DataRefImpl Symb; + Symb.p = isData() ? 1 : 2; + return BasicSymbolRef(Symb, this); + } + + const coff_import_header *getCOFFImportHeader() const { + return reinterpret_cast<const object::coff_import_header *>( + Data.getBufferStart()); + } + +private: + bool isData() const { + return getCOFFImportHeader()->getType() == COFF::IMPORT_DATA; + } +}; + +struct COFFShortExport { + /// The name of the export as specified in the .def file or on the command + /// line, i.e. "foo" in "/EXPORT:foo", and "bar" in "/EXPORT:foo=bar". This + /// may lack mangling, such as underscore prefixing and stdcall suffixing. + std::string Name; + + /// The external, exported name. Only non-empty when export renaming is in + /// effect, i.e. "foo" in "/EXPORT:foo=bar". + std::string ExtName; + + /// The real, mangled symbol name from the object file. Given + /// "/export:foo=bar", this could be "_bar@8" if bar is stdcall. + std::string SymbolName; + + /// Creates a weak alias. This is the name of the weak aliasee. In a .def + /// file, this is "baz" in "EXPORTS\nfoo = bar == baz". + std::string AliasTarget; + + uint16_t Ordinal = 0; + bool Noname = false; + bool Data = false; + bool Private = false; + bool Constant = false; + + friend bool operator==(const COFFShortExport &L, const COFFShortExport &R) { + return L.Name == R.Name && L.ExtName == R.ExtName && + L.Ordinal == R.Ordinal && L.Noname == R.Noname && + L.Data == R.Data && L.Private == R.Private; + } + + friend bool operator!=(const COFFShortExport &L, const COFFShortExport &R) { + return !(L == R); + } +}; + +Error writeImportLibrary(StringRef ImportName, StringRef Path, + ArrayRef<COFFShortExport> Exports, + COFF::MachineTypes Machine, bool MinGW); + +} // namespace object +} // namespace llvm + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/COFFModuleDefinition.h b/contrib/libs/llvm12/include/llvm/Object/COFFModuleDefinition.h new file mode 100644 index 00000000000..3661c193331 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/COFFModuleDefinition.h @@ -0,0 +1,63 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===--- COFFModuleDefinition.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 +// +//===----------------------------------------------------------------------===// +// +// Windows-specific. +// A parser for the module-definition file (.def file). +// Parsed results are directly written to Config global variable. +// +// The format of module-definition files are described in this document: +// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_COFF_MODULE_DEFINITION_H +#define LLVM_OBJECT_COFF_MODULE_DEFINITION_H + +#include "llvm/Object/COFF.h" +#include "llvm/Object/COFFImportFile.h" + +namespace llvm { +namespace object { + +struct COFFModuleDefinition { + std::vector<COFFShortExport> Exports; + std::string OutputFile; + std::string ImportName; + uint64_t ImageBase = 0; + uint64_t StackReserve = 0; + uint64_t StackCommit = 0; + uint64_t HeapReserve = 0; + uint64_t HeapCommit = 0; + uint32_t MajorImageVersion = 0; + uint32_t MinorImageVersion = 0; + uint32_t MajorOSVersion = 0; + uint32_t MinorOSVersion = 0; +}; + +// mingw and wine def files do not mangle _ for x86 which +// is a consequence of legacy binutils' dlltool functionality. +// This MingwDef flag should be removed once mingw stops this pratice. +Expected<COFFModuleDefinition> +parseCOFFModuleDefinition(MemoryBufferRef MB, COFF::MachineTypes Machine, + bool MingwDef = false); + +} // End namespace object. +} // End namespace llvm. + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/CVDebugRecord.h b/contrib/libs/llvm12/include/llvm/Object/CVDebugRecord.h new file mode 100644 index 00000000000..17685635bfd --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/CVDebugRecord.h @@ -0,0 +1,65 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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 + + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/Decompressor.h b/contrib/libs/llvm12/include/llvm/Object/Decompressor.h new file mode 100644 index 00000000000..92409641e48 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/Decompressor.h @@ -0,0 +1,77 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/ELF.h b/contrib/libs/llvm12/include/llvm/Object/ELF.h new file mode 100644 index 00000000000..20e25a9ee28 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/ELF.h @@ -0,0 +1,1211 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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 { + +struct VerdAux { + unsigned Offset; + std::string Name; +}; + +struct VerDef { + unsigned Offset; + unsigned Version; + unsigned Flags; + unsigned Ndx; + unsigned Cnt; + unsigned Hash; + std::string Name; + std::vector<VerdAux> AuxV; +}; + +struct VernAux { + unsigned Hash; + unsigned Flags; + unsigned Other; + unsigned Offset; + std::string Name; +}; + +struct VerNeed { + unsigned Version; + unsigned Cnt; + unsigned Offset; + std::string File; + std::vector<VernAux> AuxV; +}; + +struct VersionEntry { + std::string Name; + bool IsVerDef; +}; + +StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type); +uint32_t getELFRelativeRelocationType(uint32_t Machine); +StringRef getELFSectionTypeName(uint32_t Machine, uint32_t Type); + +// 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); +} + +enum PPCInstrMasks : uint64_t { + PADDI_R12_NO_DISP = 0x0610000039800000, + PLD_R12_NO_DISP = 0x04100000E5800000, + MTCTR_R12 = 0x7D8903A6, + BCTR = 0x4E800420, +}; + +template <class ELFT> class ELFFile; + +template <class T> struct DataRegion { + // This constructor is used when we know the start and the size of a data + // region. We assume that Arr does not go past the end of the file. + DataRegion(ArrayRef<T> Arr) : First(Arr.data()), Size(Arr.size()) {} + + // Sometimes we only know the start of a data region. We still don't want to + // read past the end of the file, so we provide the end of a buffer. + DataRegion(const T *Data, const uint8_t *BufferEnd) + : First(Data), BufEnd(BufferEnd) {} + + Expected<T> operator[](uint64_t N) { + assert(Size || BufEnd); + if (Size) { + if (N >= *Size) + return createError( + "the index is greater than or equal to the number of entries (" + + Twine(*Size) + ")"); + } else { + const uint8_t *EntryStart = (const uint8_t *)First + N * sizeof(T); + if (EntryStart + sizeof(T) > BufEnd) + return createError("can't read past the end of the file"); + } + return *(First + N); + } + + const T *First; + Optional<uint64_t> Size = None; + const uint8_t *BufEnd = nullptr; +}; + +template <class ELFT> +std::string getSecIndexForError(const ELFFile<ELFT> &Obj, + const typename ELFT::Shdr &Sec) { + auto TableOrErr = Obj.sections(); + 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]"; +} + +template <class ELFT> +static std::string describe(const ELFFile<ELFT> &Obj, + const typename ELFT::Shdr &Sec) { + unsigned SecNdx = &Sec - &cantFail(Obj.sections()).front(); + return (object::getELFSectionTypeName(Obj.getHeader().e_machine, + Sec.sh_type) + + " section with index " + Twine(SecNdx)) + .str(); +} + +template <class ELFT> +std::string getPhdrIndexForError(const ELFFile<ELFT> &Obj, + const typename ELFT::Phdr &Phdr) { + auto Headers = Obj.program_headers(); + if (Headers) + return ("[index " + Twine(&Phdr - &Headers->front()) + "]").str(); + // See comment in the getSecIndexForError() above. + llvm::consumeError(Headers.takeError()); + return "[unknown index]"; +} + +static inline Error defaultWarningHandler(const Twine &Msg) { + return createError(Msg); +} + +template <class ELFT> +class ELFFile { +public: + LLVM_ELF_IMPORT_TYPES_ELFT(ELFT) + + // This is a callback that can be passed to a number of functions. + // It can be used to ignore non-critical errors (warnings), which is + // useful for dumpers, like llvm-readobj. + // It accepts a warning message string and returns a success + // when the warning should be ignored or an error otherwise. + using WarningHandler = llvm::function_ref<Error(const Twine &Msg)>; + + const uint8_t *base() const { return Buf.bytes_begin(); } + const uint8_t *end() const { return base() + getBufSize(); } + + size_t getBufSize() const { return Buf.size(); } + +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<std::vector<VerDef>> + getVersionDefinitions(const Elf_Shdr &Sec) const; + Expected<std::vector<VerNeed>> getVersionDependencies( + const Elf_Shdr &Sec, + WarningHandler WarnHandler = &defaultWarningHandler) const; + Expected<StringRef> + getSymbolVersionByIndex(uint32_t SymbolVersionIndex, bool &IsDefault, + SmallVector<Optional<VersionEntry>, 0> &VersionMap, + Optional<bool> IsSymHidden) const; + + Expected<StringRef> + getStringTable(const Elf_Shdr &Section, + WarningHandler WarnHandler = &defaultWarningHandler) const; + Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section) const; + Expected<StringRef> getStringTableForSymtab(const Elf_Shdr &Section, + Elf_Shdr_Range Sections) const; + Expected<StringRef> getLinkAsStrtab(const typename ELFT::Shdr &Sec) const; + + Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section) const; + Expected<ArrayRef<Elf_Word>> getSHNDXTable(const Elf_Shdr &Section, + Elf_Shdr_Range Sections) const; + + Expected<uint64_t> getDynSymtabSize() const; + + 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; + + Expected<SmallVector<Optional<VersionEntry>, 0>> + loadVersionMap(const Elf_Shdr *VerNeedSec, const Elf_Shdr *VerDefSec) const; + + static Expected<ELFFile> create(StringRef Object); + + bool isLE() const { + return getHeader().getDataEncoding() == ELF::ELFDATA2LSB; + } + + 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, + WarningHandler WarnHandler = &defaultWarningHandler) const; + + Expected<Elf_Sym_Range> symbols(const Elf_Shdr *Sec) const { + if (!Sec) + return makeArrayRef<Elf_Sym>(nullptr, nullptr); + return getSectionContentsAsArray<Elf_Sym>(*Sec); + } + + 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); + } + + std::vector<Elf_Rel> 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)); + + uint64_t HeadersSize = + (uint64_t)getHeader().e_phnum * getHeader().e_phentsize; + uint64_t PhOff = getHeader().e_phoff; + if (PhOff + HeadersSize < PhOff || PhOff + HeadersSize > getBufSize()) + return createError("program headers are longer than binary of size " + + Twine(getBufSize()) + ": e_phoff = 0x" + + Twine::utohexstr(getHeader().e_phoff) + + ", e_phnum = " + Twine(getHeader().e_phnum) + + ", e_phentsize = " + Twine(getHeader().e_phentsize)); + + auto *Begin = reinterpret_cast<const Elf_Phdr *>(base() + 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("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("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, + DataRegion<Elf_Word> ShndxTable) const; + Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym, + const Elf_Shdr *SymTab, + DataRegion<Elf_Word> ShndxTable) const; + Expected<const Elf_Shdr *> getSection(const Elf_Sym &Sym, + Elf_Sym_Range Symtab, + DataRegion<Elf_Word> ShndxTable) const; + Expected<const Elf_Shdr *> getSection(uint32_t Index) const; + + Expected<const Elf_Sym *> getSymbol(const Elf_Shdr *Sec, + uint32_t Index) const; + + Expected<StringRef> + getSectionName(const Elf_Shdr &Section, + WarningHandler WarnHandler = &defaultWarningHandler) const; + Expected<StringRef> getSectionName(const Elf_Shdr &Section, + StringRef DotShstrtab) const; + template <typename T> + Expected<ArrayRef<T>> getSectionContentsAsArray(const Elf_Shdr &Sec) const; + Expected<ArrayRef<uint8_t>> getSectionContents(const Elf_Shdr &Sec) const; + Expected<ArrayRef<uint8_t>> getSegmentContents(const Elf_Phdr &Phdr) 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, unsigned SymIndex, + DataRegion<typename ELFT::Word> ShndxTable) { + assert(Sym.st_shndx == ELF::SHN_XINDEX); + if (!ShndxTable.First) + return createError( + "found an extended symbol index (" + Twine(SymIndex) + + "), but unable to locate the extended symbol index table"); + + Expected<typename ELFT::Word> TableOrErr = ShndxTable[SymIndex]; + if (!TableOrErr) + return createError("unable to read an extended symbol table at index " + + Twine(SymIndex) + ": " + + toString(TableOrErr.takeError())); + return *TableOrErr; +} + +template <class ELFT> +Expected<uint32_t> +ELFFile<ELFT>::getSectionIndex(const Elf_Sym &Sym, Elf_Sym_Range Syms, + DataRegion<Elf_Word> ShndxTable) const { + uint32_t Index = Sym.st_shndx; + if (Index == ELF::SHN_XINDEX) { + Expected<uint32_t> ErrorOrIndex = + getExtendedSymbolTableIndex<ELFT>(Sym, &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, + DataRegion<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, + DataRegion<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 invalid sh_entsize: expected " + Twine(sizeof(T)) + + ", but got " + Twine(Sec.sh_entsize)); + + uintX_t Offset = Sec.sh_offset; + uintX_t Size = Sec.sh_size; + + 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) + return createError("section " + getSecIndexForError(*this, Sec) + + " has a sh_offset (0x" + Twine::utohexstr(Offset) + + ") + sh_size (0x" + Twine::utohexstr(Size) + + ") that cannot be represented"); + if (Offset + Size > Buf.size()) + return createError("section " + getSecIndexForError(*this, Sec) + + " has a sh_offset (0x" + Twine::utohexstr(Offset) + + ") + sh_size (0x" + Twine::utohexstr(Size) + + ") that is greater than the file size (0x" + + Twine::utohexstr(Buf.size()) + ")"); + + if (Offset % alignof(T)) + // TODO: this error is untested. + 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>::getSegmentContents(const Elf_Phdr &Phdr) const { + uintX_t Offset = Phdr.p_offset; + uintX_t Size = Phdr.p_filesz; + + if (std::numeric_limits<uintX_t>::max() - Offset < Size) + return createError("program header " + getPhdrIndexForError(*this, Phdr) + + " has a p_offset (0x" + Twine::utohexstr(Offset) + + ") + p_filesz (0x" + Twine::utohexstr(Size) + + ") that cannot be represented"); + if (Offset + Size > Buf.size()) + return createError("program header " + getPhdrIndexForError(*this, Phdr) + + " has a p_offset (0x" + Twine::utohexstr(Offset) + + ") + p_filesz (0x" + Twine::utohexstr(Size) + + ") that is greater than the file size (0x" + + Twine::utohexstr(Buf.size()) + ")"); + return makeArrayRef(base() + Offset, Size); +} + +template <class ELFT> +Expected<ArrayRef<uint8_t>> +ELFFile<ELFT>::getSectionContents(const Elf_Shdr &Sec) const { + return getSectionContentsAsArray<uint8_t>(Sec); +} + +template <class ELFT> +StringRef ELFFile<ELFT>::getRelocationTypeName(uint32_t Type) const { + return getELFRelocationTypeName(getHeader().e_machine, Type); +} + +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<SmallVector<Optional<VersionEntry>, 0>> +ELFFile<ELFT>::loadVersionMap(const Elf_Shdr *VerNeedSec, + const Elf_Shdr *VerDefSec) const { + SmallVector<Optional<VersionEntry>, 0> VersionMap; + + // The first two version indexes are reserved. + // Index 0 is VER_NDX_LOCAL, index 1 is VER_NDX_GLOBAL. + VersionMap.push_back(VersionEntry()); + VersionMap.push_back(VersionEntry()); + + auto InsertEntry = [&](unsigned N, StringRef Version, bool IsVerdef) { + if (N >= VersionMap.size()) + VersionMap.resize(N + 1); + VersionMap[N] = {std::string(Version), IsVerdef}; + }; + + if (VerDefSec) { + Expected<std::vector<VerDef>> Defs = getVersionDefinitions(*VerDefSec); + if (!Defs) + return Defs.takeError(); + for (const VerDef &Def : *Defs) + InsertEntry(Def.Ndx & ELF::VERSYM_VERSION, Def.Name, true); + } + + if (VerNeedSec) { + Expected<std::vector<VerNeed>> Deps = getVersionDependencies(*VerNeedSec); + if (!Deps) + return Deps.takeError(); + for (const VerNeed &Dep : *Deps) + for (const VernAux &Aux : Dep.AuxV) + InsertEntry(Aux.Other & ELF::VERSYM_VERSION, Aux.Name, false); + } + + return VersionMap; +} + +template <class ELFT> +Expected<const typename ELFT::Sym *> +ELFFile<ELFT>::getRelocationSymbol(const Elf_Rel &Rel, + 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) { + // If the section name string table section index is greater than + // or equal to SHN_LORESERVE, then the actual index of the section name + // string table section is contained in the sh_link field of the section + // header at index 0. + if (Sections.empty()) + return createError( + "e_shstrndx == SHN_XINDEX, but the section header table is empty"); + + Index = Sections[0].sh_link; + } + + if (!Index) // no section string table. + return ""; + if (Index >= Sections.size()) + return createError("section header string table index " + Twine(Index) + + " does not exist"); + return getStringTable(Sections[Index], WarnHandler); +} + +/// This function finds the number of dynamic symbols using a GNU hash table. +/// +/// @param Table The GNU hash table for .dynsym. +template <class ELFT> +static Expected<uint64_t> +getDynSymtabSizeFromGnuHash(const typename ELFT::GnuHash &Table, + const void *BufEnd) { + using Elf_Word = typename ELFT::Word; + if (Table.nbuckets == 0) + return Table.symndx + 1; + uint64_t LastSymIdx = 0; + // Find the index of the first symbol in the last chain. + for (Elf_Word Val : Table.buckets()) + LastSymIdx = std::max(LastSymIdx, (uint64_t)Val); + const Elf_Word *It = + reinterpret_cast<const Elf_Word *>(Table.values(LastSymIdx).end()); + // Locate the end of the chain to find the last symbol index. + while (It < BufEnd && (*It & 1) == 0) { + ++LastSymIdx; + ++It; + } + if (It >= BufEnd) { + return createStringError( + object_error::parse_failed, + "no terminator found for GNU hash section before buffer end"); + } + return LastSymIdx + 1; +} + +/// This function determines the number of dynamic symbols. It reads section +/// headers first. If section headers are not available, the number of +/// symbols will be inferred by parsing dynamic hash tables. +template <class ELFT> +Expected<uint64_t> ELFFile<ELFT>::getDynSymtabSize() const { + // Read .dynsym section header first if available. + Expected<Elf_Shdr_Range> SectionsOrError = sections(); + if (!SectionsOrError) + return SectionsOrError.takeError(); + for (const Elf_Shdr &Sec : *SectionsOrError) { + if (Sec.sh_type == ELF::SHT_DYNSYM) { + if (Sec.sh_size % Sec.sh_entsize != 0) { + return createStringError(object_error::parse_failed, + "SHT_DYNSYM section has sh_size (" + + Twine(Sec.sh_size) + ") % sh_entsize (" + + Twine(Sec.sh_entsize) + ") that is not 0"); + } + return Sec.sh_size / Sec.sh_entsize; + } + } + + if (!SectionsOrError->empty()) { + // Section headers are available but .dynsym header is not found. + // Return 0 as .dynsym does not exist. + return 0; + } + + // Section headers do not exist. Falling back to infer + // upper bound of .dynsym from .gnu.hash and .hash. + Expected<Elf_Dyn_Range> DynTable = dynamicEntries(); + if (!DynTable) + return DynTable.takeError(); + llvm::Optional<uint64_t> ElfHash; + llvm::Optional<uint64_t> ElfGnuHash; + for (const Elf_Dyn &Entry : *DynTable) { + switch (Entry.d_tag) { + case ELF::DT_HASH: + ElfHash = Entry.d_un.d_ptr; + break; + case ELF::DT_GNU_HASH: + ElfGnuHash = Entry.d_un.d_ptr; + break; + } + } + if (ElfGnuHash) { + Expected<const uint8_t *> TablePtr = toMappedAddr(*ElfGnuHash); + if (!TablePtr) + return TablePtr.takeError(); + const Elf_GnuHash *Table = + reinterpret_cast<const Elf_GnuHash *>(TablePtr.get()); + return getDynSymtabSizeFromGnuHash<ELFT>(*Table, this->Buf.bytes_end()); + } + + // Search SYSV hash table to try to find the upper bound of dynsym. + if (ElfHash) { + Expected<const uint8_t *> TablePtr = toMappedAddr(*ElfHash); + if (!TablePtr) + return TablePtr.takeError(); + const Elf_Hash *Table = reinterpret_cast<const Elf_Hash *>(TablePtr.get()); + return Table->nchain; + } + return 0; +} + +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 { + Expected<ArrayRef<T>> EntriesOrErr = getSectionContentsAsArray<T>(Section); + if (!EntriesOrErr) + return EntriesOrErr.takeError(); + + ArrayRef<T> Arr = *EntriesOrErr; + if (Entry >= Arr.size()) + return createError( + "can't read an entry at 0x" + + Twine::utohexstr(Entry * static_cast<uint64_t>(sizeof(T))) + + ": it goes past the end of the section (0x" + + Twine::utohexstr(Section.sh_size) + ")"); + return &Arr[Entry]; +} + +template <typename ELFT> +Expected<StringRef> ELFFile<ELFT>::getSymbolVersionByIndex( + uint32_t SymbolVersionIndex, bool &IsDefault, + SmallVector<Optional<VersionEntry>, 0> &VersionMap, + Optional<bool> IsSymHidden) const { + size_t VersionIndex = SymbolVersionIndex & llvm::ELF::VERSYM_VERSION; + + // Special markers for unversioned symbols. + if (VersionIndex == llvm::ELF::VER_NDX_LOCAL || + VersionIndex == llvm::ELF::VER_NDX_GLOBAL) { + IsDefault = false; + return ""; + } + + // Lookup this symbol in the version table. + if (VersionIndex >= VersionMap.size() || !VersionMap[VersionIndex]) + return createError("SHT_GNU_versym section refers to a version index " + + Twine(VersionIndex) + " which is missing"); + + const VersionEntry &Entry = *VersionMap[VersionIndex]; + // A default version (@@) is only available for defined symbols. + if (!Entry.IsVerDef || IsSymHidden.getValueOr(false)) + IsDefault = false; + else + IsDefault = !(SymbolVersionIndex & llvm::ELF::VERSYM_HIDDEN); + return Entry.Name.c_str(); +} + +template <class ELFT> +Expected<std::vector<VerDef>> +ELFFile<ELFT>::getVersionDefinitions(const Elf_Shdr &Sec) const { + Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec); + if (!StrTabOrErr) + return StrTabOrErr.takeError(); + + Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return createError("cannot read content of " + describe(*this, Sec) + ": " + + toString(ContentsOrErr.takeError())); + + const uint8_t *Start = ContentsOrErr->data(); + const uint8_t *End = Start + ContentsOrErr->size(); + + auto ExtractNextAux = [&](const uint8_t *&VerdauxBuf, + unsigned VerDefNdx) -> Expected<VerdAux> { + if (VerdauxBuf + sizeof(Elf_Verdaux) > End) + return createError("invalid " + describe(*this, Sec) + + ": version definition " + Twine(VerDefNdx) + + " refers to an auxiliary entry that goes past the end " + "of the section"); + + auto *Verdaux = reinterpret_cast<const Elf_Verdaux *>(VerdauxBuf); + VerdauxBuf += Verdaux->vda_next; + + VerdAux Aux; + Aux.Offset = VerdauxBuf - Start; + if (Verdaux->vda_name <= StrTabOrErr->size()) + Aux.Name = std::string(StrTabOrErr->drop_front(Verdaux->vda_name)); + else + Aux.Name = ("<invalid vda_name: " + Twine(Verdaux->vda_name) + ">").str(); + return Aux; + }; + + std::vector<VerDef> Ret; + const uint8_t *VerdefBuf = Start; + for (unsigned I = 1; I <= /*VerDefsNum=*/Sec.sh_info; ++I) { + if (VerdefBuf + sizeof(Elf_Verdef) > End) + return createError("invalid " + describe(*this, Sec) + + ": version definition " + Twine(I) + + " goes past the end of the section"); + + if (reinterpret_cast<uintptr_t>(VerdefBuf) % sizeof(uint32_t) != 0) + return createError( + "invalid " + describe(*this, Sec) + + ": found a misaligned version definition entry at offset 0x" + + Twine::utohexstr(VerdefBuf - Start)); + + unsigned Version = *reinterpret_cast<const Elf_Half *>(VerdefBuf); + if (Version != 1) + return createError("unable to dump " + describe(*this, Sec) + + ": version " + Twine(Version) + + " is not yet supported"); + + const Elf_Verdef *D = reinterpret_cast<const Elf_Verdef *>(VerdefBuf); + VerDef &VD = *Ret.emplace(Ret.end()); + VD.Offset = VerdefBuf - Start; + VD.Version = D->vd_version; + VD.Flags = D->vd_flags; + VD.Ndx = D->vd_ndx; + VD.Cnt = D->vd_cnt; + VD.Hash = D->vd_hash; + + const uint8_t *VerdauxBuf = VerdefBuf + D->vd_aux; + for (unsigned J = 0; J < D->vd_cnt; ++J) { + if (reinterpret_cast<uintptr_t>(VerdauxBuf) % sizeof(uint32_t) != 0) + return createError("invalid " + describe(*this, Sec) + + ": found a misaligned auxiliary entry at offset 0x" + + Twine::utohexstr(VerdauxBuf - Start)); + + Expected<VerdAux> AuxOrErr = ExtractNextAux(VerdauxBuf, I); + if (!AuxOrErr) + return AuxOrErr.takeError(); + + if (J == 0) + VD.Name = AuxOrErr->Name; + else + VD.AuxV.push_back(*AuxOrErr); + } + + VerdefBuf += D->vd_next; + } + + return Ret; +} + +template <class ELFT> +Expected<std::vector<VerNeed>> +ELFFile<ELFT>::getVersionDependencies(const Elf_Shdr &Sec, + WarningHandler WarnHandler) const { + StringRef StrTab; + Expected<StringRef> StrTabOrErr = getLinkAsStrtab(Sec); + if (!StrTabOrErr) { + if (Error E = WarnHandler(toString(StrTabOrErr.takeError()))) + return std::move(E); + } else { + StrTab = *StrTabOrErr; + } + + Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return createError("cannot read content of " + describe(*this, Sec) + ": " + + toString(ContentsOrErr.takeError())); + + const uint8_t *Start = ContentsOrErr->data(); + const uint8_t *End = Start + ContentsOrErr->size(); + const uint8_t *VerneedBuf = Start; + + std::vector<VerNeed> Ret; + for (unsigned I = 1; I <= /*VerneedNum=*/Sec.sh_info; ++I) { + if (VerneedBuf + sizeof(Elf_Verdef) > End) + return createError("invalid " + describe(*this, Sec) + + ": version dependency " + Twine(I) + + " goes past the end of the section"); + + if (reinterpret_cast<uintptr_t>(VerneedBuf) % sizeof(uint32_t) != 0) + return createError( + "invalid " + describe(*this, Sec) + + ": found a misaligned version dependency entry at offset 0x" + + Twine::utohexstr(VerneedBuf - Start)); + + unsigned Version = *reinterpret_cast<const Elf_Half *>(VerneedBuf); + if (Version != 1) + return createError("unable to dump " + describe(*this, Sec) + + ": version " + Twine(Version) + + " is not yet supported"); + + const Elf_Verneed *Verneed = + reinterpret_cast<const Elf_Verneed *>(VerneedBuf); + + VerNeed &VN = *Ret.emplace(Ret.end()); + VN.Version = Verneed->vn_version; + VN.Cnt = Verneed->vn_cnt; + VN.Offset = VerneedBuf - Start; + + if (Verneed->vn_file < StrTab.size()) + VN.File = std::string(StrTab.drop_front(Verneed->vn_file)); + else + VN.File = ("<corrupt vn_file: " + Twine(Verneed->vn_file) + ">").str(); + + const uint8_t *VernauxBuf = VerneedBuf + Verneed->vn_aux; + for (unsigned J = 0; J < Verneed->vn_cnt; ++J) { + if (reinterpret_cast<uintptr_t>(VernauxBuf) % sizeof(uint32_t) != 0) + return createError("invalid " + describe(*this, Sec) + + ": found a misaligned auxiliary entry at offset 0x" + + Twine::utohexstr(VernauxBuf - Start)); + + if (VernauxBuf + sizeof(Elf_Vernaux) > End) + return createError( + "invalid " + describe(*this, Sec) + ": version dependency " + + Twine(I) + + " refers to an auxiliary entry that goes past the end " + "of the section"); + + const Elf_Vernaux *Vernaux = + reinterpret_cast<const Elf_Vernaux *>(VernauxBuf); + + VernAux &Aux = *VN.AuxV.emplace(VN.AuxV.end()); + Aux.Hash = Vernaux->vna_hash; + Aux.Flags = Vernaux->vna_flags; + Aux.Other = Vernaux->vna_other; + Aux.Offset = VernauxBuf - Start; + if (StrTab.size() <= Vernaux->vna_name) + Aux.Name = "<corrupt>"; + else + Aux.Name = std::string(StrTab.drop_front(Vernaux->vna_name)); + + VernauxBuf += Vernaux->vna_next; + } + VerneedBuf += Verneed->vn_next; + } + return Ret; +} + +template <class ELFT> +Expected<const typename ELFT::Shdr *> +ELFFile<ELFT>::getSection(uint32_t Index) const { + auto TableOrErr = sections(); + 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) + return createError( + "invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM"); + Expected<const Elf_Shdr *> SectionOrErr = + object::getSection<ELFT>(Sections, Sec.sh_link); + if (!SectionOrErr) + return SectionOrErr.takeError(); + return getStringTable(**SectionOrErr); +} + +template <class ELFT> +Expected<StringRef> +ELFFile<ELFT>::getLinkAsStrtab(const typename ELFT::Shdr &Sec) const { + Expected<const typename ELFT::Shdr *> StrTabSecOrErr = + getSection(Sec.sh_link); + if (!StrTabSecOrErr) + return createError("invalid section linked to " + describe(*this, Sec) + + ": " + toString(StrTabSecOrErr.takeError())); + + Expected<StringRef> StrTabOrErr = getStringTable(**StrTabSecOrErr); + if (!StrTabOrErr) + return createError("invalid string table linked to " + + describe(*this, Sec) + ": " + + toString(StrTabOrErr.takeError())); + return *StrTabOrErr; +} + +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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/ELFObjectFile.h b/contrib/libs/llvm12/include/llvm/Object/ELFObjectFile.h new file mode 100644 index 00000000000..28c6ec9bfc8 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/ELFObjectFile.h @@ -0,0 +1,1316 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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/Casting.h" +#include "llvm/Support/ELFAttributes.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; + + SubtargetFeatures getMIPSFeatures() const; + SubtargetFeatures getARMFeatures() const; + SubtargetFeatures getRISCVFeatures() const; + + StringRef getAMDGPUCPUName() const; + +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(ELFAttributeParser &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; + + Optional<StringRef> tryGetCPUName() const override; + + void setARMSubArch(Triple &TheTriple) const override; + + virtual uint16_t getEType() const = 0; + + virtual uint16_t getEMachine() const = 0; + + std::vector<std::pair<Optional<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) + + SectionRef toSectionRef(const Elf_Shdr *Sec) const { + return SectionRef(toDRI(Sec), this); + } + + ELFSymbolRef toSymbolRef(const Elf_Shdr *SymTable, unsigned SymbolNum) const { + return ELFSymbolRef({toDRI(SymTable, SymbolNum), this}); + } + + bool IsContentValid() const { return ContentValid; } + +private: + ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF, + const Elf_Shdr *DotDynSymSec, const Elf_Shdr *DotSymtabSec, + const Elf_Shdr *DotSymtabShndxSec); + + bool ContentValid = false; + +protected: + ELFFile<ELFT> EF; + + const Elf_Shdr *DotDynSymSec = nullptr; // Dynamic symbol table section. + const Elf_Shdr *DotSymtabSec = nullptr; // Symbol table section. + const Elf_Shdr *DotSymtabShndxSec = nullptr; // SHT_SYMTAB_SHNDX section. + + Error initContent() override; + + 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; + Expected<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; + bool isDebugSection(StringRef SectionName) 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; + + 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(ELFAttributeParser &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 || + Sec.sh_type == ELF::SHT_RISCV_ATTRIBUTES) { + auto ErrorOrContents = EF.getSectionContents(Sec); + if (!ErrorOrContents) + return ErrorOrContents.takeError(); + + auto Contents = ErrorOrContents.get(); + if (Contents[0] != ELFAttrs::Format_Version || Contents.size() == 1) + return Error::success(); + + if (Error E = Attributes.parse(Contents, ELFT::TargetEndianness)) + return E; + 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, + bool InitContent = true); + + const Elf_Rel *getRel(DataRefImpl Rel) const; + const Elf_Rela *getRela(DataRefImpl Rela) const; + + Expected<const Elf_Sym *> getSymbol(DataRefImpl Sym) const { + return EF.template getEntry<Elf_Sym>(Sym.d.a, Sym.d.b); + } + + /// 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; + } + + 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> Error ELFObjectFile<ELFT>::initContent() { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + + 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: { + if (!DotSymtabShndxSec) + DotSymtabShndxSec = &Sec; + break; + } + } + } + + ContentValid = true; + return Error::success(); +} + +template <class ELFT> +Expected<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Sym); + if (!SymOrErr) + return SymOrErr.takeError(); + 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 = (*SymOrErr)->getName(*SymStrTabOrErr); + if (Name && !Name->empty()) + return Name; + + // If the symbol name is empty use the section name. + if ((*SymOrErr)->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 { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb); + if (!SymOrErr) + report_fatal_error(SymOrErr.takeError()); + + uint64_t Ret = (*SymOrErr)->st_value; + if ((*SymOrErr)->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) && + (*SymOrErr)->getType() == ELF::STT_FUNC) + Ret &= ~1; + + return Ret; +} + +template <class ELFT> +Expected<uint64_t> +ELFObjectFile<ELFT>::getSymbolAddress(DataRefImpl Symb) const { + Expected<uint64_t> SymbolValueOrErr = getSymbolValue(Symb); + if (!SymbolValueOrErr) + // TODO: Test this error. + return SymbolValueOrErr.takeError(); + + uint64_t Result = *SymbolValueOrErr; + Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb); + if (!SymOrErr) + return SymOrErr.takeError(); + + switch ((*SymOrErr)->st_shndx) { + case ELF::SHN_COMMON: + case ELF::SHN_UNDEF: + case ELF::SHN_ABS: + return Result; + } + + auto SymTabOrErr = EF.getSection(Symb.d.a); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + + if (EF.getHeader().e_type == ELF::ET_REL) { + ArrayRef<Elf_Word> ShndxTable; + if (DotSymtabShndxSec) { + // TODO: Test this error. + if (Expected<ArrayRef<Elf_Word>> ShndxTableOrErr = + EF.getSHNDXTable(*DotSymtabShndxSec)) + ShndxTable = *ShndxTableOrErr; + else + return ShndxTableOrErr.takeError(); + } + + Expected<const Elf_Shdr *> SectionOrErr = + EF.getSection(**SymOrErr, *SymTabOrErr, 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 { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb); + if (!SymOrErr) + report_fatal_error(SymOrErr.takeError()); + if ((*SymOrErr)->st_shndx == ELF::SHN_COMMON) + return (*SymOrErr)->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 { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Sym); + if (!SymOrErr) + report_fatal_error(SymOrErr.takeError()); + return (*SymOrErr)->st_size; +} + +template <class ELFT> +uint64_t ELFObjectFile<ELFT>::getCommonSymbolSizeImpl(DataRefImpl Symb) const { + return getSymbolSize(Symb); +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolBinding(DataRefImpl Symb) const { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb); + if (!SymOrErr) + report_fatal_error(SymOrErr.takeError()); + return (*SymOrErr)->getBinding(); +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolOther(DataRefImpl Symb) const { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb); + if (!SymOrErr) + report_fatal_error(SymOrErr.takeError()); + return (*SymOrErr)->st_other; +} + +template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolELFType(DataRefImpl Symb) const { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb); + if (!SymOrErr) + report_fatal_error(SymOrErr.takeError()); + return (*SymOrErr)->getType(); +} + +template <class ELFT> +Expected<SymbolRef::Type> +ELFObjectFile<ELFT>::getSymbolType(DataRefImpl Symb) const { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb); + if (!SymOrErr) + return SymOrErr.takeError(); + + switch ((*SymOrErr)->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> +Expected<uint32_t> ELFObjectFile<ELFT>::getSymbolFlags(DataRefImpl Sym) const { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Sym); + if (!SymOrErr) + return SymOrErr.takeError(); + + const Elf_Sym *ESym = *SymOrErr; + 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; + + if (Expected<typename ELFT::SymRange> SymbolsOrErr = + EF.symbols(DotSymtabSec)) { + // Set the SF_FormatSpecific flag for the 0-index null symbol. + if (ESym == SymbolsOrErr->begin()) + Result |= SymbolRef::SF_FormatSpecific; + } else + // TODO: Test this error. + return SymbolsOrErr.takeError(); + + if (Expected<typename ELFT::SymRange> SymbolsOrErr = + EF.symbols(DotDynSymSec)) { + // Set the SF_FormatSpecific flag for the 0-index null symbol. + if (ESym == SymbolsOrErr->begin()) + Result |= SymbolRef::SF_FormatSpecific; + } else + // TODO: Test this error. + return SymbolsOrErr.takeError(); + + 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 { + ArrayRef<Elf_Word> ShndxTable; + if (DotSymtabShndxSec) { + // TODO: Test this error. + Expected<ArrayRef<Elf_Word>> ShndxTableOrErr = + EF.getSHNDXTable(*DotSymtabShndxSec); + if (!ShndxTableOrErr) + return ShndxTableOrErr.takeError(); + ShndxTable = *ShndxTableOrErr; + } + + 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 { + Expected<const Elf_Sym *> SymOrErr = getSymbol(Symb); + if (!SymOrErr) + return SymOrErr.takeError(); + + auto SymTabOrErr = EF.getSection(Symb.d.a); + if (!SymTabOrErr) + return SymTabOrErr.takeError(); + return getSymbolSection(*SymOrErr, *SymTabOrErr); +} + +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 (Error E = + checkOffset(getMemoryBufferRef(), + (uintptr_t)base() + EShdr->sh_offset, EShdr->sh_size)) + return std::move(E); + 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> +bool ELFObjectFile<ELFT>::isDebugSection(StringRef SectionName) const { + return SectionName.startswith(".debug") || + SectionName.startswith(".zdebug") || SectionName == ".gdb_index"; +} + +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, bool InitContent) { + auto EFOrErr = ELFFile<ELFT>::create(Object.getBuffer()); + if (Error E = EFOrErr.takeError()) + return std::move(E); + + ELFObjectFile<ELFT> Obj = {Object, std::move(*EFOrErr), nullptr, nullptr, + nullptr}; + if (InitContent) + if (Error E = Obj.initContent()) + return std::move(E); + return std::move(Obj); +} + +template <class ELFT> +ELFObjectFile<ELFT>::ELFObjectFile(MemoryBufferRef Object, ELFFile<ELFT> EF, + const Elf_Shdr *DotDynSymSec, + const Elf_Shdr *DotSymtabSec, + const Elf_Shdr *DotSymtabShndx) + : ELFObjectFileBase( + getELFType(ELFT::TargetEndianness == support::little, ELFT::Is64Bits), + Object), + EF(EF), DotDynSymSec(DotDynSymSec), DotSymtabSec(DotSymtabSec), + DotSymtabShndxSec(DotSymtabShndx) {} + +template <class ELFT> +ELFObjectFile<ELFT>::ELFObjectFile(ELFObjectFile<ELFT> &&Other) + : ELFObjectFile(Other.Data, Other.EF, Other.DotDynSymSec, + Other.DotSymtabSec, Other.DotSymtabShndxSec) {} + +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 { + if (!DotDynSymSec || DotDynSymSec->sh_size < sizeof(Elf_Sym)) + // Ignore errors here where the dynsym is empty or sh_size less than the + // size of one symbol. These should be handled elsewhere. + return symbol_iterator(SymbolRef(toDRI(DotDynSymSec, 0), this)); + // Skip 0-index NULL symbol. + return symbol_iterator(SymbolRef(toDRI(DotDynSymSec, 1), 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-littlearm" : "elf32-bigarm"); + 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 (IsLittleEndian ? "elf32-powerpcle" : "elf32-powerpc"); + case ELF::EM_RISCV: + return "elf32-littleriscv"; + case ELF::EM_CSKY: + return "elf32-csky"; + 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-littleaarch64" : "elf64-bigaarch64"); + case ELF::EM_PPC64: + return (IsLittleEndian ? "elf64-powerpcle" : "elf64-powerpc"); + case ELF::EM_RISCV: + return "elf64-littleriscv"; + 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"; + case ELF::EM_VE: + return "elf64-ve"; + 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 IsLittleEndian ? Triple::ppcle : 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; + + case ELF::EM_VE: + return Triple::ve; + case ELF::EM_CSKY: + return Triple::csky; + 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/ELFTypes.h b/contrib/libs/llvm12/include/llvm/Object/ELFTypes.h new file mode 100644 index 00000000000..320dfaa573e --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/ELFTypes.h @@ -0,0 +1,805 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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 = std::conditional_t<Is64, uint64_t, uint32_t>; + 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; \ + 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_CGProfile = typename ELFT::CGProfile; \ + 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; \ + +#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) + 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 = std::conditional_t<ELFT::Is64Bits, int64_t, int32_t>; + using uintX_t = std::conditional_t<ELFT::Is64Bits, uint64_t, uint32_t>; + intX_t getTag() const { return d_tag; } + uintX_t getVal() const { return d_un.d_val; } + uintX_t getPtr() const { return d_un.d_ptr; } +}; + +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 { + assert(DynamicSymCount >= symndx); + 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 descriptor as StringRef + StringRef getDescAsStringRef() const { + ArrayRef<uint8_t> Desc = getDesc(); + return StringRef(reinterpret_cast<const char *>(Desc.data()), Desc.size()); + } + + /// 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/Error.h b/contrib/libs/llvm12/include/llvm/Object/Error.h new file mode 100644 index 00000000000..8cfaa1a87cb --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/Error.h @@ -0,0 +1,105 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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/Support/Error.h" +#include <system_error> + +namespace llvm { + +class Twine; + +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> { + void anchor() override; +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(const Twine &Msg); + GenericBinaryError(const 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/IRObjectFile.h b/contrib/libs/llvm12/include/llvm/Object/IRObjectFile.h new file mode 100644 index 00000000000..da4a9d74aaa --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/IRObjectFile.h @@ -0,0 +1,102 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- IRObjectFile.h - LLVM IR 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 IRObjectFile template class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_IROBJECTFILE_H +#define LLVM_OBJECT_IROBJECTFILE_H + +#include "llvm/ADT/PointerUnion.h" +#include "llvm/Object/IRSymtab.h" +#include "llvm/Object/ModuleSymbolTable.h" +#include "llvm/Object/SymbolicFile.h" + +namespace llvm { +class BitcodeModule; +class Mangler; +class Module; +class GlobalValue; +class Triple; + +namespace object { +class ObjectFile; + +class IRObjectFile : public SymbolicFile { + std::vector<std::unique_ptr<Module>> Mods; + ModuleSymbolTable SymTab; + IRObjectFile(MemoryBufferRef Object, + std::vector<std::unique_ptr<Module>> Mods); + +public: + ~IRObjectFile() override; + void moveSymbolNext(DataRefImpl &Symb) const override; + Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override; + Expected<uint32_t> getSymbolFlags(DataRefImpl Symb) const override; + basic_symbol_iterator symbol_begin() const override; + basic_symbol_iterator symbol_end() const override; + + StringRef getTargetTriple() const; + + static bool classof(const Binary *v) { + return v->isIR(); + } + + using module_iterator = + pointee_iterator<std::vector<std::unique_ptr<Module>>::const_iterator, + const Module>; + + module_iterator module_begin() const { return module_iterator(Mods.begin()); } + module_iterator module_end() const { return module_iterator(Mods.end()); } + + iterator_range<module_iterator> modules() const { + return make_range(module_begin(), module_end()); + } + + /// Finds and returns bitcode embedded in the given object file, or an + /// error code if not found. + static Expected<MemoryBufferRef> findBitcodeInObject(const ObjectFile &Obj); + + /// Finds and returns bitcode in the given memory buffer (which may + /// be either a bitcode file or a native object file with embedded bitcode), + /// or an error code if not found. + static Expected<MemoryBufferRef> + findBitcodeInMemBuffer(MemoryBufferRef Object); + + static Expected<std::unique_ptr<IRObjectFile>> create(MemoryBufferRef Object, + LLVMContext &Context); +}; + +/// The contents of a bitcode file and its irsymtab. Any underlying data +/// for the irsymtab are owned by Symtab and Strtab. +struct IRSymtabFile { + std::vector<BitcodeModule> Mods; + SmallVector<char, 0> Symtab, Strtab; + irsymtab::Reader TheReader; +}; + +/// Reads a bitcode file, creating its irsymtab if necessary. +Expected<IRSymtabFile> readIRSymtab(MemoryBufferRef MBRef); + +} + +} + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/IRSymtab.h b/contrib/libs/llvm12/include/llvm/Object/IRSymtab.h new file mode 100644 index 00000000000..59a6817bd5d --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/IRSymtab.h @@ -0,0 +1,385 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- IRSymtab.h - data definitions for IR symbol tables -------*- 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 contains data definitions and a reader and builder for a symbol +// table for LLVM IR. Its purpose is to allow linkers and other consumers of +// bitcode files to efficiently read the symbol table for symbol resolution +// purposes without needing to construct a module in memory. +// +// As with most object files the symbol table has two parts: the symbol table +// itself and a string table which is referenced by the symbol table. +// +// A symbol table corresponds to a single bitcode file, which may consist of +// multiple modules, so symbol tables may likewise contain symbols for multiple +// modules. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_IRSYMTAB_H +#define LLVM_OBJECT_IRSYMTAB_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" +#include <cassert> +#include <cstdint> +#include <vector> + +namespace llvm { + +struct BitcodeFileContents; +class StringTableBuilder; + +namespace irsymtab { + +namespace storage { + +// The data structures in this namespace define the low-level serialization +// format. Clients that just want to read a symbol table should use the +// irsymtab::Reader class. + +using Word = support::ulittle32_t; + +/// A reference to a string in the string table. +struct Str { + Word Offset, Size; + + StringRef get(StringRef Strtab) const { + return {Strtab.data() + Offset, Size}; + } +}; + +/// A reference to a range of objects in the symbol table. +template <typename T> struct Range { + Word Offset, Size; + + ArrayRef<T> get(StringRef Symtab) const { + return {reinterpret_cast<const T *>(Symtab.data() + Offset), Size}; + } +}; + +/// Describes the range of a particular module's symbols within the symbol +/// table. +struct Module { + Word Begin, End; + + /// The index of the first Uncommon for this Module. + Word UncBegin; +}; + +/// This is equivalent to an IR comdat. +struct Comdat { + Str Name; +}; + +/// Contains the information needed by linkers for symbol resolution, as well as +/// by the LTO implementation itself. +struct Symbol { + /// The mangled symbol name. + Str Name; + + /// The unmangled symbol name, or the empty string if this is not an IR + /// symbol. + Str IRName; + + /// The index into Header::Comdats, or -1 if not a comdat member. + Word ComdatIndex; + + Word Flags; + enum FlagBits { + FB_visibility, // 2 bits + FB_has_uncommon = FB_visibility + 2, + FB_undefined, + FB_weak, + FB_common, + FB_indirect, + FB_used, + FB_tls, + FB_may_omit, + FB_global, + FB_format_specific, + FB_unnamed_addr, + FB_executable, + }; +}; + +/// This data structure contains rarely used symbol fields and is optionally +/// referenced by a Symbol. +struct Uncommon { + Word CommonSize, CommonAlign; + + /// COFF-specific: the name of the symbol that a weak external resolves to + /// if not defined. + Str COFFWeakExternFallbackName; + + /// Specified section name, if any. + Str SectionName; +}; + + +struct Header { + /// Version number of the symtab format. This number should be incremented + /// when the format changes, but it does not need to be incremented if a + /// change to LLVM would cause it to create a different symbol table. + Word Version; + enum { kCurrentVersion = 2 }; + + /// The producer's version string (LLVM_VERSION_STRING " " LLVM_REVISION). + /// Consumers should rebuild the symbol table from IR if the producer's + /// version does not match the consumer's version due to potential differences + /// in symbol table format, symbol enumeration order and so on. + Str Producer; + + Range<Module> Modules; + Range<Comdat> Comdats; + Range<Symbol> Symbols; + Range<Uncommon> Uncommons; + + Str TargetTriple, SourceFileName; + + /// COFF-specific: linker directives. + Str COFFLinkerOpts; + + /// Dependent Library Specifiers + Range<Str> DependentLibraries; +}; + +} // end namespace storage + +/// Fills in Symtab and StrtabBuilder with a valid symbol and string table for +/// Mods. +Error build(ArrayRef<Module *> Mods, SmallVector<char, 0> &Symtab, + StringTableBuilder &StrtabBuilder, BumpPtrAllocator &Alloc); + +/// This represents a symbol that has been read from a storage::Symbol and +/// possibly a storage::Uncommon. +struct Symbol { + // Copied from storage::Symbol. + StringRef Name, IRName; + int ComdatIndex; + uint32_t Flags; + + // Copied from storage::Uncommon. + uint32_t CommonSize, CommonAlign; + StringRef COFFWeakExternFallbackName; + StringRef SectionName; + + /// Returns the mangled symbol name. + StringRef getName() const { return Name; } + + /// Returns the unmangled symbol name, or the empty string if this is not an + /// IR symbol. + StringRef getIRName() const { return IRName; } + + /// Returns the index into the comdat table (see Reader::getComdatTable()), or + /// -1 if not a comdat member. + int getComdatIndex() const { return ComdatIndex; } + + using S = storage::Symbol; + + GlobalValue::VisibilityTypes getVisibility() const { + return GlobalValue::VisibilityTypes((Flags >> S::FB_visibility) & 3); + } + + bool isUndefined() const { return (Flags >> S::FB_undefined) & 1; } + bool isWeak() const { return (Flags >> S::FB_weak) & 1; } + bool isCommon() const { return (Flags >> S::FB_common) & 1; } + bool isIndirect() const { return (Flags >> S::FB_indirect) & 1; } + bool isUsed() const { return (Flags >> S::FB_used) & 1; } + bool isTLS() const { return (Flags >> S::FB_tls) & 1; } + + bool canBeOmittedFromSymbolTable() const { + return (Flags >> S::FB_may_omit) & 1; + } + + bool isGlobal() const { return (Flags >> S::FB_global) & 1; } + bool isFormatSpecific() const { return (Flags >> S::FB_format_specific) & 1; } + bool isUnnamedAddr() const { return (Flags >> S::FB_unnamed_addr) & 1; } + bool isExecutable() const { return (Flags >> S::FB_executable) & 1; } + + uint64_t getCommonSize() const { + assert(isCommon()); + return CommonSize; + } + + uint32_t getCommonAlignment() const { + assert(isCommon()); + return CommonAlign; + } + + /// COFF-specific: for weak externals, returns the name of the symbol that is + /// used as a fallback if the weak external remains undefined. + StringRef getCOFFWeakExternalFallback() const { + assert(isWeak() && isIndirect()); + return COFFWeakExternFallbackName; + } + + StringRef getSectionName() const { return SectionName; } +}; + +/// This class can be used to read a Symtab and Strtab produced by +/// irsymtab::build. +class Reader { + StringRef Symtab, Strtab; + + ArrayRef<storage::Module> Modules; + ArrayRef<storage::Comdat> Comdats; + ArrayRef<storage::Symbol> Symbols; + ArrayRef<storage::Uncommon> Uncommons; + ArrayRef<storage::Str> DependentLibraries; + + StringRef str(storage::Str S) const { return S.get(Strtab); } + + template <typename T> ArrayRef<T> range(storage::Range<T> R) const { + return R.get(Symtab); + } + + const storage::Header &header() const { + return *reinterpret_cast<const storage::Header *>(Symtab.data()); + } + +public: + class SymbolRef; + + Reader() = default; + Reader(StringRef Symtab, StringRef Strtab) : Symtab(Symtab), Strtab(Strtab) { + Modules = range(header().Modules); + Comdats = range(header().Comdats); + Symbols = range(header().Symbols); + Uncommons = range(header().Uncommons); + DependentLibraries = range(header().DependentLibraries); + } + + using symbol_range = iterator_range<object::content_iterator<SymbolRef>>; + + /// Returns the symbol table for the entire bitcode file. + /// The symbols enumerated by this method are ephemeral, but they can be + /// copied into an irsymtab::Symbol object. + symbol_range symbols() const; + + size_t getNumModules() const { return Modules.size(); } + + /// Returns a slice of the symbol table for the I'th module in the file. + /// The symbols enumerated by this method are ephemeral, but they can be + /// copied into an irsymtab::Symbol object. + symbol_range module_symbols(unsigned I) const; + + StringRef getTargetTriple() const { return str(header().TargetTriple); } + + /// Returns the source file path specified at compile time. + StringRef getSourceFileName() const { return str(header().SourceFileName); } + + /// Returns a table with all the comdats used by this file. + std::vector<StringRef> getComdatTable() const { + std::vector<StringRef> ComdatTable; + ComdatTable.reserve(Comdats.size()); + for (auto C : Comdats) + ComdatTable.push_back(str(C.Name)); + return ComdatTable; + } + + /// COFF-specific: returns linker options specified in the input file. + StringRef getCOFFLinkerOpts() const { return str(header().COFFLinkerOpts); } + + /// Returns dependent library specifiers + std::vector<StringRef> getDependentLibraries() const { + std::vector<StringRef> Specifiers; + Specifiers.reserve(DependentLibraries.size()); + for (auto S : DependentLibraries) { + Specifiers.push_back(str(S)); + } + return Specifiers; + } +}; + +/// Ephemeral symbols produced by Reader::symbols() and +/// Reader::module_symbols(). +class Reader::SymbolRef : public Symbol { + const storage::Symbol *SymI, *SymE; + const storage::Uncommon *UncI; + const Reader *R; + + void read() { + if (SymI == SymE) + return; + + Name = R->str(SymI->Name); + IRName = R->str(SymI->IRName); + ComdatIndex = SymI->ComdatIndex; + Flags = SymI->Flags; + + if (Flags & (1 << storage::Symbol::FB_has_uncommon)) { + CommonSize = UncI->CommonSize; + CommonAlign = UncI->CommonAlign; + COFFWeakExternFallbackName = R->str(UncI->COFFWeakExternFallbackName); + SectionName = R->str(UncI->SectionName); + } else + // Reset this field so it can be queried unconditionally for all symbols. + SectionName = ""; + } + +public: + SymbolRef(const storage::Symbol *SymI, const storage::Symbol *SymE, + const storage::Uncommon *UncI, const Reader *R) + : SymI(SymI), SymE(SymE), UncI(UncI), R(R) { + read(); + } + + void moveNext() { + ++SymI; + if (Flags & (1 << storage::Symbol::FB_has_uncommon)) + ++UncI; + read(); + } + + bool operator==(const SymbolRef &Other) const { return SymI == Other.SymI; } +}; + +inline Reader::symbol_range Reader::symbols() const { + return {SymbolRef(Symbols.begin(), Symbols.end(), Uncommons.begin(), this), + SymbolRef(Symbols.end(), Symbols.end(), nullptr, this)}; +} + +inline Reader::symbol_range Reader::module_symbols(unsigned I) const { + const storage::Module &M = Modules[I]; + const storage::Symbol *MBegin = Symbols.begin() + M.Begin, + *MEnd = Symbols.begin() + M.End; + return {SymbolRef(MBegin, MEnd, Uncommons.begin() + M.UncBegin, this), + SymbolRef(MEnd, MEnd, nullptr, this)}; +} + +/// The contents of the irsymtab in a bitcode file. Any underlying data for the +/// irsymtab are owned by Symtab and Strtab. +struct FileContents { + SmallVector<char, 0> Symtab, Strtab; + Reader TheReader; +}; + +/// Reads the contents of a bitcode file, creating its irsymtab if necessary. +Expected<FileContents> readBitcode(const BitcodeFileContents &BFC); + +} // end namespace irsymtab +} // end namespace llvm + +#endif // LLVM_OBJECT_IRSYMTAB_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/MachO.h b/contrib/libs/llvm12/include/llvm/Object/MachO.h new file mode 100644 index 00000000000..bbc0a233ee1 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/MachO.h @@ -0,0 +1,750 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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 = Error::success(); +/// 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 = Error::success(); +/// 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 = Error::success(); +/// 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; + Expected<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; + bool isDebugSection(StringRef SectionName) 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, uint32_t CPUSubType); + 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"; + case MachO::PLATFORM_DRIVERKIT: return "driverkit"; + 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 std::string(std::string(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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/MachOUniversal.h b/contrib/libs/llvm12/include/llvm/Object/MachOUniversal.h new file mode 100644 index 00000000000..2f34b6a71ba --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/MachOUniversal.h @@ -0,0 +1,183 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- MachOUniversal.h - Mach-O universal binaries -------------*- 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 Mach-O fat/universal binaries. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_MACHOUNIVERSAL_H +#define LLVM_OBJECT_MACHOUNIVERSAL_H + +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Object/Archive.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/MachO.h" + +namespace llvm { +class StringRef; +class Module; +class LLVMContext; + +namespace object { +class IRObjectFile; + +class MachOUniversalBinary : public Binary { + virtual void anchor(); + + uint32_t Magic; + uint32_t NumberOfObjects; +public: + static constexpr uint32_t MaxSectionAlignment = 15; /* 2**15 or 0x8000 */ + + class ObjectForArch { + const MachOUniversalBinary *Parent; + /// Index of object in the universal binary. + uint32_t Index; + /// Descriptor of the object. + MachO::fat_arch Header; + MachO::fat_arch_64 Header64; + + public: + ObjectForArch(const MachOUniversalBinary *Parent, uint32_t Index); + + void clear() { + Parent = nullptr; + Index = 0; + } + + bool operator==(const ObjectForArch &Other) const { + return (Parent == Other.Parent) && (Index == Other.Index); + } + + ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); } + uint32_t getCPUType() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.cputype; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.cputype; + } + uint32_t getCPUSubType() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.cpusubtype; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.cpusubtype; + } + uint64_t getOffset() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.offset; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.offset; + } + uint64_t getSize() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.size; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.size; + } + uint32_t getAlign() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return Header.align; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.align; + } + uint32_t getReserved() const { + if (Parent->getMagic() == MachO::FAT_MAGIC) + return 0; + else // Parent->getMagic() == MachO::FAT_MAGIC_64 + return Header64.reserved; + } + Triple getTriple() const { + return MachOObjectFile::getArchTriple(getCPUType(), getCPUSubType()); + } + std::string getArchFlagName() const { + const char *McpuDefault, *ArchFlag; + MachOObjectFile::getArchTriple(getCPUType(), getCPUSubType(), + &McpuDefault, &ArchFlag); + return ArchFlag ? ArchFlag : std::string(); + } + + Expected<std::unique_ptr<MachOObjectFile>> getAsObjectFile() const; + Expected<std::unique_ptr<IRObjectFile>> + getAsIRObject(LLVMContext &Ctx) const; + + Expected<std::unique_ptr<Archive>> getAsArchive() const; + }; + + class object_iterator { + ObjectForArch Obj; + public: + object_iterator(const ObjectForArch &Obj) : Obj(Obj) {} + const ObjectForArch *operator->() const { return &Obj; } + const ObjectForArch &operator*() const { return Obj; } + + bool operator==(const object_iterator &Other) const { + return Obj == Other.Obj; + } + bool operator!=(const object_iterator &Other) const { + return !(*this == Other); + } + + object_iterator& operator++() { // Preincrement + Obj = Obj.getNext(); + return *this; + } + }; + + MachOUniversalBinary(MemoryBufferRef Souce, Error &Err); + static Expected<std::unique_ptr<MachOUniversalBinary>> + create(MemoryBufferRef Source); + + object_iterator begin_objects() const { + return ObjectForArch(this, 0); + } + object_iterator end_objects() const { + return ObjectForArch(nullptr, 0); + } + + iterator_range<object_iterator> objects() const { + return make_range(begin_objects(), end_objects()); + } + + uint32_t getMagic() const { return Magic; } + uint32_t getNumberOfObjects() const { return NumberOfObjects; } + + // Cast methods. + static bool classof(Binary const *V) { + return V->isMachOUniversalBinary(); + } + + Expected<ObjectForArch> + getObjectForArch(StringRef ArchName) const; + + Expected<std::unique_ptr<MachOObjectFile>> + getMachOObjectForArch(StringRef ArchName) const; + + Expected<std::unique_ptr<IRObjectFile>> + getIRObjectForArch(StringRef ArchName, LLVMContext &Ctx) const; + + Expected<std::unique_ptr<Archive>> + getArchiveForArch(StringRef ArchName) const; +}; + +} +} + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/MachOUniversalWriter.h b/contrib/libs/llvm12/include/llvm/Object/MachOUniversalWriter.h new file mode 100644 index 00000000000..0ff4beabc79 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/MachOUniversalWriter.h @@ -0,0 +1,113 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- MachOUniversalWriter.h - MachO universal binary writer----*- 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 +// +//===----------------------------------------------------------------------===// +// +// Declares the Slice class and writeUniversalBinary function for writing a +// MachO universal binary file. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_MACHOUNIVERSALWRITER_H +#define LLVM_OBJECT_MACHOUNIVERSALWRITER_H + +#include "llvm/Object/Archive.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/MachO.h" + +namespace llvm { +class LLVMContext; + +namespace object { +class IRObjectFile; + +class Slice { + const Binary *B; + uint32_t CPUType; + uint32_t CPUSubType; + std::string ArchName; + + // P2Alignment field stores slice alignment values from universal + // binaries. This is also needed to order the slices so the total + // file size can be calculated before creating the output buffer. + uint32_t P2Alignment; + + Slice(const IRObjectFile &IRO, uint32_t CPUType, uint32_t CPUSubType, + std::string ArchName, uint32_t Align); + +public: + explicit Slice(const MachOObjectFile &O); + + Slice(const MachOObjectFile &O, uint32_t Align); + + /// This constructor takes pre-specified \param CPUType , \param CPUSubType , + /// \param ArchName , \param Align instead of inferring them from the archive + /// members. + Slice(const Archive &A, uint32_t CPUType, uint32_t CPUSubType, + std::string ArchName, uint32_t Align); + + static Expected<Slice> create(const Archive &A, + LLVMContext *LLVMCtx = nullptr); + + static Expected<Slice> create(const IRObjectFile &IRO, uint32_t Align); + + void setP2Alignment(uint32_t Align) { P2Alignment = Align; } + + const Binary *getBinary() const { return B; } + + uint32_t getCPUType() const { return CPUType; } + + uint32_t getCPUSubType() const { return CPUSubType; } + + uint32_t getP2Alignment() const { return P2Alignment; } + + uint64_t getCPUID() const { + return static_cast<uint64_t>(CPUType) << 32 | CPUSubType; + } + + std::string getArchString() const { + if (!ArchName.empty()) + return ArchName; + return ("unknown(" + Twine(CPUType) + "," + + Twine(CPUSubType & ~MachO::CPU_SUBTYPE_MASK) + ")") + .str(); + } + + friend bool operator<(const Slice &Lhs, const Slice &Rhs) { + if (Lhs.CPUType == Rhs.CPUType) + return Lhs.CPUSubType < Rhs.CPUSubType; + // force arm64-family to follow after all other slices for + // compatibility with cctools lipo + if (Lhs.CPUType == MachO::CPU_TYPE_ARM64) + return false; + if (Rhs.CPUType == MachO::CPU_TYPE_ARM64) + return true; + // Sort by alignment to minimize file size + return Lhs.P2Alignment < Rhs.P2Alignment; + } +}; + +Error writeUniversalBinary(ArrayRef<Slice> Slices, StringRef OutputFileName); + +Expected<std::unique_ptr<MemoryBuffer>> +writeUniversalBinaryToBuffer(ArrayRef<Slice> Slices); + +} // end namespace object + +} // end namespace llvm + +#endif // LLVM_OBJECT_MACHOUNIVERSALWRITER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/Minidump.h b/contrib/libs/llvm12/include/llvm/Object/Minidump.h new file mode 100644 index 00000000000..7adc325663d --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/Minidump.h @@ -0,0 +1,227 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/ModuleSymbolTable.h b/contrib/libs/llvm12/include/llvm/Object/ModuleSymbolTable.h new file mode 100644 index 00000000000..b661386eebb --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/ModuleSymbolTable.h @@ -0,0 +1,84 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- ModuleSymbolTable.h - symbol table for in-memory IR ------*- 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 class represents a symbol table built from in-memory IR. It provides +// access to GlobalValues and should only be used if such access is required +// (e.g. in the LTO implementation). +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_MODULESYMBOLTABLE_H +#define LLVM_OBJECT_MODULESYMBOLTABLE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/PointerUnion.h" +#include "llvm/IR/Mangler.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Allocator.h" +#include <cstdint> +#include <string> +#include <utility> +#include <vector> + +namespace llvm { + +class GlobalValue; +class Module; + +class ModuleSymbolTable { +public: + using AsmSymbol = std::pair<std::string, uint32_t>; + using Symbol = PointerUnion<GlobalValue *, AsmSymbol *>; + +private: + Module *FirstMod = nullptr; + + SpecificBumpPtrAllocator<AsmSymbol> AsmSymbols; + std::vector<Symbol> SymTab; + Mangler Mang; + +public: + ArrayRef<Symbol> symbols() const { return SymTab; } + void addModule(Module *M); + + void printSymbolName(raw_ostream &OS, Symbol S) const; + uint32_t getSymbolFlags(Symbol S) const; + + /// Parse inline ASM and collect the symbols that are defined or referenced in + /// the current module. + /// + /// For each found symbol, call \p AsmSymbol with the name of the symbol found + /// and the associated flags. + static void CollectAsmSymbols( + const Module &M, + function_ref<void(StringRef, object::BasicSymbolRef::Flags)> AsmSymbol); + + /// Parse inline ASM and collect the symvers directives that are defined in + /// the current module. + /// + /// For each found symbol, call \p AsmSymver with the name of the symbol and + /// its alias. + static void + CollectAsmSymvers(const Module &M, + function_ref<void(StringRef, StringRef)> AsmSymver); +}; + +} // end namespace llvm + +#endif // LLVM_OBJECT_MODULESYMBOLTABLE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/ObjectFile.h b/contrib/libs/llvm12/include/llvm/Object/ObjectFile.h new file mode 100644 index 00000000000..7f9ec78c1d4 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/ObjectFile.h @@ -0,0 +1,603 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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/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/MemoryBuffer.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <system_error> + +namespace llvm { + +class ARMAttributeParser; +class SubtargetFeatures; + +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; + + /// Whether this section is a debug section. + bool isDebugSection(StringRef SectionName) 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); +} + +raw_ostream &operator<<(raw_ostream &OS, const SectionedAddress &Addr); + +/// 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. + Expected<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 bool isDebugSection(StringRef SectionName) 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; + + Expected<uint64_t> getSymbolValue(DataRefImpl Symb) const; + +public: + ObjectFile() = delete; + ObjectFile(const ObjectFile &other) = delete; + + uint64_t getCommonSymbolSize(DataRefImpl Symb) const { + Expected<uint32_t> SymbolFlagsOrErr = getSymbolFlags(Symb); + if (!SymbolFlagsOrErr) + // TODO: Actually report errors helpfully. + report_fatal_error(SymbolFlagsOrErr.takeError()); + assert(*SymbolFlagsOrErr & 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 Optional<StringRef> tryGetCPUName() const { return None; }; + virtual void setARMSubArch(Triple &TheTriple) const { } + virtual Expected<uint64_t> getStartAddress() const { + 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, + bool InitContent = true); + 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, bool InitContent = true); + + 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 Expected<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 bool SectionRef::isDebugSection(StringRef SectionName) const { + return OwningObject->isDebugSection(SectionName); +} + +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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/RelocationResolver.h b/contrib/libs/llvm12/include/llvm/Object/RelocationResolver.h new file mode 100644 index 00000000000..d53f50e3e5e --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/RelocationResolver.h @@ -0,0 +1,59 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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 SupportsRelocation = bool (*)(uint64_t); +using RelocationResolver = uint64_t (*)(uint64_t Type, uint64_t Offset, + uint64_t S, uint64_t LocData, + int64_t Addend); + +std::pair<SupportsRelocation, RelocationResolver> +getRelocationResolver(const ObjectFile &Obj); + +uint64_t resolveRelocation(RelocationResolver Resolver, const RelocationRef &R, + uint64_t S, uint64_t LocData); + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_RELOCVISITOR_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/StackMapParser.h b/contrib/libs/llvm12/include/llvm/Object/StackMapParser.h new file mode 100644 index 00000000000..4551e80bb23 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/StackMapParser.h @@ -0,0 +1,478 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- StackMapParser.h - StackMap Parsing Support --------------*- 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_CODEGEN_STACKMAPPARSER_H +#define LLVM_CODEGEN_STACKMAPPARSER_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/ELF.h" +#include "llvm/Support/Endian.h" +#include <cassert> +#include <cstddef> +#include <cstdint> +#include <vector> + +namespace llvm { + +/// A parser for the latest stackmap format. At the moment, latest=V3. +template <support::endianness Endianness> +class StackMapParser { +public: + template <typename AccessorT> + class AccessorIterator { + public: + AccessorIterator(AccessorT A) : A(A) {} + + AccessorIterator& operator++() { A = A.next(); return *this; } + AccessorIterator operator++(int) { + auto tmp = *this; + ++*this; + return tmp; + } + + bool operator==(const AccessorIterator &Other) const { + return A.P == Other.A.P; + } + + bool operator!=(const AccessorIterator &Other) const { + return !(*this == Other); + } + + AccessorT& operator*() { return A; } + AccessorT* operator->() { return &A; } + + private: + AccessorT A; + }; + + /// Accessor for function records. + class FunctionAccessor { + friend class StackMapParser; + + public: + /// Get the function address. + uint64_t getFunctionAddress() const { + return read<uint64_t>(P); + } + + /// Get the function's stack size. + uint64_t getStackSize() const { + return read<uint64_t>(P + sizeof(uint64_t)); + } + + /// Get the number of callsite records. + uint64_t getRecordCount() const { + return read<uint64_t>(P + (2 * sizeof(uint64_t))); + } + + private: + FunctionAccessor(const uint8_t *P) : P(P) {} + + const static int FunctionAccessorSize = 3 * sizeof(uint64_t); + + FunctionAccessor next() const { + return FunctionAccessor(P + FunctionAccessorSize); + } + + const uint8_t *P; + }; + + /// Accessor for constants. + class ConstantAccessor { + friend class StackMapParser; + + public: + /// Return the value of this constant. + uint64_t getValue() const { return read<uint64_t>(P); } + + private: + ConstantAccessor(const uint8_t *P) : P(P) {} + + const static int ConstantAccessorSize = sizeof(uint64_t); + + ConstantAccessor next() const { + return ConstantAccessor(P + ConstantAccessorSize); + } + + const uint8_t *P; + }; + + enum class LocationKind : uint8_t { + Register = 1, Direct = 2, Indirect = 3, Constant = 4, ConstantIndex = 5 + }; + + /// Accessor for location records. + class LocationAccessor { + friend class StackMapParser; + friend class RecordAccessor; + + public: + /// Get the Kind for this location. + LocationKind getKind() const { + return LocationKind(P[KindOffset]); + } + + /// Get the Size for this location. + unsigned getSizeInBytes() const { + return read<uint16_t>(P + SizeOffset); + + } + + /// Get the Dwarf register number for this location. + uint16_t getDwarfRegNum() const { + return read<uint16_t>(P + DwarfRegNumOffset); + } + + /// Get the small-constant for this location. (Kind must be Constant). + uint32_t getSmallConstant() const { + assert(getKind() == LocationKind::Constant && "Not a small constant."); + return read<uint32_t>(P + SmallConstantOffset); + } + + /// Get the constant-index for this location. (Kind must be ConstantIndex). + uint32_t getConstantIndex() const { + assert(getKind() == LocationKind::ConstantIndex && + "Not a constant-index."); + return read<uint32_t>(P + SmallConstantOffset); + } + + /// Get the offset for this location. (Kind must be Direct or Indirect). + int32_t getOffset() const { + assert((getKind() == LocationKind::Direct || + getKind() == LocationKind::Indirect) && + "Not direct or indirect."); + return read<int32_t>(P + SmallConstantOffset); + } + + private: + LocationAccessor(const uint8_t *P) : P(P) {} + + LocationAccessor next() const { + return LocationAccessor(P + LocationAccessorSize); + } + + static const int KindOffset = 0; + static const int SizeOffset = KindOffset + sizeof(uint16_t); + static const int DwarfRegNumOffset = SizeOffset + sizeof(uint16_t); + static const int SmallConstantOffset = DwarfRegNumOffset + sizeof(uint32_t); + static const int LocationAccessorSize = sizeof(uint64_t) + sizeof(uint32_t); + + const uint8_t *P; + }; + + /// Accessor for stackmap live-out fields. + class LiveOutAccessor { + friend class StackMapParser; + friend class RecordAccessor; + + public: + /// Get the Dwarf register number for this live-out. + uint16_t getDwarfRegNum() const { + return read<uint16_t>(P + DwarfRegNumOffset); + } + + /// Get the size in bytes of live [sub]register. + unsigned getSizeInBytes() const { + return read<uint8_t>(P + SizeOffset); + } + + private: + LiveOutAccessor(const uint8_t *P) : P(P) {} + + LiveOutAccessor next() const { + return LiveOutAccessor(P + LiveOutAccessorSize); + } + + static const int DwarfRegNumOffset = 0; + static const int SizeOffset = + DwarfRegNumOffset + sizeof(uint16_t) + sizeof(uint8_t); + static const int LiveOutAccessorSize = sizeof(uint32_t); + + const uint8_t *P; + }; + + /// Accessor for stackmap records. + class RecordAccessor { + friend class StackMapParser; + + public: + using location_iterator = AccessorIterator<LocationAccessor>; + using liveout_iterator = AccessorIterator<LiveOutAccessor>; + + /// Get the patchpoint/stackmap ID for this record. + uint64_t getID() const { + return read<uint64_t>(P + PatchpointIDOffset); + } + + /// Get the instruction offset (from the start of the containing function) + /// for this record. + uint32_t getInstructionOffset() const { + return read<uint32_t>(P + InstructionOffsetOffset); + } + + /// Get the number of locations contained in this record. + uint16_t getNumLocations() const { + return read<uint16_t>(P + NumLocationsOffset); + } + + /// Get the location with the given index. + LocationAccessor getLocation(unsigned LocationIndex) const { + unsigned LocationOffset = + LocationListOffset + LocationIndex * LocationSize; + return LocationAccessor(P + LocationOffset); + } + + /// Begin iterator for locations. + location_iterator location_begin() const { + return location_iterator(getLocation(0)); + } + + /// End iterator for locations. + location_iterator location_end() const { + return location_iterator(getLocation(getNumLocations())); + } + + /// Iterator range for locations. + iterator_range<location_iterator> locations() const { + return make_range(location_begin(), location_end()); + } + + /// Get the number of liveouts contained in this record. + uint16_t getNumLiveOuts() const { + return read<uint16_t>(P + getNumLiveOutsOffset()); + } + + /// Get the live-out with the given index. + LiveOutAccessor getLiveOut(unsigned LiveOutIndex) const { + unsigned LiveOutOffset = + getNumLiveOutsOffset() + sizeof(uint16_t) + LiveOutIndex * LiveOutSize; + return LiveOutAccessor(P + LiveOutOffset); + } + + /// Begin iterator for live-outs. + liveout_iterator liveouts_begin() const { + return liveout_iterator(getLiveOut(0)); + } + + /// End iterator for live-outs. + liveout_iterator liveouts_end() const { + return liveout_iterator(getLiveOut(getNumLiveOuts())); + } + + /// Iterator range for live-outs. + iterator_range<liveout_iterator> liveouts() const { + return make_range(liveouts_begin(), liveouts_end()); + } + + private: + RecordAccessor(const uint8_t *P) : P(P) {} + + unsigned getNumLiveOutsOffset() const { + unsigned LocOffset = + ((LocationListOffset + LocationSize * getNumLocations()) + 7) & ~0x7; + return LocOffset + sizeof(uint16_t); + } + + unsigned getSizeInBytes() const { + unsigned RecordSize = + getNumLiveOutsOffset() + sizeof(uint16_t) + getNumLiveOuts() * LiveOutSize; + return (RecordSize + 7) & ~0x7; + } + + RecordAccessor next() const { + return RecordAccessor(P + getSizeInBytes()); + } + + static const unsigned PatchpointIDOffset = 0; + static const unsigned InstructionOffsetOffset = + PatchpointIDOffset + sizeof(uint64_t); + static const unsigned NumLocationsOffset = + InstructionOffsetOffset + sizeof(uint32_t) + sizeof(uint16_t); + static const unsigned LocationListOffset = + NumLocationsOffset + sizeof(uint16_t); + static const unsigned LocationSize = sizeof(uint64_t) + sizeof(uint32_t); + static const unsigned LiveOutSize = sizeof(uint32_t); + + const uint8_t *P; + }; + + /// Construct a parser for a version-3 stackmap. StackMap data will be read + /// from the given array. + StackMapParser(ArrayRef<uint8_t> StackMapSection) + : StackMapSection(StackMapSection) { + ConstantsListOffset = FunctionListOffset + getNumFunctions() * FunctionSize; + + assert(StackMapSection[0] == 3 && + "StackMapParser can only parse version 3 stackmaps"); + + unsigned CurrentRecordOffset = + ConstantsListOffset + getNumConstants() * ConstantSize; + + for (unsigned I = 0, E = getNumRecords(); I != E; ++I) { + StackMapRecordOffsets.push_back(CurrentRecordOffset); + CurrentRecordOffset += + RecordAccessor(&StackMapSection[CurrentRecordOffset]).getSizeInBytes(); + } + } + + /// Validates the header of the specified stack map section. + static Error validateHeader(ArrayRef<uint8_t> StackMapSection) { + // See the comment for StackMaps::emitStackmapHeader(). + if (StackMapSection.size() < 16) + return object::createError( + "the stack map section size (" + Twine(StackMapSection.size()) + + ") is less than the minimum possible size of its header (16)"); + + unsigned Version = StackMapSection[0]; + if (Version != 3) + return object::createError( + "the version (" + Twine(Version) + + ") of the stack map section is unsupported, the " + "supported version is 3"); + return Error::success(); + } + + using function_iterator = AccessorIterator<FunctionAccessor>; + using constant_iterator = AccessorIterator<ConstantAccessor>; + using record_iterator = AccessorIterator<RecordAccessor>; + + /// Get the version number of this stackmap. (Always returns 3). + unsigned getVersion() const { return 3; } + + /// Get the number of functions in the stack map. + uint32_t getNumFunctions() const { + return read<uint32_t>(&StackMapSection[NumFunctionsOffset]); + } + + /// Get the number of large constants in the stack map. + uint32_t getNumConstants() const { + return read<uint32_t>(&StackMapSection[NumConstantsOffset]); + } + + /// Get the number of stackmap records in the stackmap. + uint32_t getNumRecords() const { + return read<uint32_t>(&StackMapSection[NumRecordsOffset]); + } + + /// Return an FunctionAccessor for the given function index. + FunctionAccessor getFunction(unsigned FunctionIndex) const { + return FunctionAccessor(StackMapSection.data() + + getFunctionOffset(FunctionIndex)); + } + + /// Begin iterator for functions. + function_iterator functions_begin() const { + return function_iterator(getFunction(0)); + } + + /// End iterator for functions. + function_iterator functions_end() const { + return function_iterator( + FunctionAccessor(StackMapSection.data() + + getFunctionOffset(getNumFunctions()))); + } + + /// Iterator range for functions. + iterator_range<function_iterator> functions() const { + return make_range(functions_begin(), functions_end()); + } + + /// Return the large constant at the given index. + ConstantAccessor getConstant(unsigned ConstantIndex) const { + return ConstantAccessor(StackMapSection.data() + + getConstantOffset(ConstantIndex)); + } + + /// Begin iterator for constants. + constant_iterator constants_begin() const { + return constant_iterator(getConstant(0)); + } + + /// End iterator for constants. + constant_iterator constants_end() const { + return constant_iterator( + ConstantAccessor(StackMapSection.data() + + getConstantOffset(getNumConstants()))); + } + + /// Iterator range for constants. + iterator_range<constant_iterator> constants() const { + return make_range(constants_begin(), constants_end()); + } + + /// Return a RecordAccessor for the given record index. + RecordAccessor getRecord(unsigned RecordIndex) const { + std::size_t RecordOffset = StackMapRecordOffsets[RecordIndex]; + return RecordAccessor(StackMapSection.data() + RecordOffset); + } + + /// Begin iterator for records. + record_iterator records_begin() const { + if (getNumRecords() == 0) + return record_iterator(RecordAccessor(nullptr)); + return record_iterator(getRecord(0)); + } + + /// End iterator for records. + record_iterator records_end() const { + // Records need to be handled specially, since we cache the start addresses + // for them: We can't just compute the 1-past-the-end address, we have to + // look at the last record and use the 'next' method. + if (getNumRecords() == 0) + return record_iterator(RecordAccessor(nullptr)); + return record_iterator(getRecord(getNumRecords() - 1).next()); + } + + /// Iterator range for records. + iterator_range<record_iterator> records() const { + return make_range(records_begin(), records_end()); + } + +private: + template <typename T> + static T read(const uint8_t *P) { + return support::endian::read<T, Endianness, 1>(P); + } + + static const unsigned HeaderOffset = 0; + static const unsigned NumFunctionsOffset = HeaderOffset + sizeof(uint32_t); + static const unsigned NumConstantsOffset = NumFunctionsOffset + sizeof(uint32_t); + static const unsigned NumRecordsOffset = NumConstantsOffset + sizeof(uint32_t); + static const unsigned FunctionListOffset = NumRecordsOffset + sizeof(uint32_t); + + static const unsigned FunctionSize = 3 * sizeof(uint64_t); + static const unsigned ConstantSize = sizeof(uint64_t); + + std::size_t getFunctionOffset(unsigned FunctionIndex) const { + return FunctionListOffset + FunctionIndex * FunctionSize; + } + + std::size_t getConstantOffset(unsigned ConstantIndex) const { + return ConstantsListOffset + ConstantIndex * ConstantSize; + } + + ArrayRef<uint8_t> StackMapSection; + unsigned ConstantsListOffset; + std::vector<unsigned> StackMapRecordOffsets; +}; + +} // end namespace llvm + +#endif // LLVM_CODEGEN_STACKMAPPARSER_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/SymbolSize.h b/contrib/libs/llvm12/include/llvm/Object/SymbolSize.h new file mode 100644 index 00000000000..ae0fb0b12ff --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/SymbolSize.h @@ -0,0 +1,44 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- SymbolSize.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_SYMBOLSIZE_H +#define LLVM_OBJECT_SYMBOLSIZE_H + +#include "llvm/Object/ObjectFile.h" + +namespace llvm { +namespace object { + +struct SymEntry { + symbol_iterator I; + uint64_t Address; + unsigned Number; + unsigned SectionID; +}; + +int compareAddress(const SymEntry *A, const SymEntry *B); + +std::vector<std::pair<SymbolRef, uint64_t>> +computeSymbolSizes(const ObjectFile &O); + +} +} // namespace llvm + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/SymbolicFile.h b/contrib/libs/llvm12/include/llvm/Object/SymbolicFile.h new file mode 100644 index 00000000000..928c0ad8b35 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/SymbolicFile.h @@ -0,0 +1,224 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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/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) + Expected<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 Expected<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, bool InitContent = true); + + static Expected<std::unique_ptr<SymbolicFile>> + createSymbolicFile(MemoryBufferRef Object) { + return createSymbolicFile(Object, llvm::file_magic::unknown, nullptr); + } + + static bool classof(const Binary *v) { + return v->isSymbolic(); + } + + static bool isSymbolicFile(file_magic Type, const LLVMContext *Context); +}; + +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 Expected<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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/TapiFile.h b/contrib/libs/llvm12/include/llvm/Object/TapiFile.h new file mode 100644 index 00000000000..04c07c01cbc --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/TapiFile.h @@ -0,0 +1,74 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- TapiFile.h - Text-based Dynamic Library Stub -------------*- 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 TapiFile interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_TAPI_FILE_H +#define LLVM_OBJECT_TAPI_FILE_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" + +namespace llvm { +namespace object { + +class TapiFile : public SymbolicFile { +public: + TapiFile(MemoryBufferRef Source, const MachO::InterfaceFile &interface, + MachO::Architecture Arch); + ~TapiFile() override; + + void moveSymbolNext(DataRefImpl &DRI) const override; + + Error printSymbolName(raw_ostream &OS, DataRefImpl DRI) const override; + + Expected<uint32_t> getSymbolFlags(DataRefImpl DRI) const override; + + basic_symbol_iterator symbol_begin() const override; + + basic_symbol_iterator symbol_end() const override; + + static bool classof(const Binary *v) { return v->isTapiFile(); } + + bool is64Bit() { return MachO::is64Bit(Arch); } + +private: + struct Symbol { + StringRef Prefix; + StringRef Name; + uint32_t Flags; + + constexpr Symbol(StringRef Prefix, StringRef Name, uint32_t Flags) + : Prefix(Prefix), Name(Name), Flags(Flags) {} + }; + + std::vector<Symbol> Symbols; + MachO::Architecture Arch; +}; + +} // end namespace object. +} // end namespace llvm. + +#endif // LLVM_OBJECT_TAPI_FILE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/TapiUniversal.h b/contrib/libs/llvm12/include/llvm/Object/TapiUniversal.h new file mode 100644 index 00000000000..20eed191dd4 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/TapiUniversal.h @@ -0,0 +1,132 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- TapiUniversal.h - Text-based Dynamic Library Stub -------*- 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 TapiUniversal interface. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_TAPI_UNIVERSAL_H +#define LLVM_OBJECT_TAPI_UNIVERSAL_H + +#include "llvm/Object/Binary.h" +#include "llvm/Object/TapiFile.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/TextAPI/MachO/Architecture.h" +#include "llvm/TextAPI/MachO/InterfaceFile.h" + +namespace llvm { +namespace object { + +class TapiUniversal : public Binary { +public: + class ObjectForArch { + const TapiUniversal *Parent; + int Index; + + public: + ObjectForArch(const TapiUniversal *Parent, int Index) + : Parent(Parent), Index(Index) {} + + ObjectForArch getNext() const { return ObjectForArch(Parent, Index + 1); } + + bool operator==(const ObjectForArch &Other) const { + return (Parent == Other.Parent) && (Index == Other.Index); + } + + uint32_t getCPUType() const { + auto Result = + MachO::getCPUTypeFromArchitecture(Parent->Libraries[Index].Arch); + return Result.first; + } + + uint32_t getCPUSubType() const { + auto Result = + MachO::getCPUTypeFromArchitecture(Parent->Libraries[Index].Arch); + return Result.second; + } + + StringRef getArchFlagName() const { + return MachO::getArchitectureName(Parent->Libraries[Index].Arch); + } + + std::string getInstallName() const { + return std::string(Parent->Libraries[Index].InstallName); + } + + bool isTopLevelLib() const { + return Parent->ParsedFile->getInstallName() == getInstallName(); + } + + Expected<std::unique_ptr<TapiFile>> getAsObjectFile() const; + }; + + class object_iterator { + ObjectForArch Obj; + + public: + object_iterator(const ObjectForArch &Obj) : Obj(Obj) {} + const ObjectForArch *operator->() const { return &Obj; } + const ObjectForArch &operator*() const { return Obj; } + + bool operator==(const object_iterator &Other) const { + return Obj == Other.Obj; + } + bool operator!=(const object_iterator &Other) const { + return !(*this == Other); + } + + object_iterator &operator++() { // Preincrement + Obj = Obj.getNext(); + return *this; + } + }; + + TapiUniversal(MemoryBufferRef Source, Error &Err); + static Expected<std::unique_ptr<TapiUniversal>> + create(MemoryBufferRef Source); + ~TapiUniversal() override; + + object_iterator begin_objects() const { return ObjectForArch(this, 0); } + object_iterator end_objects() const { + return ObjectForArch(this, Libraries.size()); + } + + iterator_range<object_iterator> objects() const { + return make_range(begin_objects(), end_objects()); + } + + uint32_t getNumberOfObjects() const { return Libraries.size(); } + + static bool classof(const Binary *v) { return v->isTapiUniversal(); } + +private: + struct Library { + StringRef InstallName; + MachO::Architecture Arch; + }; + + std::unique_ptr<MachO::InterfaceFile> ParsedFile; + std::vector<Library> Libraries; +}; + +} // end namespace object. +} // end namespace llvm. + +#endif // LLVM_OBJECT_TAPI_UNIVERSAL_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/Wasm.h b/contrib/libs/llvm12/include/llvm/Object/Wasm.h new file mode 100644 index 00000000000..80e3ddd109f --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/Wasm.h @@ -0,0 +1,381 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- 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/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::WasmTableType *TableType, + const wasm::WasmEventType *EventType, + const wasm::WasmSignature *Signature) + : Info(Info), GlobalType(GlobalType), TableType(TableType), + EventType(EventType), Signature(Signature) {} + + const wasm::WasmSymbolInfo &Info; + const wasm::WasmGlobalType *GlobalType; + const wasm::WasmTableType *TableType; + const wasm::WasmEventType *EventType; + const wasm::WasmSignature *Signature; + + bool isTypeFunction() const { + return Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION; + } + + bool isTypeTable() const { return Info.Kind == wasm::WASM_SYMBOL_TYPE_TABLE; } + + 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) + uint32_t Comdat = UINT32_MAX; // From the "comdat info" section + 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::WasmDebugName> debugNames() const { return DebugNames; } + uint32_t startFunction() const { return StartFunction; } + uint32_t getNumImportedGlobals() const { return NumImportedGlobals; } + uint32_t getNumImportedTables() const { return NumImportedTables; } + uint32_t getNumImportedFunctions() const { return NumImportedFunctions; } + uint32_t getNumImportedEvents() const { return NumImportedEvents; } + uint32_t getNumSections() const { return Sections.size(); } + void moveSymbolNext(DataRefImpl &Symb) const override; + + Expected<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; + uint32_t getSymbolSectionId(SymbolRef Sym) const; + + // 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; + 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 isValidTableIndex(uint32_t Index) const; + bool isDefinedGlobalIndex(uint32_t Index) const; + bool isDefinedTableIndex(uint32_t Index) const; + bool isValidEventIndex(uint32_t Index) const; + bool isDefinedEventIndex(uint32_t Index) const; + bool isValidFunctionSymbol(uint32_t Index) const; + bool isValidTableSymbol(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; + uint32_t getSymbolSectionIdImpl(const WasmSymbol &Symb) 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 parseEventSection(ReadContext &Ctx); + Error parseGlobalSection(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::WasmDebugName> DebugNames; + uint32_t StartFunction = -1; + bool HasLinkingSection = false; + bool HasDylinkSection = false; + bool SeenCodeSection = false; + bool HasMemory64 = false; + wasm::WasmLinkingData LinkingData; + uint32_t NumImportedGlobals = 0; + uint32_t NumImportedTables = 0; + uint32_t NumImportedFunctions = 0; + uint32_t NumImportedEvents = 0; + uint32_t CodeSection = 0; + uint32_t DataSection = 0; + uint32_t EventSection = 0; + uint32_t GlobalSection = 0; + uint32_t TableSection = 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_EVENT, + WASM_SEC_ORDER_GLOBAL, + 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 + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/WindowsMachineFlag.h b/contrib/libs/llvm12/include/llvm/Object/WindowsMachineFlag.h new file mode 100644 index 00000000000..c6e06c47d09 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/WindowsMachineFlag.h @@ -0,0 +1,44 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- WindowsMachineFlag.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 +// +//===----------------------------------------------------------------------===// +// +// Functions for implementing the /machine: flag. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TOOLDRIVERS_MACHINEFLAG_MACHINEFLAG_H +#define LLVM_TOOLDRIVERS_MACHINEFLAG_MACHINEFLAG_H + +namespace llvm { + +class StringRef; +namespace COFF { +enum MachineTypes : unsigned; +} + +// Returns a user-readable string for ARMNT, ARM64, AMD64, I386. +// Other MachineTypes values must not be passed in. +StringRef machineToStr(COFF::MachineTypes MT); + +// Maps /machine: arguments to a MachineTypes value. +// Only returns ARMNT, ARM64, AMD64, I386, or IMAGE_FILE_MACHINE_UNKNOWN. +COFF::MachineTypes getMachineType(StringRef S); + +} + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/WindowsResource.h b/contrib/libs/llvm12/include/llvm/Object/WindowsResource.h new file mode 100644 index 00000000000..42f6885aef9 --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/WindowsResource.h @@ -0,0 +1,282 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===-- WindowsResource.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 +// +//===---------------------------------------------------------------------===// +// +// This file declares the .res file class. .res files are intermediate +// products of the typical resource-compilation process on Windows. This +// process is as follows: +// +// .rc file(s) ---(rc.exe)---> .res file(s) ---(cvtres.exe)---> COFF file +// +// .rc files are human-readable scripts that list all resources a program uses. +// +// They are compiled into .res files, which are a list of the resources in +// binary form. +// +// Finally the data stored in the .res is compiled into a COFF file, where it +// is organized in a directory tree structure for optimized access by the +// program during runtime. +// +// Ref: msdn.microsoft.com/en-us/library/windows/desktop/ms648007(v=vs.85).aspx +// +//===---------------------------------------------------------------------===// + +#ifndef LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H +#define LLVM_INCLUDE_LLVM_OBJECT_RESFILE_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/BinaryByteStream.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Error.h" + +#include <map> + +namespace llvm { + +class raw_ostream; +class ScopedPrinter; + +namespace object { + +class WindowsResource; +class ResourceSectionRef; + +const size_t WIN_RES_MAGIC_SIZE = 16; +const size_t WIN_RES_NULL_ENTRY_SIZE = 16; +const uint32_t WIN_RES_HEADER_ALIGNMENT = 4; +const uint32_t WIN_RES_DATA_ALIGNMENT = 4; +const uint16_t WIN_RES_PURE_MOVEABLE = 0x0030; + +struct WinResHeaderPrefix { + support::ulittle32_t DataSize; + support::ulittle32_t HeaderSize; +}; + +// Type and Name may each either be an integer ID or a string. This struct is +// only used in the case where they are both IDs. +struct WinResIDs { + uint16_t TypeFlag; + support::ulittle16_t TypeID; + uint16_t NameFlag; + support::ulittle16_t NameID; + + void setType(uint16_t ID) { + TypeFlag = 0xffff; + TypeID = ID; + } + + void setName(uint16_t ID) { + NameFlag = 0xffff; + NameID = ID; + } +}; + +struct WinResHeaderSuffix { + support::ulittle32_t DataVersion; + support::ulittle16_t MemoryFlags; + support::ulittle16_t Language; + support::ulittle32_t Version; + support::ulittle32_t Characteristics; +}; + +class EmptyResError : public GenericBinaryError { +public: + EmptyResError(Twine Msg, object_error ECOverride) + : GenericBinaryError(Msg, ECOverride) {} +}; + +class ResourceEntryRef { +public: + Error moveNext(bool &End); + bool checkTypeString() const { return IsStringType; } + ArrayRef<UTF16> getTypeString() const { return Type; } + uint16_t getTypeID() const { return TypeID; } + bool checkNameString() const { return IsStringName; } + ArrayRef<UTF16> getNameString() const { return Name; } + uint16_t getNameID() const { return NameID; } + uint16_t getDataVersion() const { return Suffix->DataVersion; } + uint16_t getLanguage() const { return Suffix->Language; } + uint16_t getMemoryFlags() const { return Suffix->MemoryFlags; } + uint16_t getMajorVersion() const { return Suffix->Version >> 16; } + uint16_t getMinorVersion() const { return Suffix->Version; } + uint32_t getCharacteristics() const { return Suffix->Characteristics; } + ArrayRef<uint8_t> getData() const { return Data; } + +private: + friend class WindowsResource; + + ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner); + Error loadNext(); + + static Expected<ResourceEntryRef> create(BinaryStreamRef Ref, + const WindowsResource *Owner); + + BinaryStreamReader Reader; + const WindowsResource *Owner; + bool IsStringType; + ArrayRef<UTF16> Type; + uint16_t TypeID; + bool IsStringName; + ArrayRef<UTF16> Name; + uint16_t NameID; + const WinResHeaderSuffix *Suffix = nullptr; + ArrayRef<uint8_t> Data; +}; + +class WindowsResource : public Binary { +public: + Expected<ResourceEntryRef> getHeadEntry(); + + static bool classof(const Binary *V) { return V->isWinRes(); } + + static Expected<std::unique_ptr<WindowsResource>> + createWindowsResource(MemoryBufferRef Source); + +private: + friend class ResourceEntryRef; + + WindowsResource(MemoryBufferRef Source); + + BinaryByteStream BBS; +}; + +class WindowsResourceParser { +public: + class TreeNode; + WindowsResourceParser(bool MinGW = false); + Error parse(WindowsResource *WR, std::vector<std::string> &Duplicates); + Error parse(ResourceSectionRef &RSR, StringRef Filename, + std::vector<std::string> &Duplicates); + void cleanUpManifests(std::vector<std::string> &Duplicates); + void printTree(raw_ostream &OS) const; + const TreeNode &getTree() const { return Root; } + const ArrayRef<std::vector<uint8_t>> getData() const { return Data; } + const ArrayRef<std::vector<UTF16>> getStringTable() const { + return StringTable; + } + + class TreeNode { + public: + template <typename T> + using Children = std::map<T, std::unique_ptr<TreeNode>>; + + void print(ScopedPrinter &Writer, StringRef Name) const; + uint32_t getTreeSize() const; + uint32_t getStringIndex() const { return StringIndex; } + uint32_t getDataIndex() const { return DataIndex; } + uint16_t getMajorVersion() const { return MajorVersion; } + uint16_t getMinorVersion() const { return MinorVersion; } + uint32_t getCharacteristics() const { return Characteristics; } + bool checkIsDataNode() const { return IsDataNode; } + const Children<uint32_t> &getIDChildren() const { return IDChildren; } + const Children<std::string> &getStringChildren() const { + return StringChildren; + } + + private: + friend class WindowsResourceParser; + + // Index is the StringTable vector index for this node's name. + static std::unique_ptr<TreeNode> createStringNode(uint32_t Index); + static std::unique_ptr<TreeNode> createIDNode(); + // DataIndex is the Data vector index that the data node points at. + static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion, + uint16_t MinorVersion, + uint32_t Characteristics, + uint32_t Origin, + uint32_t DataIndex); + + explicit TreeNode(uint32_t StringIndex); + TreeNode(uint16_t MajorVersion, uint16_t MinorVersion, + uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex); + + bool addEntry(const ResourceEntryRef &Entry, uint32_t Origin, + std::vector<std::vector<uint8_t>> &Data, + std::vector<std::vector<UTF16>> &StringTable, + TreeNode *&Result); + TreeNode &addTypeNode(const ResourceEntryRef &Entry, + std::vector<std::vector<UTF16>> &StringTable); + TreeNode &addNameNode(const ResourceEntryRef &Entry, + std::vector<std::vector<UTF16>> &StringTable); + bool addLanguageNode(const ResourceEntryRef &Entry, uint32_t Origin, + std::vector<std::vector<uint8_t>> &Data, + TreeNode *&Result); + bool addDataChild(uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, + uint32_t Characteristics, uint32_t Origin, + uint32_t DataIndex, TreeNode *&Result); + TreeNode &addIDChild(uint32_t ID); + TreeNode &addNameChild(ArrayRef<UTF16> NameRef, + std::vector<std::vector<UTF16>> &StringTable); + void shiftDataIndexDown(uint32_t Index); + + bool IsDataNode = false; + uint32_t StringIndex; + uint32_t DataIndex; + Children<uint32_t> IDChildren; + Children<std::string> StringChildren; + uint16_t MajorVersion = 0; + uint16_t MinorVersion = 0; + uint32_t Characteristics = 0; + + // The .res file that defined this TreeNode, for diagnostics. + // Index into InputFilenames. + uint32_t Origin; + }; + + struct StringOrID { + bool IsString; + ArrayRef<UTF16> String; + uint32_t ID; + + StringOrID(uint32_t ID) : IsString(false), ID(ID) {} + StringOrID(ArrayRef<UTF16> String) : IsString(true), String(String) {} + }; + +private: + Error addChildren(TreeNode &Node, ResourceSectionRef &RSR, + const coff_resource_dir_table &Table, uint32_t Origin, + std::vector<StringOrID> &Context, + std::vector<std::string> &Duplicates); + bool shouldIgnoreDuplicate(const ResourceEntryRef &Entry) const; + bool shouldIgnoreDuplicate(const std::vector<StringOrID> &Context) const; + + TreeNode Root; + std::vector<std::vector<uint8_t>> Data; + std::vector<std::vector<UTF16>> StringTable; + + std::vector<std::string> InputFilenames; + + bool MinGW; +}; + +Expected<std::unique_ptr<MemoryBuffer>> +writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, + const WindowsResourceParser &Parser, + uint32_t TimeDateStamp); + +void printResourceTypeName(uint16_t TypeID, raw_ostream &OS); +} // namespace object +} // namespace llvm + +#endif + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif diff --git a/contrib/libs/llvm12/include/llvm/Object/XCOFFObjectFile.h b/contrib/libs/llvm12/include/llvm/Object/XCOFFObjectFile.h new file mode 100644 index 00000000000..ba11d43c43d --- /dev/null +++ b/contrib/libs/llvm12/include/llvm/Object/XCOFFObjectFile.h @@ -0,0 +1,509 @@ +#pragma once + +#ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +//===- XCOFFObjectFile.h - XCOFF 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 XCOFFObjectFile class. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_XCOFFOBJECTFILE_H +#define LLVM_OBJECT_XCOFFOBJECTFILE_H + +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Endian.h" +#include <limits> + +namespace llvm { +namespace object { + +struct XCOFFFileHeader32 { + support::ubig16_t Magic; + support::ubig16_t NumberOfSections; + + // Unix time value, value of 0 indicates no timestamp. + // Negative values are reserved. + support::big32_t TimeStamp; + + support::ubig32_t SymbolTableOffset; // File offset to symbol table. + support::big32_t NumberOfSymTableEntries; + support::ubig16_t AuxHeaderSize; + support::ubig16_t Flags; +}; + +struct XCOFFFileHeader64 { + support::ubig16_t Magic; + support::ubig16_t NumberOfSections; + + // Unix time value, value of 0 indicates no timestamp. + // Negative values are reserved. + support::big32_t TimeStamp; + + support::ubig64_t SymbolTableOffset; // File offset to symbol table. + support::ubig16_t AuxHeaderSize; + support::ubig16_t Flags; + support::ubig32_t NumberOfSymTableEntries; +}; + +template <typename T> struct XCOFFSectionHeader { + // Least significant 3 bits are reserved. + static constexpr unsigned SectionFlagsReservedMask = 0x7; + + // The low order 16 bits of section flags denotes the section type. + static constexpr unsigned SectionFlagsTypeMask = 0xffffu; + +public: + StringRef getName() const; + uint16_t getSectionType() const; + bool isReservedSectionType() const; +}; + +// Explicit extern template declarations. +struct XCOFFSectionHeader32; +struct XCOFFSectionHeader64; +extern template struct XCOFFSectionHeader<XCOFFSectionHeader32>; +extern template struct XCOFFSectionHeader<XCOFFSectionHeader64>; + +struct XCOFFSectionHeader32 : XCOFFSectionHeader<XCOFFSectionHeader32> { + char Name[XCOFF::NameSize]; + support::ubig32_t PhysicalAddress; + support::ubig32_t VirtualAddress; + support::ubig32_t SectionSize; + support::ubig32_t FileOffsetToRawData; + support::ubig32_t FileOffsetToRelocationInfo; + support::ubig32_t FileOffsetToLineNumberInfo; + support::ubig16_t NumberOfRelocations; + support::ubig16_t NumberOfLineNumbers; + support::big32_t Flags; +}; + +struct XCOFFSectionHeader64 : XCOFFSectionHeader<XCOFFSectionHeader64> { + char Name[XCOFF::NameSize]; + support::ubig64_t PhysicalAddress; + support::ubig64_t VirtualAddress; + support::ubig64_t SectionSize; + support::big64_t FileOffsetToRawData; + support::big64_t FileOffsetToRelocationInfo; + support::big64_t FileOffsetToLineNumberInfo; + support::ubig32_t NumberOfRelocations; + support::ubig32_t NumberOfLineNumbers; + support::big32_t Flags; + char Padding[4]; +}; + +struct XCOFFSymbolEntry { + enum { NAME_IN_STR_TBL_MAGIC = 0x0 }; + typedef struct { + support::big32_t Magic; // Zero indicates name in string table. + support::ubig32_t Offset; + } NameInStrTblType; + + typedef struct { + uint8_t LanguageId; + uint8_t CpuTypeId; + } CFileLanguageIdAndTypeIdType; + + union { + char SymbolName[XCOFF::NameSize]; + NameInStrTblType NameInStrTbl; + }; + + support::ubig32_t Value; // Symbol value; storage class-dependent. + support::big16_t SectionNumber; + + union { + support::ubig16_t SymbolType; + CFileLanguageIdAndTypeIdType CFileLanguageIdAndTypeId; + }; + + XCOFF::StorageClass StorageClass; + uint8_t NumberOfAuxEntries; +}; + +struct XCOFFStringTable { + uint32_t Size; + const char *Data; +}; + +struct XCOFFCsectAuxEnt32 { + static constexpr uint8_t SymbolTypeMask = 0x07; + static constexpr uint8_t SymbolAlignmentMask = 0xF8; + static constexpr size_t SymbolAlignmentBitOffset = 3; + + support::ubig32_t + SectionOrLength; // If the symbol type is XTY_SD or XTY_CM, the csect + // length. + // If the symbol type is XTY_LD, the symbol table + // index of the containing csect. + // If the symbol type is XTY_ER, 0. + support::ubig32_t ParameterHashIndex; + support::ubig16_t TypeChkSectNum; + uint8_t SymbolAlignmentAndType; + XCOFF::StorageMappingClass StorageMappingClass; + support::ubig32_t StabInfoIndex; + support::ubig16_t StabSectNum; + + uint16_t getAlignmentLog2() const { + return (SymbolAlignmentAndType & SymbolAlignmentMask) >> + SymbolAlignmentBitOffset; + } + + uint8_t getSymbolType() const { + return SymbolAlignmentAndType & SymbolTypeMask; + } + + bool isLabel() const { return getSymbolType() == XCOFF::XTY_LD; } +}; + +struct XCOFFFileAuxEnt { + typedef struct { + support::big32_t Magic; // Zero indicates name in string table. + support::ubig32_t Offset; + char NamePad[XCOFF::FileNamePadSize]; + } NameInStrTblType; + union { + char Name[XCOFF::NameSize + XCOFF::FileNamePadSize]; + NameInStrTblType NameInStrTbl; + }; + XCOFF::CFileStringType Type; + uint8_t ReservedZeros[2]; + uint8_t AuxType; // 64-bit XCOFF file only. +}; + +struct XCOFFSectAuxEntForStat { + support::ubig32_t SectionLength; + support::ubig16_t NumberOfRelocEnt; + support::ubig16_t NumberOfLineNum; + uint8_t Pad[10]; +}; + +struct XCOFFRelocation32 { + // Masks for packing/unpacking the r_rsize field of relocations. + + // The msb is used to indicate if the bits being relocated are signed or + // unsigned. + static constexpr uint8_t XR_SIGN_INDICATOR_MASK = 0x80; + + // The 2nd msb is used to indicate that the binder has replaced/modified the + // original instruction. + static constexpr uint8_t XR_FIXUP_INDICATOR_MASK = 0x40; + + // The remaining bits specify the bit length of the relocatable reference + // minus one. + static constexpr uint8_t XR_BIASED_LENGTH_MASK = 0x3f; + +public: + support::ubig32_t VirtualAddress; + support::ubig32_t SymbolIndex; + + // Packed field, see XR_* masks for details of packing. + uint8_t Info; + + XCOFF::RelocationType Type; + +public: + bool isRelocationSigned() const; + bool isFixupIndicated() const; + + // Returns the number of bits being relocated. + uint8_t getRelocatedLength() const; +}; + +class XCOFFObjectFile : public ObjectFile { +private: + const void *FileHeader = nullptr; + const void *SectionHeaderTable = nullptr; + + const XCOFFSymbolEntry *SymbolTblPtr = nullptr; + XCOFFStringTable StringTable = {0, nullptr}; + + const XCOFFFileHeader32 *fileHeader32() const; + const XCOFFFileHeader64 *fileHeader64() const; + + const XCOFFSectionHeader32 *sectionHeaderTable32() const; + const XCOFFSectionHeader64 *sectionHeaderTable64() const; + + size_t getFileHeaderSize() const; + size_t getSectionHeaderSize() const; + + const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; + const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; + uintptr_t getSectionHeaderTableAddress() const; + uintptr_t getEndOfSymbolTableAddress() const; + + // This returns a pointer to the start of the storage for the name field of + // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily + // null-terminated. + const char *getSectionNameInternal(DataRefImpl Sec) const; + + // This function returns string table entry. + Expected<StringRef> getStringTableEntry(uint32_t Offset) const; + + static bool isReservedSectionNumber(int16_t SectionNumber); + + // Constructor and "create" factory function. The constructor is only a thin + // wrapper around the base constructor. The "create" function fills out the + // XCOFF-specific information and performs the error checking along the way. + XCOFFObjectFile(unsigned Type, MemoryBufferRef Object); + static Expected<std::unique_ptr<XCOFFObjectFile>> create(unsigned Type, + MemoryBufferRef MBR); + + // Helper for parsing the StringTable. Returns an 'Error' if parsing failed + // and an XCOFFStringTable if parsing succeeded. + static Expected<XCOFFStringTable> parseStringTable(const XCOFFObjectFile *Obj, + uint64_t Offset); + + // Make a friend so it can call the private 'create' function. + friend Expected<std::unique_ptr<ObjectFile>> + ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); + + void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; + +public: + static constexpr uint64_t InvalidRelocOffset = + std::numeric_limits<uint64_t>::max(); + + // Interface inherited from base classes. + void moveSymbolNext(DataRefImpl &Symb) const override; + Expected<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 getSymbolValueImpl(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; + + 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; + + /// \returns the relocation offset with the base address of the containing + /// section as zero, or InvalidRelocOffset on errors (such as a relocation + /// that does not refer to an address in any section). + 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; + Expected<uint64_t> getStartAddress() const override; + bool isRelocatableObject() const override; + + // Below here is the non-inherited interface. + bool is64Bit() const; + + const XCOFFSymbolEntry *getPointerToSymbolTable() const { + assert(!is64Bit() && "Symbol table handling not supported yet."); + return SymbolTblPtr; + } + + Expected<StringRef> + getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const; + + const XCOFFSymbolEntry *toSymbolEntry(DataRefImpl Ref) const; + + // File header related interfaces. + uint16_t getMagic() const; + uint16_t getNumberOfSections() const; + int32_t getTimeStamp() const; + + // Symbol table offset and entry count are handled differently between + // XCOFF32 and XCOFF64. + uint32_t getSymbolTableOffset32() const; + uint64_t getSymbolTableOffset64() const; + + // Note that this value is signed and might return a negative value. Negative + // values are reserved for future use. + int32_t getRawNumberOfSymbolTableEntries32() const; + + // The sanitized value appropriate to use as an index into the symbol table. + uint32_t getLogicalNumberOfSymbolTableEntries32() const; + + uint32_t getNumberOfSymbolTableEntries64() const; + uint32_t getSymbolIndex(uintptr_t SymEntPtr) const; + Expected<StringRef> getSymbolNameByIndex(uint32_t SymbolTableIndex) const; + + Expected<StringRef> getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const; + uint16_t getOptionalHeaderSize() const; + uint16_t getFlags() const; + + // Section header table related interfaces. + ArrayRef<XCOFFSectionHeader32> sections32() const; + ArrayRef<XCOFFSectionHeader64> sections64() const; + + int32_t getSectionFlags(DataRefImpl Sec) const; + Expected<DataRefImpl> getSectionByNum(int16_t Num) const; + + void checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const; + + // Relocation-related interfaces. + Expected<uint32_t> + getLogicalNumberOfRelocationEntries(const XCOFFSectionHeader32 &Sec) const; + + Expected<ArrayRef<XCOFFRelocation32>> + relocations(const XCOFFSectionHeader32 &) const; + + static bool classof(const Binary *B) { return B->isXCOFF(); } +}; // XCOFFObjectFile + +class XCOFFSymbolRef { + const DataRefImpl SymEntDataRef; + const XCOFFObjectFile *const OwningObjectPtr; + +public: + XCOFFSymbolRef(DataRefImpl SymEntDataRef, + const XCOFFObjectFile *OwningObjectPtr) + : SymEntDataRef(SymEntDataRef), OwningObjectPtr(OwningObjectPtr){}; + + XCOFF::StorageClass getStorageClass() const; + uint8_t getNumberOfAuxEntries() const; + const XCOFFCsectAuxEnt32 *getXCOFFCsectAuxEnt32() const; + uint16_t getType() const; + int16_t getSectionNumber() const; + + bool hasCsectAuxEnt() const; + bool isFunction() const; +}; + +class TBVectorExt { + friend class XCOFFTracebackTable; + + uint16_t Data; + uint32_t VecParmsInfo; + + TBVectorExt(StringRef TBvectorStrRef); + +public: + uint8_t getNumberOfVRSaved() const; + bool isVRSavedOnStack() const; + bool hasVarArgs() const; + uint8_t getNumberOfVectorParms() const; + bool hasVMXInstruction() const; + SmallString<32> getVectorParmsInfoString() const; +}; + +/// This class provides methods to extract traceback table data from a buffer. +/// The various accessors may reference the buffer provided via the constructor. + +class XCOFFTracebackTable { + const uint8_t *const TBPtr; + Optional<SmallString<32>> ParmsType; + Optional<uint32_t> TraceBackTableOffset; + Optional<uint32_t> HandlerMask; + Optional<uint32_t> NumOfCtlAnchors; + Optional<SmallVector<uint32_t, 8>> ControlledStorageInfoDisp; + Optional<StringRef> FunctionName; + Optional<uint8_t> AllocaRegister; + Optional<TBVectorExt> VecExt; + Optional<uint8_t> ExtensionTable; + + XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, Error &Err); +public: + /// Parse an XCOFF Traceback Table from \a Ptr with \a Size bytes. + /// Returns an XCOFFTracebackTable upon successful parsing, otherwise an + /// Error is returned. + /// + /// \param[in] Ptr + /// A pointer that points just past the initial 4 bytes of zeros at the + /// beginning of an XCOFF Traceback Table. + /// + /// \param[in, out] Size + /// A pointer that points to the length of the XCOFF Traceback Table. + /// If the XCOFF Traceback Table is not parsed successfully or there are + /// extra bytes that are not recognized, \a Size will be updated to be the + /// size up to the end of the last successfully parsed field of the table. + static Expected<XCOFFTracebackTable> create(const uint8_t *Ptr, + uint64_t &Size); + uint8_t getVersion() const; + uint8_t getLanguageID() const; + + bool isGlobalLinkage() const; + bool isOutOfLineEpilogOrPrologue() const; + bool hasTraceBackTableOffset() const; + bool isInternalProcedure() const; + bool hasControlledStorage() const; + bool isTOCless() const; + bool isFloatingPointPresent() const; + bool isFloatingPointOperationLogOrAbortEnabled() const; + + bool isInterruptHandler() const; + bool isFuncNamePresent() const; + bool isAllocaUsed() const; + uint8_t getOnConditionDirective() const; + bool isCRSaved() const; + bool isLRSaved() const; + + bool isBackChainStored() const; + bool isFixup() const; + uint8_t getNumOfFPRsSaved() const; + + bool hasVectorInfo() const; + bool hasExtensionTable() const; + uint8_t getNumOfGPRsSaved() const; + + uint8_t getNumberOfFixedParms() const; + + uint8_t getNumberOfFPParms() const; + bool hasParmsOnStack() const; + + const Optional<SmallString<32>> &getParmsType() const { return ParmsType; } + const Optional<uint32_t> &getTraceBackTableOffset() const { + return TraceBackTableOffset; + } + const Optional<uint32_t> &getHandlerMask() const { return HandlerMask; } + const Optional<uint32_t> &getNumOfCtlAnchors() { return NumOfCtlAnchors; } + const Optional<SmallVector<uint32_t, 8>> &getControlledStorageInfoDisp() { + return ControlledStorageInfoDisp; + } + const Optional<StringRef> &getFunctionName() const { return FunctionName; } + const Optional<uint8_t> &getAllocaRegister() const { return AllocaRegister; } + const Optional<TBVectorExt> &getVectorExt() const { return VecExt; } + const Optional<uint8_t> &getExtensionTable() const { return ExtensionTable; } +}; + +bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes); +} // namespace object +} // namespace llvm + +#endif // LLVM_OBJECT_XCOFFOBJECTFILE_H + +#ifdef __GNUC__ +#pragma GCC diagnostic pop +#endif |
