diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
| commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
| tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/Object | |
| parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) | |
Notes
Diffstat (limited to 'lib/Object')
27 files changed, 2357 insertions, 587 deletions
diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp index 8ec115a5566c..49e66f46ab3f 100644 --- a/lib/Object/Archive.cpp +++ b/lib/Object/Archive.cpp @@ -1,9 +1,8 @@ //===- Archive.cpp - ar File Format implementation ------------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -512,7 +511,7 @@ Expected<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const { StringRef Name = NameOrErr.get(); Expected<StringRef> Buf = getBuffer(); if (!Buf) - return Buf.takeError(); + return createFileError(Name, Buf.takeError()); return MemoryBufferRef(*Buf, Name); } @@ -779,19 +778,18 @@ Archive::child_iterator Archive::child_begin(Error &Err, return child_end(); if (SkipInternal) - return child_iterator(Child(this, FirstRegularData, - FirstRegularStartOfFile), - &Err); + return child_iterator::itr( + Child(this, FirstRegularData, FirstRegularStartOfFile), Err); const char *Loc = Data.getBufferStart() + strlen(Magic); Child C(this, Loc, &Err); if (Err) return child_end(); - return child_iterator(C, &Err); + return child_iterator::itr(C, Err); } Archive::child_iterator Archive::child_end() const { - return child_iterator(Child(nullptr, nullptr, nullptr), nullptr); + return child_iterator::end(Child(nullptr, nullptr, nullptr)); } StringRef Archive::Symbol::getName() const { diff --git a/lib/Object/ArchiveWriter.cpp b/lib/Object/ArchiveWriter.cpp index da93602cbb28..228f6b40c5ec 100644 --- a/lib/Object/ArchiveWriter.cpp +++ b/lib/Object/ArchiveWriter.cpp @@ -1,9 +1,8 @@ //===- ArchiveWriter.cpp - ar File Format 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 // //===----------------------------------------------------------------------===// // @@ -49,7 +48,6 @@ NewArchiveMember::getOldMember(const object::Archive::Child &OldMember, return BufOrErr.takeError(); NewArchiveMember M; - assert(M.IsNew == false); M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false); M.MemberName = M.Buf->getBufferIdentifier(); if (!Deterministic) { @@ -76,10 +74,11 @@ NewArchiveMember::getOldMember(const object::Archive::Child &OldMember, Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName, bool Deterministic) { sys::fs::file_status Status; - int FD; - if (auto EC = sys::fs::openFileForRead(FileName, FD)) - return errorCodeToError(EC); - assert(FD != -1); + auto FDOrErr = sys::fs::openNativeFileForRead(FileName); + if (!FDOrErr) + return FDOrErr.takeError(); + sys::fs::file_t FD = *FDOrErr; + assert(FD != sys::fs::kInvalidFile); if (auto EC = sys::fs::status(FD, Status)) return errorCodeToError(EC); @@ -95,11 +94,10 @@ Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName, if (!MemberBufferOrErr) return errorCodeToError(MemberBufferOrErr.getError()); - if (close(FD) != 0) - return errorCodeToError(std::error_code(errno, std::generic_category())); + if (auto EC = sys::fs::closeFile(FD)) + return errorCodeToError(EC); NewArchiveMember M; - M.IsNew = true; M.Buf = std::move(*MemberBufferOrErr); M.MemberName = M.Buf->getBufferIdentifier(); if (!Deterministic) { @@ -192,35 +190,6 @@ static bool useStringTable(bool Thin, StringRef Name) { return Thin || Name.size() >= 16 || Name.contains('/'); } -// Compute the relative path from From to To. -static std::string computeRelativePath(StringRef From, StringRef To) { - if (sys::path::is_absolute(From) || sys::path::is_absolute(To)) - return To; - - StringRef DirFrom = sys::path::parent_path(From); - auto FromI = sys::path::begin(DirFrom); - auto ToI = sys::path::begin(To); - while (*FromI == *ToI) { - ++FromI; - ++ToI; - } - - SmallString<128> Relative; - for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI) - sys::path::append(Relative, ".."); - - for (auto ToE = sys::path::end(To); ToI != ToE; ++ToI) - sys::path::append(Relative, *ToI); - -#ifdef _WIN32 - // Replace backslashes with slashes so that the path is portable between *nix - // and Windows. - std::replace(Relative.begin(), Relative.end(), '\\', '/'); -#endif - - return Relative.str(); -} - static bool is64BitKind(object::Archive::Kind Kind) { switch (Kind) { case object::Archive::K_GNU: @@ -235,27 +204,11 @@ static bool is64BitKind(object::Archive::Kind Kind) { llvm_unreachable("not supported for writting"); } -static void addToStringTable(raw_ostream &Out, StringRef ArcName, - const NewArchiveMember &M, bool Thin) { - StringRef ID = M.Buf->getBufferIdentifier(); - if (Thin) { - if (M.IsNew) - Out << computeRelativePath(ArcName, ID); - else - Out << ID; - } else - Out << M.MemberName; - Out << "/\n"; -} - -static void printMemberHeader(raw_ostream &Out, uint64_t Pos, - raw_ostream &StringTable, - StringMap<uint64_t> &MemberNames, - object::Archive::Kind Kind, bool Thin, - StringRef ArcName, const NewArchiveMember &M, - sys::TimePoint<std::chrono::seconds> ModTime, - unsigned Size) { - +static void +printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable, + StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind, + bool Thin, const NewArchiveMember &M, + sys::TimePoint<std::chrono::seconds> ModTime, unsigned Size) { if (isBSDLike(Kind)) return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID, M.Perms, Size); @@ -266,12 +219,12 @@ static void printMemberHeader(raw_ostream &Out, uint64_t Pos, uint64_t NamePos; if (Thin) { NamePos = StringTable.tell(); - addToStringTable(StringTable, ArcName, M, Thin); + StringTable << M.MemberName << "/\n"; } else { auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)}); if (Insertion.second) { Insertion.first->second = StringTable.tell(); - addToStringTable(StringTable, ArcName, M, Thin); + StringTable << M.MemberName << "/\n"; } NamePos = Insertion.first->second; } @@ -424,8 +377,8 @@ getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) { if (!isArchiveSymbol(S)) continue; Ret.push_back(SymNames.tell()); - if (auto EC = S.printName(SymNames)) - return errorCodeToError(EC); + if (Error E = S.printName(SymNames)) + return std::move(E); SymNames << '\0'; } return Ret; @@ -433,8 +386,8 @@ getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) { static Expected<std::vector<MemberData>> computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, - object::Archive::Kind Kind, bool Thin, StringRef ArcName, - bool Deterministic, ArrayRef<NewArchiveMember> NewMembers) { + object::Archive::Kind Kind, bool Thin, bool Deterministic, + ArrayRef<NewArchiveMember> NewMembers) { static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; // This ignores the symbol table, but we only need the value mod 8 and the @@ -521,8 +474,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++); else ModTime = M.ModTime; - printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, ArcName, - M, ModTime, Buf.getBufferSize() + MemberPadding); + printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M, + ModTime, Buf.getBufferSize() + MemberPadding); Out.flush(); Expected<std::vector<unsigned>> Symbols = @@ -541,11 +494,53 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, return Ret; } -Error llvm::writeArchive(StringRef ArcName, - ArrayRef<NewArchiveMember> NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, - bool Deterministic, bool Thin, - std::unique_ptr<MemoryBuffer> OldArchiveBuf) { +namespace llvm { + +static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) { + SmallString<128> Ret = P; + std::error_code Err = sys::fs::make_absolute(Ret); + if (Err) + return Err; + sys::path::remove_dots(Ret, /*removedotdot*/ true); + return Ret; +} + +// Compute the relative path from From to To. +Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) { + ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To); + ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From); + if (!PathToOrErr || !DirFromOrErr) + return errorCodeToError(std::error_code(errno, std::generic_category())); + + const SmallString<128> &PathTo = *PathToOrErr; + const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr); + + // Can't construct a relative path between different roots + if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom)) + return sys::path::convert_to_slash(PathTo); + + // Skip common prefixes + auto FromTo = + std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom), + sys::path::begin(PathTo)); + auto FromI = FromTo.first; + auto ToI = FromTo.second; + + // Construct relative path + SmallString<128> Relative; + for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI) + sys::path::append(Relative, sys::path::Style::posix, ".."); + + for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI) + sys::path::append(Relative, sys::path::Style::posix, *ToI); + + return Relative.str(); +} + +Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, + bool WriteSymtab, object::Archive::Kind Kind, + bool Deterministic, bool Thin, + std::unique_ptr<MemoryBuffer> OldArchiveBuf) { assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); SmallString<0> SymNamesBuf; @@ -554,7 +549,7 @@ Error llvm::writeArchive(StringRef ArcName, raw_svector_ostream StringTable(StringTableBuf); Expected<std::vector<MemberData>> DataOrErr = computeMemberData( - StringTable, SymNames, Kind, Thin, ArcName, Deterministic, NewMembers); + StringTable, SymNames, Kind, Thin, Deterministic, NewMembers); if (Error E = DataOrErr.takeError()) return E; std::vector<MemberData> &Data = *DataOrErr; @@ -631,3 +626,5 @@ Error llvm::writeArchive(StringRef ArcName, return Temp->keep(ArcName); } + +} // namespace llvm diff --git a/lib/Object/Binary.cpp b/lib/Object/Binary.cpp index fe41987f5c27..a953c1d8cb80 100644 --- a/lib/Object/Binary.cpp +++ b/lib/Object/Binary.cpp @@ -1,9 +1,8 @@ //===- Binary.cpp - A generic binary file ---------------------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -17,6 +16,7 @@ #include "llvm/Object/Archive.h" #include "llvm/Object/Error.h" #include "llvm/Object/MachOUniversal.h" +#include "llvm/Object/Minidump.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/WindowsResource.h" #include "llvm/Support/Error.h" @@ -69,6 +69,8 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer, case file_magic::coff_import_library: case file_magic::pecoff_executable: case file_magic::bitcode: + case file_magic::xcoff_object_32: + case file_magic::xcoff_object_64: case file_magic::wasm_object: return ObjectFile::createSymbolicFile(Buffer, Type, Context); case file_magic::macho_universal_binary: @@ -82,6 +84,8 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer, case file_magic::coff_cl_gl_object: // Unrecognized object file format. return errorCodeToError(object_error::invalid_file_type); + case file_magic::minidump: + return MinidumpFile::create(Buffer); } llvm_unreachable("Unexpected Binary File Type"); } diff --git a/lib/Object/COFFImportFile.cpp b/lib/Object/COFFImportFile.cpp index dc11cc4bcffe..ff4a799be60c 100644 --- a/lib/Object/COFFImportFile.cpp +++ b/lib/Object/COFFImportFile.cpp @@ -1,9 +1,8 @@ //===- COFFImportFile.cpp - COFF short import file implementation ---------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -496,7 +495,7 @@ NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, // COFF Header coff_file_header Header{ - u16(0), + u16(Machine), u16(NumberOfSections), u32(0), u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))), @@ -596,7 +595,10 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path, ImportType = IMPORT_CONST; StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; - ImportNameType NameType = getNameType(SymbolName, E.Name, Machine, MinGW); + ImportNameType NameType = E.Noname + ? IMPORT_ORDINAL + : getNameType(SymbolName, E.Name, + Machine, MinGW); Expected<std::string> Name = E.ExtName.empty() ? SymbolName : replace(SymbolName, E.Name, E.ExtName); diff --git a/lib/Object/COFFModuleDefinition.cpp b/lib/Object/COFFModuleDefinition.cpp index c703071b86e0..64d4cf0efda2 100644 --- a/lib/Object/COFFModuleDefinition.cpp +++ b/lib/Object/COFFModuleDefinition.cpp @@ -1,9 +1,8 @@ //===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===// // -// 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/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index fc1deeba339a..854664e679df 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -1,9 +1,8 @@ //===- COFFObjectFile.cpp - COFF object file implementation ---------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -270,10 +269,9 @@ void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const { Ref.p = reinterpret_cast<uintptr_t>(Sec); } -std::error_code COFFObjectFile::getSectionName(DataRefImpl Ref, - StringRef &Result) const { +Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); - return getSectionName(Sec, Result); + return getSectionName(Sec); } uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const { @@ -294,13 +292,13 @@ uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const { return getSectionSize(toSec(Ref)); } -std::error_code COFFObjectFile::getSectionContents(DataRefImpl Ref, - StringRef &Result) const { +Expected<ArrayRef<uint8_t>> +COFFObjectFile::getSectionContents(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); ArrayRef<uint8_t> Res; - std::error_code EC = getSectionContents(Sec, Res); - Result = StringRef(reinterpret_cast<const char*>(Res.data()), Res.size()); - return EC; + if (Error E = getSectionContents(Sec, Res)) + return std::move(E); + return Res; } uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const { @@ -1075,8 +1073,8 @@ uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const { return Index; } -std::error_code COFFObjectFile::getSectionName(const coff_section *Sec, - StringRef &Res) const { +Expected<StringRef> +COFFObjectFile::getSectionName(const coff_section *Sec) const { StringRef Name; if (Sec->Name[COFF::NameSize - 1] == 0) // Null terminated, let ::strlen figure out the length. @@ -1090,17 +1088,18 @@ std::error_code COFFObjectFile::getSectionName(const coff_section *Sec, uint32_t Offset; if (Name.startswith("//")) { if (decodeBase64StringEntry(Name.substr(2), Offset)) - return object_error::parse_failed; + return createStringError(object_error::parse_failed, + "inalid section name"); } else { if (Name.substr(1).getAsInteger(10, Offset)) - return object_error::parse_failed; + return createStringError(object_error::parse_failed, + "invalid section name"); } if (std::error_code EC = getString(Offset, Name)) - return EC; + return errorCodeToError(EC); } - Res = Name; - return std::error_code(); + return Name; } uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const { @@ -1119,22 +1118,21 @@ uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const { return Sec->SizeOfRawData; } -std::error_code -COFFObjectFile::getSectionContents(const coff_section *Sec, - ArrayRef<uint8_t> &Res) const { +Error COFFObjectFile::getSectionContents(const coff_section *Sec, + ArrayRef<uint8_t> &Res) const { // In COFF, a virtual section won't have any in-file // content, so the file pointer to the content will be zero. if (Sec->PointerToRawData == 0) - return std::error_code(); + return Error::success(); // The only thing that we need to verify is that the contents is contained // within the file bounds. We don't need to make sure it doesn't cover other // data, as there's nothing that says that is not allowed. uintptr_t ConStart = uintptr_t(base()) + Sec->PointerToRawData; uint32_t SectionSize = getSectionSize(Sec); if (checkOffset(Data, ConStart, SectionSize)) - return object_error::parse_failed; + return make_error<BinaryError>(); Res = makeArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize); - return std::error_code(); + return Error::success(); } const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const { @@ -1237,6 +1235,7 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A); @@ -1244,6 +1243,7 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR); default: return "Unknown"; } @@ -1267,6 +1267,7 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14); + LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32); default: return "Unknown"; } @@ -1455,7 +1456,7 @@ std::error_code DelayImportDirectoryEntryRef::getName(StringRef &Result) const { std::error_code DelayImportDirectoryEntryRef:: getDelayImportTable(const delay_import_directory_table_entry *&Result) const { - Result = Table; + Result = &Table[Index]; return std::error_code(); } diff --git a/lib/Object/Decompressor.cpp b/lib/Object/Decompressor.cpp index 53f084d7620e..ec15e6f69ada 100644 --- a/lib/Object/Decompressor.cpp +++ b/lib/Object/Decompressor.cpp @@ -1,9 +1,8 @@ //===-- Decompressor.cpp --------------------------------------------------===// // -// 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/lib/Object/ELF.cpp b/lib/Object/ELF.cpp index cf8313f88f93..8660b1a64bdd 100644 --- a/lib/Object/ELF.cpp +++ b/lib/Object/ELF.cpp @@ -1,9 +1,8 @@ //===- ELF.cpp - ELF object file implementation ---------------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -220,8 +219,8 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_REGINFO); STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_OPTIONS); - STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS); STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_DWARF); + STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS); } break; default: @@ -254,6 +253,8 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LINKER_OPTIONS); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG); + STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_DEPENDENT_LIBRARIES); + STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef); @@ -425,7 +426,7 @@ ELFFile<ELFT>::android_relas(const Elf_Shdr *Sec) const { } template <class ELFT> -const char *ELFFile<ELFT>::getDynamicTagAsString(unsigned Arch, +std::string ELFFile<ELFT>::getDynamicTagAsString(unsigned Arch, uint64_t Type) const { #define DYNAMIC_STRINGIFY_ENUM(tag, value) \ case value: \ @@ -433,12 +434,21 @@ const char *ELFFile<ELFT>::getDynamicTagAsString(unsigned Arch, #define DYNAMIC_TAG(n, v) switch (Arch) { + case ELF::EM_AARCH64: + switch (Type) { +#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) +#include "llvm/BinaryFormat/DynamicTags.def" +#undef AARCH64_DYNAMIC_TAG + } + break; + case ELF::EM_HEXAGON: switch (Type) { #define HEXAGON_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) #include "llvm/BinaryFormat/DynamicTags.def" #undef HEXAGON_DYNAMIC_TAG } + break; case ELF::EM_MIPS: switch (Type) { @@ -446,6 +456,7 @@ const char *ELFFile<ELFT>::getDynamicTagAsString(unsigned Arch, #include "llvm/BinaryFormat/DynamicTags.def" #undef MIPS_DYNAMIC_TAG } + break; case ELF::EM_PPC64: switch (Type) { @@ -453,10 +464,12 @@ const char *ELFFile<ELFT>::getDynamicTagAsString(unsigned Arch, #include "llvm/BinaryFormat/DynamicTags.def" #undef PPC64_DYNAMIC_TAG } + break; } #undef DYNAMIC_TAG switch (Type) { // Now handle all dynamic tags except the architecture specific ones +#define AARCH64_DYNAMIC_TAG(name, value) #define MIPS_DYNAMIC_TAG(name, value) #define HEXAGON_DYNAMIC_TAG(name, value) #define PPC64_DYNAMIC_TAG(name, value) @@ -465,18 +478,19 @@ const char *ELFFile<ELFT>::getDynamicTagAsString(unsigned Arch, #define DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value) #include "llvm/BinaryFormat/DynamicTags.def" #undef DYNAMIC_TAG +#undef AARCH64_DYNAMIC_TAG #undef MIPS_DYNAMIC_TAG #undef HEXAGON_DYNAMIC_TAG #undef PPC64_DYNAMIC_TAG #undef DYNAMIC_TAG_MARKER #undef DYNAMIC_STRINGIFY_ENUM default: - return "unknown"; + return "<unknown:>0x" + utohexstr(Type, true); } } template <class ELFT> -const char *ELFFile<ELFT>::getDynamicTagAsString(uint64_t Type) const { +std::string ELFFile<ELFT>::getDynamicTagAsString(uint64_t Type) const { return getDynamicTagAsString(getHeader()->e_machine, Type); } @@ -523,12 +537,15 @@ Expected<typename ELFT::DynRange> ELFFile<ELFT>::dynamicEntries() const { } if (Dyn.empty()) + // TODO: this error is untested. return createError("invalid empty dynamic section"); if (DynSecSize % sizeof(Elf_Dyn) != 0) + // TODO: this error is untested. return createError("malformed dynamic section"); if (Dyn.back().d_tag != ELF::DT_NULL) + // TODO: this error is untested. return createError("dynamic sections must be DT_NULL terminated"); return Dyn; @@ -553,12 +570,14 @@ Expected<const uint8_t *> ELFFile<ELFT>::toMappedAddr(uint64_t VAddr) const { }); if (I == LoadSegments.begin()) - return createError("Virtual address is not in any segment"); + return createError("virtual address is not in any segment: 0x" + + Twine::utohexstr(VAddr)); --I; const Elf_Phdr &Phdr = **I; uint64_t Delta = VAddr - Phdr.p_vaddr; if (Delta >= Phdr.p_filesz) - return createError("Virtual address is not in any segment"); + return createError("virtual address is not in any segment: 0x" + + Twine::utohexstr(VAddr)); return base() + Phdr.p_offset + Delta; } diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp index 9fb3a55ac7b1..c7b715793048 100644 --- a/lib/Object/ELFObjectFile.cpp +++ b/lib/Object/ELFObjectFile.cpp @@ -1,9 +1,8 @@ //===- ELFObjectFile.cpp - ELF object file implementation -----------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -36,6 +35,16 @@ using namespace llvm; using namespace object; +const EnumEntry<unsigned> llvm::object::ElfSymbolTypes[NumElfSymbolTypes] = { + {"None", "NOTYPE", ELF::STT_NOTYPE}, + {"Object", "OBJECT", ELF::STT_OBJECT}, + {"Function", "FUNC", ELF::STT_FUNC}, + {"Section", "SECTION", ELF::STT_SECTION}, + {"File", "FILE", ELF::STT_FILE}, + {"Common", "COMMON", ELF::STT_COMMON}, + {"TLS", "TLS", ELF::STT_TLS}, + {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}}; + ELFObjectFileBase::ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source) : ObjectFile(Type, Source) {} @@ -139,8 +148,7 @@ SubtargetFeatures ELFObjectFileBase::getMIPSFeatures() const { SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { SubtargetFeatures Features; ARMAttributeParser Attributes; - std::error_code EC = getBuildAttributes(Attributes); - if (EC) + if (Error E = getBuildAttributes(Attributes)) return SubtargetFeatures(); // both ARMv7-M and R have to support thumb hardware div @@ -186,9 +194,9 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { default: break; case ARMBuildAttrs::Not_Allowed: - Features.AddFeature("vfp2", false); - Features.AddFeature("vfp3", false); - Features.AddFeature("vfp4", false); + Features.AddFeature("vfp2d16sp", false); + Features.AddFeature("vfp3d16sp", false); + Features.AddFeature("vfp4d16sp", false); break; case ARMBuildAttrs::AllowFPv2: Features.AddFeature("vfp2"); @@ -222,6 +230,24 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { } } + if (Attributes.hasAttribute(ARMBuildAttrs::MVE_arch)) { + switch(Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch)) { + default: + break; + case ARMBuildAttrs::Not_Allowed: + Features.AddFeature("mve", false); + Features.AddFeature("mve.fp", false); + break; + case ARMBuildAttrs::AllowMVEInteger: + Features.AddFeature("mve.fp", false); + Features.AddFeature("mve"); + break; + case ARMBuildAttrs::AllowMVEIntegerAndFloat: + Features.AddFeature("mve.fp"); + break; + } + } + if (Attributes.hasAttribute(ARMBuildAttrs::DIV_use)) { switch(Attributes.getAttributeValue(ARMBuildAttrs::DIV_use)) { default: @@ -270,8 +296,7 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { return; ARMAttributeParser Attributes; - std::error_code EC = getBuildAttributes(Attributes); - if (EC) + if (Error E = getBuildAttributes(Attributes)) return; std::string Triple; @@ -370,12 +395,13 @@ ELFObjectFileBase::getPltAddresses() const { } if (!Plt || !RelaPlt || !GotPlt) return {}; - StringRef PltContents; - if (Plt->getContents(PltContents)) + Expected<StringRef> PltContents = Plt->getContents(); + if (!PltContents) { + consumeError(PltContents.takeError()); return {}; - ArrayRef<uint8_t> PltBytes((const uint8_t *)PltContents.data(), - Plt->getSize()); - auto PltEntries = MIA->findPltEntries(Plt->getAddress(), PltBytes, + } + auto PltEntries = MIA->findPltEntries(Plt->getAddress(), + arrayRefFromStringRef(*PltContents), GotPlt->getAddress(), Triple); // Build a map from GOT entry virtual address to PLT entry virtual address. DenseMap<uint64_t, uint64_t> GotToPlt; diff --git a/lib/Object/Error.cpp b/lib/Object/Error.cpp index 6fa23e06c409..010c5b42dac2 100644 --- a/lib/Object/Error.cpp +++ b/lib/Object/Error.cpp @@ -1,9 +1,8 @@ //===- Error.cpp - 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 // //===----------------------------------------------------------------------===// // @@ -79,18 +78,15 @@ const std::error_category &object::object_category() { } llvm::Error llvm::object::isNotObjectErrorInvalidFileType(llvm::Error Err) { - if (auto Err2 = - handleErrors(std::move(Err), [](std::unique_ptr<ECError> M) -> Error { - // Try to handle 'M'. If successful, return a success value from - // the handler. - if (M->convertToErrorCode() == object_error::invalid_file_type) - return Error::success(); + return handleErrors(std::move(Err), [](std::unique_ptr<ECError> M) -> Error { + // Try to handle 'M'. If successful, return a success value from + // the handler. + if (M->convertToErrorCode() == object_error::invalid_file_type) + return Error::success(); - // We failed to handle 'M' - return it from the handler. - // This value will be passed back from catchErrors and - // wind up in Err2, where it will be returned from this function. - return Error(std::move(M)); - })) - return Err2; - return Err; + // We failed to handle 'M' - return it from the handler. + // This value will be passed back from catchErrors and + // wind up in Err2, where it will be returned from this function. + return Error(std::move(M)); + }); } diff --git a/lib/Object/IRObjectFile.cpp b/lib/Object/IRObjectFile.cpp index 1ecb26d60bce..636f1521262f 100644 --- a/lib/Object/IRObjectFile.cpp +++ b/lib/Object/IRObjectFile.cpp @@ -1,9 +1,8 @@ //===- IRObjectFile.cpp - 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 // //===----------------------------------------------------------------------===// // @@ -43,10 +42,9 @@ void IRObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.p += sizeof(ModuleSymbolTable::Symbol); } -std::error_code IRObjectFile::printSymbolName(raw_ostream &OS, - DataRefImpl Symb) const { +Error IRObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { SymTab.printSymbolName(OS, getSym(Symb)); - return std::error_code(); + return Error::success(); } uint32_t IRObjectFile::getSymbolFlags(DataRefImpl Symb) const { @@ -76,10 +74,12 @@ Expected<MemoryBufferRef> IRObjectFile::findBitcodeInObject(const ObjectFile &Obj) { for (const SectionRef &Sec : Obj.sections()) { if (Sec.isBitcode()) { - StringRef SecContents; - if (std::error_code EC = Sec.getContents(SecContents)) - return errorCodeToError(EC); - return MemoryBufferRef(SecContents, Obj.getFileName()); + Expected<StringRef> Contents = Sec.getContents(); + if (!Contents) + return Contents.takeError(); + if (Contents->size() <= 1) + return errorCodeToError(object_error::bitcode_section_not_found); + return MemoryBufferRef(*Contents, Obj.getFileName()); } } diff --git a/lib/Object/IRSymtab.cpp b/lib/Object/IRSymtab.cpp index 344d565349c0..e4282b9d6bd3 100644 --- a/lib/Object/IRSymtab.cpp +++ b/lib/Object/IRSymtab.cpp @@ -1,9 +1,8 @@ //===- IRSymtab.cpp - implementation of IR symbol tables ------------------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -90,6 +89,8 @@ struct Builder { std::string COFFLinkerOpts; raw_string_ostream COFFLinkerOptsOS{COFFLinkerOpts}; + std::vector<storage::Str> DependentLibraries; + void setStr(storage::Str &S, StringRef Value) { S.Offset = StrtabBuilder.add(Value); S.Size = Value.size(); @@ -141,6 +142,20 @@ Error Builder::addModule(Module *M) { } } + if (TT.isOSBinFormatELF()) { + if (auto E = M->materializeMetadata()) + return E; + if (NamedMDNode *N = M->getNamedMetadata("llvm.dependent-libraries")) { + for (MDNode *MDOptions : N->operands()) { + const auto OperandStr = + cast<MDString>(cast<MDNode>(MDOptions)->getOperand(0))->getString(); + storage::Str Specifier; + setStr(Specifier, OperandStr); + DependentLibraries.emplace_back(Specifier); + } + } + } + for (ModuleSymbolTable::Symbol Msym : Msymtab.symbols()) if (Error Err = addSymbol(Msymtab, Used, Msym)) return Err; @@ -313,7 +328,7 @@ Error Builder::build(ArrayRef<Module *> IRMods) { writeRange(Hdr.Comdats, Comdats); writeRange(Hdr.Symbols, Syms); writeRange(Hdr.Uncommons, Uncommons); - + writeRange(Hdr.DependentLibraries, DependentLibraries); *reinterpret_cast<storage::Header *>(Symtab.data()) = Hdr; return Error::success(); } diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index ce4d1cf92e20..5aec844003c0 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -1,9 +1,8 @@ //===- MachOObjectFile.cpp - Mach-O object file binding -------------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -58,6 +57,12 @@ namespace { } // end anonymous namespace +static const std::array<StringRef, 17> validArchs = { + "i386", "x86_64", "x86_64h", "armv4t", "arm", "armv5e", + "armv6", "armv6m", "armv7", "armv7em", "armv7k", "armv7m", + "armv7s", "arm64", "arm64_32", "ppc", "ppc64", +}; + static Error malformedError(const Twine &Msg) { return make_error<GenericBinaryError>("truncated or malformed object (" + Msg + ")", @@ -292,7 +297,10 @@ static Error parseSegmentLoadCommand( for (unsigned J = 0; J < S.nsects; ++J) { const char *Sec = getSectionPtr(Obj, Load, J); Sections.push_back(Sec); - Section s = getStruct<Section>(Obj, Sec); + auto SectionOrErr = getStructOrErr<Section>(Obj, Sec); + if (!SectionOrErr) + return SectionOrErr.takeError(); + Section s = SectionOrErr.get(); if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB && Obj.getHeader().filetype != MachO::MH_DSYM && s.flags != MachO::S_ZEROFILL && @@ -402,8 +410,10 @@ static Error checkSymtabCommand(const MachOObjectFile &Obj, " LC_SYMTAB cmdsize too small"); if (*SymtabLoadCmd != nullptr) return malformedError("more than one LC_SYMTAB command"); - MachO::symtab_command Symtab = - getStruct<MachO::symtab_command>(Obj, Load.Ptr); + auto SymtabOrErr = getStructOrErr<MachO::symtab_command>(Obj, Load.Ptr); + if (!SymtabOrErr) + return SymtabOrErr.takeError(); + MachO::symtab_command Symtab = SymtabOrErr.get(); if (Symtab.cmdsize != sizeof(MachO::symtab_command)) return malformedError("LC_SYMTAB command " + Twine(LoadCommandIndex) + " has incorrect cmdsize"); @@ -458,8 +468,11 @@ static Error checkDysymtabCommand(const MachOObjectFile &Obj, " LC_DYSYMTAB cmdsize too small"); if (*DysymtabLoadCmd != nullptr) return malformedError("more than one LC_DYSYMTAB command"); - MachO::dysymtab_command Dysymtab = - getStruct<MachO::dysymtab_command>(Obj, Load.Ptr); + auto DysymtabOrErr = + getStructOrErr<MachO::dysymtab_command>(Obj, Load.Ptr); + if (!DysymtabOrErr) + return DysymtabOrErr.takeError(); + MachO::dysymtab_command Dysymtab = DysymtabOrErr.get(); if (Dysymtab.cmdsize != sizeof(MachO::dysymtab_command)) return malformedError("LC_DYSYMTAB command " + Twine(LoadCommandIndex) + " has incorrect cmdsize"); @@ -589,8 +602,11 @@ static Error checkLinkeditDataCommand(const MachOObjectFile &Obj, CmdName + " cmdsize too small"); if (*LoadCmd != nullptr) return malformedError("more than one " + Twine(CmdName) + " command"); - MachO::linkedit_data_command LinkData = - getStruct<MachO::linkedit_data_command>(Obj, Load.Ptr); + auto LinkDataOrError = + getStructOrErr<MachO::linkedit_data_command>(Obj, Load.Ptr); + if (!LinkDataOrError) + return LinkDataOrError.takeError(); + MachO::linkedit_data_command LinkData = LinkDataOrError.get(); if (LinkData.cmdsize != sizeof(MachO::linkedit_data_command)) return malformedError(Twine(CmdName) + " command " + Twine(LoadCommandIndex) + " has incorrect cmdsize"); @@ -624,8 +640,11 @@ static Error checkDyldInfoCommand(const MachOObjectFile &Obj, if (*LoadCmd != nullptr) return malformedError("more than one LC_DYLD_INFO and or LC_DYLD_INFO_ONLY " "command"); - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(Obj, Load.Ptr); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(Obj, Load.Ptr); + if (!DyldInfoOrErr) + return DyldInfoOrErr.takeError(); + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); if (DyldInfo.cmdsize != sizeof(MachO::dyld_info_command)) return malformedError(Twine(CmdName) + " command " + Twine(LoadCommandIndex) + " has incorrect cmdsize"); @@ -715,7 +734,10 @@ static Error checkDylibCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::dylib_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " cmdsize too small"); - MachO::dylib_command D = getStruct<MachO::dylib_command>(Obj, Load.Ptr); + auto CommandOrErr = getStructOrErr<MachO::dylib_command>(Obj, Load.Ptr); + if (!CommandOrErr) + return CommandOrErr.takeError(); + MachO::dylib_command D = CommandOrErr.get(); if (D.dylib.name < sizeof(MachO::dylib_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " name.offset field too small, not past " @@ -761,7 +783,10 @@ static Error checkDyldCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::dylinker_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " cmdsize too small"); - MachO::dylinker_command D = getStruct<MachO::dylinker_command>(Obj, Load.Ptr); + auto CommandOrErr = getStructOrErr<MachO::dylinker_command>(Obj, Load.Ptr); + if (!CommandOrErr) + return CommandOrErr.takeError(); + MachO::dylinker_command D = CommandOrErr.get(); if (D.name < sizeof(MachO::dylinker_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " name.offset field too small, not past " @@ -806,7 +831,10 @@ static Error checkNoteCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize != sizeof(MachO::note_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " LC_NOTE has incorrect cmdsize"); - MachO::note_command Nt = getStruct<MachO::note_command>(Obj, Load.Ptr); + auto NoteCmdOrErr = getStructOrErr<MachO::note_command>(Obj, Load.Ptr); + if (!NoteCmdOrErr) + return NoteCmdOrErr.takeError(); + MachO::note_command Nt = NoteCmdOrErr.get(); uint64_t FileSize = Obj.getData().size(); if (Nt.offset > FileSize) return malformedError("offset field of LC_NOTE command " + @@ -829,8 +857,11 @@ parseBuildVersionCommand(const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &Load, SmallVectorImpl<const char*> &BuildTools, uint32_t LoadCommandIndex) { - MachO::build_version_command BVC = - getStruct<MachO::build_version_command>(Obj, Load.Ptr); + auto BVCOrErr = + getStructOrErr<MachO::build_version_command>(Obj, Load.Ptr); + if (!BVCOrErr) + return BVCOrErr.takeError(); + MachO::build_version_command BVC = BVCOrErr.get(); if (Load.C.cmdsize != sizeof(MachO::build_version_command) + BVC.ntools * sizeof(MachO::build_tool_version)) @@ -851,7 +882,10 @@ static Error checkRpathCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::rpath_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " LC_RPATH cmdsize too small"); - MachO::rpath_command R = getStruct<MachO::rpath_command>(Obj, Load.Ptr); + auto ROrErr = getStructOrErr<MachO::rpath_command>(Obj, Load.Ptr); + if (!ROrErr) + return ROrErr.takeError(); + MachO::rpath_command R = ROrErr.get(); if (R.path < sizeof(MachO::rpath_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " LC_RPATH path.offset field too small, not past " @@ -904,8 +938,11 @@ static Error checkLinkerOptCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::linker_option_command)) return malformedError("load command " + Twine(LoadCommandIndex) + " LC_LINKER_OPTION cmdsize too small"); - MachO::linker_option_command L = - getStruct<MachO::linker_option_command>(Obj, Load.Ptr); + auto LinkOptionOrErr = + getStructOrErr<MachO::linker_option_command>(Obj, Load.Ptr); + if (!LinkOptionOrErr) + return LinkOptionOrErr.takeError(); + MachO::linker_option_command L = LinkOptionOrErr.get(); // Make sure the count of strings is correct. const char *string = (const char *)Load.Ptr + sizeof(struct MachO::linker_option_command); @@ -919,6 +956,10 @@ static Error checkLinkerOptCommand(const MachOObjectFile &Obj, if (left > 0) { i++; uint32_t NullPos = StringRef(string, left).find('\0'); + if (0xffffffff == NullPos) + return malformedError("load command " + Twine(LoadCommandIndex) + + " LC_LINKER_OPTION string #" + Twine(i) + + " is not NULL terminated"); uint32_t len = std::min(NullPos, left) + 1; string += len; left -= len; @@ -965,8 +1006,11 @@ static Error checkThreadCommand(const MachOObjectFile &Obj, if (Load.C.cmdsize < sizeof(MachO::thread_command)) return malformedError("load command " + Twine(LoadCommandIndex) + CmdName + " cmdsize too small"); - MachO::thread_command T = - getStruct<MachO::thread_command>(Obj, Load.Ptr); + auto ThreadCommandOrErr = + getStructOrErr<MachO::thread_command>(Obj, Load.Ptr); + if (!ThreadCommandOrErr) + return ThreadCommandOrErr.takeError(); + MachO::thread_command T = ThreadCommandOrErr.get(); const char *state = Load.Ptr + sizeof(MachO::thread_command); const char *end = Load.Ptr + T.cmdsize; uint32_t nflavor = 0; @@ -1097,7 +1141,8 @@ static Error checkThreadCommand(const MachOObjectFile &Obj, "flavor number " + Twine(nflavor) + " in " + CmdName + " command"); } - } else if (cputype == MachO::CPU_TYPE_ARM64) { + } else if (cputype == MachO::CPU_TYPE_ARM64 || + cputype == MachO::CPU_TYPE_ARM64_32) { if (flavor == MachO::ARM_THREAD_STATE64) { if (count != MachO::ARM_THREAD_STATE64_COUNT) return malformedError("load command " + Twine(LoadCommandIndex) + @@ -1156,8 +1201,10 @@ static Error checkTwoLevelHintsCommand(const MachOObjectFile &Obj, " LC_TWOLEVEL_HINTS has incorrect cmdsize"); if (*LoadCmd != nullptr) return malformedError("more than one LC_TWOLEVEL_HINTS command"); - MachO::twolevel_hints_command Hints = - getStruct<MachO::twolevel_hints_command>(Obj, Load.Ptr); + auto HintsOrErr = getStructOrErr<MachO::twolevel_hints_command>(Obj, Load.Ptr); + if(!HintsOrErr) + return HintsOrErr.takeError(); + MachO::twolevel_hints_command Hints = HintsOrErr.get(); uint64_t FileSize = Obj.getData().size(); if (Hints.offset > FileSize) return malformedError("offset field of LC_TWOLEVEL_HINTS command " + @@ -1658,36 +1705,35 @@ Error MachOObjectFile::checkSymbolTable() const { } else { MachO::nlist STE = getSymbolTableEntry(SymDRI); NType = STE.n_type; - NType = STE.n_type; NSect = STE.n_sect; NDesc = STE.n_desc; NStrx = STE.n_strx; NValue = STE.n_value; } - if ((NType & MachO::N_STAB) == 0 && - (NType & MachO::N_TYPE) == MachO::N_SECT) { - if (NSect == 0 || NSect > Sections.size()) - return malformedError("bad section index: " + Twine((int)NSect) + - " for symbol at index " + Twine(SymbolIndex)); - } - if ((NType & MachO::N_STAB) == 0 && - (NType & MachO::N_TYPE) == MachO::N_INDR) { - if (NValue >= S.strsize) - return malformedError("bad n_value: " + Twine((int)NValue) + " past " - "the end of string table, for N_INDR symbol at " - "index " + Twine(SymbolIndex)); - } - if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL && - (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) || - (NType & MachO::N_TYPE) == MachO::N_PBUD)) { - uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc); - if (LibraryOrdinal != 0 && - LibraryOrdinal != MachO::EXECUTABLE_ORDINAL && - LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL && - LibraryOrdinal - 1 >= Libraries.size() ) { - return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) + - " for symbol at index " + Twine(SymbolIndex)); + if ((NType & MachO::N_STAB) == 0) { + if ((NType & MachO::N_TYPE) == MachO::N_SECT) { + if (NSect == 0 || NSect > Sections.size()) + return malformedError("bad section index: " + Twine((int)NSect) + + " for symbol at index " + Twine(SymbolIndex)); + } + if ((NType & MachO::N_TYPE) == MachO::N_INDR) { + if (NValue >= S.strsize) + return malformedError("bad n_value: " + Twine((int)NValue) + " past " + "the end of string table, for N_INDR symbol at " + "index " + Twine(SymbolIndex)); } + if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL && + (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) || + (NType & MachO::N_TYPE) == MachO::N_PBUD)) { + uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc); + if (LibraryOrdinal != 0 && + LibraryOrdinal != MachO::EXECUTABLE_ORDINAL && + LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL && + LibraryOrdinal - 1 >= Libraries.size() ) { + return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) + + " for symbol at index " + Twine(SymbolIndex)); + } + } } if (NStrx >= S.strsize) return malformedError("bad string table index: " + Twine((int)NStrx) + @@ -1861,11 +1907,9 @@ void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } -std::error_code MachOObjectFile::getSectionName(DataRefImpl Sec, - StringRef &Result) const { +Expected<StringRef> MachOObjectFile::getSectionName(DataRefImpl Sec) const { ArrayRef<char> Raw = getSectionRawName(Sec); - Result = parseSegmentOrSectionName(Raw.data()); - return std::error_code(); + return parseSegmentOrSectionName(Raw.data()); } uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const { @@ -1907,8 +1951,8 @@ uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const { return SectSize; } -std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, - StringRef &Res) const { +Expected<ArrayRef<uint8_t>> +MachOObjectFile::getSectionContents(DataRefImpl Sec) const { uint32_t Offset; uint64_t Size; @@ -1922,8 +1966,7 @@ std::error_code MachOObjectFile::getSectionContents(DataRefImpl Sec, Size = Sect.size; } - Res = this->getData().substr(Offset, Size); - return std::error_code(); + return arrayRefFromStringRef(getData().substr(Offset, Size)); } uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const { @@ -1998,9 +2041,8 @@ bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const { bool MachOObjectFile::isSectionBitcode(DataRefImpl Sec) const { StringRef SegmentName = getSectionFinalSegmentName(Sec); - StringRef SectName; - if (!getSectionName(Sec, SectName)) - return (SegmentName == "__LLVM" && SectName == "__bitcode"); + if (Expected<StringRef> NameOrErr = getSectionName(Sec)) + return (SegmentName == "__LLVM" && *NameOrErr == "__bitcode"); return false; } @@ -2172,7 +2214,8 @@ void MachOObjectFile::getRelocationTypeName( res = Table[RType]; break; } - case Triple::aarch64: { + case Triple::aarch64: + case Triple::aarch64_32: { static const char *const Table[] = { "ARM64_RELOC_UNSIGNED", "ARM64_RELOC_SUBTRACTOR", "ARM64_RELOC_BRANCH26", "ARM64_RELOC_PAGE21", @@ -2242,9 +2285,18 @@ uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const { // one of the two following forms: // libFoo.A.dylib // libFoo.dylib +// // The library may have a suffix trailing the name Foo of the form: // libFoo_profile.A.dylib // libFoo_profile.dylib +// These dyld image suffixes are separated from the short name by a '_' +// character. Because the '_' character is commonly used to separate words in +// filenames guessLibraryShortName() cannot reliably separate a dylib's short +// name from an arbitrary image suffix; imagine if both the short name and the +// suffix contains an '_' character! To better deal with this ambiguity, +// guessLibraryShortName() will recognize only "_debug" and "_profile" as valid +// Suffix values. Calling code needs to be tolerant of guessLibraryShortName() +// guessing incorrectly. // // The Name of the dynamic library is also recognized as a library name if it // has the following form: @@ -2252,7 +2304,6 @@ uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const { // // If the Name of the dynamic library is none of the forms above then a NULL // StringRef is returned. -// StringRef MachOObjectFile::guessLibraryShortName(StringRef Name, bool &isFramework, StringRef &Suffix) { @@ -2272,7 +2323,10 @@ StringRef MachOObjectFile::guessLibraryShortName(StringRef Name, Idx = Foo.rfind('_'); if (Idx != Foo.npos && Foo.size() >= 2) { Suffix = Foo.slice(Idx, Foo.npos); - Foo = Foo.slice(0, Idx); + if (Suffix != "_debug" && Suffix != "_profile") + Suffix = StringRef(); + else + Foo = Foo.slice(0, Idx); } // First look for the form Foo.framework/Foo @@ -2333,10 +2387,14 @@ guess_library: else b = b+1; // ignore any suffix after an underbar like Foo_profile.A.dylib - Idx = Name.find('_', b); + Idx = Name.rfind('_'); if (Idx != Name.npos && Idx != b) { Lib = Name.slice(b, Idx); Suffix = Name.slice(Idx, a); + if (Suffix != "_debug" && Suffix != "_profile") { + Suffix = StringRef(); + Lib = Name.slice(b, a); + } } else Lib = Name.slice(b, a); @@ -2381,8 +2439,11 @@ std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, // all the Libraries. if (LibrariesShortNames.size() == 0) { for (unsigned i = 0; i < Libraries.size(); i++) { - MachO::dylib_command D = - getStruct<MachO::dylib_command>(*this, Libraries[i]); + auto CommandOrErr = + getStructOrErr<MachO::dylib_command>(*this, Libraries[i]); + if (!CommandOrErr) + return object_error::parse_failed; + MachO::dylib_command D = CommandOrErr.get(); if (D.dylib.name >= D.cmdsize) return object_error::parse_failed; const char *P = (const char *)(Libraries[i]) + D.dylib.name; @@ -2485,6 +2546,8 @@ StringRef MachOObjectFile::getFileFormatName() const { return "Mach-O 32-bit i386"; case MachO::CPU_TYPE_ARM: return "Mach-O arm"; + case MachO::CPU_TYPE_ARM64_32: + return "Mach-O arm64 (ILP32)"; case MachO::CPU_TYPE_POWERPC: return "Mach-O 32-bit ppc"; default: @@ -2514,6 +2577,8 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { return Triple::arm; case MachO::CPU_TYPE_ARM64: return Triple::aarch64; + case MachO::CPU_TYPE_ARM64_32: + return Triple::aarch64_32; case MachO::CPU_TYPE_POWERPC: return Triple::ppc; case MachO::CPU_TYPE_POWERPC64: @@ -2620,6 +2685,17 @@ Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType, default: return Triple(); } + case MachO::CPU_TYPE_ARM64_32: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM64_32_V8: + if (McpuDefault) + *McpuDefault = "cyclone"; + if (ArchFlag) + *ArchFlag = "arm64_32"; + return Triple("arm64_32-apple-darwin"); + default: + return Triple(); + } case MachO::CPU_TYPE_POWERPC: switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { case MachO::CPU_SUBTYPE_POWERPC_ALL: @@ -2648,26 +2724,12 @@ Triple MachOObjectFile::getHostArch() { } bool MachOObjectFile::isValidArch(StringRef ArchFlag) { - return StringSwitch<bool>(ArchFlag) - .Case("i386", true) - .Case("x86_64", true) - .Case("x86_64h", true) - .Case("armv4t", true) - .Case("arm", true) - .Case("armv5e", true) - .Case("armv6", true) - .Case("armv6m", true) - .Case("armv7", true) - .Case("armv7em", true) - .Case("armv7k", true) - .Case("armv7m", true) - .Case("armv7s", true) - .Case("arm64", true) - .Case("ppc", true) - .Case("ppc64", true) - .Default(false); + return std::find(validArchs.cbegin(), validArchs.cend(), ArchFlag) != + validArchs.cend(); } +ArrayRef<StringRef> MachOObjectFile::getValidArchs() { return validArchs; } + Triple::ArchType MachOObjectFile::getArch() const { return getArch(getCPUType(*this)); } @@ -3102,8 +3164,8 @@ void MachORebaseEntry::moveNext() { moveToEnd(); return; } - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3127,8 +3189,8 @@ void MachORebaseEntry::moveNext() { moveToEnd(); return; } - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3142,8 +3204,8 @@ void MachORebaseEntry::moveNext() { SegmentOffset) << "\n"); break; case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " + Twine(error) + " for opcode at: 0x" + @@ -3152,8 +3214,8 @@ void MachORebaseEntry::moveNext() { return; } SegmentOffset += ImmValue * PointerSize; - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - false); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " @@ -3169,15 +3231,6 @@ void MachORebaseEntry::moveNext() { SegmentOffset) << "\n"); break; case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); - if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } AdvanceAmount = PointerSize; Skip = 0; Count = ImmValue; @@ -3185,8 +3238,8 @@ void MachORebaseEntry::moveNext() { RemainingLoopCount = ImmValue - 1; else RemainingLoopCount = 0; - error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + Twine(error) + " for opcode at: 0x" + @@ -3203,15 +3256,6 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); - if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } AdvanceAmount = PointerSize; Skip = 0; Count = readULEB128(&error); @@ -3226,8 +3270,8 @@ void MachORebaseEntry::moveNext() { RemainingLoopCount = Count - 1; else RemainingLoopCount = 0; - error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + Twine(error) + " for opcode at: 0x" + @@ -3244,15 +3288,6 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); - if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } Skip = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + @@ -3264,8 +3299,8 @@ void MachORebaseEntry::moveNext() { AdvanceAmount = Skip + PointerSize; Count = 1; RemainingLoopCount = 0; - error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3282,16 +3317,6 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: - error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, - true); - if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" - "ULEB " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } Count = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" @@ -3316,8 +3341,8 @@ void MachORebaseEntry::moveNext() { } AdvanceAmount = Skip + PointerSize; - error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" "ULEB " + @@ -3624,7 +3649,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3648,7 +3674,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3664,7 +3691,8 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_DO_BIND: AdvanceAmount = PointerSize; RemainingLoopCount = 0; - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND " + Twine(error) + " for opcode at: 0x" + @@ -3701,7 +3729,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " + Twine(error) + " for opcode at: 0x" + @@ -3737,8 +3766,8 @@ void MachOBindEntry::moveNext() { // Note, this is not really an error until the next bind but make no sense // for a BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB to not be followed by another // bind operation. - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset + - AdvanceAmount, false); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset + + AdvanceAmount, PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB (after adding " "ULEB) " + @@ -3764,7 +3793,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " + Twine(error) + " for opcode at: 0x" + @@ -3792,8 +3822,8 @@ void MachOBindEntry::moveNext() { } AdvanceAmount = ImmValue * PointerSize + PointerSize; RemainingLoopCount = 0; - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset + - AdvanceAmount, false); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset + + AdvanceAmount, PointerSize); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " @@ -3839,15 +3869,6 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); - if (error) { - *E = - malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + - Twine(error) + " for opcode at: 0x" + - Twine::utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; - } if (SymbolName == StringRef()) { *E = malformedError( "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " @@ -3866,8 +3887,8 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - error = O->BindEntryCheckCountAndSkip(Count, Skip, PointerSize, - SegmentIndex, SegmentOffset); + error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset, + PointerSize, Count, Skip); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + @@ -3990,53 +4011,40 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) { MaxSegIndex = CurSegIndex; } -// For use with a SegIndex,SegOffset pair in MachOBindEntry::moveNext() to -// validate a MachOBindEntry or MachORebaseEntry. -const char * BindRebaseSegInfo::checkSegAndOffset(int32_t SegIndex, - uint64_t SegOffset, - bool endInvalid) { +// For use with a SegIndex, SegOffset, and PointerSize triple in +// MachOBindEntry::moveNext() to validate a MachOBindEntry or MachORebaseEntry. +// +// 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. +const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex, + uint64_t SegOffset, + uint8_t PointerSize, + uint32_t Count, + uint32_t Skip) { if (SegIndex == -1) return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"; if (SegIndex >= MaxSegIndex) return "bad segIndex (too large)"; - for (const SectionInfo &SI : Sections) { - if (SI.SegmentIndex != SegIndex) - continue; - if (SI.OffsetInSegment > SegOffset) - continue; - if (SegOffset > (SI.OffsetInSegment + SI.Size)) - continue; - if (endInvalid && SegOffset >= (SI.OffsetInSegment + SI.Size)) - continue; - return nullptr; - } - return "bad segOffset, too large"; -} - -// For use in MachOBindEntry::moveNext() to validate a MachOBindEntry for -// the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode and for use in -// MachORebaseEntry::moveNext() to validate a MachORebaseEntry for -// REBASE_OPCODE_DO_*_TIMES* opcodes. The SegIndex and SegOffset must have -// been already checked. -const char * BindRebaseSegInfo::checkCountAndSkip(uint32_t Count, uint32_t Skip, - uint8_t PointerSize, - int32_t SegIndex, - uint64_t SegOffset) { - const SectionInfo &SI = findSection(SegIndex, SegOffset); - uint64_t addr = SI.SegmentStartAddress + SegOffset; - if (addr >= SI.Address + SI.Size) - return "bad segOffset, too large"; - uint64_t i = 0; - if (Count > 1) - i = (Skip + PointerSize) * (Count - 1); - else if (Count == 1) - i = Skip + PointerSize; - if (addr + i >= SI.Address + SI.Size) { - // For rebase opcodes they can step from one section to another. - uint64_t TrailingSegOffset = (addr + i) - SI.SegmentStartAddress; - const char *error = checkSegAndOffset(SegIndex, TrailingSegOffset, false); - if (error) - return "bad count and skip, too large"; + for (uint32_t i = 0; i < Count; ++i) { + uint32_t Start = SegOffset + i * (PointerSize + Skip); + uint32_t End = Start + PointerSize; + bool Found = false; + for (const SectionInfo &SI : Sections) { + if (SI.SegmentIndex != SegIndex) + continue; + if ((SI.OffsetInSegment<=Start) && (Start<(SI.OffsetInSegment+SI.Size))) { + if (End <= SI.OffsetInSegment + SI.Size) { + Found = true; + break; + } + else + return "bad offset, extends beyond section boundary"; + } + } + if (!Found) + return "bad offset, not in section"; } return nullptr; } @@ -4514,8 +4522,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.rebase_off)); return makeArrayRef(Ptr, DyldInfo.rebase_size); @@ -4525,8 +4536,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.bind_off)); return makeArrayRef(Ptr, DyldInfo.bind_size); @@ -4536,8 +4550,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.weak_bind_off)); return makeArrayRef(Ptr, DyldInfo.weak_bind_size); @@ -4547,8 +4564,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.lazy_bind_off)); return makeArrayRef(Ptr, DyldInfo.lazy_bind_size); @@ -4558,8 +4578,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const { if (!DyldInfoLoadCmd) return None; - MachO::dyld_info_command DyldInfo = - getStruct<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + auto DyldInfoOrErr = + getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd); + if (!DyldInfoOrErr) + return None; + MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get(); const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.export_off)); return makeArrayRef(Ptr, DyldInfo.export_size); diff --git a/lib/Object/MachOUniversal.cpp b/lib/Object/MachOUniversal.cpp index 309708e9b37c..b3f0993412c6 100644 --- a/lib/Object/MachOUniversal.cpp +++ b/lib/Object/MachOUniversal.cpp @@ -1,9 +1,8 @@ //===- MachOUniversal.cpp - Mach-O universal binary -------------*- 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/lib/Object/Minidump.cpp b/lib/Object/Minidump.cpp new file mode 100644 index 000000000000..7b5b21558699 --- /dev/null +++ b/lib/Object/Minidump.cpp @@ -0,0 +1,137 @@ +//===- Minidump.cpp - Minidump object file implementation -----------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/Minidump.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/ConvertUTF.h" + +using namespace llvm; +using namespace llvm::object; +using namespace llvm::minidump; + +Optional<ArrayRef<uint8_t>> +MinidumpFile::getRawStream(minidump::StreamType Type) const { + auto It = StreamMap.find(Type); + if (It != StreamMap.end()) + return getRawStream(Streams[It->second]); + return None; +} + +Expected<std::string> MinidumpFile::getString(size_t Offset) const { + // Minidump strings consist of a 32-bit length field, which gives the size of + // the string in *bytes*. This is followed by the actual string encoded in + // UTF16. + auto ExpectedSize = + getDataSliceAs<support::ulittle32_t>(getData(), Offset, 1); + if (!ExpectedSize) + return ExpectedSize.takeError(); + size_t Size = (*ExpectedSize)[0]; + if (Size % 2 != 0) + return createError("String size not even"); + Size /= 2; + if (Size == 0) + return ""; + + Offset += sizeof(support::ulittle32_t); + auto ExpectedData = + getDataSliceAs<support::ulittle16_t>(getData(), Offset, Size); + if (!ExpectedData) + return ExpectedData.takeError(); + + SmallVector<UTF16, 32> WStr(Size); + copy(*ExpectedData, WStr.begin()); + + std::string Result; + if (!convertUTF16ToUTF8String(WStr, Result)) + return createError("String decoding failed"); + + return Result; +} + +template <typename T> +Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Stream) const { + auto OptionalStream = getRawStream(Stream); + if (!OptionalStream) + return createError("No such stream"); + auto ExpectedSize = + getDataSliceAs<support::ulittle32_t>(*OptionalStream, 0, 1); + if (!ExpectedSize) + return ExpectedSize.takeError(); + + size_t ListSize = ExpectedSize.get()[0]; + + size_t ListOffset = 4; + // Some producers insert additional padding bytes to align the list to an + // 8-byte boundary. Check for that by comparing the list size with the overall + // stream size. + if (ListOffset + sizeof(T) * ListSize < OptionalStream->size()) + ListOffset = 8; + + return getDataSliceAs<T>(*OptionalStream, ListOffset, ListSize); +} +template Expected<ArrayRef<Module>> + MinidumpFile::getListStream(StreamType) const; +template Expected<ArrayRef<Thread>> + MinidumpFile::getListStream(StreamType) const; +template Expected<ArrayRef<MemoryDescriptor>> + MinidumpFile::getListStream(StreamType) const; + +Expected<ArrayRef<uint8_t>> +MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) { + // Check for overflow. + if (Offset + Size < Offset || Offset + Size < Size || + Offset + Size > Data.size()) + return createEOFError(); + return Data.slice(Offset, Size); +} + +Expected<std::unique_ptr<MinidumpFile>> +MinidumpFile::create(MemoryBufferRef Source) { + ArrayRef<uint8_t> Data = arrayRefFromStringRef(Source.getBuffer()); + auto ExpectedHeader = getDataSliceAs<minidump::Header>(Data, 0, 1); + if (!ExpectedHeader) + return ExpectedHeader.takeError(); + + const minidump::Header &Hdr = (*ExpectedHeader)[0]; + if (Hdr.Signature != Header::MagicSignature) + return createError("Invalid signature"); + if ((Hdr.Version & 0xffff) != Header::MagicVersion) + return createError("Invalid version"); + + auto ExpectedStreams = getDataSliceAs<Directory>(Data, Hdr.StreamDirectoryRVA, + Hdr.NumberOfStreams); + if (!ExpectedStreams) + return ExpectedStreams.takeError(); + + DenseMap<StreamType, std::size_t> StreamMap; + for (const auto &Stream : llvm::enumerate(*ExpectedStreams)) { + StreamType Type = Stream.value().Type; + const LocationDescriptor &Loc = Stream.value().Location; + + auto ExpectedStream = getDataSlice(Data, Loc.RVA, Loc.DataSize); + if (!ExpectedStream) + return ExpectedStream.takeError(); + + if (Type == StreamType::Unused && Loc.DataSize == 0) { + // Ignore dummy streams. This is technically ill-formed, but a number of + // existing minidumps seem to contain such streams. + continue; + } + + if (Type == DenseMapInfo<StreamType>::getEmptyKey() || + Type == DenseMapInfo<StreamType>::getTombstoneKey()) + return createError("Cannot handle one of the minidump streams"); + + // Update the directory map, checking for duplicate stream types. + if (!StreamMap.try_emplace(Type, Stream.index()).second) + return createError("Duplicate stream type"); + } + + return std::unique_ptr<MinidumpFile>( + new MinidumpFile(Source, Hdr, *ExpectedStreams, std::move(StreamMap))); +} diff --git a/lib/Object/ModuleSymbolTable.cpp b/lib/Object/ModuleSymbolTable.cpp index 33ce7d8109fb..d1e0ce5edae1 100644 --- a/lib/Object/ModuleSymbolTable.cpp +++ b/lib/Object/ModuleSymbolTable.cpp @@ -1,9 +1,8 @@ //===- ModuleSymbolTable.cpp - symbol table for in-memory IR --------------===// // -// 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/lib/Object/Object.cpp b/lib/Object/Object.cpp index f5de2e1d5ce2..d84798cc6dd0 100644 --- a/lib/Object/Object.cpp +++ b/lib/Object/Object.cpp @@ -1,9 +1,8 @@ //===- Object.cpp - C bindings to the object file library--------*- 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,7 +13,9 @@ #include "llvm-c/Object.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/IR/LLVMContext.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/MachOUniversal.h" using namespace llvm; using namespace object; @@ -58,6 +59,121 @@ wrap(const relocation_iterator *SI) { (const_cast<relocation_iterator*>(SI)); } +/*--.. Operations on binary files ..........................................--*/ + +LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf, + LLVMContextRef Context, + char **ErrorMessage) { + auto maybeContext = Context ? unwrap(Context) : nullptr; + Expected<std::unique_ptr<Binary>> ObjOrErr( + createBinary(unwrap(MemBuf)->getMemBufferRef(), maybeContext)); + if (!ObjOrErr) { + *ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str()); + return nullptr; + } + + return wrap(ObjOrErr.get().release()); +} + +LLVMMemoryBufferRef LLVMBinaryCopyMemoryBuffer(LLVMBinaryRef BR) { + auto Buf = unwrap(BR)->getMemoryBufferRef(); + return wrap(llvm::MemoryBuffer::getMemBuffer( + Buf.getBuffer(), Buf.getBufferIdentifier(), + /*RequiresNullTerminator*/false).release()); +} + +void LLVMDisposeBinary(LLVMBinaryRef BR) { + delete unwrap(BR); +} + +LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) { + class BinaryTypeMapper final : public Binary { + public: + static LLVMBinaryType mapBinaryTypeToLLVMBinaryType(unsigned Kind) { + switch (Kind) { + case ID_Archive: + return LLVMBinaryTypeArchive; + case ID_MachOUniversalBinary: + return LLVMBinaryTypeMachOUniversalBinary; + case ID_COFFImportFile: + return LLVMBinaryTypeCOFFImportFile; + case ID_IR: + return LLVMBinaryTypeIR; + case ID_WinRes: + return LLVMBinaryTypeWinRes; + case ID_COFF: + return LLVMBinaryTypeCOFF; + case ID_ELF32L: + return LLVMBinaryTypeELF32L; + case ID_ELF32B: + return LLVMBinaryTypeELF32B; + case ID_ELF64L: + return LLVMBinaryTypeELF64L; + case ID_ELF64B: + return LLVMBinaryTypeELF64B; + case ID_MachO32L: + return LLVMBinaryTypeMachO32L; + case ID_MachO32B: + return LLVMBinaryTypeMachO32B; + case ID_MachO64L: + return LLVMBinaryTypeMachO64L; + case ID_MachO64B: + return LLVMBinaryTypeMachO64B; + case ID_Wasm: + return LLVMBinaryTypeWasm; + case ID_StartObjects: + case ID_EndObjects: + llvm_unreachable("Marker types are not valid binary kinds!"); + default: + llvm_unreachable("Unknown binary kind!"); + } + } + }; + return BinaryTypeMapper::mapBinaryTypeToLLVMBinaryType(unwrap(BR)->getType()); +} + +LLVMBinaryRef LLVMMachOUniversalBinaryCopyObjectForArch(LLVMBinaryRef BR, + const char *Arch, + size_t ArchLen, + char **ErrorMessage) { + auto universal = cast<MachOUniversalBinary>(unwrap(BR)); + Expected<std::unique_ptr<ObjectFile>> ObjOrErr( + universal->getObjectForArch({Arch, ArchLen})); + if (!ObjOrErr) { + *ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str()); + return nullptr; + } + return wrap(ObjOrErr.get().release()); +} + +LLVMSectionIteratorRef LLVMObjectFileCopySectionIterator(LLVMBinaryRef BR) { + auto OF = cast<ObjectFile>(unwrap(BR)); + auto sections = OF->sections(); + if (sections.begin() == sections.end()) + return nullptr; + return wrap(new section_iterator(sections.begin())); +} + +LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR, + LLVMSectionIteratorRef SI) { + auto OF = cast<ObjectFile>(unwrap(BR)); + return (*unwrap(SI) == OF->section_end()) ? 1 : 0; +} + +LLVMSymbolIteratorRef LLVMObjectFileCopySymbolIterator(LLVMBinaryRef BR) { + auto OF = cast<ObjectFile>(unwrap(BR)); + auto symbols = OF->symbols(); + if (symbols.begin() == symbols.end()) + return nullptr; + return wrap(new symbol_iterator(symbols.begin())); +} + +LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR, + LLVMSymbolIteratorRef SI) { + auto OF = cast<ObjectFile>(unwrap(BR)); + return (*unwrap(SI) == OF->symbol_end()) ? 1 : 0; +} + // ObjectFile creation LLVMObjectFileRef LLVMCreateObjectFile(LLVMMemoryBufferRef MemBuf) { std::unique_ptr<MemoryBuffer> Buf(unwrap(MemBuf)); @@ -146,10 +262,10 @@ uint64_t LLVMGetSectionSize(LLVMSectionIteratorRef SI) { } const char *LLVMGetSectionContents(LLVMSectionIteratorRef SI) { - StringRef ret; - if (std::error_code ec = (*unwrap(SI))->getContents(ret)) - report_fatal_error(ec.message()); - return ret.data(); + if (Expected<StringRef> E = (*unwrap(SI))->getContents()) + return E->data(); + else + report_fatal_error(E.takeError()); } uint64_t LLVMGetSectionAddress(LLVMSectionIteratorRef SI) { diff --git a/lib/Object/ObjectFile.cpp b/lib/Object/ObjectFile.cpp index cf63b89adc12..101f5dcc0821 100644 --- a/lib/Object/ObjectFile.cpp +++ b/lib/Object/ObjectFile.cpp @@ -1,9 +1,8 @@ //===- ObjectFile.cpp - File format independent object file ---------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -57,21 +56,19 @@ uint64_t ObjectFile::getSymbolValue(DataRefImpl Ref) const { return getSymbolValueImpl(Ref); } -std::error_code ObjectFile::printSymbolName(raw_ostream &OS, - DataRefImpl Symb) const { +Error ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { Expected<StringRef> Name = getSymbolName(Symb); if (!Name) - return errorToErrorCode(Name.takeError()); + return Name.takeError(); OS << *Name; - return std::error_code(); + return Error::success(); } uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; } bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const { - StringRef SectName; - if (!getSectionName(Sec, SectName)) - return SectName == ".llvmbc"; + if (Expected<StringRef> NameOrErr = getSectionName(Sec)) + return *NameOrErr == ".llvmbc"; return false; } @@ -128,6 +125,7 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) { case file_magic::macho_universal_binary: case file_magic::windows_resource: case file_magic::pdb: + case file_magic::minidump: return errorCodeToError(object_error::invalid_file_type); case file_magic::elf: case file_magic::elf_relocatable: @@ -151,6 +149,10 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) { case file_magic::coff_import_library: case file_magic::pecoff_executable: return createCOFFObjectFile(Object); + case file_magic::xcoff_object_32: + return createXCOFFObjectFile(Object, Binary::ID_XCOFF32); + case file_magic::xcoff_object_64: + return createXCOFFObjectFile(Object, Binary::ID_XCOFF64); case file_magic::wasm_object: return createWasmObjectFile(Object); } diff --git a/lib/Object/RecordStreamer.cpp b/lib/Object/RecordStreamer.cpp index 1f57867dd21a..f39a6c28ed50 100644 --- a/lib/Object/RecordStreamer.cpp +++ b/lib/Object/RecordStreamer.cpp @@ -1,9 +1,8 @@ //===-- RecordStreamer.cpp - Record asm defined and used symbols ----------===// // -// 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 // //===----------------------------------------------------------------------===// @@ -83,7 +82,7 @@ RecordStreamer::const_iterator RecordStreamer::begin() { RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); } void RecordStreamer::EmitInstruction(const MCInst &Inst, - const MCSubtargetInfo &STI, bool) { + const MCSubtargetInfo &STI) { MCStreamer::EmitInstruction(Inst, STI); } diff --git a/lib/Object/RecordStreamer.h b/lib/Object/RecordStreamer.h index 3d5ae59b58fe..c8b75bcc6d1d 100644 --- a/lib/Object/RecordStreamer.h +++ b/lib/Object/RecordStreamer.h @@ -1,9 +1,8 @@ //===- RecordStreamer.h - Record asm defined and used 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 // //===----------------------------------------------------------------------===// @@ -47,8 +46,7 @@ private: public: RecordStreamer(MCContext &Context, const Module &M); - void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, - bool) override; + void EmitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override; void EmitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override; void EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) override; bool EmitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override; @@ -56,6 +54,15 @@ public: unsigned ByteAlignment, SMLoc Loc = SMLoc()) override; void EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size, unsigned ByteAlignment) override; + + // Ignore COFF-specific directives; we do not need any information from them, + // but the default implementation of these methods crashes, so we override + // them with versions that do nothing. + void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {} + void EmitCOFFSymbolStorageClass(int StorageClass) override {} + void EmitCOFFSymbolType(int Type) override {} + void EndCOFFSymbolDef() override {} + /// Record .symver aliases for later processing. void emitELFSymverDirective(StringRef AliasName, const MCSymbol *Aliasee) override; diff --git a/lib/Object/RelocationResolver.cpp b/lib/Object/RelocationResolver.cpp new file mode 100644 index 000000000000..0a243f32e12c --- /dev/null +++ b/lib/Object/RelocationResolver.cpp @@ -0,0 +1,550 @@ +//===- RelocationResolver.cpp ------------------------------------*- 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 defines utilities to resolve relocations in object files. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/RelocationResolver.h" + +namespace llvm { +namespace object { + +static 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; +} + +static bool supportsX86_64(uint64_t Type) { + switch (Type) { + case ELF::R_X86_64_NONE: + case ELF::R_X86_64_64: + case ELF::R_X86_64_DTPOFF32: + case ELF::R_X86_64_DTPOFF64: + case ELF::R_X86_64_PC32: + case ELF::R_X86_64_32: + case ELF::R_X86_64_32S: + return true; + default: + return false; + } +} + +static uint64_t resolveX86_64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_X86_64_NONE: + return A; + case ELF::R_X86_64_64: + case ELF::R_X86_64_DTPOFF32: + case ELF::R_X86_64_DTPOFF64: + return S + getELFAddend(R); + case ELF::R_X86_64_PC32: + return S + getELFAddend(R) - R.getOffset(); + case ELF::R_X86_64_32: + case ELF::R_X86_64_32S: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsAArch64(uint64_t Type) { + switch (Type) { + case ELF::R_AARCH64_ABS32: + case ELF::R_AARCH64_ABS64: + return true; + default: + return false; + } +} + +static uint64_t resolveAArch64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_AARCH64_ABS32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_AARCH64_ABS64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsBPF(uint64_t Type) { + switch (Type) { + case ELF::R_BPF_64_32: + case ELF::R_BPF_64_64: + return true; + default: + return false; + } +} + +static uint64_t resolveBPF(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_BPF_64_32: + return S & 0xFFFFFFFF; + case ELF::R_BPF_64_64: + return S; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsMips64(uint64_t Type) { + switch (Type) { + case ELF::R_MIPS_32: + case ELF::R_MIPS_64: + case ELF::R_MIPS_TLS_DTPREL64: + return true; + default: + return false; + } +} + +static uint64_t resolveMips64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_MIPS_32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_MIPS_64: + return S + getELFAddend(R); + case ELF::R_MIPS_TLS_DTPREL64: + return S + getELFAddend(R) - 0x8000; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsPPC64(uint64_t Type) { + switch (Type) { + case ELF::R_PPC64_ADDR32: + case ELF::R_PPC64_ADDR64: + return true; + default: + return false; + } +} + +static uint64_t resolvePPC64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_PPC64_ADDR32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_PPC64_ADDR64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsSystemZ(uint64_t Type) { + switch (Type) { + case ELF::R_390_32: + case ELF::R_390_64: + return true; + default: + return false; + } +} + +static uint64_t resolveSystemZ(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_390_32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + case ELF::R_390_64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsSparc64(uint64_t Type) { + switch (Type) { + case ELF::R_SPARC_32: + case ELF::R_SPARC_64: + case ELF::R_SPARC_UA32: + case ELF::R_SPARC_UA64: + return true; + default: + return false; + } +} + +static uint64_t resolveSparc64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_SPARC_32: + case ELF::R_SPARC_64: + case ELF::R_SPARC_UA32: + case ELF::R_SPARC_UA64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsAmdgpu(uint64_t Type) { + switch (Type) { + case ELF::R_AMDGPU_ABS32: + case ELF::R_AMDGPU_ABS64: + return true; + default: + return false; + } +} + +static uint64_t resolveAmdgpu(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_AMDGPU_ABS32: + case ELF::R_AMDGPU_ABS64: + return S + getELFAddend(R); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsX86(uint64_t Type) { + switch (Type) { + case ELF::R_386_NONE: + case ELF::R_386_32: + case ELF::R_386_PC32: + return true; + default: + return false; + } +} + +static uint64_t resolveX86(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_386_NONE: + return A; + case ELF::R_386_32: + return S + A; + case ELF::R_386_PC32: + return S - R.getOffset() + A; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsPPC32(uint64_t Type) { + return Type == ELF::R_PPC_ADDR32; +} + +static uint64_t resolvePPC32(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == ELF::R_PPC_ADDR32) + return (S + getELFAddend(R)) & 0xFFFFFFFF; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsARM(uint64_t Type) { + return Type == ELF::R_ARM_ABS32; +} + +static uint64_t resolveARM(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == ELF::R_ARM_ABS32) + return (S + A) & 0xFFFFFFFF; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsAVR(uint64_t Type) { + switch (Type) { + case ELF::R_AVR_16: + case ELF::R_AVR_32: + return true; + default: + return false; + } +} + +static uint64_t resolveAVR(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case ELF::R_AVR_16: + return (S + getELFAddend(R)) & 0xFFFF; + case ELF::R_AVR_32: + return (S + getELFAddend(R)) & 0xFFFFFFFF; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsLanai(uint64_t Type) { + return Type == ELF::R_LANAI_32; +} + +static uint64_t resolveLanai(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == ELF::R_LANAI_32) + return (S + getELFAddend(R)) & 0xFFFFFFFF; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsMips32(uint64_t Type) { + switch (Type) { + case ELF::R_MIPS_32: + case ELF::R_MIPS_TLS_DTPREL32: + return true; + default: + return false; + } +} + +static uint64_t resolveMips32(RelocationRef R, uint64_t S, uint64_t A) { + // FIXME: Take in account implicit addends to get correct results. + uint32_t Rel = R.getType(); + if (Rel == ELF::R_MIPS_32) + return (S + A) & 0xFFFFFFFF; + if (Rel == ELF::R_MIPS_TLS_DTPREL32) + return (S + A) & 0xFFFFFFFF; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsSparc32(uint64_t Type) { + switch (Type) { + case ELF::R_SPARC_32: + case ELF::R_SPARC_UA32: + return true; + default: + return false; + } +} + +static uint64_t resolveSparc32(RelocationRef R, uint64_t S, uint64_t A) { + uint32_t Rel = R.getType(); + if (Rel == ELF::R_SPARC_32 || Rel == ELF::R_SPARC_UA32) + return S + getELFAddend(R); + return A; +} + +static bool supportsHexagon(uint64_t Type) { + return Type == ELF::R_HEX_32; +} + +static uint64_t resolveHexagon(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == ELF::R_HEX_32) + return S + getELFAddend(R); + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsRISCV(uint64_t Type) { + switch (Type) { + case ELF::R_RISCV_NONE: + case ELF::R_RISCV_32: + case ELF::R_RISCV_64: + case ELF::R_RISCV_ADD8: + case ELF::R_RISCV_SUB8: + case ELF::R_RISCV_ADD16: + case ELF::R_RISCV_SUB16: + case ELF::R_RISCV_ADD32: + case ELF::R_RISCV_SUB32: + case ELF::R_RISCV_ADD64: + case ELF::R_RISCV_SUB64: + return true; + default: + return false; + } +} + +static uint64_t resolveRISCV(RelocationRef R, uint64_t S, uint64_t A) { + int64_t RA = getELFAddend(R); + switch (R.getType()) { + case ELF::R_RISCV_NONE: + return A; + case ELF::R_RISCV_32: + return (S + RA) & 0xFFFFFFFF; + case ELF::R_RISCV_64: + return S + RA; + case ELF::R_RISCV_ADD8: + return (A + (S + RA)) & 0xFF; + case ELF::R_RISCV_SUB8: + return (A - (S + RA)) & 0xFF; + case ELF::R_RISCV_ADD16: + return (A + (S + RA)) & 0xFFFF; + case ELF::R_RISCV_SUB16: + return (A - (S + RA)) & 0xFFFF; + case ELF::R_RISCV_ADD32: + return (A + (S + RA)) & 0xFFFFFFFF; + case ELF::R_RISCV_SUB32: + return (A - (S + RA)) & 0xFFFFFFFF; + case ELF::R_RISCV_ADD64: + return (A + (S + RA)); + case ELF::R_RISCV_SUB64: + return (A - (S + RA)); + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsCOFFX86(uint64_t Type) { + switch (Type) { + case COFF::IMAGE_REL_I386_SECREL: + case COFF::IMAGE_REL_I386_DIR32: + return true; + default: + return false; + } +} + +static uint64_t resolveCOFFX86(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case COFF::IMAGE_REL_I386_SECREL: + case COFF::IMAGE_REL_I386_DIR32: + return (S + A) & 0xFFFFFFFF; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsCOFFX86_64(uint64_t Type) { + switch (Type) { + case COFF::IMAGE_REL_AMD64_SECREL: + case COFF::IMAGE_REL_AMD64_ADDR64: + return true; + default: + return false; + } +} + +static uint64_t resolveCOFFX86_64(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case COFF::IMAGE_REL_AMD64_SECREL: + return (S + A) & 0xFFFFFFFF; + case COFF::IMAGE_REL_AMD64_ADDR64: + return S + A; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +static bool supportsMachOX86_64(uint64_t Type) { + return Type == MachO::X86_64_RELOC_UNSIGNED; +} + +static uint64_t resolveMachOX86_64(RelocationRef R, uint64_t S, uint64_t A) { + if (R.getType() == MachO::X86_64_RELOC_UNSIGNED) + return S; + llvm_unreachable("Invalid relocation type"); +} + +static bool supportsWasm32(uint64_t Type) { + switch (Type) { + case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_SLEB: + case wasm::R_WASM_TABLE_INDEX_I32: + case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_TYPE_INDEX_LEB: + case wasm::R_WASM_GLOBAL_INDEX_LEB: + case wasm::R_WASM_FUNCTION_OFFSET_I32: + case wasm::R_WASM_SECTION_OFFSET_I32: + case wasm::R_WASM_EVENT_INDEX_LEB: + return true; + default: + return false; + } +} + +static uint64_t resolveWasm32(RelocationRef R, uint64_t S, uint64_t A) { + switch (R.getType()) { + case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_SLEB: + case wasm::R_WASM_TABLE_INDEX_I32: + case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_TYPE_INDEX_LEB: + case wasm::R_WASM_GLOBAL_INDEX_LEB: + case wasm::R_WASM_FUNCTION_OFFSET_I32: + case wasm::R_WASM_SECTION_OFFSET_I32: + case wasm::R_WASM_EVENT_INDEX_LEB: + // For wasm section, its offset at 0 -- ignoring Value + return A; + default: + llvm_unreachable("Invalid relocation type"); + } +} + +std::pair<bool (*)(uint64_t), RelocationResolver> +getRelocationResolver(const ObjectFile &Obj) { + if (Obj.isCOFF()) { + if (Obj.getBytesInAddress() == 8) + return {supportsCOFFX86_64, resolveCOFFX86_64}; + return {supportsCOFFX86, resolveCOFFX86}; + } else if (Obj.isELF()) { + if (Obj.getBytesInAddress() == 8) { + switch (Obj.getArch()) { + case Triple::x86_64: + return {supportsX86_64, resolveX86_64}; + case Triple::aarch64: + case Triple::aarch64_be: + return {supportsAArch64, resolveAArch64}; + case Triple::bpfel: + case Triple::bpfeb: + return {supportsBPF, resolveBPF}; + case Triple::mips64el: + case Triple::mips64: + return {supportsMips64, resolveMips64}; + case Triple::ppc64le: + case Triple::ppc64: + return {supportsPPC64, resolvePPC64}; + case Triple::systemz: + return {supportsSystemZ, resolveSystemZ}; + case Triple::sparcv9: + return {supportsSparc64, resolveSparc64}; + case Triple::amdgcn: + return {supportsAmdgpu, resolveAmdgpu}; + case Triple::riscv64: + return {supportsRISCV, resolveRISCV}; + default: + return {nullptr, nullptr}; + } + } + + // 32-bit object file + assert(Obj.getBytesInAddress() == 4 && + "Invalid word size in object file"); + + switch (Obj.getArch()) { + case Triple::x86: + return {supportsX86, resolveX86}; + case Triple::ppc: + return {supportsPPC32, resolvePPC32}; + case Triple::arm: + case Triple::armeb: + return {supportsARM, resolveARM}; + case Triple::avr: + return {supportsAVR, resolveAVR}; + case Triple::lanai: + return {supportsLanai, resolveLanai}; + case Triple::mipsel: + case Triple::mips: + return {supportsMips32, resolveMips32}; + case Triple::sparc: + return {supportsSparc32, resolveSparc32}; + case Triple::hexagon: + return {supportsHexagon, resolveHexagon}; + case Triple::riscv32: + return {supportsRISCV, resolveRISCV}; + default: + return {nullptr, nullptr}; + } + } else if (Obj.isMachO()) { + if (Obj.getArch() == Triple::x86_64) + return {supportsMachOX86_64, resolveMachOX86_64}; + return {nullptr, nullptr}; + } else if (Obj.isWasm()) { + if (Obj.getArch() == Triple::wasm32) + return {supportsWasm32, resolveWasm32}; + return {nullptr, nullptr}; + } + + llvm_unreachable("Invalid object file"); +} + +} // namespace object +} // namespace llvm diff --git a/lib/Object/SymbolSize.cpp b/lib/Object/SymbolSize.cpp index 004fb1b07546..bdf4dc55cf3c 100644 --- a/lib/Object/SymbolSize.cpp +++ b/lib/Object/SymbolSize.cpp @@ -1,9 +1,8 @@ //===- SymbolSize.cpp -----------------------------------------------------===// // -// 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/lib/Object/SymbolicFile.cpp b/lib/Object/SymbolicFile.cpp index 3e998a2682b8..2b152b7d8da3 100644 --- a/lib/Object/SymbolicFile.cpp +++ b/lib/Object/SymbolicFile.cpp @@ -1,9 +1,8 @@ //===- SymbolicFile.cpp - Interface that only provides symbols ------------===// // -// 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 // //===----------------------------------------------------------------------===// // @@ -53,6 +52,7 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type, case file_magic::macho_universal_binary: case file_magic::windows_resource: case file_magic::pdb: + case file_magic::minidump: return errorCodeToError(object_error::invalid_file_type); case file_magic::elf: case file_magic::elf_executable: @@ -69,6 +69,8 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type, case file_magic::macho_dsym_companion: case file_magic::macho_kext_bundle: case file_magic::pecoff_executable: + case file_magic::xcoff_object_32: + case file_magic::xcoff_object_64: case file_magic::wasm_object: return ObjectFile::createObjectFile(Object, Type); case file_magic::coff_import_library: diff --git a/lib/Object/WasmObjectFile.cpp b/lib/Object/WasmObjectFile.cpp index d84cb48c9fbd..82aa1830dced 100644 --- a/lib/Object/WasmObjectFile.cpp +++ b/lib/Object/WasmObjectFile.cpp @@ -1,15 +1,15 @@ //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===// // -// 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 // //===----------------------------------------------------------------------===// #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSet.h" #include "llvm/ADT/Triple.h" @@ -131,24 +131,24 @@ static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) { } static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) { - int64_t result = readLEB128(Ctx); - if (result > VARUINT1_MAX || result < 0) + int64_t Result = readLEB128(Ctx); + if (Result > VARUINT1_MAX || Result < 0) report_fatal_error("LEB is outside Varuint1 range"); - return result; + return Result; } static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) { - int64_t result = readLEB128(Ctx); - if (result > INT32_MAX || result < INT32_MIN) + int64_t Result = readLEB128(Ctx); + if (Result > INT32_MAX || Result < INT32_MIN) report_fatal_error("LEB is outside Varint32 range"); - return result; + return Result; } static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) { - uint64_t result = readULEB128(Ctx); - if (result > UINT32_MAX) + uint64_t Result = readULEB128(Ctx); + if (Result > UINT32_MAX) report_fatal_error("LEB is outside Varuint32 range"); - return result; + return Result; } static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) { @@ -255,7 +255,7 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) } ReadContext Ctx; - Ctx.Start = getPtr(0); + Ctx.Start = getData().bytes_begin(); Ctx.Ptr = Ctx.Start + 4; Ctx.End = Ctx.Start + getData().size(); @@ -316,14 +316,17 @@ Error WasmObjectFile::parseSection(WasmSection &Sec) { return parseCodeSection(Ctx); case wasm::WASM_SEC_DATA: return parseDataSection(Ctx); + case wasm::WASM_SEC_DATACOUNT: + return parseDataCountSection(Ctx); default: - return make_error<GenericBinaryError>("Bad section type", - object_error::parse_failed); + return make_error<GenericBinaryError>( + "Invalid section type: " + Twine(Sec.Type), object_error::parse_failed); } } Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) { // See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md + HasDylinkSection = true; DylinkInfo.MemorySize = readVaruint32(Ctx); DylinkInfo.MemoryAlignment = readVaruint32(Ctx); DylinkInfo.TableSize = readVaruint32(Ctx); @@ -418,17 +421,17 @@ Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) { if (Count > DataSegments.size()) return make_error<GenericBinaryError>("Too many segment names", object_error::parse_failed); - for (uint32_t i = 0; i < Count; i++) { - DataSegments[i].Data.Name = readString(Ctx); - DataSegments[i].Data.Alignment = readVaruint32(Ctx); - DataSegments[i].Data.Flags = readVaruint32(Ctx); + for (uint32_t I = 0; I < Count; I++) { + DataSegments[I].Data.Name = readString(Ctx); + DataSegments[I].Data.Alignment = readVaruint32(Ctx); + DataSegments[I].Data.LinkerFlags = readVaruint32(Ctx); } break; } case wasm::WASM_INIT_FUNCS: { uint32_t Count = readVaruint32(Ctx); LinkingData.InitFunctions.reserve(Count); - for (uint32_t i = 0; i < Count; i++) { + for (uint32_t I = 0; I < Count; I++) { wasm::WasmInitFunc Init; Init.Priority = readVaruint32(Ctx); Init.Symbol = readVaruint32(Ctx); @@ -505,9 +508,13 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { Function.SymbolName = Info.Name; } else { wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex]; + if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) + Info.Name = readString(Ctx); + else + Info.Name = Import.Field; Signature = &Signatures[Import.SigIndex]; - Info.Name = Import.Field; - Info.Module = Import.Module; + Info.ImportName = Import.Field; + Info.ImportModule = Import.Module; } break; @@ -530,8 +537,13 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { Global.SymbolName = Info.Name; } else { wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex]; - Info.Name = Import.Field; + if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) + Info.Name = readString(Ctx); + else + Info.Name = Import.Field; GlobalType = &Import.Global; + Info.ImportName = Import.Field; + Info.ImportModule = Import.Module; } break; @@ -585,9 +597,14 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { } else { wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex]; + if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) + Info.Name = readString(Ctx); + else + Info.Name = Import.Field; EventType = &Import.Event; Signature = &Signatures[EventType->SigIndex]; - Info.Name = Import.Field; + Info.ImportName = Import.Field; + Info.ImportModule = Import.Module; } break; } @@ -659,6 +676,77 @@ Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) { return Error::success(); } +Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) { + llvm::SmallSet<StringRef, 3> FieldsSeen; + uint32_t Fields = readVaruint32(Ctx); + for (size_t I = 0; I < Fields; ++I) { + StringRef FieldName = readString(Ctx); + if (!FieldsSeen.insert(FieldName).second) + return make_error<GenericBinaryError>( + "Producers section does not have unique fields", + object_error::parse_failed); + std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr; + if (FieldName == "language") { + ProducerVec = &ProducerInfo.Languages; + } else if (FieldName == "processed-by") { + ProducerVec = &ProducerInfo.Tools; + } else if (FieldName == "sdk") { + ProducerVec = &ProducerInfo.SDKs; + } else { + return make_error<GenericBinaryError>( + "Producers section field is not named one of language, processed-by, " + "or sdk", + object_error::parse_failed); + } + uint32_t ValueCount = readVaruint32(Ctx); + llvm::SmallSet<StringRef, 8> ProducersSeen; + for (size_t J = 0; J < ValueCount; ++J) { + StringRef Name = readString(Ctx); + StringRef Version = readString(Ctx); + if (!ProducersSeen.insert(Name).second) { + return make_error<GenericBinaryError>( + "Producers section contains repeated producer", + object_error::parse_failed); + } + ProducerVec->emplace_back(Name, Version); + } + } + if (Ctx.Ptr != Ctx.End) + return make_error<GenericBinaryError>("Producers section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + +Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) { + llvm::SmallSet<std::string, 8> FeaturesSeen; + uint32_t FeatureCount = readVaruint32(Ctx); + for (size_t I = 0; I < FeatureCount; ++I) { + wasm::WasmFeatureEntry Feature; + Feature.Prefix = readUint8(Ctx); + switch (Feature.Prefix) { + case wasm::WASM_FEATURE_PREFIX_USED: + case wasm::WASM_FEATURE_PREFIX_REQUIRED: + case wasm::WASM_FEATURE_PREFIX_DISALLOWED: + break; + default: + return make_error<GenericBinaryError>("Unknown feature policy prefix", + object_error::parse_failed); + } + Feature.Name = readString(Ctx); + if (!FeaturesSeen.insert(Feature.Name).second) + return make_error<GenericBinaryError>( + "Target features section contains repeated feature \"" + + Feature.Name + "\"", + object_error::parse_failed); + TargetFeatures.push_back(Feature); + } + if (Ctx.Ptr != Ctx.End) + return make_error<GenericBinaryError>( + "Target features section ended prematurely", + object_error::parse_failed); + return Error::success(); +} + Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { uint32_t SectionIndex = readVaruint32(Ctx); if (SectionIndex >= Sections.size()) @@ -678,43 +766,49 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { PreviousOffset = Reloc.Offset; Reloc.Index = readVaruint32(Ctx); switch (Reloc.Type) { - case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: - case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: - case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: + case wasm::R_WASM_FUNCTION_INDEX_LEB: + case wasm::R_WASM_TABLE_INDEX_SLEB: + case wasm::R_WASM_TABLE_INDEX_I32: + case wasm::R_WASM_TABLE_INDEX_REL_SLEB: if (!isValidFunctionSymbol(Reloc.Index)) return make_error<GenericBinaryError>("Bad relocation function index", object_error::parse_failed); break; - case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: + case wasm::R_WASM_TYPE_INDEX_LEB: if (Reloc.Index >= Signatures.size()) return make_error<GenericBinaryError>("Bad relocation type index", object_error::parse_failed); break; - case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: - if (!isValidGlobalSymbol(Reloc.Index)) + case wasm::R_WASM_GLOBAL_INDEX_LEB: + // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data + // symbols to refer to thier GOT enties. + if (!isValidGlobalSymbol(Reloc.Index) && + !isValidDataSymbol(Reloc.Index) && + !isValidFunctionSymbol(Reloc.Index)) return make_error<GenericBinaryError>("Bad relocation global index", object_error::parse_failed); break; - case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB: + case wasm::R_WASM_EVENT_INDEX_LEB: if (!isValidEventSymbol(Reloc.Index)) return make_error<GenericBinaryError>("Bad relocation event index", object_error::parse_failed); break; - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_LEB: + case wasm::R_WASM_MEMORY_ADDR_SLEB: + case wasm::R_WASM_MEMORY_ADDR_I32: + case wasm::R_WASM_MEMORY_ADDR_REL_SLEB: if (!isValidDataSymbol(Reloc.Index)) return make_error<GenericBinaryError>("Bad relocation data index", object_error::parse_failed); Reloc.Addend = readVarint32(Ctx); break; - case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32: + case wasm::R_WASM_FUNCTION_OFFSET_I32: if (!isValidFunctionSymbol(Reloc.Index)) return make_error<GenericBinaryError>("Bad relocation function index", object_error::parse_failed); Reloc.Addend = readVarint32(Ctx); break; - case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32: + case wasm::R_WASM_SECTION_OFFSET_I32: if (!isValidSectionSymbol(Reloc.Index)) return make_error<GenericBinaryError>("Bad relocation section index", object_error::parse_failed); @@ -730,10 +824,10 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { // also shouldn't overlap a function/element boundary, but we don't bother // to check that. uint64_t Size = 5; - if (Reloc.Type == wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 || - Reloc.Type == wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32 || - Reloc.Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32 || - Reloc.Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32) + if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 || + Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 || + Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 || + Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32) Size = 4; if (Reloc.Offset + Size > EndOffset) return make_error<GenericBinaryError>("Bad relocation offset", @@ -757,6 +851,12 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) { } else if (Sec.Name == "linking") { if (Error Err = parseLinkingSection(Ctx)) return Err; + } else if (Sec.Name == "producers") { + if (Error Err = parseProducersSection(Ctx)) + return Err; + } else if (Sec.Name == "target_features") { + if (Error Err = parseTargetFeaturesSection(Ctx)) + return Err; } else if (Sec.Name.startswith("reloc.")) { if (Error Err = parseRelocSection(Sec.Name, Ctx)) return Err; @@ -799,7 +899,7 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { Error WasmObjectFile::parseImportSection(ReadContext &Ctx) { uint32_t Count = readVaruint32(Ctx); Imports.reserve(Count); - for (uint32_t i = 0; i < Count; i++) { + for (uint32_t I = 0; I < Count; I++) { wasm::WasmImport Im; Im.Module = readString(Ctx); Im.Field = readString(Ctx); @@ -925,7 +1025,7 @@ Error WasmObjectFile::parseEventSection(ReadContext &Ctx) { Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { uint32_t Count = readVaruint32(Ctx); Exports.reserve(Count); - for (uint32_t i = 0; i < Count; i++) { + for (uint32_t I = 0; I < Count; I++) { wasm::WasmExport Ex; Ex.Name = readString(Ctx); Ex.Kind = readUint8(Ctx); @@ -1010,6 +1110,12 @@ wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) { return Functions[Index - NumImportedFunctions]; } +const wasm::WasmFunction & +WasmObjectFile::getDefinedFunction(uint32_t Index) const { + assert(isDefinedFunctionIndex(Index)); + return Functions[Index - NumImportedFunctions]; +} + wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) { assert(isDefinedGlobalIndex(Index)); return Globals[Index - NumImportedGlobals]; @@ -1097,12 +1203,22 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { Error WasmObjectFile::parseDataSection(ReadContext &Ctx) { DataSection = Sections.size(); uint32_t Count = readVaruint32(Ctx); + if (DataCount && Count != DataCount.getValue()) + return make_error<GenericBinaryError>( + "Number of data segments does not match DataCount section"); DataSegments.reserve(Count); while (Count--) { WasmSegment Segment; - Segment.Data.MemoryIndex = readVaruint32(Ctx); - if (Error Err = readInitExpr(Segment.Data.Offset, Ctx)) - return Err; + Segment.Data.InitFlags = readVaruint32(Ctx); + Segment.Data.MemoryIndex = (Segment.Data.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX) + ? readVaruint32(Ctx) : 0; + if ((Segment.Data.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) { + if (Error Err = readInitExpr(Segment.Data.Offset, Ctx)) + return Err; + } else { + Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST; + Segment.Data.Offset.Value.Int32 = 0; + } uint32_t Size = readVaruint32(Ctx); if (Size > (size_t)(Ctx.End - Ctx.Ptr)) return make_error<GenericBinaryError>("Invalid segment size", @@ -1111,7 +1227,7 @@ Error WasmObjectFile::parseDataSection(ReadContext &Ctx) { // The rest of these Data fields are set later, when reading in the linking // metadata section. Segment.Data.Alignment = 0; - Segment.Data.Flags = 0; + Segment.Data.LinkerFlags = 0; Segment.Data.Comdat = UINT32_MAX; Segment.SectionOffset = Ctx.Ptr - Ctx.Start; Ctx.Ptr += Size; @@ -1123,15 +1239,16 @@ Error WasmObjectFile::parseDataSection(ReadContext &Ctx) { return Error::success(); } -const uint8_t *WasmObjectFile::getPtr(size_t Offset) const { - return reinterpret_cast<const uint8_t *>(getData().data() + Offset); +Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) { + DataCount = readVaruint32(Ctx); + return Error::success(); } const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const { return Header; } -void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.a++; } +void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; } uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { uint32_t Result = SymbolRef::SF_None; @@ -1153,18 +1270,20 @@ uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { basic_symbol_iterator WasmObjectFile::symbol_begin() const { DataRefImpl Ref; - Ref.d.a = 0; + Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null + Ref.d.b = 0; // Symbol index return BasicSymbolRef(Ref, this); } basic_symbol_iterator WasmObjectFile::symbol_end() const { DataRefImpl Ref; - Ref.d.a = Symbols.size(); + Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null + Ref.d.b = Symbols.size(); // Symbol index return BasicSymbolRef(Ref, this); } const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const { - return Symbols[Symb.d.a]; + return Symbols[Symb.d.b]; } const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const { @@ -1176,7 +1295,12 @@ Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const { } Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { - return getSymbolValue(Symb); + auto &Sym = getWasmSymbol(Symb); + if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION && + isDefinedFunctionIndex(Sym.Info.ElementIndex)) + return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset; + else + return getSymbolValue(Symb); } uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const { @@ -1265,13 +1389,11 @@ WasmObjectFile::getSymbolSection(DataRefImpl Symb) const { void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } -std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, - StringRef &Res) const { +Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const { const WasmSection &S = Sections[Sec.d.a]; #define ECase(X) \ case wasm::WASM_SEC_##X: \ - Res = #X; \ - break + return #X; switch (S.Type) { ECase(TYPE); ECase(IMPORT); @@ -1285,14 +1407,13 @@ std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec, ECase(ELEM); ECase(CODE); ECase(DATA); + ECase(DATACOUNT); case wasm::WASM_SEC_CUSTOM: - Res = S.Name; - break; + return S.Name; default: - return object_error::invalid_section_index; + return createStringError(object_error::invalid_section_index, ""); } #undef ECase - return std::error_code(); } uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; } @@ -1306,14 +1427,12 @@ uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const { return S.Content.size(); } -std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec, - StringRef &Res) const { +Expected<ArrayRef<uint8_t>> +WasmObjectFile::getSectionContents(DataRefImpl Sec) const { const WasmSection &S = Sections[Sec.d.a]; // This will never fail since wasm sections can never be empty (user-sections // must have a name and non-user sections each have a defined structure). - Res = StringRef(reinterpret_cast<const char *>(S.Content.data()), - S.Content.size()); - return std::error_code(); + return S.Content; } uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const { @@ -1362,11 +1481,11 @@ uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const { symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const { const wasm::WasmRelocation &Rel = getWasmRelocation(Ref); - if (Rel.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB) + if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB) return symbol_end(); DataRefImpl Sym; - Sym.d.a = Rel.Index; - Sym.d.b = 0; + Sym.d.a = 1; + Sym.d.b = Rel.Index; return symbol_iterator(SymbolRef(Sym, this)); } @@ -1453,7 +1572,8 @@ int WasmSectionOrderChecker::getSectionOrder(unsigned ID, .StartsWith("reloc.", WASM_SEC_ORDER_RELOC) .Case("name", WASM_SEC_ORDER_NAME) .Case("producers", WASM_SEC_ORDER_PRODUCERS) - .Default(-1); + .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES) + .Default(WASM_SEC_ORDER_NONE); case wasm::WASM_SEC_TYPE: return WASM_SEC_ORDER_TYPE; case wasm::WASM_SEC_IMPORT: @@ -1481,19 +1601,73 @@ int WasmSectionOrderChecker::getSectionOrder(unsigned ID, case wasm::WASM_SEC_EVENT: return WASM_SEC_ORDER_EVENT; default: - llvm_unreachable("invalid section"); + return WASM_SEC_ORDER_NONE; } } +// Represents the edges in a directed graph where any node B reachable from node +// A is not allowed to appear before A in the section ordering, but may appear +// afterward. +int WasmSectionOrderChecker::DisallowedPredecessors[WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = { + {}, // WASM_SEC_ORDER_NONE + {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT}, // WASM_SEC_ORDER_TYPE, + {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION}, // WASM_SEC_ORDER_IMPORT, + {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE}, // WASM_SEC_ORDER_FUNCTION, + {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY}, // WASM_SEC_ORDER_TABLE, + {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_GLOBAL}, // WASM_SEC_ORDER_MEMORY, + {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EVENT}, // WASM_SEC_ORDER_GLOBAL, + {WASM_SEC_ORDER_EVENT, WASM_SEC_ORDER_EXPORT}, // WASM_SEC_ORDER_EVENT, + {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START}, // WASM_SEC_ORDER_EXPORT, + {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM}, // WASM_SEC_ORDER_START, + {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT}, // WASM_SEC_ORDER_ELEM, + {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE}, // WASM_SEC_ORDER_DATACOUNT, + {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA}, // WASM_SEC_ORDER_CODE, + {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING}, // WASM_SEC_ORDER_DATA, + + // Custom Sections + {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE}, // WASM_SEC_ORDER_DYLINK, + {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME}, // WASM_SEC_ORDER_LINKING, + {}, // WASM_SEC_ORDER_RELOC (can be repeated), + {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS}, // WASM_SEC_ORDER_NAME, + {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES}, // WASM_SEC_ORDER_PRODUCERS, + {WASM_SEC_ORDER_TARGET_FEATURES} // WASM_SEC_ORDER_TARGET_FEATURES +}; + bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID, StringRef CustomSectionName) { int Order = getSectionOrder(ID, CustomSectionName); - if (Order == -1) // Skip unknown sections + if (Order == WASM_SEC_ORDER_NONE) return true; - // There can be multiple "reloc." sections. Otherwise there shouldn't be any - // duplicate section orders. - bool IsValid = (LastOrder == Order && Order == WASM_SEC_ORDER_RELOC) || - LastOrder < Order; - LastOrder = Order; - return IsValid; + + // Disallowed predecessors we need to check for + SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList; + + // Keep track of completed checks to avoid repeating work + bool Checked[WASM_NUM_SEC_ORDERS] = {}; + + int Curr = Order; + while (true) { + // Add new disallowed predecessors to work list + for (size_t I = 0;; ++I) { + int Next = DisallowedPredecessors[Curr][I]; + if (Next == WASM_SEC_ORDER_NONE) + break; + if (Checked[Next]) + continue; + WorkList.push_back(Next); + Checked[Next] = true; + } + + if (WorkList.empty()) + break; + + // Consider next disallowed predecessor + Curr = WorkList.pop_back_val(); + if (Seen[Curr]) + return false; + } + + // Have not seen any disallowed predecessors + Seen[Order] = true; + return true; } diff --git a/lib/Object/WindowsMachineFlag.cpp b/lib/Object/WindowsMachineFlag.cpp new file mode 100644 index 000000000000..f7f2b20ae1a2 --- /dev/null +++ b/lib/Object/WindowsMachineFlag.cpp @@ -0,0 +1,44 @@ +//===- WindowsMachineFlag.cpp ---------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/WindowsMachineFlag.h" + +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/COFF.h" + +using namespace llvm; + +// Returns /machine's value. +COFF::MachineTypes llvm::getMachineType(StringRef S) { + return StringSwitch<COFF::MachineTypes>(S.lower()) + .Cases("x64", "amd64", COFF::IMAGE_FILE_MACHINE_AMD64) + .Cases("x86", "i386", COFF::IMAGE_FILE_MACHINE_I386) + .Case("arm", COFF::IMAGE_FILE_MACHINE_ARMNT) + .Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64) + .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN); +} + +StringRef llvm::machineToStr(COFF::MachineTypes MT) { + switch (MT) { + case COFF::IMAGE_FILE_MACHINE_ARMNT: + return "arm"; + case COFF::IMAGE_FILE_MACHINE_ARM64: + return "arm64"; + case COFF::IMAGE_FILE_MACHINE_AMD64: + return "x64"; + case COFF::IMAGE_FILE_MACHINE_I386: + return "x86"; + default: + llvm_unreachable("unknown machine type"); + } +} diff --git a/lib/Object/WindowsResource.cpp b/lib/Object/WindowsResource.cpp index 65413dd8bea1..d76e1231684c 100644 --- a/lib/Object/WindowsResource.cpp +++ b/lib/Object/WindowsResource.cpp @@ -1,9 +1,8 @@ //===-- WindowsResource.cpp -------------------------------------*- 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/Support/FileOutputBuffer.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" +#include "llvm/Support/ScopedPrinter.h" #include <ctime> #include <queue> #include <system_error> @@ -46,11 +46,12 @@ WindowsResource::WindowsResource(MemoryBufferRef Source) support::little); } +// static Expected<std::unique_ptr<WindowsResource>> WindowsResource::createWindowsResource(MemoryBufferRef Source) { if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE) return make_error<GenericBinaryError>( - "File too small to be a resource file", + Source.getBufferIdentifier() + ": too small to be a resource file", object_error::invalid_file_type); std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source)); return std::move(Ret); @@ -58,14 +59,14 @@ WindowsResource::createWindowsResource(MemoryBufferRef Source) { Expected<ResourceEntryRef> WindowsResource::getHeadEntry() { if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix)) - return make_error<EmptyResError>(".res contains no entries", + return make_error<EmptyResError>(getFileName() + " contains no entries", object_error::unexpected_eof); return ResourceEntryRef::create(BinaryStreamRef(BBS), this); } ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, const WindowsResource *Owner) - : Reader(Ref) {} + : Reader(Ref), Owner(Owner) {} Expected<ResourceEntryRef> ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) { @@ -108,7 +109,8 @@ Error ResourceEntryRef::loadNext() { RETURN_IF_ERROR(Reader.readObject(Prefix)); if (Prefix->HeaderSize < MIN_HEADER_SIZE) - return make_error<GenericBinaryError>("Header size is too small.", + return make_error<GenericBinaryError>(Owner->getFileName() + + ": header size too small", object_error::parse_failed); RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType)); @@ -128,7 +130,78 @@ Error ResourceEntryRef::loadNext() { WindowsResourceParser::WindowsResourceParser() : Root(false) {} -Error WindowsResourceParser::parse(WindowsResource *WR) { +void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) { + switch (TypeID) { + case 1: OS << "CURSOR (ID 1)"; break; + case 2: OS << "BITMAP (ID 2)"; break; + case 3: OS << "ICON (ID 3)"; break; + case 4: OS << "MENU (ID 4)"; break; + case 5: OS << "DIALOG (ID 5)"; break; + case 6: OS << "STRINGTABLE (ID 6)"; break; + case 7: OS << "FONTDIR (ID 7)"; break; + case 8: OS << "FONT (ID 8)"; break; + case 9: OS << "ACCELERATOR (ID 9)"; break; + case 10: OS << "RCDATA (ID 10)"; break; + case 11: OS << "MESSAGETABLE (ID 11)"; break; + case 12: OS << "GROUP_CURSOR (ID 12)"; break; + case 14: OS << "GROUP_ICON (ID 14)"; break; + case 16: OS << "VERSIONINFO (ID 16)"; break; + case 17: OS << "DLGINCLUDE (ID 17)"; break; + case 19: OS << "PLUGPLAY (ID 19)"; break; + case 20: OS << "VXD (ID 20)"; break; + case 21: OS << "ANICURSOR (ID 21)"; break; + case 22: OS << "ANIICON (ID 22)"; break; + case 23: OS << "HTML (ID 23)"; break; + case 24: OS << "MANIFEST (ID 24)"; break; + default: OS << "ID " << TypeID; break; + } +} + +static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) { + if (!sys::IsBigEndianHost) + return convertUTF16ToUTF8String(Src, Out); + + std::vector<UTF16> EndianCorrectedSrc; + EndianCorrectedSrc.resize(Src.size() + 1); + llvm::copy(Src, EndianCorrectedSrc.begin() + 1); + EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; + return convertUTF16ToUTF8String(makeArrayRef(EndianCorrectedSrc), Out); +} + +static std::string makeDuplicateResourceError( + const ResourceEntryRef &Entry, StringRef File1, StringRef File2) { + std::string Ret; + raw_string_ostream OS(Ret); + + OS << "duplicate resource:"; + + OS << " type "; + if (Entry.checkTypeString()) { + std::string UTF8; + if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8)) + UTF8 = "(failed conversion from UTF16)"; + OS << '\"' << UTF8 << '\"'; + } else + printResourceTypeName(Entry.getTypeID(), OS); + + OS << "/name "; + if (Entry.checkNameString()) { + std::string UTF8; + if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8)) + UTF8 = "(failed conversion from UTF16)"; + OS << '\"' << UTF8 << '\"'; + } else { + OS << "ID " << Entry.getNameID(); + } + + OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in " + << File2; + + return OS.str(); +} + +Error WindowsResourceParser::parse(WindowsResource *WR, + std::vector<std::string> &Duplicates) { auto EntryOrErr = WR->getHeadEntry(); if (!EntryOrErr) { auto E = EntryOrErr.takeError(); @@ -153,7 +226,14 @@ Error WindowsResourceParser::parse(WindowsResource *WR) { bool IsNewTypeString = false; bool IsNewNameString = false; - Root.addEntry(Entry, IsNewTypeString, IsNewNameString); + TreeNode* Node; + bool IsNewNode = Root.addEntry(Entry, InputFilenames.size(), + IsNewTypeString, IsNewNameString, Node); + InputFilenames.push_back(WR->getFileName()); + if (!IsNewNode) { + Duplicates.push_back(makeDuplicateResourceError( + Entry, InputFilenames[Node->Origin], WR->getFileName())); + } if (IsNewTypeString) StringTable.push_back(Entry.getTypeString()); @@ -172,12 +252,14 @@ void WindowsResourceParser::printTree(raw_ostream &OS) const { Root.print(Writer, "Resource Tree"); } -void WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry, +bool WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry, + uint32_t Origin, bool &IsNewTypeString, - bool &IsNewNameString) { + bool &IsNewNameString, + TreeNode *&Result) { TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString); TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString); - NameNode.addLanguageNode(Entry); + return NameNode.addLanguageNode(Entry, Origin, Result); } WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) { @@ -187,10 +269,11 @@ WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) { WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion, uint16_t MinorVersion, - uint32_t Characteristics) + uint32_t Characteristics, + uint32_t Origin) : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion), - Characteristics(Characteristics) { - DataIndex = DataCount++; + Characteristics(Characteristics), Origin(Origin) { + DataIndex = DataCount++; } std::unique_ptr<WindowsResourceParser::TreeNode> @@ -206,44 +289,52 @@ WindowsResourceParser::TreeNode::createIDNode() { std::unique_ptr<WindowsResourceParser::TreeNode> WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion, uint16_t MinorVersion, - uint32_t Characteristics) { + uint32_t Characteristics, + uint32_t Origin) { return std::unique_ptr<TreeNode>( - new TreeNode(MajorVersion, MinorVersion, Characteristics)); + new TreeNode(MajorVersion, MinorVersion, Characteristics, Origin)); } WindowsResourceParser::TreeNode & WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry, bool &IsNewTypeString) { if (Entry.checkTypeString()) - return addChild(Entry.getTypeString(), IsNewTypeString); + return addNameChild(Entry.getTypeString(), IsNewTypeString); else - return addChild(Entry.getTypeID()); + return addIDChild(Entry.getTypeID()); } WindowsResourceParser::TreeNode & WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry, bool &IsNewNameString) { if (Entry.checkNameString()) - return addChild(Entry.getNameString(), IsNewNameString); + return addNameChild(Entry.getNameString(), IsNewNameString); else - return addChild(Entry.getNameID()); + return addIDChild(Entry.getNameID()); } -WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addLanguageNode( - const ResourceEntryRef &Entry) { - return addChild(Entry.getLanguage(), true, Entry.getMajorVersion(), - Entry.getMinorVersion(), Entry.getCharacteristics()); +bool WindowsResourceParser::TreeNode::addLanguageNode( + const ResourceEntryRef &Entry, uint32_t Origin, TreeNode *&Result) { + return addDataChild(Entry.getLanguage(), Entry.getMajorVersion(), + Entry.getMinorVersion(), Entry.getCharacteristics(), + Origin, Result); } -WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild( - uint32_t ID, bool IsDataNode, uint16_t MajorVersion, uint16_t MinorVersion, - uint32_t Characteristics) { +bool WindowsResourceParser::TreeNode::addDataChild( + uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion, + uint32_t Characteristics, uint32_t Origin, TreeNode *&Result) { + auto NewChild = + createDataNode(MajorVersion, MinorVersion, Characteristics, Origin); + auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild)); + Result = ElementInserted.first->second.get(); + return ElementInserted.second; +} + +WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild( + uint32_t ID) { auto Child = IDChildren.find(ID); if (Child == IDChildren.end()) { - auto NewChild = - IsDataNode ? createDataNode(MajorVersion, MinorVersion, Characteristics) - : createIDNode(); + auto NewChild = createIDNode(); WindowsResourceParser::TreeNode &Node = *NewChild; IDChildren.emplace(ID, std::move(NewChild)); return Node; @@ -252,19 +343,10 @@ WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addChild( } WindowsResourceParser::TreeNode & -WindowsResourceParser::TreeNode::addChild(ArrayRef<UTF16> NameRef, - bool &IsNewString) { +WindowsResourceParser::TreeNode::addNameChild(ArrayRef<UTF16> NameRef, + bool &IsNewString) { std::string NameString; - ArrayRef<UTF16> CorrectedName; - std::vector<UTF16> EndianCorrectedName; - if (sys::IsBigEndianHost) { - EndianCorrectedName.resize(NameRef.size() + 1); - llvm::copy(NameRef, EndianCorrectedName.begin() + 1); - EndianCorrectedName[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED; - CorrectedName = makeArrayRef(EndianCorrectedName); - } else - CorrectedName = NameRef; - convertUTF16ToUTF8String(CorrectedName, NameString); + convertUTF16LEToUTF8String(NameRef, NameString); auto Child = StringChildren.find(NameString); if (Child == StringChildren.end()) { @@ -318,13 +400,13 @@ class WindowsResourceCOFFWriter { public: WindowsResourceCOFFWriter(COFF::MachineTypes MachineType, const WindowsResourceParser &Parser, Error &E); - std::unique_ptr<MemoryBuffer> write(); + std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp); private: void performFileLayout(); void performSectionOneLayout(); void performSectionTwoLayout(); - void writeCOFFHeader(); + void writeCOFFHeader(uint32_t TimeDateStamp); void writeFirstSectionHeader(); void writeSecondSectionHeader(); void writeFirstSection(); @@ -360,7 +442,8 @@ WindowsResourceCOFFWriter::WindowsResourceCOFFWriter( Data(Parser.getData()), StringTable(Parser.getStringTable()) { performFileLayout(); - OutputBuffer = WritableMemoryBuffer::getNewMemBuffer(FileSize); + OutputBuffer = WritableMemoryBuffer::getNewMemBuffer( + FileSize, "internal .obj file created from .res files"); } void WindowsResourceCOFFWriter::performFileLayout() { @@ -417,17 +500,11 @@ void WindowsResourceCOFFWriter::performSectionTwoLayout() { FileSize = alignTo(FileSize, SECTION_ALIGNMENT); } -static std::time_t getTime() { - std::time_t Now = time(nullptr); - if (Now < 0 || !isUInt<32>(Now)) - return UINT32_MAX; - return Now; -} - -std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() { +std::unique_ptr<MemoryBuffer> +WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) { BufferStart = OutputBuffer->getBufferStart(); - writeCOFFHeader(); + writeCOFFHeader(TimeDateStamp); writeFirstSectionHeader(); writeSecondSectionHeader(); writeFirstSection(); @@ -438,16 +515,17 @@ std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() { return std::move(OutputBuffer); } -void WindowsResourceCOFFWriter::writeCOFFHeader() { +void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) { // Write the COFF header. auto *Header = reinterpret_cast<coff_file_header *>(BufferStart); Header->Machine = MachineType; Header->NumberOfSections = 2; - Header->TimeDateStamp = getTime(); + Header->TimeDateStamp = TimeDateStamp; Header->PointerToSymbolTable = SymbolTableOffset; - // One symbol for every resource plus 2 for each section and @feat.00 + // One symbol for every resource plus 2 for each section and 1 for @feat.00 Header->NumberOfSymbols = Data.size() + 5; Header->SizeOfOptionalHeader = 0; + // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it. Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE; } @@ -712,12 +790,13 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { Expected<std::unique_ptr<MemoryBuffer>> writeWindowsResourceCOFF(COFF::MachineTypes MachineType, - const WindowsResourceParser &Parser) { + const WindowsResourceParser &Parser, + uint32_t TimeDateStamp) { Error E = Error::success(); WindowsResourceCOFFWriter Writer(MachineType, Parser, E); if (E) return std::move(E); - return Writer.write(); + return Writer.write(TimeDateStamp); } } // namespace object diff --git a/lib/Object/XCOFFObjectFile.cpp b/lib/Object/XCOFFObjectFile.cpp new file mode 100644 index 000000000000..602b7357986a --- /dev/null +++ b/lib/Object/XCOFFObjectFile.cpp @@ -0,0 +1,584 @@ +//===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===// +// +// 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 defines the XCOFFObjectFile class. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/XCOFFObjectFile.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/BinaryStreamReader.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MathExtras.h" +#include <cstddef> +#include <cstring> + +namespace llvm { +namespace object { + +// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer +// 'M'. Returns a pointer to the underlying object on success. +template <typename T> +static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr, + const uint64_t Size = sizeof(T)) { + uintptr_t Addr = uintptr_t(Ptr); + if (std::error_code EC = Binary::checkOffset(M, Addr, Size)) + return errorCodeToError(EC); + return reinterpret_cast<const T *>(Addr); +} + +static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) { + return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) + + Offset); +} + +template <typename T> static const T *viewAs(uintptr_t in) { + return reinterpret_cast<const T *>(in); +} + +static StringRef generateStringRef(const char *Name, uint64_t Size) { + auto NulCharPtr = static_cast<const char *>(memchr(Name, '\0', Size)); + return NulCharPtr ? StringRef(Name, NulCharPtr - Name) + : StringRef(Name, Size); +} + +void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr, + uintptr_t TableAddress) const { + if (Addr < TableAddress) + report_fatal_error("Section header outside of section header table."); + + uintptr_t Offset = Addr - TableAddress; + if (Offset >= getSectionHeaderSize() * getNumberOfSections()) + report_fatal_error("Section header outside of section header table."); + + if (Offset % getSectionHeaderSize() != 0) + report_fatal_error( + "Section header pointer does not point to a valid section header."); +} + +const XCOFFSectionHeader32 * +XCOFFObjectFile::toSection32(DataRefImpl Ref) const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); +#ifndef NDEBUG + checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); +#endif + return viewAs<XCOFFSectionHeader32>(Ref.p); +} + +const XCOFFSectionHeader64 * +XCOFFObjectFile::toSection64(DataRefImpl Ref) const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); +#ifndef NDEBUG + checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); +#endif + return viewAs<XCOFFSectionHeader64>(Ref.p); +} + +const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); + assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!"); + auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p); + return SymEntPtr; +} + +const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); + return static_cast<const XCOFFFileHeader32 *>(FileHeader); +} + +const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); + return static_cast<const XCOFFFileHeader64 *>(FileHeader); +} + +const XCOFFSectionHeader32 * +XCOFFObjectFile::sectionHeaderTable32() const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); + return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable); +} + +const XCOFFSectionHeader64 * +XCOFFObjectFile::sectionHeaderTable64() const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); + return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable); +} + +void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { + const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); + SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1; + Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr); +} + +Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { + const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); + + if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) + return generateStringRef(SymEntPtr->SymbolName, XCOFF::SymbolNameSize); + + // A storage class value with the high-order bit on indicates that the name is + // a symbolic debugger stabstring. + if (SymEntPtr->StorageClass & 0x80) + return StringRef("Unimplemented Debug Name"); + + uint32_t Offset = SymEntPtr->NameInStrTbl.Offset; + // The byte offset is relative to the start of the string table + // or .debug section. A byte offset value of 0 is a null or zero-length symbol + // name. A byte offset in the range 1 to 3 (inclusive) points into the length + // field; as a soft-error recovery mechanism, we treat such cases as having an + // offset of 0. + if (Offset < 4) + return StringRef(nullptr, 0); + + if (StringTable.Data != nullptr && StringTable.Size > Offset) + return (StringTable.Data + Offset); + + return make_error<GenericBinaryError>("Symbol Name parse failed", + object_error::parse_failed); +} + +Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { + uint64_t Result = 0; + llvm_unreachable("Not yet implemented!"); + return Result; +} + +uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + return toSymbolEntry(Symb)->Value; +} + +uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { + uint64_t Result = 0; + llvm_unreachable("Not yet implemented!"); + return Result; +} + +Expected<SymbolRef::Type> +XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const { + llvm_unreachable("Not yet implemented!"); + return SymbolRef::ST_Other; +} + +Expected<section_iterator> +XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { + const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); + int16_t SectNum = SymEntPtr->SectionNumber; + + if (isReservedSectionNumber(SectNum)) + return section_end(); + + Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum); + if (!ExpSec) + return ExpSec.takeError(); + + return section_iterator(SectionRef(ExpSec.get(), this)); +} + +void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { + const char *Ptr = reinterpret_cast<const char *>(Sec.p); + Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize()); +} + +Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { + return generateStringRef(getSectionNameInternal(Sec), XCOFF::SectionNameSize); +} + +uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { + // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t + // with MSVC. + if (is64Bit()) + return toSection64(Sec)->VirtualAddress; + + return toSection32(Sec)->VirtualAddress; +} + +uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { + // Section numbers in XCOFF are numbered beginning at 1. A section number of + // zero is used to indicate that a symbol is being imported or is undefined. + if (is64Bit()) + return toSection64(Sec) - sectionHeaderTable64() + 1; + else + return toSection32(Sec) - sectionHeaderTable32() + 1; +} + +uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const { + // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t + // with MSVC. + if (is64Bit()) + return toSection64(Sec)->SectionSize; + + return toSection32(Sec)->SectionSize; +} + +Expected<ArrayRef<uint8_t>> +XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const { + llvm_unreachable("Not yet implemented!"); +} + +uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { + uint64_t Result = 0; + llvm_unreachable("Not yet implemented!"); + return Result; +} + +bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { + bool Result = false; + llvm_unreachable("Not yet implemented!"); + return Result; +} + +bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { + return getSectionFlags(Sec) & XCOFF::STYP_TEXT; +} + +bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { + uint32_t Flags = getSectionFlags(Sec); + return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); +} + +bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { + uint32_t Flags = getSectionFlags(Sec); + return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); +} + +bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const { + bool Result = false; + llvm_unreachable("Not yet implemented!"); + return Result; +} + +relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { + llvm_unreachable("Not yet implemented!"); + return relocation_iterator(RelocationRef()); +} + +relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const { + llvm_unreachable("Not yet implemented!"); + return relocation_iterator(RelocationRef()); +} + +void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { + llvm_unreachable("Not yet implemented!"); + return; +} + +uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { + llvm_unreachable("Not yet implemented!"); + uint64_t Result = 0; + return Result; +} + +symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { + llvm_unreachable("Not yet implemented!"); + return symbol_iterator(SymbolRef()); +} + +uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const { + llvm_unreachable("Not yet implemented!"); + uint64_t Result = 0; + return Result; +} + +void XCOFFObjectFile::getRelocationTypeName( + DataRefImpl Rel, SmallVectorImpl<char> &Result) const { + llvm_unreachable("Not yet implemented!"); + return; +} + +uint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { + uint32_t Result = 0; + llvm_unreachable("Not yet implemented!"); + return Result; +} + +basic_symbol_iterator XCOFFObjectFile::symbol_begin() const { + assert(!is64Bit() && "64-bit support not implemented yet."); + DataRefImpl SymDRI; + SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr); + return basic_symbol_iterator(SymbolRef(SymDRI, this)); +} + +basic_symbol_iterator XCOFFObjectFile::symbol_end() const { + assert(!is64Bit() && "64-bit support not implemented yet."); + DataRefImpl SymDRI; + SymDRI.p = reinterpret_cast<uintptr_t>( + SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32()); + return basic_symbol_iterator(SymbolRef(SymDRI, this)); +} + +section_iterator XCOFFObjectFile::section_begin() const { + DataRefImpl DRI; + DRI.p = getSectionHeaderTableAddress(); + return section_iterator(SectionRef(DRI, this)); +} + +section_iterator XCOFFObjectFile::section_end() const { + DataRefImpl DRI; + DRI.p = getWithOffset(getSectionHeaderTableAddress(), + getNumberOfSections() * getSectionHeaderSize()); + return section_iterator(SectionRef(DRI, this)); +} + +uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } + +StringRef XCOFFObjectFile::getFileFormatName() const { + return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000"; +} + +Triple::ArchType XCOFFObjectFile::getArch() const { + return is64Bit() ? Triple::ppc64 : Triple::ppc; +} + +SubtargetFeatures XCOFFObjectFile::getFeatures() const { + llvm_unreachable("Not yet implemented!"); + return SubtargetFeatures(); +} + +bool XCOFFObjectFile::isRelocatableObject() const { + bool Result = false; + llvm_unreachable("Not yet implemented!"); + return Result; +} + +Expected<uint64_t> XCOFFObjectFile::getStartAddress() const { + // TODO FIXME Should get from auxiliary_header->o_entry when support for the + // auxiliary_header is added. + return 0; +} + +size_t XCOFFObjectFile::getFileHeaderSize() const { + return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32); +} + +size_t XCOFFObjectFile::getSectionHeaderSize() const { + return is64Bit() ? sizeof(XCOFFSectionHeader64) : + sizeof(XCOFFSectionHeader32); +} + +bool XCOFFObjectFile::is64Bit() const { + return Binary::ID_XCOFF64 == getType(); +} + +uint16_t XCOFFObjectFile::getMagic() const { + return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; +} + +Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const { + if (Num <= 0 || Num > getNumberOfSections()) + return errorCodeToError(object_error::invalid_section_index); + + DataRefImpl DRI; + DRI.p = getWithOffset(getSectionHeaderTableAddress(), + getSectionHeaderSize() * (Num - 1)); + return DRI; +} + +Expected<StringRef> +XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); + int16_t SectionNum = SymEntPtr->SectionNumber; + + switch (SectionNum) { + case XCOFF::N_DEBUG: + return "N_DEBUG"; + case XCOFF::N_ABS: + return "N_ABS"; + case XCOFF::N_UNDEF: + return "N_UNDEF"; + default: + Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum); + if (SecRef) + return generateStringRef(getSectionNameInternal(SecRef.get()), + XCOFF::SectionNameSize); + return SecRef.takeError(); + } +} + +bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) { + return (SectionNumber <= 0 && SectionNumber >= -2); +} + +uint16_t XCOFFObjectFile::getNumberOfSections() const { + return is64Bit() ? fileHeader64()->NumberOfSections + : fileHeader32()->NumberOfSections; +} + +int32_t XCOFFObjectFile::getTimeStamp() const { + return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp; +} + +uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { + return is64Bit() ? fileHeader64()->AuxHeaderSize + : fileHeader32()->AuxHeaderSize; +} + +uint32_t XCOFFObjectFile::getSymbolTableOffset32() const { + return fileHeader32()->SymbolTableOffset; +} + +int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const { + // As far as symbol table size is concerned, if this field is negative it is + // to be treated as a 0. However since this field is also used for printing we + // don't want to truncate any negative values. + return fileHeader32()->NumberOfSymTableEntries; +} + +uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const { + return (fileHeader32()->NumberOfSymTableEntries >= 0 + ? fileHeader32()->NumberOfSymTableEntries + : 0); +} + +uint64_t XCOFFObjectFile::getSymbolTableOffset64() const { + return fileHeader64()->SymbolTableOffset; +} + +uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { + return fileHeader64()->NumberOfSymTableEntries; +} + +uint16_t XCOFFObjectFile::getFlags() const { + return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; +} + +const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const { + return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name; +} + +uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const { + return reinterpret_cast<uintptr_t>(SectionHeaderTable); +} + +int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const { + return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags; +} + +XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object) + : ObjectFile(Type, Object) { + assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64); +} + +ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const { + assert(is64Bit() && "64-bit interface called for non 64-bit file."); + const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64(); + return ArrayRef<XCOFFSectionHeader64>(TablePtr, + TablePtr + getNumberOfSections()); +} + +ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const { + assert(!is64Bit() && "32-bit interface called for non 32-bit file."); + const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32(); + return ArrayRef<XCOFFSectionHeader32>(TablePtr, + TablePtr + getNumberOfSections()); +} + +Expected<XCOFFStringTable> +XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { + // If there is a string table, then the buffer must contain at least 4 bytes + // for the string table's size. Not having a string table is not an error. + if (auto EC = Binary::checkOffset( + Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) + return XCOFFStringTable{0, nullptr}; + + // Read the size out of the buffer. + uint32_t Size = support::endian::read32be(Obj->base() + Offset); + + // If the size is less then 4, then the string table is just a size and no + // string data. + if (Size <= 4) + return XCOFFStringTable{4, nullptr}; + + auto StringTableOrErr = + getObject<char>(Obj->Data, Obj->base() + Offset, Size); + if (Error E = StringTableOrErr.takeError()) + return std::move(E); + + const char *StringTablePtr = StringTableOrErr.get(); + if (StringTablePtr[Size - 1] != '\0') + return errorCodeToError(object_error::string_table_non_null_end); + + return XCOFFStringTable{Size, StringTablePtr}; +} + +Expected<std::unique_ptr<XCOFFObjectFile>> +XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { + // Can't use make_unique because of the private constructor. + std::unique_ptr<XCOFFObjectFile> Obj; + Obj.reset(new XCOFFObjectFile(Type, MBR)); + + uint64_t CurOffset = 0; + const auto *Base = Obj->base(); + MemoryBufferRef Data = Obj->Data; + + // Parse file header. + auto FileHeaderOrErr = + getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize()); + if (Error E = FileHeaderOrErr.takeError()) + return std::move(E); + Obj->FileHeader = FileHeaderOrErr.get(); + + CurOffset += Obj->getFileHeaderSize(); + // TODO FIXME we don't have support for an optional header yet, so just skip + // past it. + CurOffset += Obj->getOptionalHeaderSize(); + + // Parse the section header table if it is present. + if (Obj->getNumberOfSections()) { + auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset, + Obj->getNumberOfSections() * + Obj->getSectionHeaderSize()); + if (Error E = SecHeadersOrErr.takeError()) + return std::move(E); + Obj->SectionHeaderTable = SecHeadersOrErr.get(); + } + + // 64-bit object supports only file header and section headers for now. + if (Obj->is64Bit()) + return std::move(Obj); + + // If there is no symbol table we are done parsing the memory buffer. + if (Obj->getLogicalNumberOfSymbolTableEntries32() == 0) + return std::move(Obj); + + // Parse symbol table. + CurOffset = Obj->fileHeader32()->SymbolTableOffset; + uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) * + Obj->getLogicalNumberOfSymbolTableEntries32(); + auto SymTableOrErr = + getObject<XCOFFSymbolEntry>(Data, Base + CurOffset, SymbolTableSize); + if (Error E = SymTableOrErr.takeError()) + return std::move(E); + Obj->SymbolTblPtr = SymTableOrErr.get(); + CurOffset += SymbolTableSize; + + // Parse String table. + Expected<XCOFFStringTable> StringTableOrErr = + parseStringTable(Obj.get(), CurOffset); + if (Error E = StringTableOrErr.takeError()) + return std::move(E); + Obj->StringTable = StringTableOrErr.get(); + + return std::move(Obj); +} + +Expected<std::unique_ptr<ObjectFile>> +ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef, + unsigned FileType) { + return XCOFFObjectFile::create(FileType, MemBufRef); +} + +StringRef XCOFFSectionHeader32::getName() const { + return generateStringRef(Name, XCOFF::SectionNameSize); +} + +StringRef XCOFFSectionHeader64::getName() const { + return generateStringRef(Name, XCOFF::SectionNameSize); +} + +} // namespace object +} // namespace llvm |
