diff options
Diffstat (limited to 'include/llvm/Object')
29 files changed, 1033 insertions, 690 deletions
diff --git a/include/llvm/Object/Archive.h b/include/llvm/Object/Archive.h index 9ef1e4875191f..c40278a4f923b 100644 --- a/include/llvm/Object/Archive.h +++ b/include/llvm/Object/Archive.h @@ -1,9 +1,8 @@ //===- Archive.h - ar archive file format -----------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -16,6 +15,7 @@ #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" @@ -143,44 +143,38 @@ public: getAsBinary(LLVMContext *Context = nullptr) const; }; - class child_iterator { + class ChildFallibleIterator { Child C; - Error *E = nullptr; public: - child_iterator() : C(Child(nullptr, nullptr, nullptr)) {} - child_iterator(const Child &C, Error *E) : C(C), E(E) {} + 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 child_iterator &other) const { + 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 child_iterator &other) const { + bool operator!=(const ChildFallibleIterator &other) const { return !(*this == other); } - // Code in loops with child_iterators must check for errors on each loop - // iteration. And if there is an error break out of the loop. - child_iterator &operator++() { // Preincrement - assert(E && "Can't increment iterator with no Error attached"); - ErrorAsOutParameter ErrAsOutParam(E); - if (auto ChildOrErr = C.getNext()) - C = *ChildOrErr; - else { - C = C.getParent()->child_end().C; - *E = ChildOrErr.takeError(); - E = nullptr; - } - return *this; + 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; diff --git a/include/llvm/Object/ArchiveWriter.h b/include/llvm/Object/ArchiveWriter.h index 495b943d04c00..9e6daf2da36e9 100644 --- a/include/llvm/Object/ArchiveWriter.h +++ b/include/llvm/Object/ArchiveWriter.h @@ -1,9 +1,8 @@ //===- ArchiveWriter.h - ar archive file format writer ----------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -27,7 +26,6 @@ struct NewArchiveMember { sys::TimePoint<std::chrono::seconds> ModTime; unsigned UID = 0, GID = 0, Perms = 0644; - bool IsNew = false; NewArchiveMember() = default; NewArchiveMember(MemoryBufferRef BufRef); @@ -38,6 +36,8 @@ struct NewArchiveMember { 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, diff --git a/include/llvm/Object/Binary.h b/include/llvm/Object/Binary.h index 99745e24b8c86..3c3e977baff47 100644 --- a/include/llvm/Object/Binary.h +++ b/include/llvm/Object/Binary.h @@ -1,9 +1,8 @@ //===- Binary.h - A generic binary file -------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -14,6 +13,7 @@ #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" @@ -42,7 +42,9 @@ protected: ID_Archive, ID_MachOUniversalBinary, ID_COFFImportFile, - ID_IR, // LLVM IR + ID_IR, // LLVM IR + + ID_Minidump, ID_WinRes, // Windows resource (.res) file. @@ -50,6 +52,9 @@ protected: 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 @@ -118,6 +123,8 @@ public: return TypeID == ID_COFF; } + bool isXCOFF() const { return TypeID == ID_XCOFF32 || TypeID == ID_XCOFF64; } + bool isWasm() const { return TypeID == ID_Wasm; } bool isCOFFImportFile() const { @@ -128,6 +135,8 @@ public: return TypeID == ID_IR; } + bool isMinidump() const { return TypeID == ID_Minidump; } + bool isLittleEndian() const { return !(TypeID == ID_ELF32B || TypeID == ID_ELF64B || TypeID == ID_MachO32B || TypeID == ID_MachO64B); @@ -156,6 +165,9 @@ public: } }; +// 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. diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index b753d261a0fc8..c53cbc46c7476 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -1,9 +1,8 @@ //===- COFF.h - COFF object file implementation -----------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -898,13 +897,12 @@ protected: Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; void moveSectionNext(DataRefImpl &Sec) const override; - std::error_code getSectionName(DataRefImpl Sec, - StringRef &Res) 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; - std::error_code getSectionContents(DataRefImpl Sec, - StringRef &Res) 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; @@ -1034,10 +1032,10 @@ public: ArrayRef<coff_relocation> getRelocations(const coff_section *Sec) const; - std::error_code getSectionName(const coff_section *Sec, StringRef &Res) const; + Expected<StringRef> getSectionName(const coff_section *Sec) const; uint64_t getSectionSize(const coff_section *Sec) const; - std::error_code getSectionContents(const coff_section *Sec, - ArrayRef<uint8_t> &Res) const; + Error getSectionContents(const coff_section *Sec, + ArrayRef<uint8_t> &Res) const; uint64_t getImageBase() const; std::error_code getVaPtr(uint64_t VA, uintptr_t &Res) const; diff --git a/include/llvm/Object/COFFImportFile.h b/include/llvm/Object/COFFImportFile.h index 0a4556ad88845..5aa8364111180 100644 --- a/include/llvm/Object/COFFImportFile.h +++ b/include/llvm/Object/COFFImportFile.h @@ -1,9 +1,8 @@ //===- COFFImportFile.h - COFF short import file implementation -*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -37,12 +36,11 @@ public: void moveSymbolNext(DataRefImpl &Symb) const override { ++Symb.p; } - std::error_code printSymbolName(raw_ostream &OS, - DataRefImpl Symb) const override { + Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override { if (Symb.p == 0) OS << "__imp_"; OS << StringRef(Data.getBufferStart() + sizeof(coff_import_header)); - return std::error_code(); + return Error::success(); } uint32_t getSymbolFlags(DataRefImpl Symb) const override { @@ -71,9 +69,21 @@ private: }; 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; diff --git a/include/llvm/Object/COFFModuleDefinition.h b/include/llvm/Object/COFFModuleDefinition.h index be139a2833b0b..ab52259fea1a3 100644 --- a/include/llvm/Object/COFFModuleDefinition.h +++ b/include/llvm/Object/COFFModuleDefinition.h @@ -1,9 +1,8 @@ //===--- COFFModuleDefinition.h ---------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/include/llvm/Object/CVDebugRecord.h b/include/llvm/Object/CVDebugRecord.h index faad72c0df29f..d41c7391f7019 100644 --- a/include/llvm/Object/CVDebugRecord.h +++ b/include/llvm/Object/CVDebugRecord.h @@ -1,9 +1,8 @@ //===- CVDebugRecord.h ------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// diff --git a/include/llvm/Object/Decompressor.h b/include/llvm/Object/Decompressor.h index 2a77d2ffbf687..cc918481b308f 100644 --- a/include/llvm/Object/Decompressor.h +++ b/include/llvm/Object/Decompressor.h @@ -1,9 +1,8 @@ //===-- Decompressor.h ------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===/ diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index bcdc190cc7dcc..cf8e4529bad96 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -1,9 +1,8 @@ //===- ELF.h - ELF object file implementation -------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -45,10 +44,26 @@ getElfArchType(StringRef Object) { (uint8_t)Object[ELF::EI_DATA]); } -static inline Error createError(StringRef Err) { +static inline Error createError(const Twine &Err) { return make_error<StringError>(Err, object_error::parse_failed); } +template <class ELFT> class ELFFile; + +template <class ELFT> +std::string getSecIndexForError(const ELFFile<ELFT> *Obj, + const typename ELFT::Shdr *Sec) { + auto TableOrErr = Obj->sections(); + if (TableOrErr) + return "[index " + std::to_string(Sec - &TableOrErr->front()) + "]"; + // To make this helper be more convenient for error reporting purposes we + // drop the error. But really it should never be triggered. Before this point, + // our code should have called 'sections()' and reported a proper error on + // failure. + llvm::consumeError(TableOrErr.takeError()); + return "[unknown index]"; +} + template <class ELFT> class ELFFile { public: @@ -80,9 +95,7 @@ public: using Elf_Relr_Range = typename ELFT::RelrRange; using Elf_Phdr_Range = typename ELFT::PhdrRange; - const uint8_t *base() const { - return reinterpret_cast<const uint8_t *>(Buf.data()); - } + const uint8_t *base() const { return Buf.bytes_begin(); } size_t getBufSize() const { return Buf.size(); } @@ -115,8 +128,8 @@ public: SmallVectorImpl<char> &Result) const; uint32_t getRelativeRelocationType() const; - const char *getDynamicTagAsString(unsigned Arch, uint64_t Type) const; - const char *getDynamicTagAsString(uint64_t Type) 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, @@ -165,11 +178,16 @@ public: /// 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"); + return createError("invalid e_phentsize: " + + Twine(getHeader()->e_phentsize)); if (getHeader()->e_phoff + (getHeader()->e_phnum * getHeader()->e_phentsize) > getBufSize()) - return createError("program headers longer than binary"); + return createError("program headers are longer than binary of size " + + Twine(getBufSize()) + ": e_phoff = 0x" + + Twine::utohexstr(getHeader()->e_phoff) + + ", e_phnum = " + Twine(getHeader()->e_phnum) + + ", e_phentsize = " + Twine(getHeader()->e_phentsize)); auto *Begin = reinterpret_cast<const Elf_Phdr *>(base() + getHeader()->e_phoff); return makeArrayRef(Begin, Begin + getHeader()->e_phnum); @@ -183,12 +201,12 @@ public: /// \param Err [out] an error to support fallible iteration, which should /// be checked after iteration ends. Elf_Note_Iterator notes_begin(const Elf_Phdr &Phdr, Error &Err) const { - if (Phdr.p_type != ELF::PT_NOTE) { - Err = createError("attempt to iterate notes of non-note program header"); - return Elf_Note_Iterator(Err); - } + assert(Phdr.p_type == ELF::PT_NOTE && "Phdr is not of type PT_NOTE"); + ErrorAsOutParameter ErrAsOutParam(&Err); if (Phdr.p_offset + Phdr.p_filesz > getBufSize()) { - Err = createError("invalid program header offset/size"); + Err = createError("PT_NOTE header has invalid offset (0x" + + Twine::utohexstr(Phdr.p_offset) + ") or size (0x" + + Twine::utohexstr(Phdr.p_filesz) + ")"); return Elf_Note_Iterator(Err); } return Elf_Note_Iterator(base() + Phdr.p_offset, Phdr.p_filesz, Err); @@ -202,12 +220,13 @@ public: /// \param Err [out] an error to support fallible iteration, which should /// be checked after iteration ends. Elf_Note_Iterator notes_begin(const Elf_Shdr &Shdr, Error &Err) const { - if (Shdr.sh_type != ELF::SHT_NOTE) { - Err = createError("attempt to iterate notes of non-note section"); - return Elf_Note_Iterator(Err); - } + assert(Shdr.sh_type == ELF::SHT_NOTE && "Shdr is not of type SHT_NOTE"); + ErrorAsOutParameter ErrAsOutParam(&Err); if (Shdr.sh_offset + Shdr.sh_size > getBufSize()) { - Err = createError("invalid section offset/size"); + Err = createError("SHT_NOTE section " + getSecIndexForError(this, &Shdr) + + " has invalid offset (0x" + + Twine::utohexstr(Shdr.sh_offset) + ") or size (0x" + + Twine::utohexstr(Shdr.sh_size) + ")"); return Elf_Note_Iterator(Err); } return Elf_Note_Iterator(base() + Shdr.sh_offset, Shdr.sh_size, Err); @@ -274,7 +293,7 @@ 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"); + return createError("invalid section index: " + Twine(Index)); return &Sections[Index]; } @@ -286,7 +305,10 @@ getExtendedSymbolTableIndex(const typename ELFT::Sym *Sym, assert(Sym->st_shndx == ELF::SHN_XINDEX); unsigned Index = Sym - FirstSym; if (Index >= ShndxTable.size()) - return createError("index past the end of the symbol table"); + return createError( + "extended symbol index (" + Twine(Index) + + ") is past the end of the SHT_SYMTAB_SHNDX section of size " + + Twine(ShndxTable.size())); // The size of the table was checked in getSHNDXTable. return ShndxTable[Index]; @@ -333,20 +355,18 @@ ELFFile<ELFT>::getSection(const Elf_Sym *Sym, Elf_Sym_Range Symbols, } template <class ELFT> -inline Expected<const typename ELFT::Sym *> -getSymbol(typename ELFT::SymRange Symbols, uint32_t Index) { - if (Index >= Symbols.size()) - return createError("invalid symbol index"); - return &Symbols[Index]; -} - -template <class ELFT> Expected<const typename ELFT::Sym *> ELFFile<ELFT>::getSymbol(const Elf_Shdr *Sec, uint32_t Index) const { - auto SymtabOrErr = symbols(Sec); - if (!SymtabOrErr) - return SymtabOrErr.takeError(); - return object::getSymbol<ELFT>(*SymtabOrErr, Index); + auto SymsOrErr = symbols(Sec); + if (!SymsOrErr) + return SymsOrErr.takeError(); + + Elf_Sym_Range Symbols = *SymsOrErr; + if (Index >= Symbols.size()) + return createError("unable to get symbol from section " + + getSecIndexForError(this, Sec) + + ": invalid symbol index (" + Twine(Index) + ")"); + return &Symbols[Index]; } template <class ELFT> @@ -354,18 +374,26 @@ 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("invalid sh_entsize"); + return createError("section " + getSecIndexForError(this, Sec) + + " has an invalid sh_entsize: " + Twine(Sec->sh_entsize)); uintX_t Offset = Sec->sh_offset; uintX_t Size = Sec->sh_size; if (Size % sizeof(T)) - return createError("size is not a multiple of sh_entsize"); + return createError("section " + getSecIndexForError(this, Sec) + + " has an invalid sh_size (" + Twine(Size) + + ") which is not a multiple of its sh_entsize (" + + Twine(Sec->sh_entsize) + ")"); if ((std::numeric_limits<uintX_t>::max() - Offset < Size) || Offset + Size > Buf.size()) - return createError("invalid section offset"); + return createError("section " + getSecIndexForError(this, Sec) + + " has a sh_offset (0x" + Twine::utohexstr(Offset) + + ") + sh_size (0x" + Twine(Size) + + ") that cannot be represented"); if (Offset % alignof(T)) + // TODO: this error is untested. return createError("unaligned data"); const T *Start = reinterpret_cast<const T *>(base() + Offset); @@ -438,8 +466,10 @@ ELFFile<ELFT>::getSectionStringTable(Elf_Shdr_Range Sections) const { if (!Index) // no section string table. return ""; + // TODO: Test a case when the sh_link of the section with index 0 is broken. if (Index >= Sections.size()) - return createError("invalid section index"); + return createError("section header string table index " + Twine(Index) + + " does not exist"); return getStringTable(&Sections[Index]); } @@ -448,7 +478,9 @@ 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"); + return createError("invalid buffer: the size (" + Twine(Object.size()) + + ") is smaller than an ELF header (" + + Twine(sizeof(Elf_Ehdr)) + ")"); return ELFFile(Object); } @@ -459,16 +491,18 @@ Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const { return ArrayRef<Elf_Shdr>(); if (getHeader()->e_shentsize != sizeof(Elf_Shdr)) - return createError( - "invalid section header entry size (e_shentsize) in ELF header"); + return createError("invalid e_shentsize in ELF header: " + + Twine(getHeader()->e_shentsize)); const uint64_t FileSize = Buf.size(); - if (SectionTableOffset + sizeof(Elf_Shdr) > FileSize) - return createError("section header table goes past the end of the file"); + 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 = @@ -479,6 +513,7 @@ Expected<typename ELFT::ShdrRange> ELFFile<ELFT>::sections() const { NumSections = First->sh_size; if (NumSections > UINT64_MAX / sizeof(Elf_Shdr)) + // TODO: this error is untested. return createError("section table goes past the end of file"); const uint64_t SectionTableSize = NumSections * sizeof(Elf_Shdr); @@ -505,10 +540,14 @@ template <typename T> Expected<const T *> ELFFile<ELFT>::getEntry(const Elf_Shdr *Section, uint32_t Entry) const { if (sizeof(T) != Section->sh_entsize) + // TODO: this error is untested. return createError("invalid sh_entsize"); size_t Pos = Section->sh_offset + Entry * sizeof(T); if (Pos + sizeof(T) > Buf.size()) - return createError("invalid section offset"); + return createError("unable to access section " + + getSecIndexForError(this, Section) + " data at 0x" + + Twine::utohexstr(Pos) + + ": offset goes past the end of file"); return reinterpret_cast<const T *>(base() + Pos); } @@ -534,6 +573,7 @@ ELFFile<ELFT>::getSection(const StringRef SectionName) const { if (*SecNameOrErr == SectionName) return &Sec; } + // TODO: this error is untested. return createError("invalid section name"); } @@ -541,15 +581,24 @@ template <class ELFT> Expected<StringRef> ELFFile<ELFT>::getStringTable(const Elf_Shdr *Section) const { if (Section->sh_type != ELF::SHT_STRTAB) - return createError("invalid sh_type for string table, expected SHT_STRTAB"); + return createError("invalid sh_type for string table section " + + getSecIndexForError(this, Section) + + ": expected SHT_STRTAB, but got " + + object::getELFSectionTypeName(getHeader()->e_machine, + Section->sh_type)); auto V = getSectionContentsAsArray<char>(Section); if (!V) return V.takeError(); ArrayRef<char> Data = *V; if (Data.empty()) + // TODO: this error is untested. return createError("empty string table"); if (Data.back() != '\0') - return createError("string table non-null terminated"); + return createError(object::getELFSectionTypeName(getHeader()->e_machine, + Section->sh_type) + + " string table section " + + getSecIndexForError(this, Section) + + " is non-null terminated"); return StringRef(Data.begin(), Data.size()); } @@ -577,9 +626,13 @@ ELFFile<ELFT>::getSHNDXTable(const Elf_Shdr &Section, const Elf_Shdr &SymTable = **SymTableOrErr; if (SymTable.sh_type != ELF::SHT_SYMTAB && SymTable.sh_type != ELF::SHT_DYNSYM) + // TODO: this error is untested. return createError("invalid sh_type"); if (V.size() != (SymTable.sh_size / sizeof(Elf_Sym))) - return createError("invalid section contents size"); + return createError("SHT_SYMTAB_SHNDX section has sh_size (" + + Twine(SymTable.sh_size) + + ") which is not equal to the number of symbols (" + + Twine(V.size()) + ")"); return V; } @@ -598,6 +651,7 @@ ELFFile<ELFT>::getStringTableForSymtab(const Elf_Shdr &Sec, Elf_Shdr_Range Sections) const { if (Sec.sh_type != ELF::SHT_SYMTAB && Sec.sh_type != ELF::SHT_DYNSYM) + // TODO: this error is untested. return createError( "invalid sh_type for symbol table, expected SHT_SYMTAB or SHT_DYNSYM"); auto SectionOrErr = object::getSection<ELFT>(Sections, Sec.sh_link); @@ -625,7 +679,11 @@ Expected<StringRef> ELFFile<ELFT>::getSectionName(const Elf_Shdr *Section, if (Offset == 0) return StringRef(); if (Offset >= DotShstrtab.size()) - return createError("invalid string offset"); + 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); } diff --git a/include/llvm/Object/ELFObjectFile.h b/include/llvm/Object/ELFObjectFile.h index 0f620681cd99a..86c015efd704e 100644 --- a/include/llvm/Object/ELFObjectFile.h +++ b/include/llvm/Object/ELFObjectFile.h @@ -1,9 +1,8 @@ //===- ELFObjectFile.h - ELF object file implementation ---------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -42,6 +41,9 @@ namespace llvm { namespace object { +constexpr int NumElfSymbolTypes = 8; +extern const llvm::EnumEntry<unsigned> ElfSymbolTypes[NumElfSymbolTypes]; + class elf_symbol_iterator; class ELFObjectFileBase : public ObjectFile { @@ -52,8 +54,8 @@ class ELFObjectFileBase : public ObjectFile { protected: ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source); - virtual uint16_t getEMachine() const = 0; 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; @@ -62,6 +64,7 @@ protected: virtual uint64_t getSectionOffset(DataRefImpl Sec) const = 0; virtual Expected<int64_t> getRelocationAddend(DataRefImpl Rel) const = 0; + virtual Error getBuildAttributes(ARMAttributeParser &Attributes) const = 0; public: using elf_symbol_iterator_range = iterator_range<elf_symbol_iterator>; @@ -87,6 +90,8 @@ public: virtual uint16_t getEType() const = 0; + virtual uint16_t getEMachine() const = 0; + std::vector<std::pair<DataRefImpl, uint64_t>> getPltAddresses() const; }; @@ -142,6 +147,10 @@ public: return getObject()->getSymbolSize(getRawDataRefImpl()); } + uint8_t getBinding() const { + return getObject()->getSymbolBinding(getRawDataRefImpl()); + } + uint8_t getOther() const { return getObject()->getSymbolOther(getRawDataRefImpl()); } @@ -149,6 +158,16 @@ public: 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 { @@ -239,6 +258,7 @@ protected: uint32_t getSymbolAlignment(DataRefImpl Symb) const override; uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; + uint8_t getSymbolBinding(DataRefImpl Symb) const override; uint8_t getSymbolOther(DataRefImpl Symb) const override; uint8_t getSymbolELFType(DataRefImpl Symb) const override; Expected<SymbolRef::Type> getSymbolType(DataRefImpl Symb) const override; @@ -247,13 +267,12 @@ protected: Expected<section_iterator> getSymbolSection(DataRefImpl Symb) const override; void moveSectionNext(DataRefImpl &Sec) const override; - std::error_code getSectionName(DataRefImpl Sec, - StringRef &Res) 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; - std::error_code getSectionContents(DataRefImpl Sec, - StringRef &Res) 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; @@ -341,6 +360,28 @@ protected: (Visibility == ELF::STV_DEFAULT || Visibility == ELF::STV_PROTECTED)); } + Error getBuildAttributes(ARMAttributeParser &Attributes) const override { + auto SectionsOrErr = EF.sections(); + if (!SectionsOrErr) + return SectionsOrErr.takeError(); + + for (const Elf_Shdr &Sec : *SectionsOrErr) { + if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) { + auto ErrorOrContents = EF.getSectionContents(&Sec); + if (!ErrorOrContents) + return ErrorOrContents.takeError(); + + auto Contents = ErrorOrContents.get(); + if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1) + return Error::success(); + + Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); + break; + } + } + return Error::success(); + } + // This flag is used for classof, to distinguish ELFObjectFile from // its subclass. If more subclasses will be created, this flag will // have to become an enum. @@ -382,28 +423,6 @@ public: unsigned getPlatformFlags() const override { return EF.getHeader()->e_flags; } - std::error_code getBuildAttributes(ARMAttributeParser &Attributes) const override { - auto SectionsOrErr = EF.sections(); - if (!SectionsOrErr) - return errorToErrorCode(SectionsOrErr.takeError()); - - for (const Elf_Shdr &Sec : *SectionsOrErr) { - if (Sec.sh_type == ELF::SHT_ARM_ATTRIBUTES) { - auto ErrorOrContents = EF.getSectionContents(&Sec); - if (!ErrorOrContents) - return errorToErrorCode(ErrorOrContents.takeError()); - - auto Contents = ErrorOrContents.get(); - if (Contents[0] != ARMBuildAttrs::Format_Version || Contents.size() == 1) - return std::error_code(); - - Attributes.Parse(Contents, ELFT::TargetEndianness == support::little); - break; - } - } - return std::error_code(); - } - const ELFFile<ELFT> *getELFFile() const { return &EF; } bool isDyldType() const { return isDyldELFObject; } @@ -441,7 +460,16 @@ Expected<StringRef> ELFObjectFile<ELFT>::getSymbolName(DataRefImpl Sym) const { auto SymStrTabOrErr = EF.getStringTable(StringTableSec); if (!SymStrTabOrErr) return SymStrTabOrErr.takeError(); - return ESym->getName(*SymStrTabOrErr); + Expected<StringRef> Name = ESym->getName(*SymStrTabOrErr); + + // If the symbol name is empty use the section name. + if ((!Name || Name->empty()) && ESym->getType() == ELF::STT_SECTION) { + StringRef SecName; + Expected<section_iterator> Sec = getSymbolSection(Sym); + if (Sec && !(*Sec)->getName(SecName)) + return SecName; + } + return Name; } template <class ELFT> @@ -533,6 +561,11 @@ uint64_t ELFObjectFile<ELFT>::getCommonSymbolSizeImpl(DataRefImpl Symb) const { } template <class ELFT> +uint8_t ELFObjectFile<ELFT>::getSymbolBinding(DataRefImpl Symb) const { + return getSymbol(Symb)->getBinding(); +} + +template <class ELFT> uint8_t ELFObjectFile<ELFT>::getSymbolOther(DataRefImpl Symb) const { return getSymbol(Symb)->st_other; } @@ -654,13 +687,8 @@ void ELFObjectFile<ELFT>::moveSectionNext(DataRefImpl &Sec) const { } template <class ELFT> -std::error_code ELFObjectFile<ELFT>::getSectionName(DataRefImpl Sec, - StringRef &Result) const { - auto Name = EF.getSectionName(&*getSection(Sec)); - if (!Name) - return errorToErrorCode(Name.takeError()); - Result = *Name; - return std::error_code(); +Expected<StringRef> ELFObjectFile<ELFT>::getSectionName(DataRefImpl Sec) const { + return EF.getSectionName(&*getSection(Sec)); } template <class ELFT> @@ -685,16 +713,15 @@ uint64_t ELFObjectFile<ELFT>::getSectionSize(DataRefImpl Sec) const { } template <class ELFT> -std::error_code -ELFObjectFile<ELFT>::getSectionContents(DataRefImpl Sec, - StringRef &Result) const { +Expected<ArrayRef<uint8_t>> +ELFObjectFile<ELFT>::getSectionContents(DataRefImpl Sec) const { const Elf_Shdr *EShdr = getSection(Sec); if (std::error_code EC = checkOffset(getMemoryBufferRef(), (uintptr_t)base() + EShdr->sh_offset, EShdr->sh_size)) - return EC; - Result = StringRef((const char *)base() + EShdr->sh_offset, EShdr->sh_size); - return std::error_code(); + return errorCodeToError(EC); + return makeArrayRef((const uint8_t *)base() + EShdr->sh_offset, + EShdr->sh_size); } template <class ELFT> @@ -750,7 +777,7 @@ ELFObjectFile<ELFT>::dynamic_relocation_sections() const { } } for (const Elf_Shdr &Sec : *SectionsOrErr) { - if (is_contained(Offsets, Sec.sh_offset)) + if (is_contained(Offsets, Sec.sh_addr)) Res.emplace_back(toDRI(&Sec), this); } return Res; @@ -925,15 +952,13 @@ ELFObjectFile<ELFT>::create(MemoryBufferRef Object) { for (const Elf_Shdr &Sec : *SectionsOrErr) { switch (Sec.sh_type) { case ELF::SHT_DYNSYM: { - if (DotDynSymSec) - return createError("More than one dynamic symbol table!"); - DotDynSymSec = &Sec; + if (!DotDynSymSec) + DotDynSymSec = &Sec; break; } case ELF::SHT_SYMTAB: { - if (DotSymtabSec) - return createError("More than one static symbol table!"); - DotSymtabSec = &Sec; + if (!DotSymtabSec) + DotSymtabSec = &Sec; break; } case ELF::SHT_SYMTAB_SHNDX: { @@ -967,7 +992,9 @@ ELFObjectFile<ELFT>::ELFObjectFile(ELFObjectFile<ELFT> &&Other) template <class ELFT> basic_symbol_iterator ELFObjectFile<ELFT>::symbol_begin() const { - DataRefImpl Sym = toDRI(DotSymtabSec, 0); + DataRefImpl Sym = + toDRI(DotSymtabSec, + DotSymtabSec && DotSymtabSec->sh_size >= sizeof(Elf_Sym) ? 1 : 0); return basic_symbol_iterator(SymbolRef(Sym, this)); } diff --git a/include/llvm/Object/ELFTypes.h b/include/llvm/Object/ELFTypes.h index ec3c8e7bae465..5552208b1f8a7 100644 --- a/include/llvm/Object/ELFTypes.h +++ b/include/llvm/Object/ELFTypes.h @@ -1,9 +1,8 @@ //===- ELFTypes.h - Endian specific types for ELF ---------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -593,9 +592,9 @@ class Elf_Note_Impl { template <class NoteIteratorELFT> friend class Elf_Note_Iterator_Impl; +public: Elf_Note_Impl(const Elf_Nhdr_Impl<ELFT> &Nhdr) : Nhdr(Nhdr) {} -public: /// Get the note's name, excluding the terminating null byte. StringRef getName() const { if (!Nhdr.n_namesz) diff --git a/include/llvm/Object/Error.h b/include/llvm/Object/Error.h index a15f8b9236eb2..b7bbf06fc86de 100644 --- a/include/llvm/Object/Error.h +++ b/include/llvm/Object/Error.h @@ -1,9 +1,8 @@ //===- Error.h - system_error extensions for Object -------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/include/llvm/Object/IRObjectFile.h b/include/llvm/Object/IRObjectFile.h index 993359b766a17..08b92f1bae50b 100644 --- a/include/llvm/Object/IRObjectFile.h +++ b/include/llvm/Object/IRObjectFile.h @@ -1,9 +1,8 @@ //===- IRObjectFile.h - LLVM IR object file implementation ------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -38,8 +37,7 @@ class IRObjectFile : public SymbolicFile { public: ~IRObjectFile() override; void moveSymbolNext(DataRefImpl &Symb) const override; - std::error_code printSymbolName(raw_ostream &OS, - DataRefImpl Symb) const override; + Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; basic_symbol_iterator symbol_begin() const override; basic_symbol_iterator symbol_end() const override; diff --git a/include/llvm/Object/IRSymtab.h b/include/llvm/Object/IRSymtab.h index 5f6a024cd1329..0bbfc932493c6 100644 --- a/include/llvm/Object/IRSymtab.h +++ b/include/llvm/Object/IRSymtab.h @@ -1,9 +1,8 @@ //===- IRSymtab.h - data definitions for IR symbol tables -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -126,12 +125,13 @@ struct Uncommon { 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 = 1 }; + 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 @@ -148,6 +148,9 @@ struct Header { /// COFF-specific: linker directives. Str COFFLinkerOpts; + + /// Dependent Library Specifiers + Range<Str> DependentLibraries; }; } // end namespace storage @@ -232,6 +235,7 @@ class Reader { 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); } @@ -252,6 +256,7 @@ public: 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>>; @@ -284,6 +289,16 @@ public: /// 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 diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index c2f4f40629349..ca9512f21706d 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -1,9 +1,8 @@ //===- MachO.h - MachO object file implementation ---------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -134,11 +133,9 @@ public: BindRebaseSegInfo(const MachOObjectFile *Obj); // Used to check a Mach-O Bind or Rebase entry for errors when iterating. - const char *checkSegAndOffset(int32_t SegIndex, uint64_t SegOffset, - bool endInvalid); - const char *checkCountAndSkip(uint32_t Count, uint32_t Skip, - uint8_t PointerSize, int32_t SegIndex, - uint64_t SegOffset); + 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); @@ -296,13 +293,12 @@ public: unsigned getSectionID(SectionRef Sec) const; void moveSectionNext(DataRefImpl &Sec) const override; - std::error_code getSectionName(DataRefImpl Sec, - StringRef &Res) 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; - std::error_code getSectionContents(DataRefImpl Sec, - StringRef &Res) const override; + 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; @@ -413,36 +409,32 @@ public: bool is64, MachOBindEntry::Kind); - /// For use with a SegIndex,SegOffset pair in MachOBindEntry::moveNext() to - /// validate a MachOBindEntry. - const char *BindEntryCheckSegAndOffset(int32_t SegIndex, uint64_t SegOffset, - bool endInvalid) const { - return BindRebaseSectionTable->checkSegAndOffset(SegIndex, SegOffset, - endInvalid); - } - /// For use in MachOBindEntry::moveNext() to validate a MachOBindEntry for - /// the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode. - const char *BindEntryCheckCountAndSkip(uint32_t Count, uint32_t Skip, - uint8_t PointerSize, int32_t SegIndex, - uint64_t SegOffset) const { - return BindRebaseSectionTable->checkCountAndSkip(Count, Skip, PointerSize, - SegIndex, SegOffset); + // 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); } - /// For use with a SegIndex,SegOffset pair in MachORebaseEntry::moveNext() to - /// validate a MachORebaseEntry. - const char *RebaseEntryCheckSegAndOffset(int32_t SegIndex, uint64_t SegOffset, - bool endInvalid) const { - return BindRebaseSectionTable->checkSegAndOffset(SegIndex, SegOffset, - endInvalid); - } - /// For use in MachORebaseEntry::moveNext() to validate a MachORebaseEntry for - /// the REBASE_OPCODE_DO_*_TIMES* opcodes. - const char *RebaseEntryCheckCountAndSkip(uint32_t Count, uint32_t Skip, - uint8_t PointerSize, int32_t SegIndex, - uint64_t SegOffset) const { - return BindRebaseSectionTable->checkCountAndSkip(Count, Skip, PointerSize, - SegIndex, SegOffset); + // 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 @@ -579,6 +571,7 @@ public: const char **McpuDefault = nullptr, const char **ArchFlag = nullptr); static bool isValidArch(StringRef ArchFlag); + static ArrayRef<StringRef> getValidArchs(); static Triple getHostArch(); bool isRelocatableObject() const override; @@ -616,6 +609,7 @@ public: 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"; diff --git a/include/llvm/Object/MachOUniversal.h b/include/llvm/Object/MachOUniversal.h index 9e70b0bc30c04..5bf724f2c8b2e 100644 --- a/include/llvm/Object/MachOUniversal.h +++ b/include/llvm/Object/MachOUniversal.h @@ -1,9 +1,8 @@ //===- MachOUniversal.h - Mach-O universal binaries -------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/include/llvm/Object/Minidump.h b/include/llvm/Object/Minidump.h new file mode 100644 index 0000000000000..470008d552e73 --- /dev/null +++ b/include/llvm/Object/Minidump.h @@ -0,0 +1,165 @@ +//===- 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/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 list of memory ranges embedded in the MemoryList 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 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); + } + +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 Stream) const { + if (auto OptionalStream = getRawStream(Stream)) { + if (OptionalStream->size() >= sizeof(T)) + return *reinterpret_cast<const T *>(OptionalStream->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(); + auto ExpectedArray = getDataSlice(Data, Offset, sizeof(T) * Count); + if (!ExpectedArray) + return ExpectedArray.takeError(); + return ArrayRef<T>(reinterpret_cast<const T *>(ExpectedArray->data()), Count); +} + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_MINIDUMP_H diff --git a/include/llvm/Object/ModuleSymbolTable.h b/include/llvm/Object/ModuleSymbolTable.h index c3cbc27998e5a..4c582fbcda811 100644 --- a/include/llvm/Object/ModuleSymbolTable.h +++ b/include/llvm/Object/ModuleSymbolTable.h @@ -1,9 +1,8 @@ //===- ModuleSymbolTable.h - symbol table for in-memory IR ------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 036c99cb6baff..483a3486bd724 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -1,9 +1,8 @@ //===- ObjectFile.h - File format independent object file -------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -14,6 +13,7 @@ #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" @@ -98,7 +98,7 @@ public: uint64_t getAddress() const; uint64_t getIndex() const; uint64_t getSize() const; - std::error_code getContents(StringRef &Result) const; + Expected<StringRef> getContents() const; /// Get the alignment of this section as the actual value (not log 2). uint64_t getAlignment() const; @@ -136,6 +136,30 @@ public: const ObjectFile *getObject() const; }; +struct SectionedAddress { + // TODO: constructors could be removed when C++14 would be adopted. + SectionedAddress() {} + SectionedAddress(uint64_t Addr, uint64_t SectIdx) + : Address(Addr), SectionIndex(SectIdx) {} + + const static uint64_t UndefSection = UINT64_MAX; + + uint64_t Address = 0; + uint64_t SectionIndex = UndefSection; +}; + +inline bool operator<(const SectionedAddress &LHS, + const SectionedAddress &RHS) { + return std::tie(LHS.SectionIndex, LHS.Address) < + std::tie(RHS.SectionIndex, RHS.Address); +} + +inline bool operator==(const SectionedAddress &LHS, + const SectionedAddress &RHS) { + return std::tie(LHS.SectionIndex, LHS.Address) == + std::tie(RHS.SectionIndex, RHS.Address); +} + /// This is a value type class that represents a single symbol in the list of /// symbols in the object file. class SymbolRef : public BasicSymbolRef { @@ -220,7 +244,7 @@ protected: friend class SymbolRef; virtual Expected<StringRef> getSymbolName(DataRefImpl Symb) const = 0; - std::error_code printSymbolName(raw_ostream &OS, + 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; @@ -234,13 +258,12 @@ protected: friend class SectionRef; virtual void moveSectionNext(DataRefImpl &Sec) const = 0; - virtual std::error_code getSectionName(DataRefImpl Sec, - StringRef &Res) 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 std::error_code getSectionContents(DataRefImpl Sec, - StringRef &Res) 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; @@ -308,11 +331,6 @@ public: /// Create a triple from the data in this object file. Triple makeTriple() const; - virtual std::error_code - getBuildAttributes(ARMAttributeParser &Attributes) const { - return std::error_code(); - } - /// Maps a debug section name to a standard DWARF section name. virtual StringRef mapDebugSectionName(StringRef Name) const { return Name; } @@ -341,6 +359,9 @@ public: createCOFFObjectFile(MemoryBufferRef Object); static Expected<std::unique_ptr<ObjectFile>> + createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); + + static Expected<std::unique_ptr<ObjectFile>> createELFObjectFile(MemoryBufferRef Object); static Expected<std::unique_ptr<MachOObjectFile>> @@ -396,14 +417,16 @@ inline SectionRef::SectionRef(DataRefImpl SectionP, , OwningObject(Owner) {} inline bool SectionRef::operator==(const SectionRef &Other) const { - return SectionPimpl == Other.SectionPimpl; + return OwningObject == Other.OwningObject && + SectionPimpl == Other.SectionPimpl; } inline bool SectionRef::operator!=(const SectionRef &Other) const { - return SectionPimpl != Other.SectionPimpl; + return !(*this == Other); } inline bool SectionRef::operator<(const SectionRef &Other) const { + assert(OwningObject == Other.OwningObject); return SectionPimpl < Other.SectionPimpl; } @@ -412,7 +435,11 @@ inline void SectionRef::moveNext() { } inline std::error_code SectionRef::getName(StringRef &Result) const { - return OwningObject->getSectionName(SectionPimpl, Result); + Expected<StringRef> NameOrErr = OwningObject->getSectionName(SectionPimpl); + if (!NameOrErr) + return errorToErrorCode(NameOrErr.takeError()); + Result = *NameOrErr; + return std::error_code(); } inline uint64_t SectionRef::getAddress() const { @@ -427,8 +454,12 @@ inline uint64_t SectionRef::getSize() const { return OwningObject->getSectionSize(SectionPimpl); } -inline std::error_code SectionRef::getContents(StringRef &Result) const { - return OwningObject->getSectionContents(SectionPimpl, Result); +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 { @@ -531,6 +562,25 @@ inline const ObjectFile *RelocationRef::getObject() const { } // end namespace object +template <> struct DenseMapInfo<object::SectionRef> { + static bool isEqual(const object::SectionRef &A, + const object::SectionRef &B) { + return A == B; + } + static object::SectionRef getEmptyKey() { + return object::SectionRef({}, nullptr); + } + static object::SectionRef getTombstoneKey() { + object::DataRefImpl TS; + TS.p = (uintptr_t)-1; + return object::SectionRef(TS, nullptr); + } + static unsigned getHashValue(const object::SectionRef &Sec) { + object::DataRefImpl Raw = Sec.getRawDataRefImpl(); + return hash_combine(Raw.p, Raw.d.a, Raw.d.b); + } +}; + } // end namespace llvm #endif // LLVM_OBJECT_OBJECTFILE_H diff --git a/include/llvm/Object/RelocVisitor.h b/include/llvm/Object/RelocVisitor.h deleted file mode 100644 index 9a978de2e5996..0000000000000 --- a/include/llvm/Object/RelocVisitor.h +++ /dev/null @@ -1,351 +0,0 @@ -//===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// 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 { - -/// Base class for object file relocation visitors. -class RelocVisitor { -public: - explicit RelocVisitor(const ObjectFile &Obj) : ObjToVisit(Obj) {} - - // TODO: Should handle multiple applied relocations via either passing in the - // previously computed value or just count paired relocations as a single - // visit. - uint64_t visit(uint32_t Rel, RelocationRef R, uint64_t Value = 0) { - if (isa<ELFObjectFileBase>(ObjToVisit)) - return visitELF(Rel, R, Value); - if (isa<COFFObjectFile>(ObjToVisit)) - return visitCOFF(Rel, R, Value); - if (isa<MachOObjectFile>(ObjToVisit)) - return visitMachO(Rel, R, Value); - if (isa<WasmObjectFile>(ObjToVisit)) - return visitWasm(Rel, R, Value); - - HasError = true; - return 0; - } - - bool error() { return HasError; } - -private: - const ObjectFile &ObjToVisit; - bool HasError = false; - - uint64_t visitELF(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (ObjToVisit.getBytesInAddress() == 8) { // 64-bit object file - switch (ObjToVisit.getArch()) { - case Triple::x86_64: - return visitX86_64(Rel, R, Value); - case Triple::aarch64: - case Triple::aarch64_be: - return visitAarch64(Rel, R, Value); - case Triple::bpfel: - case Triple::bpfeb: - return visitBpf(Rel, R, Value); - case Triple::mips64el: - case Triple::mips64: - return visitMips64(Rel, R, Value); - case Triple::ppc64le: - case Triple::ppc64: - return visitPPC64(Rel, R, Value); - case Triple::systemz: - return visitSystemz(Rel, R, Value); - case Triple::sparcv9: - return visitSparc64(Rel, R, Value); - case Triple::amdgcn: - return visitAmdgpu(Rel, R, Value); - default: - HasError = true; - return 0; - } - } - - // 32-bit object file - assert(ObjToVisit.getBytesInAddress() == 4 && - "Invalid word size in object file"); - - switch (ObjToVisit.getArch()) { - case Triple::x86: - return visitX86(Rel, R, Value); - case Triple::ppc: - return visitPPC32(Rel, R, Value); - case Triple::arm: - case Triple::armeb: - return visitARM(Rel, R, Value); - case Triple::lanai: - return visitLanai(Rel, R, Value); - case Triple::mipsel: - case Triple::mips: - return visitMips32(Rel, R, Value); - case Triple::sparc: - return visitSparc32(Rel, R, Value); - case Triple::hexagon: - return visitHexagon(Rel, R, Value); - default: - HasError = true; - return 0; - } - } - - int64_t getELFAddend(RelocationRef R) { - Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend(); - handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) { - report_fatal_error(EI.message()); - }); - return *AddendOrErr; - } - - uint64_t visitX86_64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_X86_64_NONE: - return 0; - case ELF::R_X86_64_64: - case ELF::R_X86_64_DTPOFF32: - case ELF::R_X86_64_DTPOFF64: - return Value + getELFAddend(R); - case ELF::R_X86_64_PC32: - return Value + getELFAddend(R) - R.getOffset(); - case ELF::R_X86_64_32: - case ELF::R_X86_64_32S: - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - } - HasError = true; - return 0; - } - - uint64_t visitAarch64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_AARCH64_ABS32: { - int64_t Res = Value + getELFAddend(R); - if (Res < INT32_MIN || Res > UINT32_MAX) - HasError = true; - return static_cast<uint32_t>(Res); - } - case ELF::R_AARCH64_ABS64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitBpf(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_BPF_64_32: - return Value & 0xFFFFFFFF; - case ELF::R_BPF_64_64: - return Value; - } - HasError = true; - return 0; - } - - uint64_t visitMips64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_MIPS_32: - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - case ELF::R_MIPS_64: - return Value + getELFAddend(R); - case ELF::R_MIPS_TLS_DTPREL64: - return Value + getELFAddend(R) - 0x8000; - } - HasError = true; - return 0; - } - - uint64_t visitPPC64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_PPC64_ADDR32: - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - case ELF::R_PPC64_ADDR64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitSystemz(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_390_32: { - int64_t Res = Value + getELFAddend(R); - if (Res < INT32_MIN || Res > UINT32_MAX) - HasError = true; - return static_cast<uint32_t>(Res); - } - case ELF::R_390_64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitSparc64(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_SPARC_32: - case ELF::R_SPARC_64: - case ELF::R_SPARC_UA32: - case ELF::R_SPARC_UA64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitAmdgpu(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_AMDGPU_ABS32: - case ELF::R_AMDGPU_ABS64: - return Value + getELFAddend(R); - } - HasError = true; - return 0; - } - - uint64_t visitX86(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (Rel) { - case ELF::R_386_NONE: - return 0; - case ELF::R_386_32: - return Value; - case ELF::R_386_PC32: - return Value - R.getOffset(); - } - HasError = true; - return 0; - } - - uint64_t visitPPC32(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_PPC_ADDR32) - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - HasError = true; - return 0; - } - - uint64_t visitARM(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_ARM_ABS32) { - if ((int64_t)Value < INT32_MIN || (int64_t)Value > UINT32_MAX) - HasError = true; - return static_cast<uint32_t>(Value); - } - HasError = true; - return 0; - } - - uint64_t visitLanai(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_LANAI_32) - return (Value + getELFAddend(R)) & 0xFFFFFFFF; - HasError = true; - return 0; - } - - uint64_t visitMips32(uint32_t Rel, RelocationRef R, uint64_t Value) { - // FIXME: Take in account implicit addends to get correct results. - if (Rel == ELF::R_MIPS_32) - return Value & 0xFFFFFFFF; - if (Rel == ELF::R_MIPS_TLS_DTPREL32) - return Value & 0xFFFFFFFF; - HasError = true; - return 0; - } - - uint64_t visitSparc32(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32) - return Value + getELFAddend(R); - HasError = true; - return 0; - } - - uint64_t visitHexagon(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (Rel == ELF::R_HEX_32) - return Value + getELFAddend(R); - HasError = true; - return 0; - } - - uint64_t visitCOFF(uint32_t Rel, RelocationRef R, uint64_t Value) { - switch (ObjToVisit.getArch()) { - case Triple::x86: - switch (Rel) { - case COFF::IMAGE_REL_I386_SECREL: - case COFF::IMAGE_REL_I386_DIR32: - return static_cast<uint32_t>(Value); - } - break; - case Triple::x86_64: - switch (Rel) { - case COFF::IMAGE_REL_AMD64_SECREL: - return static_cast<uint32_t>(Value); - case COFF::IMAGE_REL_AMD64_ADDR64: - return Value; - } - break; - default: - break; - } - HasError = true; - return 0; - } - - uint64_t visitMachO(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (ObjToVisit.getArch() == Triple::x86_64 && - Rel == MachO::X86_64_RELOC_UNSIGNED) - return Value; - HasError = true; - return 0; - } - - uint64_t visitWasm(uint32_t Rel, RelocationRef R, uint64_t Value) { - if (ObjToVisit.getArch() == Triple::wasm32) { - switch (Rel) { - case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: - case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: - case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: - case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: - case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: - // For wasm section, its offset at 0 -- ignoring Value - return 0; - } - } - HasError = true; - return 0; - } -}; - -} // end namespace object -} // end namespace llvm - -#endif // LLVM_OBJECT_RELOCVISITOR_H diff --git a/include/llvm/Object/RelocationResolver.h b/include/llvm/Object/RelocationResolver.h new file mode 100644 index 0000000000000..1246dcc5ec739 --- /dev/null +++ b/include/llvm/Object/RelocationResolver.h @@ -0,0 +1,42 @@ +//===- RelocVisitor.h - Visitor for object file relocations -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file provides a wrapper around all the different types of relocations +// in different file formats, such that a client can handle them in a unified +// manner by only implementing a minimal number of functions. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_OBJECT_RELOCVISITOR_H +#define LLVM_OBJECT_RELOCVISITOR_H + +#include "llvm/ADT/Triple.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/Object/COFF.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/MachO.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/Wasm.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include <cstdint> +#include <system_error> + +namespace llvm { +namespace object { + +using RelocationResolver = uint64_t (*)(RelocationRef R, uint64_t S, uint64_t A); + +std::pair<bool (*)(uint64_t), RelocationResolver> +getRelocationResolver(const ObjectFile &Obj); + +} // end namespace object +} // end namespace llvm + +#endif // LLVM_OBJECT_RELOCVISITOR_H diff --git a/include/llvm/Object/StackMapParser.h b/include/llvm/Object/StackMapParser.h index 557db5afa8256..ed44efbf80b96 100644 --- a/include/llvm/Object/StackMapParser.h +++ b/include/llvm/Object/StackMapParser.h @@ -1,9 +1,8 @@ //===- StackMapParser.h - StackMap Parsing Support --------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// @@ -20,8 +19,9 @@ namespace llvm { +/// A parser for the latest stackmap format. At the moment, latest=V2. template <support::endianness Endianness> -class StackMapV2Parser { +class StackMapParser { public: template <typename AccessorT> class AccessorIterator { @@ -50,7 +50,7 @@ public: /// Accessor for function records. class FunctionAccessor { - friend class StackMapV2Parser; + friend class StackMapParser; public: /// Get the function address. @@ -82,7 +82,7 @@ public: /// Accessor for constants. class ConstantAccessor { - friend class StackMapV2Parser; + friend class StackMapParser; public: /// Return the value of this constant. @@ -106,7 +106,7 @@ public: /// Accessor for location records. class LocationAccessor { - friend class StackMapV2Parser; + friend class StackMapParser; friend class RecordAccessor; public: @@ -115,6 +115,12 @@ public: 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); @@ -149,16 +155,17 @@ public: } static const int KindOffset = 0; - static const int DwarfRegNumOffset = KindOffset + sizeof(uint16_t); - static const int SmallConstantOffset = DwarfRegNumOffset + sizeof(uint16_t); - static const int LocationAccessorSize = sizeof(uint64_t); + 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 StackMapV2Parser; + friend class StackMapParser; friend class RecordAccessor; public: @@ -189,7 +196,7 @@ public: /// Accessor for stackmap records. class RecordAccessor { - friend class StackMapV2Parser; + friend class StackMapParser; public: using location_iterator = AccessorIterator<LocationAccessor>; @@ -264,8 +271,9 @@ public: RecordAccessor(const uint8_t *P) : P(P) {} unsigned getNumLiveOutsOffset() const { - return LocationListOffset + LocationSize * getNumLocations() + - sizeof(uint16_t); + unsigned LocOffset = + ((LocationListOffset + LocationSize * getNumLocations()) + 7) & ~0x7; + return LocOffset + sizeof(uint16_t); } unsigned getSizeInBytes() const { @@ -285,7 +293,7 @@ public: InstructionOffsetOffset + sizeof(uint32_t) + sizeof(uint16_t); static const unsigned LocationListOffset = NumLocationsOffset + sizeof(uint16_t); - static const unsigned LocationSize = sizeof(uint64_t); + static const unsigned LocationSize = sizeof(uint64_t) + sizeof(uint32_t); static const unsigned LiveOutSize = sizeof(uint32_t); const uint8_t *P; @@ -293,12 +301,12 @@ public: /// Construct a parser for a version-2 stackmap. StackMap data will be read /// from the given array. - StackMapV2Parser(ArrayRef<uint8_t> StackMapSection) + StackMapParser(ArrayRef<uint8_t> StackMapSection) : StackMapSection(StackMapSection) { ConstantsListOffset = FunctionListOffset + getNumFunctions() * FunctionSize; - assert(StackMapSection[0] == 2 && - "StackMapV2Parser can only parse version 2 stackmaps"); + assert(StackMapSection[0] == 3 && + "StackMapParser can only parse version 3 stackmaps"); unsigned CurrentRecordOffset = ConstantsListOffset + getNumConstants() * ConstantSize; @@ -314,8 +322,8 @@ public: using constant_iterator = AccessorIterator<ConstantAccessor>; using record_iterator = AccessorIterator<RecordAccessor>; - /// Get the version number of this stackmap. (Always returns 2). - unsigned getVersion() const { return 2; } + /// 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 { diff --git a/include/llvm/Object/SymbolSize.h b/include/llvm/Object/SymbolSize.h index 1a1dc87529430..085623e35907d 100644 --- a/include/llvm/Object/SymbolSize.h +++ b/include/llvm/Object/SymbolSize.h @@ -1,9 +1,8 @@ //===- SymbolSize.h ---------------------------------------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // // //===----------------------------------------------------------------------===// diff --git a/include/llvm/Object/SymbolicFile.h b/include/llvm/Object/SymbolicFile.h index 5b9549bc34492..1398fa134c81c 100644 --- a/include/llvm/Object/SymbolicFile.h +++ b/include/llvm/Object/SymbolicFile.h @@ -1,9 +1,8 @@ //===- SymbolicFile.h - Interface that only provides symbols ----*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -127,7 +126,7 @@ public: void moveNext(); - std::error_code printName(raw_ostream &OS) const; + Error printName(raw_ostream &OS) const; /// Get symbol flags (bitwise OR of SymbolRef::Flags) uint32_t getFlags() const; @@ -146,8 +145,7 @@ public: // virtual interface. virtual void moveSymbolNext(DataRefImpl &Symb) const = 0; - virtual std::error_code printSymbolName(raw_ostream &OS, - DataRefImpl Symb) const = 0; + virtual Error printSymbolName(raw_ostream &OS, DataRefImpl Symb) const = 0; virtual uint32_t getSymbolFlags(DataRefImpl Symb) const = 0; @@ -194,7 +192,7 @@ inline void BasicSymbolRef::moveNext() { return OwningObject->moveSymbolNext(SymbolPimpl); } -inline std::error_code BasicSymbolRef::printName(raw_ostream &OS) const { +inline Error BasicSymbolRef::printName(raw_ostream &OS) const { return OwningObject->printSymbolName(OS, SymbolPimpl); } diff --git a/include/llvm/Object/Wasm.h b/include/llvm/Object/Wasm.h index ed857652a0486..e130ea32ed21b 100644 --- a/include/llvm/Object/Wasm.h +++ b/include/llvm/Object/Wasm.h @@ -1,9 +1,8 @@ -//===- WasmObjectFile.h - Wasm object file implementation -------*- C++ -*-===// +//===- Wasm.h - Wasm object file implementation -----------------*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // @@ -130,6 +129,10 @@ public: 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; } @@ -149,7 +152,6 @@ public: uint32_t getNumImportedGlobals() const { return NumImportedGlobals; } uint32_t getNumImportedFunctions() const { return NumImportedFunctions; } uint32_t getNumImportedEvents() const { return NumImportedEvents; } - void moveSymbolNext(DataRefImpl &Symb) const override; uint32_t getSymbolFlags(DataRefImpl Symb) const override; @@ -169,13 +171,12 @@ public: // Overrides from SectionRef. void moveSectionNext(DataRefImpl &Sec) const override; - std::error_code getSectionName(DataRefImpl Sec, - StringRef &Res) 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; - std::error_code getSectionContents(DataRefImpl Sec, - StringRef &Res) 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; @@ -222,13 +223,13 @@ private: 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; - const uint8_t *getPtr(size_t Offset) const; Error parseSection(WasmSection &Sec); Error parseCustomSection(WasmSection &Sec, ReadContext &Ctx); @@ -245,6 +246,7 @@ private: Error parseElemSection(ReadContext &Ctx); Error parseCodeSection(ReadContext &Ctx); Error parseDataSection(ReadContext &Ctx); + Error parseDataCountSection(ReadContext &Ctx); // Custom section types Error parseDylinkSection(ReadContext &Ctx); @@ -252,11 +254,15 @@ private: 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; @@ -267,6 +273,7 @@ private: std::vector<wasm::WasmExport> Exports; std::vector<wasm::WasmElemSegment> ElemSegments; std::vector<WasmSegment> DataSegments; + llvm::Optional<size_t> DataCount; std::vector<wasm::WasmFunction> Functions; std::vector<WasmSymbol> Symbols; std::vector<wasm::WasmFunctionName> DebugNames; @@ -287,40 +294,51 @@ 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 - // The order of standard sections is precisely given by the spec. - WASM_SEC_ORDER_TYPE = 1, - WASM_SEC_ORDER_IMPORT = 2, - WASM_SEC_ORDER_FUNCTION = 3, - WASM_SEC_ORDER_TABLE = 4, - WASM_SEC_ORDER_MEMORY = 5, - WASM_SEC_ORDER_GLOBAL = 6, - WASM_SEC_ORDER_EVENT = 7, - WASM_SEC_ORDER_EXPORT = 8, - WASM_SEC_ORDER_START = 9, - WASM_SEC_ORDER_ELEM = 10, - WASM_SEC_ORDER_DATACOUNT = 11, - WASM_SEC_ORDER_CODE = 12, - WASM_SEC_ORDER_DATA = 13, + WASM_SEC_ORDER_TYPE, + WASM_SEC_ORDER_IMPORT, + WASM_SEC_ORDER_FUNCTION, + WASM_SEC_ORDER_TABLE, + WASM_SEC_ORDER_MEMORY, + WASM_SEC_ORDER_GLOBAL, + WASM_SEC_ORDER_EVENT, + WASM_SEC_ORDER_EXPORT, + WASM_SEC_ORDER_START, + WASM_SEC_ORDER_ELEM, + WASM_SEC_ORDER_DATACOUNT, + WASM_SEC_ORDER_CODE, + WASM_SEC_ORDER_DATA, // Custom sections // "dylink" should be the very first section in the module - WASM_SEC_ORDER_DYLINK = 0, + WASM_SEC_ORDER_DYLINK, // "linking" section requires DATA section in order to validate data symbols - WASM_SEC_ORDER_LINKING = 100, + WASM_SEC_ORDER_LINKING, // Must come after "linking" section in order to validate reloc indexes. - WASM_SEC_ORDER_RELOC = 101, + 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 = 102, + WASM_SEC_ORDER_NAME, // "producers" section must appear after "name" section. - WASM_SEC_ORDER_PRODUCERS = 103 + 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: - int LastOrder = -1; // Lastly seen known section's order + bool Seen[WASM_NUM_SEC_ORDERS] = {}; // Sections that have been seen already // Returns -1 for unknown sections. int getSectionOrder(unsigned ID, StringRef CustomSectionName = ""); diff --git a/include/llvm/Object/WasmTraits.h b/include/llvm/Object/WasmTraits.h index 049d72f79e417..3eee8e71b1876 100644 --- a/include/llvm/Object/WasmTraits.h +++ b/include/llvm/Object/WasmTraits.h @@ -1,9 +1,8 @@ //===- WasmTraits.h - DenseMap traits for the Wasm structures ---*- C++ -*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===----------------------------------------------------------------------===// // diff --git a/include/llvm/Object/WindowsMachineFlag.h b/include/llvm/Object/WindowsMachineFlag.h new file mode 100644 index 0000000000000..acc6afc0329cb --- /dev/null +++ b/include/llvm/Object/WindowsMachineFlag.h @@ -0,0 +1,33 @@ +//===- 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 diff --git a/include/llvm/Object/WindowsResource.h b/include/llvm/Object/WindowsResource.h index a077c82871bfc..356dcb03abba0 100644 --- a/include/llvm/Object/WindowsResource.h +++ b/include/llvm/Object/WindowsResource.h @@ -1,9 +1,8 @@ //===-- WindowsResource.h ---------------------------------------*- C++-*-===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// 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 // //===---------------------------------------------------------------------===// // @@ -38,11 +37,14 @@ #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" -#include "llvm/Support/ScopedPrinter.h" #include <map> namespace llvm { + +class raw_ostream; +class ScopedPrinter; + namespace object { class WindowsResource; @@ -118,6 +120,7 @@ private: const WindowsResource *Owner); BinaryStreamReader Reader; + const WindowsResource *Owner; bool IsStringType; ArrayRef<UTF16> Type; uint16_t TypeID; @@ -149,7 +152,7 @@ class WindowsResourceParser { public: class TreeNode; WindowsResourceParser(); - Error parse(WindowsResource *WR); + Error parse(WindowsResource *WR, 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; } @@ -185,21 +188,25 @@ public: static std::unique_ptr<TreeNode> createIDNode(); static std::unique_ptr<TreeNode> createDataNode(uint16_t MajorVersion, uint16_t MinorVersion, - uint32_t Characteristics); + uint32_t Characteristics, + uint32_t Origin); explicit TreeNode(bool IsStringNode); TreeNode(uint16_t MajorVersion, uint16_t MinorVersion, - uint32_t Characteristics); + uint32_t Characteristics, uint32_t Origin); - void addEntry(const ResourceEntryRef &Entry, bool &IsNewTypeString, - bool &IsNewNameString); + bool addEntry(const ResourceEntryRef &Entry, uint32_t Origin, + bool &IsNewTypeString, bool &IsNewNameString, + TreeNode *&Result); TreeNode &addTypeNode(const ResourceEntryRef &Entry, bool &IsNewTypeString); TreeNode &addNameNode(const ResourceEntryRef &Entry, bool &IsNewNameString); - TreeNode &addLanguageNode(const ResourceEntryRef &Entry); - TreeNode &addChild(uint32_t ID, bool IsDataNode = false, - uint16_t MajorVersion = 0, uint16_t MinorVersion = 0, - uint32_t Characteristics = 0); - TreeNode &addChild(ArrayRef<UTF16> NameRef, bool &IsNewString); + bool addLanguageNode(const ResourceEntryRef &Entry, uint32_t Origin, + TreeNode *&Result); + bool addDataChild(uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, + uint32_t Characteristics, uint32_t Origin, + TreeNode *&Result); + TreeNode &addIDChild(uint32_t ID); + TreeNode &addNameChild(ArrayRef<UTF16> NameRef, bool &IsNewString); bool IsDataNode = false; uint32_t StringIndex; @@ -209,18 +216,26 @@ public: 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; }; private: TreeNode Root; std::vector<std::vector<uint8_t>> Data; std::vector<std::vector<UTF16>> StringTable; + + std::vector<std::string> InputFilenames; }; Expected<std::unique_ptr<MemoryBuffer>> writeWindowsResourceCOFF(llvm::COFF::MachineTypes MachineType, - const WindowsResourceParser &Parser); + const WindowsResourceParser &Parser, + uint32_t TimeDateStamp); +void printResourceTypeName(uint16_t TypeID, raw_ostream &OS); } // namespace object } // namespace llvm diff --git a/include/llvm/Object/XCOFFObjectFile.h b/include/llvm/Object/XCOFFObjectFile.h new file mode 100644 index 0000000000000..cdee7129a2abd --- /dev/null +++ b/include/llvm/Object/XCOFFObjectFile.h @@ -0,0 +1,268 @@ +//===- 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/StringRef.h" +#include "llvm/ADT/iterator_range.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/SubtargetFeature.h" +#include "llvm/Object/Binary.h" +#include "llvm/Object/Error.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include <cassert> +#include <cstdint> +#include <memory> +#include <system_error> + +namespace llvm { +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; +}; + +struct XCOFFSectionHeader32 { + char Name[XCOFF::SectionNameSize]; + 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; + + StringRef getName() const; +}; + +struct XCOFFSectionHeader64 { + char Name[XCOFF::SectionNameSize]; + 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]; + + StringRef getName() const; +}; + +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::SymbolNameSize]; + 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; +}; + +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; + void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; + uintptr_t getSectionHeaderTableAddress() 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; + + int32_t getSectionFlags(DataRefImpl Sec) const; + + static bool isReservedSectionNumber(int16_t SectionNumber); + Expected<DataRefImpl> getSectionByNum(int16_t Num) const; + + // 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); + +public: + // Interface inherited from base classes. + void moveSymbolNext(DataRefImpl &Symb) const override; + uint32_t getSymbolFlags(DataRefImpl Symb) const override; + basic_symbol_iterator symbol_begin() const override; + basic_symbol_iterator symbol_end() const override; + + Expected<StringRef> getSymbolName(DataRefImpl Symb) const override; + Expected<uint64_t> getSymbolAddress(DataRefImpl Symb) const override; + uint64_t 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; + 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; + + uint16_t getOptionalHeaderSize() const; + uint16_t getFlags() const; + + // Section header table related interfaces. + ArrayRef<XCOFFSectionHeader32> sections32() const; + ArrayRef<XCOFFSectionHeader64> sections64() const; +}; // XCOFFObjectFile + +} // namespace object +} // namespace llvm + +#endif // LLVM_OBJECT_XCOFFOBJECTFILE_H |
