diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Object')
28 files changed, 1123 insertions, 205 deletions
diff --git a/contrib/llvm-project/llvm/lib/Object/Archive.cpp b/contrib/llvm-project/llvm/lib/Object/Archive.cpp index 9a4ef055faa4..ad03f9cae9f8 100644 --- a/contrib/llvm-project/llvm/lib/Object/Archive.cpp +++ b/contrib/llvm-project/llvm/lib/Object/Archive.cpp @@ -22,6 +22,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" @@ -30,7 +31,6 @@ #include <cassert> #include <cstddef> #include <cstdint> -#include <cstring> #include <memory> #include <string> #include <system_error> @@ -257,6 +257,14 @@ Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const { return Name; if (Name.size() == 2 && Name[1] == '/') // String table. return Name; + // System libraries from the Windows SDK for Windows 11 contain this symbol. + // It looks like a CFG guard: we just skip it for now. + if (Name.equals("/<XFGHASHMAP>/")) + return Name; + // Some libraries (e.g., arm64rt.lib) from the Windows WDK + // (version 10.0.22000.0) contain this undocumented special member. + if (Name.equals("/<ECSYMBOLS>/")) + return Name; // It's a long name. // Get the string table offset. std::size_t StringOffset; @@ -922,6 +930,14 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) Err = Error::success(); } +object::Archive::Kind Archive::getDefaultKindForHost() { + Triple HostTriple(sys::getProcessTriple()); + return HostTriple.isOSDarwin() + ? object::Archive::K_DARWIN + : (HostTriple.isOSAIX() ? object::Archive::K_AIXBIG + : object::Archive::K_GNU); +} + Archive::child_iterator Archive::child_begin(Error &Err, bool SkipInternal) const { if (isEmpty()) diff --git a/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp b/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp index 053b3dafed95..dbf5052cdac0 100644 --- a/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp @@ -18,16 +18,19 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Error.h" +#include "llvm/Object/IRObjectFile.h" +#include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Object/SymbolicFile.h" +#include "llvm/Object/XCOFFObjectFile.h" #include "llvm/Support/Alignment.h" #include "llvm/Support/EndianStream.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Format.h" +#include "llvm/Support/MathExtras.h" #include "llvm/Support/Path.h" #include "llvm/Support/SmallVectorMemoryBuffer.h" -#include "llvm/Support/ToolOutputFile.h" #include "llvm/Support/raw_ostream.h" #include <map> @@ -44,6 +47,40 @@ NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef) : Buf(MemoryBuffer::getMemBuffer(BufRef, false)), MemberName(BufRef.getBufferIdentifier()) {} +object::Archive::Kind NewArchiveMember::detectKindFromObject() const { + auto MemBufferRef = this->Buf->getMemBufferRef(); + Expected<std::unique_ptr<object::ObjectFile>> OptionalObject = + object::ObjectFile::createObjectFile(MemBufferRef); + + if (OptionalObject) + return isa<object::MachOObjectFile>(**OptionalObject) + ? object::Archive::K_DARWIN + : (isa<object::XCOFFObjectFile>(**OptionalObject) + ? object::Archive::K_AIXBIG + : object::Archive::K_GNU); + + // Squelch the error in case we had a non-object file. + consumeError(OptionalObject.takeError()); + + // If we're adding a bitcode file to the archive, detect the Archive kind + // based on the target triple. + LLVMContext Context; + if (identify_magic(MemBufferRef.getBuffer()) == file_magic::bitcode) { + if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile( + MemBufferRef, file_magic::bitcode, &Context)) { + auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr); + return Triple(IRObject.getTargetTriple()).isOSDarwin() + ? object::Archive::K_DARWIN + : object::Archive::K_GNU; + } else { + // Squelch the error in case this was not a SymbolicFile. + consumeError(ObjOrErr.takeError()); + } + } + + return object::Archive::getDefaultKindForHost(); +} + Expected<NewArchiveMember> NewArchiveMember::getOldMember(const object::Archive::Child &OldMember, bool Deterministic) { @@ -128,16 +165,20 @@ static bool isDarwin(object::Archive::Kind Kind) { Kind == object::Archive::K_DARWIN64; } +static bool isAIXBigArchive(object::Archive::Kind Kind) { + return Kind == object::Archive::K_AIXBIG; +} + static bool isBSDLike(object::Archive::Kind Kind) { switch (Kind) { case object::Archive::K_GNU: case object::Archive::K_GNU64: + case object::Archive::K_AIXBIG: return false; case object::Archive::K_BSD: case object::Archive::K_DARWIN: case object::Archive::K_DARWIN64: return true; - case object::Archive::K_AIXBIG: case object::Archive::K_COFF: break; } @@ -190,6 +231,31 @@ printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name, Out.write(uint8_t(0)); } +static void +printBigArchiveMemberHeader(raw_ostream &Out, StringRef Name, + const sys::TimePoint<std::chrono::seconds> &ModTime, + unsigned UID, unsigned GID, unsigned Perms, + uint64_t Size, unsigned PrevOffset, + unsigned NextOffset) { + unsigned NameLen = Name.size(); + + printWithSpacePadding(Out, Size, 20); // File member size + printWithSpacePadding(Out, NextOffset, 20); // Next member header offset + printWithSpacePadding(Out, PrevOffset, 20); // Previous member header offset + printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); // File member date + // The big archive format has 12 chars for uid and gid. + printWithSpacePadding(Out, UID % 1000000000000, 12); // UID + printWithSpacePadding(Out, GID % 1000000000000, 12); // GID + printWithSpacePadding(Out, format("%o", Perms), 12); // Permission + printWithSpacePadding(Out, NameLen, 4); // Name length + if (NameLen) { + printWithSpacePadding(Out, Name, NameLen); // Name + if (NameLen % 2) + Out.write(uint8_t(0)); // Null byte padding + } + Out << "`\n"; // Terminator +} + static bool useStringTable(bool Thin, StringRef Name) { return Thin || Name.size() >= 16 || Name.contains('/'); } @@ -200,8 +266,8 @@ static bool is64BitKind(object::Archive::Kind Kind) { case object::Archive::K_BSD: case object::Archive::K_DARWIN: case object::Archive::K_COFF: - case object::Archive::K_AIXBIG: return false; + case object::Archive::K_AIXBIG: case object::Archive::K_DARWIN64: case object::Archive::K_GNU64: return true; @@ -305,7 +371,11 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind, // least 4-byte aligned for 32-bit content. Opt for the larger encoding // uniformly. // We do this for all bsd formats because it simplifies aligning members. - uint32_t Pad = offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2)); + // For the big archive format, the symbol table is the last member, so there + // is no need to align. + uint32_t Pad = isAIXBigArchive(Kind) + ? 0 + : offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2)); Size += Pad; if (Padding) *Padding = Pad; @@ -313,11 +383,15 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind, } static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind, - bool Deterministic, uint64_t Size) { + bool Deterministic, uint64_t Size, + uint64_t PrevMemberOffset = 0) { if (isBSDLike(Kind)) { const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF"; printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0, Size); + } else if (isAIXBigArchive(Kind)) { + printBigArchiveMemberHeader(Out, "", now(Deterministic), 0, 0, + 0, Size, PrevMemberOffset, 0); } else { const char *Name = is64BitKind(Kind) ? "/SYM64" : ""; printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size); @@ -326,7 +400,8 @@ static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind, static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, bool Deterministic, ArrayRef<MemberData> Members, - StringRef StringTable) { + StringRef StringTable, + uint64_t PrevMemberOffset = 0) { // We don't write a symbol table on an archive with no members -- except on // Darwin, where the linker will abort unless the archive has a symbol table. if (StringTable.empty() && !isDarwin(Kind)) @@ -339,9 +414,10 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4; uint32_t Pad; uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize, StringTable, &Pad); - writeSymbolTableHeader(Out, Kind, Deterministic, Size); + writeSymbolTableHeader(Out, Kind, Deterministic, Size, PrevMemberOffset); - uint64_t Pos = Out.tell() + Size; + uint64_t Pos = isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) + : Out.tell() + Size; if (isBSDLike(Kind)) printNBits(Out, Kind, NumSyms * 2 * OffsetSize); @@ -410,9 +486,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, bool NeedSymbols, 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 - // symbol table is aligned to be a multiple of 8 bytes - uint64_t Pos = 0; + uint64_t Pos = + isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 0; std::vector<MemberData> Ret; bool HasObject = false; @@ -472,6 +547,9 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, Entry.second = Entry.second > 1 ? 1 : 0; } + // The big archive format needs to know the offset of the previous member + // header. + unsigned PrevOffset = 0; for (const NewArchiveMember &M : NewMembers) { std::string Header; raw_string_ostream Out(Header); @@ -504,8 +582,16 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, std::move(StringMsg), object::object_error::parse_failed); } - printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M, - ModTime, Size); + if (isAIXBigArchive(Kind)) { + unsigned NextOffset = Pos + sizeof(object::BigArMemHdrType) + + alignTo(M.MemberName.size(), 2) + alignTo(Size, 2); + printBigArchiveMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID, + M.Perms, Size, PrevOffset, NextOffset); + PrevOffset = Pos; + } else { + printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M, + ModTime, Size); + } Out.flush(); std::vector<unsigned> Symbols; @@ -589,22 +675,25 @@ static Error writeArchiveToStream(raw_ostream &Out, return E; std::vector<MemberData> &Data = *DataOrErr; - if (!StringTableBuf.empty()) + if (!StringTableBuf.empty() && !isAIXBigArchive(Kind)) Data.insert(Data.begin(), computeStringTable(StringTableBuf)); // We would like to detect if we need to switch to a 64-bit symbol table. - if (WriteSymtab) { - uint64_t MaxOffset = 8; // For the file signature. - uint64_t LastOffset = MaxOffset; - uint64_t NumSyms = 0; - for (const auto &M : Data) { - // Record the start of the member's offset - LastOffset = MaxOffset; - // Account for the size of each part associated with the member. - MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size(); - NumSyms += M.Symbols.size(); - } + uint64_t LastMemberEndOffset = + isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 8; + uint64_t LastMemberHeaderOffset = LastMemberEndOffset; + uint64_t NumSyms = 0; + for (const auto &M : Data) { + // Record the start of the member's offset + LastMemberHeaderOffset = LastMemberEndOffset; + // Account for the size of each part associated with the member. + LastMemberEndOffset += M.Header.size() + M.Data.size() + M.Padding.size(); + NumSyms += M.Symbols.size(); + } + // The symbol table is put at the end of the big archive file. The symbol + // table is at the start of the archive file for other archive formats. + if (WriteSymtab && !isAIXBigArchive(Kind)) { // We assume 32-bit offsets to see if 32-bit symbols are possible or not. uint64_t SymtabSize = computeSymbolTableSize(Kind, NumSyms, 4, SymNamesBuf); auto computeSymbolTableHeaderSize = @@ -614,7 +703,7 @@ static Error writeArchiveToStream(raw_ostream &Out, writeSymbolTableHeader(Tmp, Kind, Deterministic, SymtabSize); return TmpBuf.size(); }; - LastOffset += computeSymbolTableHeaderSize() + SymtabSize; + LastMemberHeaderOffset += computeSymbolTableHeaderSize() + SymtabSize; // The SYM64 format is used when an archive's member offsets are larger than // 32-bits can hold. The need for this shift in format is detected by @@ -628,10 +717,10 @@ static Error writeArchiveToStream(raw_ostream &Out, if (Sym64Env) StringRef(Sym64Env).getAsInteger(10, Sym64Threshold); - // If LastOffset isn't going to fit in a 32-bit varible we need to switch - // to 64-bit. Note that the file can be larger than 4GB as long as the last - // member starts before the 4GB offset. - if (LastOffset >= Sym64Threshold) { + // If LastMemberHeaderOffset isn't going to fit in a 32-bit varible we need + // to switch to 64-bit. Note that the file can be larger than 4GB as long as + // the last member starts before the 4GB offset. + if (LastMemberHeaderOffset >= Sym64Threshold) { if (Kind == object::Archive::K_DARWIN) Kind = object::Archive::K_DARWIN64; else @@ -641,15 +730,92 @@ static Error writeArchiveToStream(raw_ostream &Out, if (Thin) Out << "!<thin>\n"; + else if (isAIXBigArchive(Kind)) + Out << "<bigaf>\n"; else Out << "!<arch>\n"; - if (WriteSymtab) - writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf); + if (!isAIXBigArchive(Kind)) { + if (WriteSymtab) + writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf); + for (const MemberData &M : Data) + Out << M.Header << M.Data << M.Padding; + } else { + // For the big archive (AIX) format, compute a table of member names and + // offsets, used in the member table. + uint64_t MemberTableNameStrTblSize = 0; + std::vector<size_t> MemberOffsets; + std::vector<StringRef> MemberNames; + // Loop across object to find offset and names. + uint64_t MemberEndOffset = sizeof(object::BigArchive::FixLenHdr); + for (size_t I = 0, Size = NewMembers.size(); I != Size; ++I) { + const NewArchiveMember &Member = NewMembers[I]; + MemberTableNameStrTblSize += Member.MemberName.size() + 1; + MemberOffsets.push_back(MemberEndOffset); + MemberNames.push_back(Member.MemberName); + // File member name ended with "`\n". The length is included in + // BigArMemHdrType. + MemberEndOffset += sizeof(object::BigArMemHdrType) + + alignTo(Data[I].Data.size(), 2) + + alignTo(Member.MemberName.size(), 2); + } - for (const MemberData &M : Data) - Out << M.Header << M.Data << M.Padding; + // AIX member table size. + unsigned MemberTableSize = 20 + // Number of members field + 20 * MemberOffsets.size() + + MemberTableNameStrTblSize; + + unsigned GlobalSymbolOffset = + (WriteSymtab && NumSyms > 0) + ? LastMemberEndOffset + + alignTo(sizeof(object::BigArMemHdrType) + MemberTableSize, 2) + : 0; + + // Fixed Sized Header. + printWithSpacePadding(Out, NewMembers.size() ? LastMemberEndOffset : 0, + 20); // Offset to member table + // If there are no file members in the archive, there will be no global + // symbol table. + printWithSpacePadding(Out, NewMembers.size() ? GlobalSymbolOffset : 0, 20); + printWithSpacePadding( + Out, 0, + 20); // Offset to 64 bits global symbol table - Not supported yet + printWithSpacePadding( + Out, NewMembers.size() ? sizeof(object::BigArchive::FixLenHdr) : 0, + 20); // Offset to first archive member + printWithSpacePadding(Out, NewMembers.size() ? LastMemberHeaderOffset : 0, + 20); // Offset to last archive member + printWithSpacePadding( + Out, 0, + 20); // Offset to first member of free list - Not supported yet + + for (const MemberData &M : Data) { + Out << M.Header << M.Data; + if (M.Data.size() % 2) + Out << '\0'; + } + if (NewMembers.size()) { + // Member table. + printBigArchiveMemberHeader(Out, "", sys::toTimePoint(0), 0, 0, 0, + MemberTableSize, LastMemberHeaderOffset, + GlobalSymbolOffset); + printWithSpacePadding(Out, MemberOffsets.size(), 20); // Number of members + for (uint64_t MemberOffset : MemberOffsets) + printWithSpacePadding(Out, MemberOffset, + 20); // Offset to member file header. + for (StringRef MemberName : MemberNames) + Out << MemberName << '\0'; // Member file name, null byte padding. + + if (MemberTableNameStrTblSize % 2) + Out << '\0'; // Name table must be tail padded to an even number of + // bytes. + + if (WriteSymtab && NumSyms > 0) + writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf, + LastMemberEndOffset); + } + } Out.flush(); return Error::success(); } diff --git a/contrib/llvm-project/llvm/lib/Object/Binary.cpp b/contrib/llvm-project/llvm/lib/Object/Binary.cpp index 143554344256..8065e3eb1d85 100644 --- a/contrib/llvm-project/llvm/lib/Object/Binary.cpp +++ b/contrib/llvm-project/llvm/lib/Object/Binary.cpp @@ -18,14 +18,13 @@ #include "llvm/Object/MachOUniversal.h" #include "llvm/Object/Minidump.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/OffloadBinary.h" #include "llvm/Object/TapiUniversal.h" #include "llvm/Object/WindowsResource.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include <algorithm> #include <memory> #include <system_error> @@ -84,9 +83,13 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer, // PDB does not support the Binary interface. return errorCodeToError(object_error::invalid_file_type); case file_magic::unknown: + case file_magic::cuda_fatbinary: case file_magic::coff_cl_gl_object: + case file_magic::dxcontainer_object: // Unrecognized object file format. return errorCodeToError(object_error::invalid_file_type); + case file_magic::offload_binary: + return OffloadBinary::create(Buffer); case file_magic::minidump: return MinidumpFile::create(Buffer); case file_magic::tapi_file: diff --git a/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp b/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp index 69bbf70b43a1..91ecea11511d 100644 --- a/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp @@ -12,10 +12,14 @@ #include "llvm/Object/COFFImportFile.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Twine.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" #include "llvm/Object/COFF.h" +#include "llvm/Support/Allocator.h" +#include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/Path.h" #include <cstdint> diff --git a/contrib/llvm-project/llvm/lib/Object/COFFModuleDefinition.cpp b/contrib/llvm-project/llvm/lib/Object/COFFModuleDefinition.cpp index 55ddd3baca2b..0666970d5c60 100644 --- a/contrib/llvm-project/llvm/lib/Object/COFFModuleDefinition.cpp +++ b/contrib/llvm-project/llvm/lib/Object/COFFModuleDefinition.cpp @@ -17,12 +17,10 @@ #include "llvm/Object/COFFModuleDefinition.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" -#include "llvm/Object/COFF.h" #include "llvm/Object/COFFImportFile.h" #include "llvm/Object/Error.h" #include "llvm/Support/Error.h" #include "llvm/Support/Path.h" -#include "llvm/Support/raw_ostream.h" using namespace llvm::COFF; using namespace llvm; diff --git a/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp index 354b3c0d5577..1a4bb329201a 100644 --- a/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp @@ -25,7 +25,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryBufferRef.h" #include <algorithm> #include <cassert> #include <cinttypes> @@ -447,7 +447,8 @@ Error COFFObjectFile::initSymbolTablePtr() { // Check that the string table is null terminated if has any in it. if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0) - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, + "string table missing null terminator"); return Error::success(); } @@ -469,23 +470,43 @@ Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const { } // Returns the file offset for the given RVA. -Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const { +Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res, + const char *ErrorContext) const { for (const SectionRef &S : sections()) { const coff_section *Section = getCOFFSection(S); uint32_t SectionStart = Section->VirtualAddress; uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize; if (SectionStart <= Addr && Addr < SectionEnd) { + // A table/directory entry can be pointing to somewhere in a stripped + // section, in an object that went through `objcopy --only-keep-debug`. + // In this case we don't want to cause the parsing of the object file to + // fail, otherwise it will be impossible to use this object as debug info + // in LLDB. Return SectionStrippedError here so that + // COFFObjectFile::initialize can ignore the error. + // Somewhat common binaries may have RVAs pointing outside of the + // provided raw data. Instead of rejecting the binaries, just + // treat the section as stripped for these purposes. + if (Section->SizeOfRawData < Section->VirtualSize && + Addr >= SectionStart + Section->SizeOfRawData) { + return make_error<SectionStrippedError>(); + } uint32_t Offset = Addr - SectionStart; Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData + Offset; return Error::success(); } } - return errorCodeToError(object_error::parse_failed); + if (ErrorContext) + return createStringError(object_error::parse_failed, + "RVA 0x%" PRIx32 " for %s not found", Addr, + ErrorContext); + return createStringError(object_error::parse_failed, + "RVA 0x%" PRIx32 " not found", Addr); } Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size, - ArrayRef<uint8_t> &Contents) const { + ArrayRef<uint8_t> &Contents, + const char *ErrorContext) const { for (const SectionRef &S : sections()) { const coff_section *Section = getCOFFSection(S); uint32_t SectionStart = Section->VirtualAddress; @@ -501,7 +522,12 @@ Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size, return Error::success(); } } - return errorCodeToError(object_error::parse_failed); + if (ErrorContext) + return createStringError(object_error::parse_failed, + "RVA 0x%" PRIx32 " for %s not found", RVA, + ErrorContext); + return createStringError(object_error::parse_failed, + "RVA 0x%" PRIx32 " not found", RVA); } // Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name @@ -521,11 +547,12 @@ Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir, const codeview::DebugInfo *&PDBInfo, StringRef &PDBFileName) const { ArrayRef<uint8_t> InfoBytes; - if (Error E = getRvaAndSizeAsBytes( - DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes)) + if (Error E = + getRvaAndSizeAsBytes(DebugDir->AddressOfRawData, DebugDir->SizeOfData, + InfoBytes, "PDB info")) return E; if (InfoBytes.size() < sizeof(*PDBInfo) + 1) - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, "PDB info too small"); PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data()); InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo)); PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()), @@ -563,7 +590,7 @@ Error COFFObjectFile::initImportTablePtr() { // Find the section that contains the RVA. This is needed because the RVA is // the import table's memory address which is different from its file offset. uintptr_t IntPtr = 0; - if (Error E = getRvaPtr(ImportTableRva, IntPtr)) + if (Error E = getRvaPtr(ImportTableRva, IntPtr, "import table")) return E; if (Error E = checkOffset(Data, IntPtr, DataEntry->Size)) return E; @@ -586,8 +613,11 @@ Error COFFObjectFile::initDelayImportTablePtr() { sizeof(delay_import_directory_table_entry) - 1; uintptr_t IntPtr = 0; - if (Error E = getRvaPtr(RVA, IntPtr)) + if (Error E = getRvaPtr(RVA, IntPtr, "delay import table")) return E; + if (Error E = checkOffset(Data, IntPtr, DataEntry->Size)) + return E; + DelayImportDirectory = reinterpret_cast< const delay_import_directory_table_entry *>(IntPtr); return Error::success(); @@ -607,8 +637,11 @@ Error COFFObjectFile::initExportTablePtr() { uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress; uintptr_t IntPtr = 0; - if (Error E = getRvaPtr(ExportTableRva, IntPtr)) + if (Error E = getRvaPtr(ExportTableRva, IntPtr, "export table")) return E; + if (Error E = checkOffset(Data, IntPtr, DataEntry->Size)) + return E; + ExportDirectory = reinterpret_cast<const export_directory_table_entry *>(IntPtr); return Error::success(); @@ -623,8 +656,12 @@ Error COFFObjectFile::initBaseRelocPtr() { return Error::success(); uintptr_t IntPtr = 0; - if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) + if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, + "base reloc table")) + return E; + if (Error E = checkOffset(Data, IntPtr, DataEntry->Size)) return E; + BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>( IntPtr); BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>( @@ -646,11 +683,16 @@ Error COFFObjectFile::initDebugDirectoryPtr() { // Check that the size is a multiple of the entry size. if (DataEntry->Size % sizeof(debug_directory) != 0) - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, + "debug directory has uneven size"); uintptr_t IntPtr = 0; - if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) + if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, + "debug directory")) + return E; + if (Error E = checkOffset(Data, IntPtr, DataEntry->Size)) return E; + DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr); DebugDirectoryEnd = reinterpret_cast<const debug_directory *>( IntPtr + DataEntry->Size); @@ -680,7 +722,10 @@ Error COFFObjectFile::initTLSDirectoryPtr() { static_cast<uint32_t>(DataEntry->Size), DirSize); uintptr_t IntPtr = 0; - if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) + if (Error E = + getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, "TLS directory")) + return E; + if (Error E = checkOffset(Data, IntPtr, DataEntry->Size)) return E; if (is64()) @@ -701,7 +746,10 @@ Error COFFObjectFile::initLoadConfigPtr() { if (DataEntry->RelativeVirtualAddress == 0) return Error::success(); uintptr_t IntPtr = 0; - if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr)) + if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr, + "load config table")) + return E; + if (Error E = checkOffset(Data, IntPtr, DataEntry->Size)) return E; LoadConfig = (const void *)IntPtr; @@ -727,6 +775,14 @@ COFFObjectFile::COFFObjectFile(MemoryBufferRef Object) DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr), TLSDirectory32(nullptr), TLSDirectory64(nullptr) {} +static Error ignoreStrippedErrors(Error E) { + if (E.isA<SectionStrippedError>()) { + consumeError(std::move(E)); + return Error::success(); + } + return E; +} + Error COFFObjectFile::initialize() { // Check that we at least have enough room for a header. std::error_code EC; @@ -749,7 +805,8 @@ Error COFFObjectFile::initialize() { CurPtr = DH->AddressOfNewExeHeader; // Check the PE magic bytes. ("PE\0\0") if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) { - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, + "incorrect PE magic"); } CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes. HasPEHeader = true; @@ -805,7 +862,8 @@ Error COFFObjectFile::initialize() { DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize; } else { // It's neither PE32 nor PE32+. - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, + "incorrect PE magic"); } if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize)) return E; @@ -834,33 +892,34 @@ Error COFFObjectFile::initialize() { } else { // We had better not have any symbols if we don't have a symbol table. if (getNumberOfSymbols() != 0) { - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, + "symbol table missing"); } } // Initialize the pointer to the beginning of the import table. - if (Error E = initImportTablePtr()) + if (Error E = ignoreStrippedErrors(initImportTablePtr())) return E; - if (Error E = initDelayImportTablePtr()) + if (Error E = ignoreStrippedErrors(initDelayImportTablePtr())) return E; // Initialize the pointer to the export table. - if (Error E = initExportTablePtr()) + if (Error E = ignoreStrippedErrors(initExportTablePtr())) return E; // Initialize the pointer to the base relocation table. - if (Error E = initBaseRelocPtr()) + if (Error E = ignoreStrippedErrors(initBaseRelocPtr())) return E; // Initialize the pointer to the debug directory. - if (Error E = initDebugDirectoryPtr()) + if (Error E = ignoreStrippedErrors(initDebugDirectoryPtr())) return E; // Initialize the pointer to the TLS directory. - if (Error E = initTLSDirectoryPtr()) + if (Error E = ignoreStrippedErrors(initTLSDirectoryPtr())) return E; - if (Error E = initLoadConfigPtr()) + if (Error E = ignoreStrippedErrors(initLoadConfigPtr())) return E; return Error::success(); @@ -1021,13 +1080,14 @@ Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const { // We already verified the section table data, so no need to check again. return SectionTable + (Index - 1); } - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, + "section index out of bounds"); } Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const { if (StringTableSize <= 4) // Tried to get a string from an empty string table. - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, "string table empty"); if (Offset >= StringTableSize) return errorCodeToError(object_error::unexpected_eof); return StringRef(StringTable + Offset); @@ -1086,13 +1146,7 @@ uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) 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. - Name = Sec->Name; - else - // Not null terminated, use all 8 bytes. - Name = StringRef(Sec->Name, COFF::NameSize); + StringRef Name = StringRef(Sec->Name, COFF::NameSize).split('\0').first; // Check for string table entry. First byte is '/'. if (Name.startswith("/")) { @@ -1414,7 +1468,8 @@ ImportDirectoryEntryRef::lookup_table_symbols() const { Error ImportDirectoryEntryRef::getName(StringRef &Result) const { uintptr_t IntPtr = 0; - if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr)) + if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr, + "import directory name")) return E; Result = StringRef(reinterpret_cast<const char *>(IntPtr)); return Error::success(); @@ -1460,7 +1515,8 @@ DelayImportDirectoryEntryRef::imported_symbols() const { Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const { uintptr_t IntPtr = 0; - if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr)) + if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr, + "delay import directory name")) return E; Result = StringRef(reinterpret_cast<const char *>(IntPtr)); return Error::success(); @@ -1477,7 +1533,7 @@ Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex, uint32_t RVA = Table[Index].DelayImportAddressTable + AddrIndex * (OwningObject->is64() ? 8 : 4); uintptr_t IntPtr = 0; - if (Error E = OwningObject->getRvaPtr(RVA, IntPtr)) + if (Error E = OwningObject->getRvaPtr(RVA, IntPtr, "import address")) return E; if (OwningObject->is64()) Result = *reinterpret_cast<const ulittle64_t *>(IntPtr); @@ -1499,7 +1555,8 @@ void ExportDirectoryEntryRef::moveNext() { // by ordinal, the empty string is set as a result. Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const { uintptr_t IntPtr = 0; - if (Error E = OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr)) + if (Error E = + OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr, "dll name")) return E; Result = StringRef(reinterpret_cast<const char *>(IntPtr)); return Error::success(); @@ -1520,8 +1577,8 @@ Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const { // Returns the address of the current export symbol. Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const { uintptr_t IntPtr = 0; - if (Error EC = - OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr)) + if (Error EC = OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, + IntPtr, "export address")) return EC; const export_address_table_entry *entry = reinterpret_cast<const export_address_table_entry *>(IntPtr); @@ -1534,8 +1591,8 @@ Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const { Error ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const { uintptr_t IntPtr = 0; - if (Error EC = - OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr)) + if (Error EC = OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr, + "export ordinal table")) return EC; const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr); @@ -1545,11 +1602,12 @@ ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const { I < E; ++I, ++Offset) { if (*I != Index) continue; - if (Error EC = - OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr)) + if (Error EC = OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr, + "export table entry")) return EC; const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr); - if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr)) + if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr, + "export symbol name")) return EC; Result = StringRef(reinterpret_cast<const char *>(IntPtr)); return Error::success(); @@ -1562,7 +1620,8 @@ Error ExportDirectoryEntryRef::isForwarder(bool &Result) const { const data_directory *DataEntry = OwningObject->getDataDirectory(COFF::EXPORT_TABLE); if (!DataEntry) - return errorCodeToError(object_error::parse_failed); + return createStringError(object_error::parse_failed, + "export table missing"); uint32_t RVA; if (auto EC = getExportRVA(RVA)) return EC; @@ -1577,7 +1636,7 @@ Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const { if (auto EC = getExportRVA(RVA)) return EC; uintptr_t IntPtr = 0; - if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr)) + if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr, "export forward target")) return EC; Result = StringRef(reinterpret_cast<const char *>(IntPtr)); return Error::success(); @@ -1606,7 +1665,7 @@ Error ImportedSymbolRef::getSymbolName(StringRef &Result) const { RVA = Entry64[Index].getHintNameRVA(); } uintptr_t IntPtr = 0; - if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr)) + if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol name")) return EC; // +2 because the first two bytes is hint. Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2)); @@ -1645,7 +1704,7 @@ Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const { RVA = Entry64[Index].getHintNameRVA(); } uintptr_t IntPtr = 0; - if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr)) + if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr, "import symbol ordinal")) return EC; Result = *reinterpret_cast<const ulittle16_t *>(IntPtr); return Error::success(); diff --git a/contrib/llvm-project/llvm/lib/Object/DXContainer.cpp b/contrib/llvm-project/llvm/lib/Object/DXContainer.cpp new file mode 100644 index 000000000000..ca859c1f69ae --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Object/DXContainer.cpp @@ -0,0 +1,111 @@ +//===- DXContainer.cpp - DXContainer 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/DXContainer.h" +#include "llvm/BinaryFormat/DXContainer.h" +#include "llvm/Object/Error.h" + +using namespace llvm; +using namespace llvm::object; + +static Error parseFailed(const Twine &Msg) { + return make_error<GenericBinaryError>(Msg.str(), object_error::parse_failed); +} + +template <typename T> +static Error readStruct(StringRef Buffer, const char *Src, T &Struct) { + // Don't read before the beginning or past the end of the file + if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end()) + return parseFailed("Reading structure out of file bounds"); + + memcpy(&Struct, Src, sizeof(T)); + // DXContainer is always little endian + if (sys::IsBigEndianHost) + Struct.swapBytes(); + return Error::success(); +} + +template <typename T> +static Error readInteger(StringRef Buffer, const char *Src, T &Val) { + static_assert(std::is_integral<T>::value, + "Cannot call readInteger on non-integral type."); + assert(reinterpret_cast<uintptr_t>(Src) % alignof(T) == 0 && + "Unaligned read of value from buffer!"); + // Don't read before the beginning or past the end of the file + if (Src < Buffer.begin() || Src + sizeof(T) > Buffer.end()) + return parseFailed("Reading structure out of file bounds"); + + Val = *reinterpret_cast<const T *>(Src); + // DXContainer is always little endian + if (sys::IsBigEndianHost) + sys::swapByteOrder(Val); + return Error::success(); +} + +DXContainer::DXContainer(MemoryBufferRef O) : Data(O) {} + +Error DXContainer::parseHeader() { + return readStruct(Data.getBuffer(), Data.getBuffer().data(), Header); +} + +Error DXContainer::parseDXILHeader(uint32_t Offset) { + if (DXIL) + return parseFailed("More than one DXIL part is present in the file"); + const char *Current = Data.getBuffer().data() + Offset; + dxbc::ProgramHeader Header; + if (Error Err = readStruct(Data.getBuffer(), Current, Header)) + return Err; + Current += offsetof(dxbc::ProgramHeader, Bitcode) + Header.Bitcode.Offset; + DXIL.emplace(std::make_pair(Header, Current)); + return Error::success(); +} + +Error DXContainer::parsePartOffsets() { + const char *Current = Data.getBuffer().data() + sizeof(dxbc::Header); + for (uint32_t Part = 0; Part < Header.PartCount; ++Part) { + uint32_t PartOffset; + if (Error Err = readInteger(Data.getBuffer(), Current, PartOffset)) + return Err; + Current += sizeof(uint32_t); + // We need to ensure that each part offset leaves enough space for a part + // header. To prevent overflow, we subtract the part header size from the + // buffer size, rather than adding to the offset. Since the file header is + // larger than the part header we can't reach this code unless the buffer + // is larger than the part header, so this can't underflow. + if (PartOffset > Data.getBufferSize() - sizeof(dxbc::PartHeader)) + return parseFailed("Part offset points beyond boundary of the file"); + PartOffsets.push_back(PartOffset); + + // If this isn't a dxil part stop here... + if (Data.getBuffer().substr(PartOffset, 4) != "DXIL") + continue; + if (Error Err = parseDXILHeader(PartOffset + sizeof(dxbc::PartHeader))) + return Err; + } + return Error::success(); +} + +Expected<DXContainer> DXContainer::create(MemoryBufferRef Object) { + DXContainer Container(Object); + if (Error Err = Container.parseHeader()) + return std::move(Err); + if (Error Err = Container.parsePartOffsets()) + return std::move(Err); + return Container; +} + +void DXContainer::PartIterator::updateIteratorImpl(const uint32_t Offset) { + StringRef Buffer = Container.Data.getBuffer(); + const char *Current = Buffer.data() + Offset; + // Offsets are validated during parsing, so all offsets in the container are + // valid and contain enough readable data to read a header. + cantFail(readStruct(Buffer, Current, IteratorState.Part)); + IteratorState.Data = + StringRef(Current + sizeof(dxbc::PartHeader), IteratorState.Part.Size); + IteratorState.Offset = Offset; +} diff --git a/contrib/llvm-project/llvm/lib/Object/Decompressor.cpp b/contrib/llvm-project/llvm/lib/Object/Decompressor.cpp index 11efd857d1a1..de067ed59ac5 100644 --- a/contrib/llvm-project/llvm/lib/Object/Decompressor.cpp +++ b/contrib/llvm-project/llvm/lib/Object/Decompressor.cpp @@ -8,7 +8,7 @@ #include "llvm/Object/Decompressor.h" #include "llvm/BinaryFormat/ELF.h" -#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ObjectFile.h" #include "llvm/Support/Compression.h" #include "llvm/Support/DataExtractor.h" #include "llvm/Support/Endian.h" diff --git a/contrib/llvm-project/llvm/lib/Object/ELF.cpp b/contrib/llvm-project/llvm/lib/Object/ELF.cpp index 56a426211755..6acf4543be5a 100644 --- a/contrib/llvm-project/llvm/lib/Object/ELF.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ELF.cpp @@ -166,6 +166,13 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, break; } break; + case ELF::EM_LOONGARCH: + switch (Type) { +#include "llvm/BinaryFormat/ELFRelocs/LoongArch.def" + default: + break; + } + break; default: break; } @@ -288,6 +295,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_EHDR); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_PHDR); + STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP_V0); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); @@ -633,7 +641,6 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const { DataExtractor::Cursor Cur(0); Error ULEBSizeErr = Error::success(); - // Helper to extract and decode the next ULEB128 value as uint32_t. // Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t // limit. @@ -653,18 +660,34 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const { return static_cast<uint32_t>(Value); }; + uint8_t Version = 0; while (!ULEBSizeErr && Cur && Cur.tell() < Content.size()) { + if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) { + Version = Data.getU8(Cur); + if (!Cur) + break; + if (Version > 1) + return createError("unsupported SHT_LLVM_BB_ADDR_MAP version: " + + Twine(static_cast<int>(Version))); + Data.getU8(Cur); // Feature byte + } uintX_t Address = static_cast<uintX_t>(Data.getAddress(Cur)); uint32_t NumBlocks = ReadULEB128AsUInt32(); std::vector<BBAddrMap::BBEntry> BBEntries; + uint32_t PrevBBEndOffset = 0; for (uint32_t BlockID = 0; !ULEBSizeErr && Cur && (BlockID < NumBlocks); ++BlockID) { uint32_t Offset = ReadULEB128AsUInt32(); uint32_t Size = ReadULEB128AsUInt32(); uint32_t Metadata = ReadULEB128AsUInt32(); + if (Version >= 1) { + // Offset is calculated relative to the end of the previous BB. + Offset += PrevBBEndOffset; + PrevBBEndOffset = Offset + Size; + } BBEntries.push_back({Offset, Size, Metadata}); } - FunctionEntries.push_back({Address, BBEntries}); + FunctionEntries.push_back({Address, std::move(BBEntries)}); } // Either Cur is in the error state, or ULEBSizeError is set (not both), but // we join the two errors here to be safe. diff --git a/contrib/llvm-project/llvm/lib/Object/ELFObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/ELFObjectFile.cpp index cf1f12d9a9a7..38de669f1d3d 100644 --- a/contrib/llvm-project/llvm/lib/Object/ELFObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ELFObjectFile.cpp @@ -21,7 +21,6 @@ #include "llvm/Object/Error.h" #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" -#include "llvm/Support/Endian.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/RISCVAttributeParser.h" @@ -31,7 +30,6 @@ #include <cstdint> #include <memory> #include <string> -#include <system_error> #include <utility> using namespace llvm; @@ -169,11 +167,11 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { bool isV7 = false; Optional<unsigned> Attr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); - if (Attr.hasValue()) + if (Attr) isV7 = Attr.getValue() == ARMBuildAttrs::v7; Attr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile); - if (Attr.hasValue()) { + if (Attr) { switch (Attr.getValue()) { case ARMBuildAttrs::ApplicationProfile: Features.AddFeature("aclass"); @@ -192,7 +190,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { } Attr = Attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use); - if (Attr.hasValue()) { + if (Attr) { switch (Attr.getValue()) { default: break; @@ -207,7 +205,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { } Attr = Attributes.getAttributeValue(ARMBuildAttrs::FP_arch); - if (Attr.hasValue()) { + if (Attr) { switch (Attr.getValue()) { default: break; @@ -231,7 +229,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { } Attr = Attributes.getAttributeValue(ARMBuildAttrs::Advanced_SIMD_arch); - if (Attr.hasValue()) { + if (Attr) { switch (Attr.getValue()) { default: break; @@ -250,7 +248,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { } Attr = Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch); - if (Attr.hasValue()) { + if (Attr) { switch (Attr.getValue()) { default: break; @@ -269,7 +267,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { } Attr = Attributes.getAttributeValue(ARMBuildAttrs::DIV_use); - if (Attr.hasValue()) { + if (Attr) { switch (Attr.getValue()) { default: break; @@ -305,11 +303,11 @@ SubtargetFeatures ELFObjectFileBase::getRISCVFeatures() const { } Optional<StringRef> Attr = Attributes.getAttributeString(RISCVAttrs::ARCH); - if (Attr.hasValue()) { + if (Attr) { // The Arch pattern is [rv32|rv64][i|e]version(_[m|a|f|d|c]version)* // Version string pattern is (major)p(minor). Major and minor are optional. // For example, a version number could be 2p0, 2, or p92. - StringRef Arch = Attr.getValue(); + StringRef Arch = *Attr; if (Arch.consume_front("rv32")) Features.AddFeature("64bit", false); else if (Arch.consume_front("rv64")) @@ -360,6 +358,8 @@ Optional<StringRef> ELFObjectFileBase::tryGetCPUName() const { switch (getEMachine()) { case ELF::EM_AMDGPU: return getAMDGPUCPUName(); + case ELF::EM_PPC64: + return StringRef("future"); default: return None; } @@ -461,6 +461,8 @@ StringRef ELFObjectFileBase::getAMDGPUCPUName() const { return "gfx90a"; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX90C: return "gfx90c"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX940: + return "gfx940"; // AMDGCN GFX10. case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1010: @@ -483,6 +485,18 @@ StringRef ELFObjectFileBase::getAMDGPUCPUName() const { return "gfx1034"; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1035: return "gfx1035"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1036: + return "gfx1036"; + + // AMDGCN GFX11. + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1100: + return "gfx1100"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1101: + return "gfx1101"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1102: + return "gfx1102"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1103: + return "gfx1103"; default: llvm_unreachable("Unknown EF_AMDGPU_MACH value"); } @@ -509,7 +523,7 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { Optional<unsigned> Attr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch); - if (Attr.hasValue()) { + if (Attr) { switch (Attr.getValue()) { case ARMBuildAttrs::v4: Triple += "v4"; @@ -541,7 +555,7 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { case ARMBuildAttrs::v7: { Optional<unsigned> ArchProfileAttr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile); - if (ArchProfileAttr.hasValue() && + if (ArchProfileAttr && ArchProfileAttr.getValue() == ARMBuildAttrs::MicroControllerProfile) Triple += "v7m"; else @@ -572,6 +586,9 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { case ARMBuildAttrs::v8_1_M_Main: Triple += "v8.1m.main"; break; + case ARMBuildAttrs::v9_A: + Triple += "v9a"; + break; } } if (!isLittleEndian()) @@ -656,6 +673,36 @@ ELFObjectFileBase::getPltAddresses() const { } template <class ELFT> +Expected<std::vector<BBAddrMap>> +readBBAddrMapImpl(const ELFFile<ELFT> &EF, + Optional<unsigned> TextSectionIndex) { + using Elf_Shdr = typename ELFT::Shdr; + std::vector<BBAddrMap> BBAddrMaps; + const auto &Sections = cantFail(EF.sections()); + for (const Elf_Shdr &Sec : Sections) { + if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP && + Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP_V0) + continue; + if (TextSectionIndex) { + Expected<const Elf_Shdr *> TextSecOrErr = EF.getSection(Sec.sh_link); + if (!TextSecOrErr) + return createError("unable to get the linked-to section for " + + describe(EF, Sec) + ": " + + toString(TextSecOrErr.takeError())); + if (*TextSectionIndex != std::distance(Sections.begin(), *TextSecOrErr)) + continue; + } + Expected<std::vector<BBAddrMap>> BBAddrMapOrErr = EF.decodeBBAddrMap(Sec); + if (!BBAddrMapOrErr) + return createError("unable to read " + describe(EF, Sec) + ": " + + toString(BBAddrMapOrErr.takeError())); + std::move(BBAddrMapOrErr->begin(), BBAddrMapOrErr->end(), + std::back_inserter(BBAddrMaps)); + } + return BBAddrMaps; +} + +template <class ELFT> static Expected<std::vector<VersionEntry>> readDynsymVersionsImpl(const ELFFile<ELFT> &EF, ELFObjectFileBase::elf_symbol_iterator_range Symbols) { @@ -723,3 +770,17 @@ ELFObjectFileBase::readDynsymVersions() const { return readDynsymVersionsImpl(cast<ELF64BEObjectFile>(this)->getELFFile(), Symbols); } + +Expected<std::vector<BBAddrMap>> +ELFObjectFileBase::readBBAddrMap(Optional<unsigned> TextSectionIndex) const { + if (const auto *Obj = dyn_cast<ELF32LEObjectFile>(this)) + return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex); + if (const auto *Obj = dyn_cast<ELF64LEObjectFile>(this)) + return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex); + if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(this)) + return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex); + if (const auto *Obj = cast<ELF64BEObjectFile>(this)) + return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex); + else + llvm_unreachable("Unsupported binary format"); +} diff --git a/contrib/llvm-project/llvm/lib/Object/Error.cpp b/contrib/llvm-project/llvm/lib/Object/Error.cpp index bc75bc6c0445..6d1e3f2a59d0 100644 --- a/contrib/llvm-project/llvm/lib/Object/Error.cpp +++ b/contrib/llvm-project/llvm/lib/Object/Error.cpp @@ -52,6 +52,8 @@ std::string _object_error_category::message(int EV) const { return "Bitcode section not found in object file"; case object_error::invalid_symbol_index: return "Invalid symbol index"; + case object_error::section_stripped: + return "Section has been stripped from the object file"; } llvm_unreachable("An enumerator of object_error does not have a message " "defined."); diff --git a/contrib/llvm-project/llvm/lib/Object/IRObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/IRObjectFile.cpp index c653262791cc..091930988bd0 100644 --- a/contrib/llvm-project/llvm/lib/Object/IRObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/IRObjectFile.cpp @@ -11,20 +11,20 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/IRObjectFile.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/PointerUnion.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Bitcode/BitcodeReader.h" -#include "llvm/IR/GVMaterializer.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" -#include "llvm/MC/TargetRegistry.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace object; +namespace llvm { +class LLVMContext; +class raw_ostream; +} // namespace llvm + IRObjectFile::IRObjectFile(MemoryBufferRef Object, std::vector<std::unique_ptr<Module>> Mods) : SymbolicFile(Binary::ID_IR, Object), Mods(std::move(Mods)) { @@ -32,7 +32,7 @@ IRObjectFile::IRObjectFile(MemoryBufferRef Object, SymTab.addModule(M.get()); } -IRObjectFile::~IRObjectFile() {} +IRObjectFile::~IRObjectFile() = default; static ModuleSymbolTable::Symbol getSym(DataRefImpl &Symb) { return *reinterpret_cast<ModuleSymbolTable::Symbol *>(Symb.p); diff --git a/contrib/llvm-project/llvm/lib/Object/IRSymtab.cpp b/contrib/llvm-project/llvm/lib/Object/IRSymtab.cpp index dea3d90d3560..5a7ecdb1fc25 100644 --- a/contrib/llvm-project/llvm/lib/Object/IRSymtab.cpp +++ b/contrib/llvm-project/llvm/lib/Object/IRSymtab.cpp @@ -24,7 +24,6 @@ #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/MC/StringTableBuilder.h" -#include "llvm/Object/IRObjectFile.h" #include "llvm/Object/ModuleSymbolTable.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/Allocator.h" diff --git a/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp index 3d95b18f4672..2f463a1bd458 100644 --- a/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp @@ -34,7 +34,7 @@ #include "llvm/Support/Format.h" #include "llvm/Support/Host.h" #include "llvm/Support/LEB128.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/Path.h" #include "llvm/Support/SwapByteOrder.h" #include "llvm/Support/raw_ostream.h" @@ -1303,7 +1303,6 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, } const char *DyldIdLoadCmd = nullptr; - const char *FuncStartsLoadCmd = nullptr; const char *SplitInfoLoadCmd = nullptr; const char *CodeSignDrsLoadCmd = nullptr; const char *CodeSignLoadCmd = nullptr; @@ -1381,6 +1380,11 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd, "LC_DYLD_INFO_ONLY", Elements))) return; + } else if (Load.C.cmd == MachO::LC_DYLD_CHAINED_FIXUPS) { + if ((Err = checkLinkeditDataCommand( + *this, Load, I, &DyldChainedFixupsLoadCmd, + "LC_DYLD_CHAINED_FIXUPS", Elements, "chained fixups"))) + return; } else if (Load.C.cmd == MachO::LC_UUID) { if (Load.C.cmdsize != sizeof(MachO::uuid_command)) { Err = malformedError("LC_UUID command " + Twine(I) + " has incorrect " @@ -1596,9 +1600,9 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, return; // Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported. } else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) { - if ((Err = checkTwoLevelHintsCommand(*this, Load, I, - &TwoLevelHintsLoadCmd, Elements))) - return; + if ((Err = checkTwoLevelHintsCommand(*this, Load, I, + &TwoLevelHintsLoadCmd, Elements))) + return; } else if (Load.C.cmd == MachO::LC_IDENT) { // Note: LC_IDENT is ignored. continue; @@ -2993,7 +2997,9 @@ void ExportEntry::pushNode(uint64_t offset) { return; } if (O != nullptr) { - if (State.Other > O->getLibraryCount()) { + // Only positive numbers represent library ordinals. Zero and negative + // numbers have special meaning (see BindSpecialDylib). + if ((int64_t)State.Other > 0 && State.Other > O->getLibraryCount()) { *E = malformedError( "bad library ordinal: " + Twine((int)State.Other) + " (max " + Twine((int)O->getLibraryCount()) + @@ -3186,6 +3192,106 @@ iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const { return exports(Err, getDyldInfoExportsTrie(), this); } +MachOAbstractFixupEntry::MachOAbstractFixupEntry(Error *E, + const MachOObjectFile *O) + : E(E), O(O) { + // Cache the vmaddress of __TEXT + for (const auto &Command : O->load_commands()) { + if (Command.C.cmd == MachO::LC_SEGMENT) { + MachO::segment_command SLC = O->getSegmentLoadCommand(Command); + if (StringRef(SLC.segname) == StringRef("__TEXT")) { + TextAddress = SLC.vmaddr; + break; + } + } else if (Command.C.cmd == MachO::LC_SEGMENT_64) { + MachO::segment_command_64 SLC_64 = O->getSegment64LoadCommand(Command); + if (StringRef(SLC_64.segname) == StringRef("__TEXT")) { + TextAddress = SLC_64.vmaddr; + break; + } + } + } +} + +int32_t MachOAbstractFixupEntry::segmentIndex() const { return SegmentIndex; } + +uint64_t MachOAbstractFixupEntry::segmentOffset() const { + return SegmentOffset; +} + +uint64_t MachOAbstractFixupEntry::segmentAddress() const { + return O->BindRebaseAddress(SegmentIndex, 0); +} + +StringRef MachOAbstractFixupEntry::segmentName() const { + return O->BindRebaseSegmentName(SegmentIndex); +} + +StringRef MachOAbstractFixupEntry::sectionName() const { + return O->BindRebaseSectionName(SegmentIndex, SegmentOffset); +} + +uint64_t MachOAbstractFixupEntry::address() const { + return O->BindRebaseAddress(SegmentIndex, SegmentOffset); +} + +StringRef MachOAbstractFixupEntry::symbolName() const { return SymbolName; } + +int64_t MachOAbstractFixupEntry::addend() const { return Addend; } + +uint32_t MachOAbstractFixupEntry::flags() const { return Flags; } + +int MachOAbstractFixupEntry::ordinal() const { return Ordinal; } + +StringRef MachOAbstractFixupEntry::typeName() const { return "unknown"; } + +void MachOAbstractFixupEntry::moveToFirst() { + SegmentOffset = 0; + SegmentIndex = -1; + Ordinal = 0; + Flags = 0; + Addend = 0; + Done = false; +} + +void MachOAbstractFixupEntry::moveToEnd() { Done = true; } + +MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E, + const MachOObjectFile *O, + bool Parse) + : MachOAbstractFixupEntry(E, O) { + ErrorAsOutParameter e(E); + if (!Parse) + return; + if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets()) + FixupTargets = *FixupTargetsOrErr; + else { + *E = FixupTargetsOrErr.takeError(); + return; + } +} + +void MachOChainedFixupEntry::moveToFirst() { + MachOAbstractFixupEntry::moveToFirst(); + FixupIndex = 0; + moveNext(); +} + +void MachOChainedFixupEntry::moveToEnd() { + MachOAbstractFixupEntry::moveToEnd(); +} + +void MachOChainedFixupEntry::moveNext() { Done = true; } + +bool MachOChainedFixupEntry::operator==( + const MachOChainedFixupEntry &Other) const { + if (Done == Other.Done) + return true; + if ((FixupIndex == Other.FixupIndex)) + return true; + return false; +} + MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O, ArrayRef<uint8_t> Bytes, bool is64Bit) : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()), @@ -4194,6 +4300,16 @@ iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) { MachOBindEntry::Kind::Weak); } +iterator_range<fixup_iterator> MachOObjectFile::fixupTable(Error &Err) { + MachOChainedFixupEntry Start(&Err, this, true); + Start.moveToFirst(); + + MachOChainedFixupEntry Finish(&Err, this, false); + Finish.moveToEnd(); + + return make_range(fixup_iterator(Start), fixup_iterator(Finish)); +} + MachOObjectFile::load_command_iterator MachOObjectFile::begin_load_commands() const { return LoadCommands.begin(); @@ -4649,6 +4765,72 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const { return makeArrayRef(Ptr, DyldInfo.lazy_bind_size); } +Expected<Optional<MachO::dyld_chained_fixups_header>> +MachOObjectFile::getChainedFixupsHeader() const { + // Load the dyld chained fixups load command. + if (!DyldChainedFixupsLoadCmd) + return llvm::None; + auto DyldChainedFixupsOrErr = getStructOrErr<MachO::linkedit_data_command>( + *this, DyldChainedFixupsLoadCmd); + if (!DyldChainedFixupsOrErr) + return DyldChainedFixupsOrErr.takeError(); + MachO::linkedit_data_command DyldChainedFixups = DyldChainedFixupsOrErr.get(); + + // If the load command is present but the data offset has been zeroed out, + // as is the case for dylib stubs, return None (no error). + uint64_t CFHeaderOffset = DyldChainedFixups.dataoff; + if (CFHeaderOffset == 0) + return DyldChainedFixupsOrErr.takeError(); + + // Load the dyld chained fixups header. + const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset); + auto CFHeaderOrErr = + getStructOrErr<MachO::dyld_chained_fixups_header>(*this, CFHeaderPtr); + if (!CFHeaderOrErr) + return CFHeaderOrErr.takeError(); + MachO::dyld_chained_fixups_header CFHeader = CFHeaderOrErr.get(); + + // Reject unknown chained fixup formats. + if (CFHeader.fixups_version != 0) + return malformedError(Twine("bad chained fixups: unknown version: ") + + Twine(CFHeader.fixups_version)); + if (CFHeader.imports_format < 1 || CFHeader.imports_format > 3) + return malformedError( + Twine("bad chained fixups: unknown imports format: ") + + Twine(CFHeader.imports_format)); + + // Validate the image format. + // + // Load the image starts. + uint64_t CFImageStartsOffset = (CFHeaderOffset + CFHeader.starts_offset); + if (CFHeader.starts_offset < sizeof(MachO::dyld_chained_fixups_header)) { + return malformedError(Twine("bad chained fixups: image starts offset ") + + Twine(CFHeader.starts_offset) + + " overlaps with chained fixups header"); + } + uint32_t EndOffset = DyldChainedFixups.dataoff + DyldChainedFixups.datasize; + if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) > + EndOffset) { + return malformedError(Twine("bad chained fixups: image starts end ") + + Twine(CFImageStartsOffset + + sizeof(MachO::dyld_chained_starts_in_image)) + + " extends past end " + Twine(EndOffset)); + } + + return CFHeader; +} + +Expected<std::vector<ChainedFixupTarget>> +MachOObjectFile::getDyldChainedFixupTargets() const { + auto CFHeaderOrErr = getChainedFixupsHeader(); + if (!CFHeaderOrErr) + return CFHeaderOrErr.takeError(); + std::vector<ChainedFixupTarget> Targets; + if (!(*CFHeaderOrErr)) + return Targets; + return Targets; +} + ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const { if (!DyldInfoLoadCmd) return None; @@ -4663,6 +4845,21 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const { return makeArrayRef(Ptr, DyldInfo.export_size); } +SmallVector<uint64_t> MachOObjectFile::getFunctionStarts() const { + if (!FuncStartsLoadCmd) + return {}; + + auto InfoOrErr = + getStructOrErr<MachO::linkedit_data_command>(*this, FuncStartsLoadCmd); + if (!InfoOrErr) + return {}; + + MachO::linkedit_data_command Info = InfoOrErr.get(); + SmallVector<uint64_t, 8> FunctionStarts; + this->ReadULEB128s(Info.dataoff, FunctionStarts); + return std::move(FunctionStarts); +} + ArrayRef<uint8_t> MachOObjectFile::getUuid() const { if (!UuidLoadCmd) return None; @@ -4778,3 +4975,23 @@ MachOObjectFile::mapReflectionSectionNameToEnumValue( .Default(llvm::binaryformat::Swift5ReflectionSectionKind::unknown); #undef HANDLE_SWIFT_SECTION } + +bool MachOObjectFile::isMachOPairedReloc(uint64_t RelocType, uint64_t Arch) { + switch (Arch) { + case Triple::x86: + return RelocType == MachO::GENERIC_RELOC_SECTDIFF || + RelocType == MachO::GENERIC_RELOC_LOCAL_SECTDIFF; + case Triple::x86_64: + return RelocType == MachO::X86_64_RELOC_SUBTRACTOR; + case Triple::arm: + case Triple::thumb: + return RelocType == MachO::ARM_RELOC_SECTDIFF || + RelocType == MachO::ARM_RELOC_LOCAL_SECTDIFF || + RelocType == MachO::ARM_RELOC_HALF || + RelocType == MachO::ARM_RELOC_HALF_SECTDIFF; + case Triple::aarch64: + return RelocType == MachO::ARM64_RELOC_SUBTRACTOR; + default: + return false; + } +} diff --git a/contrib/llvm-project/llvm/lib/Object/MachOUniversal.cpp b/contrib/llvm-project/llvm/lib/Object/MachOUniversal.cpp index f3ce005e6ef9..c2c2b67814dc 100644 --- a/contrib/llvm-project/llvm/lib/Object/MachOUniversal.cpp +++ b/contrib/llvm-project/llvm/lib/Object/MachOUniversal.cpp @@ -15,9 +15,9 @@ #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/type_traits.h" using namespace llvm; using namespace object; diff --git a/contrib/llvm-project/llvm/lib/Object/MachOUniversalWriter.cpp b/contrib/llvm-project/llvm/lib/Object/MachOUniversalWriter.cpp index ae1ff09a4f8f..333706baf8c1 100644 --- a/contrib/llvm-project/llvm/lib/Object/MachOUniversalWriter.cpp +++ b/contrib/llvm-project/llvm/lib/Object/MachOUniversalWriter.cpp @@ -12,13 +12,21 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/MachOUniversalWriter.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Binary.h" -#include "llvm/Object/Error.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/MachO.h" #include "llvm/Object/MachOUniversal.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/MathExtras.h" +#include "llvm/Support/MemoryBufferRef.h" +#include "llvm/Support/SwapByteOrder.h" +#include "llvm/Support/raw_ostream.h" using namespace llvm; using namespace object; @@ -205,7 +213,7 @@ Expected<Slice> Slice::create(const Archive &A, LLVMContext *LLVMCtx) { .c_str()); if (MFO) { - Slice ArchiveSlice(*(MFO.get()), MFO->is64Bit() ? 3 : 2); + Slice ArchiveSlice(*(MFO), MFO->is64Bit() ? 3 : 2); ArchiveSlice.B = &A; return ArchiveSlice; } diff --git a/contrib/llvm-project/llvm/lib/Object/ModuleSymbolTable.cpp b/contrib/llvm-project/llvm/lib/Object/ModuleSymbolTable.cpp index 954d1f09f4e9..11274a7fcc16 100644 --- a/contrib/llvm-project/llvm/lib/Object/ModuleSymbolTable.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ModuleSymbolTable.cpp @@ -15,7 +15,6 @@ #include "llvm/Object/ModuleSymbolTable.h" #include "RecordStreamer.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" @@ -27,7 +26,6 @@ #include "llvm/IR/Module.h" #include "llvm/MC/MCAsmInfo.h" #include "llvm/MC/MCContext.h" -#include "llvm/MC/MCDirectives.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCAsmParser.h" @@ -39,7 +37,6 @@ #include "llvm/MC/TargetRegistry.h" #include "llvm/Object/SymbolicFile.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/CodeGen.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/SMLoc.h" diff --git a/contrib/llvm-project/llvm/lib/Object/Object.cpp b/contrib/llvm-project/llvm/lib/Object/Object.cpp index 576eb8d069d6..d5e67160dfa3 100644 --- a/contrib/llvm-project/llvm/lib/Object/Object.cpp +++ b/contrib/llvm-project/llvm/lib/Object/Object.cpp @@ -120,6 +120,8 @@ LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) { return LLVMBinaryTypeMachO64L; case ID_MachO64B: return LLVMBinaryTypeMachO64B; + case ID_Offload: + return LLVMBinaryTypeOffload; case ID_Wasm: return LLVMBinaryTypeWasm; case ID_StartObjects: diff --git a/contrib/llvm-project/llvm/lib/Object/ObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/ObjectFile.cpp index 6fd02f3b9592..1be8f11751be 100644 --- a/contrib/llvm-project/llvm/lib/Object/ObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ObjectFile.cpp @@ -21,10 +21,9 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Format.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/raw_ostream.h" -#include <algorithm> #include <cstdint> #include <memory> #include <system_error> @@ -147,6 +146,9 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type, case file_magic::pdb: case file_magic::minidump: case file_magic::goff_object: + case file_magic::cuda_fatbinary: + case file_magic::offload_binary: + case file_magic::dxcontainer_object: return errorCodeToError(object_error::invalid_file_type); case file_magic::tapi_file: return errorCodeToError(object_error::invalid_file_type); @@ -198,3 +200,12 @@ ObjectFile::createObjectFile(StringRef ObjectPath) { return OwningBinary<ObjectFile>(std::move(Obj), std::move(Buffer)); } + +bool ObjectFile::isReflectionSectionStrippable( + llvm::binaryformat::Swift5ReflectionSectionKind ReflectionSectionKind) + const { + using llvm::binaryformat::Swift5ReflectionSectionKind; + return ReflectionSectionKind == Swift5ReflectionSectionKind::fieldmd || + ReflectionSectionKind == Swift5ReflectionSectionKind::reflstr || + ReflectionSectionKind == Swift5ReflectionSectionKind::assocty; +} diff --git a/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp b/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp new file mode 100644 index 000000000000..21946ec2d6fb --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp @@ -0,0 +1,164 @@ +//===- Offloading.cpp - Utilities for handling offloading code -*- 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Object/OffloadBinary.h" + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/MC/StringTableBuilder.h" +#include "llvm/Object/Error.h" +#include "llvm/Support/Alignment.h" +#include "llvm/Support/FileOutputBuffer.h" + +using namespace llvm; +using namespace llvm::object; + +Expected<std::unique_ptr<OffloadBinary>> +OffloadBinary::create(MemoryBufferRef Buf) { + if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry)) + return errorCodeToError(object_error::parse_failed); + + // Check for 0x10FF1OAD magic bytes. + if (identify_magic(Buf.getBuffer()) != file_magic::offload_binary) + return errorCodeToError(object_error::parse_failed); + + // Make sure that the data has sufficient alignment. + if (!isAddrAligned(Align(getAlignment()), Buf.getBufferStart())) + return errorCodeToError(object_error::parse_failed); + + const char *Start = Buf.getBufferStart(); + const Header *TheHeader = reinterpret_cast<const Header *>(Start); + if (TheHeader->Version != OffloadBinary::Version) + return errorCodeToError(object_error::parse_failed); + + if (TheHeader->Size > Buf.getBufferSize() || + TheHeader->EntryOffset > TheHeader->Size - sizeof(Entry) || + TheHeader->EntrySize > TheHeader->Size - sizeof(Header)) + return errorCodeToError(object_error::unexpected_eof); + + const Entry *TheEntry = + reinterpret_cast<const Entry *>(&Start[TheHeader->EntryOffset]); + + if (TheEntry->ImageOffset > Buf.getBufferSize() || + TheEntry->StringOffset > Buf.getBufferSize()) + return errorCodeToError(object_error::unexpected_eof); + + return std::unique_ptr<OffloadBinary>( + new OffloadBinary(Buf, TheHeader, TheEntry)); +} + +std::unique_ptr<MemoryBuffer> +OffloadBinary::write(const OffloadingImage &OffloadingData) { + // Create a null-terminated string table with all the used strings. + StringTableBuilder StrTab(StringTableBuilder::ELF); + for (auto &KeyAndValue : OffloadingData.StringData) { + StrTab.add(KeyAndValue.getKey()); + StrTab.add(KeyAndValue.getValue()); + } + StrTab.finalize(); + + uint64_t StringEntrySize = + sizeof(StringEntry) * OffloadingData.StringData.size(); + + // Make sure the image we're wrapping around is aligned as well. + uint64_t BinaryDataSize = alignTo(sizeof(Header) + sizeof(Entry) + + StringEntrySize + StrTab.getSize(), + getAlignment()); + + // Create the header and fill in the offsets. The entry will be directly + // placed after the header in memory. Align the size to the alignment of the + // header so this can be placed contiguously in a single section. + Header TheHeader; + TheHeader.Size = alignTo( + BinaryDataSize + OffloadingData.Image->getBufferSize(), getAlignment()); + TheHeader.EntryOffset = sizeof(Header); + TheHeader.EntrySize = sizeof(Entry); + + // Create the entry using the string table offsets. The string table will be + // placed directly after the entry in memory, and the image after that. + Entry TheEntry; + TheEntry.TheImageKind = OffloadingData.TheImageKind; + TheEntry.TheOffloadKind = OffloadingData.TheOffloadKind; + TheEntry.Flags = OffloadingData.Flags; + TheEntry.StringOffset = sizeof(Header) + sizeof(Entry); + TheEntry.NumStrings = OffloadingData.StringData.size(); + + TheEntry.ImageOffset = BinaryDataSize; + TheEntry.ImageSize = OffloadingData.Image->getBufferSize(); + + SmallVector<char> Data; + Data.reserve(TheHeader.Size); + raw_svector_ostream OS(Data); + OS << StringRef(reinterpret_cast<char *>(&TheHeader), sizeof(Header)); + OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry)); + for (auto &KeyAndValue : OffloadingData.StringData) { + uint64_t Offset = sizeof(Header) + sizeof(Entry) + StringEntrySize; + StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.getKey()), + Offset + StrTab.getOffset(KeyAndValue.getValue())}; + OS << StringRef(reinterpret_cast<char *>(&Map), sizeof(StringEntry)); + } + StrTab.write(OS); + // Add padding to required image alignment. + OS.write_zeros(TheEntry.ImageOffset - OS.tell()); + OS << OffloadingData.Image->getBuffer(); + + // Add final padding to required alignment. + assert(TheHeader.Size >= OS.tell() && "Too much data written?"); + OS.write_zeros(TheHeader.Size - OS.tell()); + assert(TheHeader.Size == OS.tell() && "Size mismatch"); + + return MemoryBuffer::getMemBufferCopy(OS.str()); +} + +OffloadKind object::getOffloadKind(StringRef Name) { + return llvm::StringSwitch<OffloadKind>(Name) + .Case("openmp", OFK_OpenMP) + .Case("cuda", OFK_Cuda) + .Case("hip", OFK_HIP) + .Default(OFK_None); +} + +StringRef object::getOffloadKindName(OffloadKind Kind) { + switch (Kind) { + case OFK_OpenMP: + return "openmp"; + case OFK_Cuda: + return "cuda"; + case OFK_HIP: + return "hip"; + default: + return "none"; + } +} + +ImageKind object::getImageKind(StringRef Name) { + return llvm::StringSwitch<ImageKind>(Name) + .Case("o", IMG_Object) + .Case("bc", IMG_Bitcode) + .Case("cubin", IMG_Cubin) + .Case("fatbin", IMG_Fatbinary) + .Case("s", IMG_PTX) + .Default(IMG_None); +} + +StringRef object::getImageKindName(ImageKind Kind) { + switch (Kind) { + case IMG_Object: + return "o"; + case IMG_Bitcode: + return "bc"; + case IMG_Cubin: + return "cubin"; + case IMG_Fatbinary: + return "fatbin"; + case IMG_PTX: + return "s"; + default: + return ""; + } +} diff --git a/contrib/llvm-project/llvm/lib/Object/RecordStreamer.h b/contrib/llvm-project/llvm/lib/Object/RecordStreamer.h index 957d80f33bf4..5c6541e5052d 100644 --- a/contrib/llvm-project/llvm/lib/Object/RecordStreamer.h +++ b/contrib/llvm-project/llvm/lib/Object/RecordStreamer.h @@ -57,10 +57,10 @@ public: // 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 {} + 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(const MCSymbol *OriginalSym, StringRef Name, diff --git a/contrib/llvm-project/llvm/lib/Object/RelocationResolver.cpp b/contrib/llvm-project/llvm/lib/Object/RelocationResolver.cpp index 00a45e2c5d4e..e14301663df3 100644 --- a/contrib/llvm-project/llvm/lib/Object/RelocationResolver.cpp +++ b/contrib/llvm-project/llvm/lib/Object/RelocationResolver.cpp @@ -11,6 +11,21 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/RelocationResolver.h" +#include "llvm/ADT/Triple.h" +#include "llvm/ADT/Twine.h" +#include "llvm/BinaryFormat/COFF.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/Object/ELFObjectFile.h" +#include "llvm/Object/ELFTypes.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Object/SymbolicFile.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Error.h" +#include "llvm/Support/ErrorHandling.h" +#include <cassert> +#include <vector> namespace llvm { namespace object { @@ -63,6 +78,7 @@ static bool supportsAArch64(uint64_t Type) { switch (Type) { case ELF::R_AARCH64_ABS32: case ELF::R_AARCH64_ABS64: + case ELF::R_AARCH64_PREL16: case ELF::R_AARCH64_PREL32: case ELF::R_AARCH64_PREL64: return true; @@ -78,6 +94,8 @@ static uint64_t resolveAArch64(uint64_t Type, uint64_t Offset, uint64_t S, return (S + Addend) & 0xFFFFFFFF; case ELF::R_AARCH64_ABS64: return S + Addend; + case ELF::R_AARCH64_PREL16: + return (S + Addend - Offset) & 0xFFFF; case ELF::R_AARCH64_PREL32: return (S + Addend - Offset) & 0xFFFFFFFF; case ELF::R_AARCH64_PREL64: @@ -468,6 +486,31 @@ static uint64_t resolveRISCV(uint64_t Type, uint64_t Offset, uint64_t S, } } +static bool supportsCSKY(uint64_t Type) { + switch (Type) { + case ELF::R_CKCORE_NONE: + case ELF::R_CKCORE_ADDR32: + case ELF::R_CKCORE_PCREL32: + return true; + default: + return false; + } +} + +static uint64_t resolveCSKY(uint64_t Type, uint64_t Offset, uint64_t S, + uint64_t LocData, int64_t Addend) { + switch (Type) { + case ELF::R_CKCORE_NONE: + return LocData; + case ELF::R_CKCORE_ADDR32: + return (S + Addend) & 0xFFFFFFFF; + case ELF::R_CKCORE_PCREL32: + return (S + Addend - Offset) & 0xFFFFFFFF; + default: + llvm_unreachable("Invalid relocation type"); + } +} + static bool supportsCOFFX86(uint64_t Type) { switch (Type) { case COFF::IMAGE_REL_I386_SECREL: @@ -715,6 +758,8 @@ getRelocationResolver(const ObjectFile &Obj) { return {supportsHexagon, resolveHexagon}; case Triple::riscv32: return {supportsRISCV, resolveRISCV}; + case Triple::csky: + return {supportsCSKY, resolveCSKY}; default: return {nullptr, nullptr}; } diff --git a/contrib/llvm-project/llvm/lib/Object/SymbolicFile.cpp b/contrib/llvm-project/llvm/lib/Object/SymbolicFile.cpp index 58db5b672914..05f47cfbf2ff 100644 --- a/contrib/llvm-project/llvm/lib/Object/SymbolicFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/SymbolicFile.cpp @@ -17,18 +17,17 @@ #include "llvm/Object/Error.h" #include "llvm/Object/IRObjectFile.h" #include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/ErrorOr.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include <algorithm> #include <memory> using namespace llvm; using namespace object; +namespace llvm { +class LLVMContext; +} + SymbolicFile::SymbolicFile(unsigned int Type, MemoryBufferRef Source) : Binary(Type, Source) {} diff --git a/contrib/llvm-project/llvm/lib/Object/TapiFile.cpp b/contrib/llvm-project/llvm/lib/Object/TapiFile.cpp index 83568e8d823a..596445a09e85 100644 --- a/contrib/llvm-project/llvm/lib/Object/TapiFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/TapiFile.cpp @@ -12,8 +12,12 @@ #include "llvm/Object/TapiFile.h" #include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/MachO.h" #include "llvm/Object/Error.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/MemoryBufferRef.h" +#include "llvm/TextAPI/ArchitectureSet.h" +#include "llvm/TextAPI/InterfaceFile.h" +#include "llvm/TextAPI/Platform.h" #include "llvm/TextAPI/Symbol.h" using namespace llvm; diff --git a/contrib/llvm-project/llvm/lib/Object/TapiUniversal.cpp b/contrib/llvm-project/llvm/lib/Object/TapiUniversal.cpp index d73d93f6bd53..bf96b57f0321 100644 --- a/contrib/llvm-project/llvm/lib/Object/TapiUniversal.cpp +++ b/contrib/llvm-project/llvm/lib/Object/TapiUniversal.cpp @@ -13,7 +13,8 @@ #include "llvm/Object/TapiUniversal.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/Error.h" -#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Object/TapiFile.h" +#include "llvm/TextAPI/ArchitectureSet.h" #include "llvm/TextAPI/TextAPIReader.h" using namespace llvm; @@ -47,7 +48,7 @@ TapiUniversal::~TapiUniversal() = default; Expected<std::unique_ptr<TapiFile>> TapiUniversal::ObjectForArch::getAsObjectFile() const { return std::unique_ptr<TapiFile>(new TapiFile(Parent->getMemoryBufferRef(), - *Parent->ParsedFile.get(), + *Parent->ParsedFile, Parent->Libraries[Index].Arch)); } diff --git a/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp index 6a19b159f3d5..ce816b097691 100644 --- a/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp @@ -8,7 +8,6 @@ #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" @@ -30,7 +29,6 @@ #include <cassert> #include <cstdint> #include <cstring> -#include <system_error> #define DEBUG_TYPE "wasm-object" @@ -166,23 +164,25 @@ static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) { static Error readInitExpr(wasm::WasmInitExpr &Expr, WasmObjectFile::ReadContext &Ctx) { - Expr.Opcode = readOpcode(Ctx); + auto Start = Ctx.Ptr; - switch (Expr.Opcode) { + Expr.Extended = false; + Expr.Inst.Opcode = readOpcode(Ctx); + switch (Expr.Inst.Opcode) { case wasm::WASM_OPCODE_I32_CONST: - Expr.Value.Int32 = readVarint32(Ctx); + Expr.Inst.Value.Int32 = readVarint32(Ctx); break; case wasm::WASM_OPCODE_I64_CONST: - Expr.Value.Int64 = readVarint64(Ctx); + Expr.Inst.Value.Int64 = readVarint64(Ctx); break; case wasm::WASM_OPCODE_F32_CONST: - Expr.Value.Float32 = readFloat32(Ctx); + Expr.Inst.Value.Float32 = readFloat32(Ctx); break; case wasm::WASM_OPCODE_F64_CONST: - Expr.Value.Float64 = readFloat64(Ctx); + Expr.Inst.Value.Float64 = readFloat64(Ctx); break; case wasm::WASM_OPCODE_GLOBAL_GET: - Expr.Value.Global = readULEB128(Ctx); + Expr.Inst.Value.Global = readULEB128(Ctx); break; case wasm::WASM_OPCODE_REF_NULL: { wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx)); @@ -193,15 +193,46 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, break; } default: - return make_error<GenericBinaryError>("invalid opcode in init_expr", - object_error::parse_failed); + Expr.Extended = true; } - uint8_t EndOpcode = readOpcode(Ctx); - if (EndOpcode != wasm::WASM_OPCODE_END) { - return make_error<GenericBinaryError>("invalid init_expr", - object_error::parse_failed); + if (!Expr.Extended) { + uint8_t EndOpcode = readOpcode(Ctx); + if (EndOpcode != wasm::WASM_OPCODE_END) + Expr.Extended = true; + } + + if (Expr.Extended) { + Ctx.Ptr = Start; + while (1) { + uint8_t Opcode = readOpcode(Ctx); + switch (Opcode) { + case wasm::WASM_OPCODE_I32_CONST: + case wasm::WASM_OPCODE_GLOBAL_GET: + case wasm::WASM_OPCODE_REF_NULL: + case wasm::WASM_OPCODE_I64_CONST: + case wasm::WASM_OPCODE_F32_CONST: + case wasm::WASM_OPCODE_F64_CONST: + readULEB128(Ctx); + break; + case wasm::WASM_OPCODE_I32_ADD: + case wasm::WASM_OPCODE_I32_SUB: + case wasm::WASM_OPCODE_I32_MUL: + case wasm::WASM_OPCODE_I64_ADD: + case wasm::WASM_OPCODE_I64_SUB: + case wasm::WASM_OPCODE_I64_MUL: + break; + case wasm::WASM_OPCODE_END: + Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start); + return Error::success(); + default: + return make_error<GenericBinaryError>( + Twine("invalid opcode in init_expr: ") + Twine(unsigned(Opcode)), + object_error::parse_failed); + } + } } + return Error::success(); } @@ -420,10 +451,6 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { llvm::DenseSet<uint64_t> SeenFunctions; llvm::DenseSet<uint64_t> SeenGlobals; llvm::DenseSet<uint64_t> SeenSegments; - if (Functions.size() && !SeenCodeSection) { - return make_error<GenericBinaryError>("names must come after code section", - object_error::parse_failed); - } while (Ctx.Ptr < Ctx.End) { uint8_t Type = readUint8(Ctx); @@ -443,7 +470,7 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { return make_error<GenericBinaryError>( "function named more than once", object_error::parse_failed); if (!isValidFunctionIndex(Index) || Name.empty()) - return make_error<GenericBinaryError>("invalid name entry", + return make_error<GenericBinaryError>("invalid function name entry", object_error::parse_failed); if (isDefinedFunctionIndex(Index)) @@ -454,7 +481,7 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { return make_error<GenericBinaryError>("global named more than once", object_error::parse_failed); if (!isValidGlobalIndex(Index) || Name.empty()) - return make_error<GenericBinaryError>("invalid name entry", + return make_error<GenericBinaryError>("invalid global name entry", object_error::parse_failed); } else { nameType = wasm::NameType::DATA_SEGMENT; @@ -462,7 +489,7 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { return make_error<GenericBinaryError>( "segment named more than once", object_error::parse_failed); if (Index > DataSegments.size()) - return make_error<GenericBinaryError>("invalid named data segment", + return make_error<GenericBinaryError>("invalid data segment name entry", object_error::parse_failed); } DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name}); @@ -488,11 +515,6 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) { HasLinkingSection = true; - if (Functions.size() && !SeenCodeSection) { - return make_error<GenericBinaryError>( - "linking data must come after code section", - object_error::parse_failed); - } LinkingData.Version = readVaruint32(Ctx); if (LinkingData.Version != wasm::WasmMetadataVersion) { @@ -1379,7 +1401,6 @@ Error WasmObjectFile::parseStartSection(ReadContext &Ctx) { } Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) { - SeenCodeSection = true; CodeSection = Sections.size(); uint32_t FunctionCount = readVaruint32(Ctx); if (FunctionCount != Functions.size()) { @@ -1443,8 +1464,9 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { object_error::parse_failed); if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) { - Segment.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST; - Segment.Offset.Value.Int32 = 0; + Segment.Offset.Extended = false; + Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST; + Segment.Offset.Inst.Value.Int32 = 0; } else { if (Error Err = readInitExpr(Segment.Offset, Ctx)) return Err; @@ -1488,7 +1510,7 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { Error WasmObjectFile::parseDataSection(ReadContext &Ctx) { DataSection = Sections.size(); uint32_t Count = readVaruint32(Ctx); - if (DataCount && Count != DataCount.getValue()) + if (DataCount && Count != *DataCount) return make_error<GenericBinaryError>( "number of data segments does not match DataCount section"); DataSegments.reserve(Count); @@ -1503,8 +1525,9 @@ Error WasmObjectFile::parseDataSection(ReadContext &Ctx) { 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; + Segment.Data.Offset.Extended = false; + Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST; + Segment.Data.Offset.Inst.Value.Int32 = 0; } uint32_t Size = readVaruint32(Ctx); if (Size > (size_t)(Ctx.End - Ctx.Ptr)) @@ -1602,10 +1625,12 @@ uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const { // offset within the segment. uint32_t SegmentIndex = Sym.Info.DataRef.Segment; const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data; - if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) { - return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset; - } else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) { - return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset; + if (Segment.Offset.Extended) { + llvm_unreachable("extended init exprs not supported"); + } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) { + return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset; + } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) { + return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset; } else { llvm_unreachable("unknown init expr opcode"); } @@ -1692,29 +1717,11 @@ void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const { const WasmSection &S = Sections[Sec.d.a]; -#define ECase(X) \ - case wasm::WASM_SEC_##X: \ - return #X; - switch (S.Type) { - ECase(TYPE); - ECase(IMPORT); - ECase(FUNCTION); - ECase(TABLE); - ECase(MEMORY); - ECase(GLOBAL); - ECase(TAG); - ECase(EXPORT); - ECase(START); - ECase(ELEM); - ECase(CODE); - ECase(DATA); - ECase(DATACOUNT); - case wasm::WASM_SEC_CUSTOM: + if (S.Type == wasm::WASM_SEC_CUSTOM) return S.Name; - default: + if (S.Type > wasm::WASM_SEC_LAST_KNOWN) return createStringError(object_error::invalid_section_index, ""); - } -#undef ECase + return wasm::sectionTypeToString(S.Type); } uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; } diff --git a/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp b/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp index 2a69c6c46b59..d50f149629c3 100644 --- a/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp +++ b/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp @@ -12,13 +12,11 @@ #include "llvm/Object/WindowsResource.h" #include "llvm/Object/COFF.h" -#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> using namespace llvm; using namespace object; diff --git a/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp index f2f6d700ddd8..ff39fe1794c0 100644 --- a/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp @@ -615,6 +615,16 @@ Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { if (XCOFFSym.getSectionNumber() == XCOFF::N_UNDEF) Result |= SymbolRef::SF_Undefined; + // There is no visibility in old 32 bit XCOFF object file interpret. + if (is64Bit() || (auxiliaryHeader32() && (auxiliaryHeader32()->getVersion() == + NEW_XCOFF_INTERPRET))) { + uint16_t SymType = XCOFFSym.getSymbolType(); + if ((SymType & VISIBILITY_MASK) == SYM_V_HIDDEN) + Result |= SymbolRef::SF_Hidden; + + if ((SymType & VISIBILITY_MASK) == SYM_V_EXPORTED) + Result |= SymbolRef::SF_Exported; + } return Result; } @@ -699,6 +709,19 @@ bool XCOFFObjectFile::is64Bit() const { return Binary::ID_XCOFF64 == getType(); } +Expected<StringRef> XCOFFObjectFile::getRawData(const char *Start, + uint64_t Size, + StringRef Name) const { + uintptr_t StartPtr = reinterpret_cast<uintptr_t>(Start); + // TODO: this path is untested. + if (Error E = Binary::checkOffset(Data, StartPtr, Size)) + return createError(toString(std::move(E)) + ": " + Name.data() + + " data with offset 0x" + Twine::utohexstr(StartPtr) + + " and size 0x" + Twine::utohexstr(Size) + + " goes past the end of the file"); + return StringRef(Start, Size); +} + uint16_t XCOFFObjectFile::getMagic() const { return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; } @@ -1319,7 +1342,7 @@ XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, NumOfCtlAnchors = DE.getU32(Cur); if (Cur && NumOfCtlAnchors) { SmallVector<uint32_t, 8> Disp; - Disp.reserve(NumOfCtlAnchors.getValue()); + Disp.reserve(*NumOfCtlAnchors); for (uint32_t I = 0; I < NumOfCtlAnchors && Cur; ++I) Disp.push_back(DE.getU32(Cur)); if (Cur) @@ -1346,7 +1369,7 @@ XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size, return; } VecExt = TBVecExtOrErr.get(); - VectorParmsNum = VecExt.getValue().getNumberOfVectorParms(); + VectorParmsNum = VecExt->getNumberOfVectorParms(); } } |