diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2017-12-20 14:16:56 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2017-12-20 14:16:56 +0000 |
commit | 2cab237b5dbfe1b3e9c7aa7a3c02d2b98fcf7462 (patch) | |
tree | 524fe828571f81358bba62fdb6d04c6e5e96a2a4 /contrib/llvm/lib/Object | |
parent | 6c7828a2807ea5e50c79ca42dbedf2b589ce63b2 (diff) | |
parent | 044eb2f6afba375a914ac9d8024f8f5142bb912e (diff) |
Merge llvm trunk r321017 to contrib/llvm.
Notes
Notes:
svn path=/projects/clang600-import/; revision=327023
Diffstat (limited to 'contrib/llvm/lib/Object')
-rw-r--r-- | contrib/llvm/lib/Object/Archive.cpp | 18 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/ArchiveWriter.cpp | 479 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/COFFImportFile.cpp | 30 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/COFFModuleDefinition.cpp | 37 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/COFFObjectFile.cpp | 38 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/ELF.cpp | 100 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/ELFObjectFile.cpp | 37 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/IRObjectFile.cpp | 32 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/IRSymtab.cpp | 58 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/MachOObjectFile.cpp | 588 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/ModuleSymbolTable.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/ObjectFile.cpp | 31 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/SymbolicFile.cpp | 6 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/WasmObjectFile.cpp | 202 | ||||
-rw-r--r-- | contrib/llvm/lib/Object/WindowsResource.cpp | 59 |
15 files changed, 1123 insertions, 594 deletions
diff --git a/contrib/llvm/lib/Object/Archive.cpp b/contrib/llvm/lib/Object/Archive.cpp index 977cccc11dcd..b17eefd220b8 100644 --- a/contrib/llvm/lib/Object/Archive.cpp +++ b/contrib/llvm/lib/Object/Archive.cpp @@ -179,7 +179,7 @@ Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const { // GNU long file names end with a "/\n". if (Parent->kind() == Archive::K_GNU || - Parent->kind() == Archive::K_MIPS64) { + Parent->kind() == Archive::K_GNU64) { StringRef::size_type End = StringRef(addr).find('\n'); return StringRef(addr, End - 1); } @@ -338,7 +338,7 @@ Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err) ErrorAsOutParameter ErrAsOutParam(Err); - // If there was an error in the construction of the Header + // If there was an error in the construction of the Header // then just return with the error now set. if (*Err) return; @@ -698,7 +698,7 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) } if (Name == "//") { - Format = has64SymTable ? K_MIPS64 : K_GNU; + Format = has64SymTable ? K_GNU64 : K_GNU; // The string table is never an external member, but we still // must check any Expected<> return value. Expected<StringRef> BufOrErr = C->getBuffer(); @@ -715,7 +715,7 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) } if (Name[0] != '/') { - Format = has64SymTable ? K_MIPS64 : K_GNU; + Format = has64SymTable ? K_GNU64 : K_GNU; setFirstRegular(*C); Err = Error::success(); return; @@ -797,14 +797,14 @@ StringRef Archive::Symbol::getName() const { Expected<Archive::Child> Archive::Symbol::getMember() const { const char *Buf = Parent->getSymbolTable().begin(); const char *Offsets = Buf; - if (Parent->kind() == K_MIPS64 || Parent->kind() == K_DARWIN64) + if (Parent->kind() == K_GNU64 || Parent->kind() == K_DARWIN64) Offsets += sizeof(uint64_t); else Offsets += sizeof(uint32_t); - uint32_t Offset = 0; + uint64_t Offset = 0; if (Parent->kind() == K_GNU) { Offset = read32be(Offsets + SymbolIndex * 4); - } else if (Parent->kind() == K_MIPS64) { + } else if (Parent->kind() == K_GNU64) { Offset = read64be(Offsets + SymbolIndex * 8); } else if (Parent->kind() == K_BSD) { // The SymbolIndex is an index into the ranlib structs that start at @@ -902,7 +902,7 @@ Archive::symbol_iterator Archive::symbol_begin() const { uint32_t symbol_count = 0; symbol_count = read32be(buf); buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t))); - } else if (kind() == K_MIPS64) { + } else if (kind() == K_GNU64) { uint64_t symbol_count = read64be(buf); buf += sizeof(uint64_t) + (symbol_count * (sizeof(uint64_t))); } else if (kind() == K_BSD) { @@ -959,7 +959,7 @@ uint32_t Archive::getNumberOfSymbols() const { const char *buf = getSymbolTable().begin(); if (kind() == K_GNU) return read32be(buf); - if (kind() == K_MIPS64) + if (kind() == K_GNU64) return read64be(buf); if (kind() == K_BSD) return read32le(buf) / 8; diff --git a/contrib/llvm/lib/Object/ArchiveWriter.cpp b/contrib/llvm/lib/Object/ArchiveWriter.cpp index b052c76d1fed..b3b812daae2e 100644 --- a/contrib/llvm/lib/Object/ArchiveWriter.cpp +++ b/contrib/llvm/lib/Object/ArchiveWriter.cpp @@ -35,6 +35,15 @@ using namespace llvm; +// 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 +// writeArchive. To test this we need to generate a file with a member that has +// an offset larger than 32-bits but this demands a very slow test. To speed +// the test up we use this flag to pretend like the cutoff happens before +// 32-bits and instead happens at some much smaller value. +static cl::opt<int> Sym64Threshold("sym64-threshold", cl::Hidden, + cl::init(32)); + NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef) : Buf(MemoryBuffer::getMemBuffer(BufRef, false)), MemberName(BufRef.getBufferIdentifier()) {} @@ -111,29 +120,22 @@ Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName, } template <typename T> -static void printWithSpacePadding(raw_fd_ostream &OS, T Data, unsigned Size, - bool MayTruncate = false) { +static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) { uint64_t OldPos = OS.tell(); OS << Data; unsigned SizeSoFar = OS.tell() - OldPos; - if (Size > SizeSoFar) { - OS.indent(Size - SizeSoFar); - } else if (Size < SizeSoFar) { - assert(MayTruncate && "Data doesn't fit in Size"); - // Some of the data this is used for (like UID) can be larger than the - // space available in the archive format. Truncate in that case. - OS.seek(OldPos + Size); - } + assert(SizeSoFar <= Size && "Data doesn't fit in Size"); + OS.indent(Size - SizeSoFar); } static bool isBSDLike(object::Archive::Kind Kind) { switch (Kind) { case object::Archive::K_GNU: + case object::Archive::K_GNU64: return false; case object::Archive::K_BSD: case object::Archive::K_DARWIN: return true; - case object::Archive::K_MIPS64: case object::Archive::K_DARWIN64: case object::Archive::K_COFF: break; @@ -141,8 +143,8 @@ static bool isBSDLike(object::Archive::Kind Kind) { llvm_unreachable("not supported for writting"); } -static void print32(raw_ostream &Out, object::Archive::Kind Kind, - uint32_t Val) { +template <class T> +static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) { if (isBSDLike(Kind)) support::endian::Writer<support::little>(Out).write(Val); else @@ -150,18 +152,22 @@ static void print32(raw_ostream &Out, object::Archive::Kind Kind, } static void printRestOfMemberHeader( - raw_fd_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime, + raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { printWithSpacePadding(Out, sys::toTimeT(ModTime), 12); - printWithSpacePadding(Out, UID, 6, true); - printWithSpacePadding(Out, GID, 6, true); + + // The format has only 6 chars for uid and gid. Truncate if the provided + // values don't fit. + printWithSpacePadding(Out, UID % 1000000, 6); + printWithSpacePadding(Out, GID % 1000000, 6); + printWithSpacePadding(Out, format("%o", Perms), 8); printWithSpacePadding(Out, Size, 10); Out << "`\n"; } static void -printGNUSmallMemberHeader(raw_fd_ostream &Out, StringRef Name, +printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name, const sys::TimePoint<std::chrono::seconds> &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { @@ -170,11 +176,11 @@ printGNUSmallMemberHeader(raw_fd_ostream &Out, StringRef Name, } static void -printBSDMemberHeader(raw_fd_ostream &Out, StringRef Name, +printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name, const sys::TimePoint<std::chrono::seconds> &ModTime, unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { - uint64_t PosAfterHeader = Out.tell() + 60 + Name.size(); + uint64_t PosAfterHeader = Pos + 60 + Name.size(); // Pad so that even 64 bit object files are aligned. unsigned Pad = OffsetToAlignment(PosAfterHeader, 8); unsigned NameWithPadding = Name.size() + Pad; @@ -182,7 +188,6 @@ printBSDMemberHeader(raw_fd_ostream &Out, StringRef Name, printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, NameWithPadding + Size); Out << Name; - assert(PosAfterHeader == Out.tell()); while (Pad--) Out.write(uint8_t(0)); } @@ -191,21 +196,6 @@ static bool useStringTable(bool Thin, StringRef Name) { return Thin || Name.size() >= 16 || Name.contains('/'); } -static void -printMemberHeader(raw_fd_ostream &Out, object::Archive::Kind Kind, bool Thin, - StringRef Name, - std::vector<unsigned>::iterator &StringMapIndexIter, - const sys::TimePoint<std::chrono::seconds> &ModTime, - unsigned UID, unsigned GID, unsigned Perms, unsigned Size) { - if (isBSDLike(Kind)) - return printBSDMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size); - if (!useStringTable(Thin, Name)) - return printGNUSmallMemberHeader(Out, Name, ModTime, UID, GID, Perms, Size); - Out << '/'; - printWithSpacePadding(Out, *StringMapIndexIter++, 15); - printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size); -} - // Compute the relative path from From to To. static std::string computeRelativePath(StringRef From, StringRef To) { if (sys::path::is_absolute(From) || sys::path::is_absolute(To)) @@ -235,41 +225,70 @@ static std::string computeRelativePath(StringRef From, StringRef To) { return Relative.str(); } -static void writeStringTable(raw_fd_ostream &Out, StringRef ArcName, - ArrayRef<NewArchiveMember> Members, - std::vector<unsigned> &StringMapIndexes, - bool Thin) { - unsigned StartOffset = 0; - for (const NewArchiveMember &M : Members) { - StringRef Path = M.Buf->getBufferIdentifier(); - StringRef Name = M.MemberName; - if (!useStringTable(Thin, Name)) - continue; - if (StartOffset == 0) { - printWithSpacePadding(Out, "//", 58); - Out << "`\n"; - StartOffset = Out.tell(); - } - StringMapIndexes.push_back(Out.tell() - StartOffset); +static bool is64BitKind(object::Archive::Kind Kind) { + switch (Kind) { + case object::Archive::K_GNU: + case object::Archive::K_BSD: + case object::Archive::K_DARWIN: + case object::Archive::K_COFF: + return false; + case object::Archive::K_DARWIN64: + case object::Archive::K_GNU64: + return true; + } + llvm_unreachable("not supported for writting"); +} - if (Thin) { - if (M.IsNew) - Out << computeRelativePath(ArcName, Path); - else - Out << M.Buf->getBufferIdentifier(); - } else - Out << Name; +static void addToStringTable(raw_ostream &Out, StringRef ArcName, + const NewArchiveMember &M, bool Thin) { + StringRef ID = M.Buf->getBufferIdentifier(); + if (Thin) { + if (M.IsNew) + Out << computeRelativePath(ArcName, ID); + else + Out << ID; + } else + Out << M.MemberName; + Out << "/\n"; +} - Out << "/\n"; - } - if (StartOffset == 0) - return; - if (Out.tell() % 2) - Out << '\n'; - int Pos = Out.tell(); - Out.seek(StartOffset - 12); - printWithSpacePadding(Out, Pos - StartOffset, 10); - Out.seek(Pos); +static void printMemberHeader(raw_ostream &Out, uint64_t Pos, + raw_ostream &StringTable, + object::Archive::Kind Kind, bool Thin, + StringRef ArcName, const NewArchiveMember &M, + unsigned Size) { + if (isBSDLike(Kind)) + return printBSDMemberHeader(Out, Pos, M.MemberName, M.ModTime, M.UID, M.GID, + M.Perms, Size); + if (!useStringTable(Thin, M.MemberName)) + return printGNUSmallMemberHeader(Out, M.MemberName, M.ModTime, M.UID, M.GID, + M.Perms, Size); + Out << '/'; + uint64_t NamePos = StringTable.tell(); + addToStringTable(StringTable, ArcName, M, Thin); + printWithSpacePadding(Out, NamePos, 15); + printRestOfMemberHeader(Out, M.ModTime, M.UID, M.GID, M.Perms, Size); +} + +namespace { +struct MemberData { + std::vector<unsigned> Symbols; + std::string Header; + StringRef Data; + StringRef Padding; +}; +} // namespace + +static MemberData computeStringTable(StringRef Names) { + unsigned Size = Names.size(); + unsigned Pad = OffsetToAlignment(Size, 2); + std::string Header; + raw_string_ostream Out(Header); + printWithSpacePadding(Out, "//", 48); + printWithSpacePadding(Out, Size + Pad, 10); + Out << "`\n"; + Out.flush(); + return {{}, std::move(Header), Names, Pad ? "\n" : ""}; } static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) { @@ -280,177 +299,222 @@ static sys::TimePoint<std::chrono::seconds> now(bool Deterministic) { return sys::TimePoint<seconds>(); } -// Returns the offset of the first reference to a member offset. -static ErrorOr<unsigned> -writeSymbolTable(raw_fd_ostream &Out, object::Archive::Kind Kind, - ArrayRef<NewArchiveMember> Members, - std::vector<unsigned> &MemberOffsetRefs, bool Deterministic) { - unsigned HeaderStartOffset = 0; - unsigned BodyStartOffset = 0; - SmallString<128> NameBuf; - raw_svector_ostream NameOS(NameBuf); - LLVMContext Context; - for (unsigned MemberNum = 0, N = Members.size(); MemberNum < N; ++MemberNum) { - MemoryBufferRef MemberBuffer = Members[MemberNum].Buf->getMemBufferRef(); - Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = - object::SymbolicFile::createSymbolicFile( - MemberBuffer, llvm::file_magic::unknown, &Context); - if (!ObjOrErr) { - // FIXME: check only for "not an object file" errors. - consumeError(ObjOrErr.takeError()); - continue; - } - object::SymbolicFile &Obj = *ObjOrErr.get(); +static bool isArchiveSymbol(const object::BasicSymbolRef &S) { + uint32_t Symflags = S.getFlags(); + if (Symflags & object::SymbolRef::SF_FormatSpecific) + return false; + if (!(Symflags & object::SymbolRef::SF_Global)) + return false; + if (Symflags & object::SymbolRef::SF_Undefined && + !(Symflags & object::SymbolRef::SF_Indirect)) + return false; + return true; +} - if (!HeaderStartOffset) { - HeaderStartOffset = Out.tell(); - if (isBSDLike(Kind)) - printBSDMemberHeader(Out, "__.SYMDEF", now(Deterministic), 0, 0, 0, 0); - else - printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, 0); - BodyStartOffset = Out.tell(); - print32(Out, Kind, 0); // number of entries or bytes - } +static void printNBits(raw_ostream &Out, object::Archive::Kind Kind, + uint64_t Val) { + if (is64BitKind(Kind)) + print<uint64_t>(Out, Kind, Val); + else + print<uint32_t>(Out, Kind, Val); +} - for (const object::BasicSymbolRef &S : Obj.symbols()) { - uint32_t Symflags = S.getFlags(); - if (Symflags & object::SymbolRef::SF_FormatSpecific) - continue; - if (!(Symflags & object::SymbolRef::SF_Global)) - continue; - if (Symflags & object::SymbolRef::SF_Undefined && - !(Symflags & object::SymbolRef::SF_Indirect)) - continue; - - unsigned NameOffset = NameOS.tell(); - if (auto EC = S.printName(NameOS)) - return EC; - NameOS << '\0'; - MemberOffsetRefs.push_back(MemberNum); - if (isBSDLike(Kind)) - print32(Out, Kind, NameOffset); - print32(Out, Kind, 0); // member offset - } - } +static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind, + bool Deterministic, ArrayRef<MemberData> Members, + StringRef StringTable) { + if (StringTable.empty()) + return; - if (HeaderStartOffset == 0) - return 0; + unsigned NumSyms = 0; + for (const MemberData &M : Members) + NumSyms += M.Symbols.size(); - // ld64 prefers the cctools type archive which pads its string table to a - // boundary of sizeof(int32_t). + unsigned Size = 0; + Size += is64BitKind(Kind) ? 8 : 4; // Number of entries if (isBSDLike(Kind)) - for (unsigned P = OffsetToAlignment(NameOS.tell(), sizeof(int32_t)); P--;) - NameOS << '\0'; - - StringRef StringTable = NameOS.str(); + Size += NumSyms * 8; // Table + else if (is64BitKind(Kind)) + Size += NumSyms * 8; // Table + else + Size += NumSyms * 4; // Table if (isBSDLike(Kind)) - print32(Out, Kind, StringTable.size()); // byte count of the string table - Out << StringTable; - // If there are no symbols, emit an empty symbol table, to satisfy Solaris - // tools, older versions of which expect a symbol table in a non-empty - // archive, regardless of whether there are any symbols in it. - if (StringTable.size() == 0) - print32(Out, Kind, 0); + Size += 4; // byte count + Size += StringTable.size(); + // ld64 expects the members to be 8-byte aligned for 64-bit content and at + // 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. + unsigned Alignment = isBSDLike(Kind) ? 8 : 2; + unsigned Pad = OffsetToAlignment(Size, Alignment); + Size += Pad; - // ld64 requires the next member header to start at an offset that is - // 4 bytes aligned. - unsigned Pad = OffsetToAlignment(Out.tell(), 4); - while (Pad--) - Out.write(uint8_t(0)); + if (isBSDLike(Kind)) + printBSDMemberHeader(Out, Out.tell(), "__.SYMDEF", now(Deterministic), 0, 0, + 0, Size); + else if (is64BitKind(Kind)) + printGNUSmallMemberHeader(Out, "/SYM64", now(Deterministic), 0, 0, 0, Size); + else + printGNUSmallMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size); - // Patch up the size of the symbol table now that we know how big it is. - unsigned Pos = Out.tell(); - const unsigned MemberHeaderSize = 60; - Out.seek(HeaderStartOffset + 48); // offset of the size field. - printWithSpacePadding(Out, Pos - MemberHeaderSize - HeaderStartOffset, 10); + uint64_t Pos = Out.tell() + Size; - // Patch up the number of symbols. - Out.seek(BodyStartOffset); - unsigned NumSyms = MemberOffsetRefs.size(); if (isBSDLike(Kind)) - print32(Out, Kind, NumSyms * 8); + print<uint32_t>(Out, Kind, NumSyms * 8); else - print32(Out, Kind, NumSyms); + printNBits(Out, Kind, NumSyms); + + for (const MemberData &M : Members) { + for (unsigned StringOffset : M.Symbols) { + if (isBSDLike(Kind)) + print<uint32_t>(Out, Kind, StringOffset); + printNBits(Out, Kind, Pos); // member offset + } + Pos += M.Header.size() + M.Data.size() + M.Padding.size(); + } + + if (isBSDLike(Kind)) + // byte count of the string table + print<uint32_t>(Out, Kind, StringTable.size()); + Out << StringTable; - Out.seek(Pos); - return BodyStartOffset + 4; + while (Pad--) + Out.write(uint8_t(0)); } -std::pair<StringRef, std::error_code> -llvm::writeArchive(StringRef ArcName, - std::vector<NewArchiveMember> &NewMembers, - bool WriteSymtab, object::Archive::Kind Kind, - bool Deterministic, bool Thin, - std::unique_ptr<MemoryBuffer> OldArchiveBuf) { - assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); - SmallString<128> TmpArchive; - int TmpArchiveFD; - if (auto EC = sys::fs::createUniqueFile(ArcName + ".temp-archive-%%%%%%%.a", - TmpArchiveFD, TmpArchive)) - return std::make_pair(ArcName, EC); - - tool_output_file Output(TmpArchive, TmpArchiveFD); - raw_fd_ostream &Out = Output.os(); - if (Thin) - Out << "!<thin>\n"; - else - Out << "!<arch>\n"; +static Expected<std::vector<unsigned>> +getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) { + std::vector<unsigned> Ret; + LLVMContext Context; - std::vector<unsigned> MemberOffsetRefs; + Expected<std::unique_ptr<object::SymbolicFile>> ObjOrErr = + object::SymbolicFile::createSymbolicFile(Buf, llvm::file_magic::unknown, + &Context); + if (!ObjOrErr) { + // FIXME: check only for "not an object file" errors. + consumeError(ObjOrErr.takeError()); + return Ret; + } - unsigned MemberReferenceOffset = 0; - if (WriteSymtab) { - ErrorOr<unsigned> MemberReferenceOffsetOrErr = writeSymbolTable( - Out, Kind, NewMembers, MemberOffsetRefs, Deterministic); - if (auto EC = MemberReferenceOffsetOrErr.getError()) - return std::make_pair(ArcName, EC); - MemberReferenceOffset = MemberReferenceOffsetOrErr.get(); + HasObject = true; + object::SymbolicFile &Obj = *ObjOrErr.get(); + for (const object::BasicSymbolRef &S : Obj.symbols()) { + if (!isArchiveSymbol(S)) + continue; + Ret.push_back(SymNames.tell()); + if (auto EC = S.printName(SymNames)) + return errorCodeToError(EC); + SymNames << '\0'; } + return Ret; +} + +static Expected<std::vector<MemberData>> +computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, + object::Archive::Kind Kind, bool Thin, StringRef ArcName, + ArrayRef<NewArchiveMember> NewMembers) { + static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; - std::vector<unsigned> StringMapIndexes; - if (!isBSDLike(Kind)) - writeStringTable(Out, ArcName, NewMembers, StringMapIndexes, Thin); + // 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; - std::vector<unsigned>::iterator StringMapIndexIter = StringMapIndexes.begin(); - std::vector<unsigned> MemberOffset; + std::vector<MemberData> Ret; + bool HasObject = false; for (const NewArchiveMember &M : NewMembers) { - MemoryBufferRef File = M.Buf->getMemBufferRef(); - unsigned Padding = 0; + std::string Header; + raw_string_ostream Out(Header); - unsigned Pos = Out.tell(); - MemberOffset.push_back(Pos); + MemoryBufferRef Buf = M.Buf->getMemBufferRef(); + StringRef Data = Thin ? "" : Buf.getBuffer(); // ld64 expects the members to be 8-byte aligned for 64-bit content and at // least 4-byte aligned for 32-bit content. Opt for the larger encoding // uniformly. This matches the behaviour with cctools and ensures that ld64 // is happy with archives that we generate. - if (Kind == object::Archive::K_DARWIN) - Padding = OffsetToAlignment(M.Buf->getBufferSize(), 8); + unsigned MemberPadding = Kind == object::Archive::K_DARWIN + ? OffsetToAlignment(Data.size(), 8) + : 0; + unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2); + StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding); + + printMemberHeader(Out, Pos, StringTable, Kind, Thin, ArcName, M, + Buf.getBufferSize() + MemberPadding); + Out.flush(); + + Expected<std::vector<unsigned>> Symbols = + getSymbols(Buf, SymNames, HasObject); + if (auto E = Symbols.takeError()) + return std::move(E); + + Pos += Header.size() + Data.size() + Padding.size(); + Ret.push_back({std::move(*Symbols), std::move(Header), Data, Padding}); + } + // If there are no symbols, emit an empty symbol table, to satisfy Solaris + // tools, older versions of which expect a symbol table in a non-empty + // archive, regardless of whether there are any symbols in it. + if (HasObject && SymNames.tell() == 0) + SymNames << '\0' << '\0' << '\0'; + return Ret; +} - printMemberHeader(Out, Kind, Thin, M.MemberName, StringMapIndexIter, - M.ModTime, M.UID, M.GID, M.Perms, - M.Buf->getBufferSize() + Padding); +Error llvm::writeArchive(StringRef ArcName, + ArrayRef<NewArchiveMember> NewMembers, + bool WriteSymtab, object::Archive::Kind Kind, + bool Deterministic, bool Thin, + std::unique_ptr<MemoryBuffer> OldArchiveBuf) { + assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); - if (!Thin) - Out << File.getBuffer(); + SmallString<0> SymNamesBuf; + raw_svector_ostream SymNames(SymNamesBuf); + SmallString<0> StringTableBuf; + raw_svector_ostream StringTable(StringTableBuf); - while (Padding--) - Out << '\n'; - if (Out.tell() % 2) - Out << '\n'; - } + Expected<std::vector<MemberData>> DataOrErr = + computeMemberData(StringTable, SymNames, Kind, Thin, ArcName, NewMembers); + if (Error E = DataOrErr.takeError()) + return E; + std::vector<MemberData> &Data = *DataOrErr; - if (MemberReferenceOffset) { - Out.seek(MemberReferenceOffset); - for (unsigned MemberNum : MemberOffsetRefs) { - if (isBSDLike(Kind)) - Out.seek(Out.tell() + 4); // skip over the string offset - print32(Out, Kind, MemberOffset[MemberNum]); + if (!StringTableBuf.empty()) + 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 = 0; + uint64_t LastOffset = MaxOffset; + 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(); + // We assume 32-bit symbols to see if 32-bit symbols are possible or not. + MaxOffset += M.Symbols.size() * 4; } + // 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 >= (1ULL << Sym64Threshold)) + Kind = object::Archive::K_GNU64; } - Output.keep(); - Out.close(); + Expected<sys::fs::TempFile> Temp = + sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a"); + if (!Temp) + return Temp.takeError(); + + raw_fd_ostream Out(Temp->FD, false); + if (Thin) + Out << "!<thin>\n"; + else + Out << "!<arch>\n"; + + if (WriteSymtab) + writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf); + + for (const MemberData &M : Data) + Out << M.Header << M.Data << M.Padding; + + Out.flush(); // At this point, we no longer need whatever backing memory // was used to generate the NewMembers. On Windows, this buffer @@ -464,6 +528,5 @@ llvm::writeArchive(StringRef ArcName, // closed before we attempt to rename. OldArchiveBuf.reset(); - sys::fs::rename(TmpArchive, ArcName); - return std::make_pair("", std::error_code()); + return Temp->keep(ArcName); } diff --git a/contrib/llvm/lib/Object/COFFImportFile.cpp b/contrib/llvm/lib/Object/COFFImportFile.cpp index ff039463d08c..93631f1ad811 100644 --- a/contrib/llvm/lib/Object/COFFImportFile.cpp +++ b/contrib/llvm/lib/Object/COFFImportFile.cpp @@ -20,8 +20,6 @@ #include "llvm/Support/Path.h" #include <cstdint> -#include <map> -#include <set> #include <string> #include <vector> @@ -36,6 +34,7 @@ static bool is32bit(MachineTypes Machine) { switch (Machine) { default: llvm_unreachable("unsupported machine"); + case IMAGE_FILE_MACHINE_ARM64: case IMAGE_FILE_MACHINE_AMD64: return false; case IMAGE_FILE_MACHINE_ARMNT: @@ -52,6 +51,8 @@ static uint16_t getImgRelRelocation(MachineTypes Machine) { return IMAGE_REL_AMD64_ADDR32NB; case IMAGE_FILE_MACHINE_ARMNT: return IMAGE_REL_ARM_ADDR32NB; + case IMAGE_FILE_MACHINE_ARM64: + return IMAGE_REL_ARM64_ADDR32NB; case IMAGE_FILE_MACHINE_I386: return IMAGE_REL_I386_DIR32NB; } @@ -187,7 +188,7 @@ ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) { (ImportName.size() + 1)), u32(NumberOfSymbols), u16(0), - u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0), + u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid), }; append(Buffer, Header); @@ -323,7 +324,7 @@ ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) { sizeof(coff_import_directory_table_entry)), u32(NumberOfSymbols), u16(0), - u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0), + u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid), }; append(Buffer, Header); @@ -386,7 +387,7 @@ NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) { VASize), u32(NumberOfSymbols), u16(0), - u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : 0), + u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid), }; append(Buffer, Header); @@ -555,9 +556,9 @@ NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)}; } -std::error_code writeImportLibrary(StringRef ImportName, StringRef Path, - ArrayRef<COFFShortExport> Exports, - MachineTypes Machine, bool MakeWeakAliases) { +Error writeImportLibrary(StringRef ImportName, StringRef Path, + ArrayRef<COFFShortExport> Exports, + MachineTypes Machine, bool MakeWeakAliases) { std::vector<NewArchiveMember> Members; ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine); @@ -593,19 +594,16 @@ std::error_code writeImportLibrary(StringRef ImportName, StringRef Path, ? SymbolName : replace(SymbolName, E.Name, E.ExtName); - if (!Name) { - return errorToErrorCode(Name.takeError()); - } + if (!Name) + return Name.takeError(); Members.push_back( OF.createShortImport(*Name, E.Ordinal, ImportType, NameType)); } - std::pair<StringRef, std::error_code> Result = - writeArchive(Path, Members, /*WriteSymtab*/ true, object::Archive::K_GNU, - /*Deterministic*/ true, /*Thin*/ false); - - return Result.second; + return writeArchive(Path, Members, /*WriteSymtab*/ true, + object::Archive::K_GNU, + /*Deterministic*/ true, /*Thin*/ false); } } // namespace object diff --git a/contrib/llvm/lib/Object/COFFModuleDefinition.cpp b/contrib/llvm/lib/Object/COFFModuleDefinition.cpp index 510eac8b239b..a571354648d6 100644 --- a/contrib/llvm/lib/Object/COFFModuleDefinition.cpp +++ b/contrib/llvm/lib/Object/COFFModuleDefinition.cpp @@ -57,9 +57,27 @@ struct Token { }; static bool isDecorated(StringRef Sym, bool MingwDef) { - // mingw does not prepend "_". - return (!MingwDef && Sym.startswith("_")) || Sym.startswith("@") || - Sym.startswith("?"); + // In def files, the symbols can either be listed decorated or undecorated. + // + // - For cdecl symbols, only the undecorated form is allowed. + // - For fastcall and vectorcall symbols, both fully decorated or + // undecorated forms can be present. + // - For stdcall symbols in non-MinGW environments, the decorated form is + // fully decorated with leading underscore and trailing stack argument + // size - like "_Func@0". + // - In MinGW def files, a decorated stdcall symbol does not include the + // leading underscore though, like "Func@0". + + // This function controls whether a leading underscore should be added to + // the given symbol name or not. For MinGW, treat a stdcall symbol name such + // as "Func@0" as undecorated, i.e. a leading underscore must be added. + // For non-MinGW, look for '@' in the whole string and consider "_Func@0" + // as decorated, i.e. don't add any more leading underscores. + // We can't check for a leading underscore here, since function names + // themselves can start with an underscore, while a second one still needs + // to be added. + return Sym.startswith("@") || Sym.contains("@@") || Sym.startswith("?") || + (!MingwDef && Sym.contains('@')); } static Error createError(const Twine &Err) { @@ -99,7 +117,7 @@ public: return Token(Identifier, S); } default: { - size_t End = Buf.find_first_of("=,\r\n \t\v"); + size_t End = Buf.find_first_of("=,;\r\n \t\v"); StringRef Word = Buf.substr(0, End); Kind K = llvm::StringSwitch<Kind>(Word) .Case("BASE", KwBase) @@ -232,13 +250,18 @@ private: for (;;) { read(); if (Tok.K == Identifier && Tok.Value[0] == '@') { - if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) { - // Not an ordinal modifier at all, but the next export (fastcall - // decorated) - complete the current one. + if (Tok.Value == "@") { + // "foo @ 10" + read(); + Tok.Value.getAsInteger(10, E.Ordinal); + } else if (Tok.Value.drop_front().getAsInteger(10, E.Ordinal)) { + // "foo \n @bar" - Not an ordinal modifier at all, but the next + // export (fastcall decorated) - complete the current one. unget(); Info.Exports.push_back(E); return Error::success(); } + // "foo @10" read(); if (Tok.K == KwNoname) { E.Noname = true; diff --git a/contrib/llvm/lib/Object/COFFObjectFile.cpp b/contrib/llvm/lib/Object/COFFObjectFile.cpp index 0a2053477caf..b544fa5c1470 100644 --- a/contrib/llvm/lib/Object/COFFObjectFile.cpp +++ b/contrib/llvm/lib/Object/COFFObjectFile.cpp @@ -52,16 +52,6 @@ static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) { return true; } -static std::error_code checkOffset(MemoryBufferRef M, uintptr_t Addr, - const uint64_t Size) { - if (Addr + Size < Addr || Addr + Size < Size || - Addr + Size > uintptr_t(M.getBufferEnd()) || - Addr < uintptr_t(M.getBufferStart())) { - return object_error::unexpected_eof; - } - return std::error_code(); -} - // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. // Returns unexpected_eof if error. template <typename T> @@ -69,7 +59,7 @@ static std::error_code getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr, const uint64_t Size = sizeof(T)) { uintptr_t Addr = uintptr_t(Ptr); - if (std::error_code EC = checkOffset(M, Addr, Size)) + if (std::error_code EC = Binary::checkOffset(M, Addr, Size)) return EC; Obj = reinterpret_cast<const T *>(Addr); return std::error_code(); @@ -383,7 +373,8 @@ getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) { // relocations. begin++; } - if (checkOffset(M, uintptr_t(begin), sizeof(coff_relocation) * NumRelocs)) + if (Binary::checkOffset(M, uintptr_t(begin), + sizeof(coff_relocation) * NumRelocs)) return nullptr; return begin; } @@ -904,7 +895,7 @@ StringRef COFFObjectFile::getFileFormatName() const { } } -unsigned COFFObjectFile::getArch() const { +Triple::ArchType COFFObjectFile::getArch() const { switch (getMachine()) { case COFF::IMAGE_FILE_MACHINE_I386: return Triple::x86; @@ -1599,12 +1590,12 @@ std::error_code ImportedSymbolRef::getOrdinal(uint16_t &Result) const { return std::error_code(); } -ErrorOr<std::unique_ptr<COFFObjectFile>> +Expected<std::unique_ptr<COFFObjectFile>> ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) { std::error_code EC; std::unique_ptr<COFFObjectFile> Ret(new COFFObjectFile(Object, EC)); if (EC) - return EC; + return errorCodeToError(EC); return std::move(Ret); } @@ -1642,11 +1633,12 @@ std::error_code BaseRelocRef::getRVA(uint32_t &Result) const { return std::error_code(); } -#define RETURN_IF_ERROR(X) \ - if (auto EC = errorToErrorCode(X)) \ - return EC; +#define RETURN_IF_ERROR(E) \ + if (E) \ + return E; -ErrorOr<ArrayRef<UTF16>> ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) { +Expected<ArrayRef<UTF16>> +ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) { BinaryStreamReader Reader = BinaryStreamReader(BBS); Reader.setOffset(Offset); uint16_t Length; @@ -1656,12 +1648,12 @@ ErrorOr<ArrayRef<UTF16>> ResourceSectionRef::getDirStringAtOffset(uint32_t Offse return RawDirString; } -ErrorOr<ArrayRef<UTF16>> +Expected<ArrayRef<UTF16>> ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) { return getDirStringAtOffset(Entry.Identifier.getNameOffset()); } -ErrorOr<const coff_resource_dir_table &> +Expected<const coff_resource_dir_table &> ResourceSectionRef::getTableAtOffset(uint32_t Offset) { const coff_resource_dir_table *Table = nullptr; @@ -1672,11 +1664,11 @@ ResourceSectionRef::getTableAtOffset(uint32_t Offset) { return *Table; } -ErrorOr<const coff_resource_dir_table &> +Expected<const coff_resource_dir_table &> ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) { return getTableAtOffset(Entry.Offset.value()); } -ErrorOr<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() { +Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() { return getTableAtOffset(0); } diff --git a/contrib/llvm/lib/Object/ELF.cpp b/contrib/llvm/lib/Object/ELF.cpp index 448fb1bd6b56..c72a1258c1ee 100644 --- a/contrib/llvm/lib/Object/ELF.cpp +++ b/contrib/llvm/lib/Object/ELF.cpp @@ -9,6 +9,7 @@ #include "llvm/Object/ELF.h" #include "llvm/BinaryFormat/ELF.h" +#include "llvm/Support/LEB128.h" using namespace llvm; using namespace object; @@ -58,6 +59,14 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, break; } break; + case ELF::EM_ARC_COMPACT: + case ELF::EM_ARC_COMPACT2: + switch (Type) { +#include "llvm/BinaryFormat/ELFRelocs/ARC.def" + default: + break; + } + break; case ELF::EM_AVR: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/AVR.def" @@ -192,6 +201,8 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { STRINGIFY_ENUM_CASE(ELF, SHT_PREINIT_ARRAY); STRINGIFY_ENUM_CASE(ELF, SHT_GROUP); STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX); + STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL); + STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA); STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES); STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH); @@ -202,3 +213,92 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { return "Unknown"; } } + +template <class ELFT> +Expected<std::vector<typename ELFT::Rela>> +ELFFile<ELFT>::android_relas(const Elf_Shdr *Sec) const { + // This function reads relocations in Android's packed relocation format, + // which is based on SLEB128 and delta encoding. + Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + const uint8_t *Cur = ContentsOrErr->begin(); + const uint8_t *End = ContentsOrErr->end(); + if (ContentsOrErr->size() < 4 || Cur[0] != 'A' || Cur[1] != 'P' || + Cur[2] != 'S' || Cur[3] != '2') + return createError("invalid packed relocation header"); + Cur += 4; + + const char *ErrStr = nullptr; + auto ReadSLEB = [&]() -> int64_t { + if (ErrStr) + return 0; + unsigned Len; + int64_t Result = decodeSLEB128(Cur, &Len, End, &ErrStr); + Cur += Len; + return Result; + }; + + uint64_t NumRelocs = ReadSLEB(); + uint64_t Offset = ReadSLEB(); + uint64_t Addend = 0; + + if (ErrStr) + return createError(ErrStr); + + std::vector<Elf_Rela> Relocs; + Relocs.reserve(NumRelocs); + while (NumRelocs) { + uint64_t NumRelocsInGroup = ReadSLEB(); + if (NumRelocsInGroup > NumRelocs) + return createError("relocation group unexpectedly large"); + NumRelocs -= NumRelocsInGroup; + + uint64_t GroupFlags = ReadSLEB(); + bool GroupedByInfo = GroupFlags & ELF::RELOCATION_GROUPED_BY_INFO_FLAG; + bool GroupedByOffsetDelta = GroupFlags & ELF::RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG; + bool GroupedByAddend = GroupFlags & ELF::RELOCATION_GROUPED_BY_ADDEND_FLAG; + bool GroupHasAddend = GroupFlags & ELF::RELOCATION_GROUP_HAS_ADDEND_FLAG; + + uint64_t GroupOffsetDelta; + if (GroupedByOffsetDelta) + GroupOffsetDelta = ReadSLEB(); + + uint64_t GroupRInfo; + if (GroupedByInfo) + GroupRInfo = ReadSLEB(); + + if (GroupedByAddend && GroupHasAddend) + Addend += ReadSLEB(); + + for (uint64_t I = 0; I != NumRelocsInGroup; ++I) { + Elf_Rela R; + Offset += GroupedByOffsetDelta ? GroupOffsetDelta : ReadSLEB(); + R.r_offset = Offset; + R.r_info = GroupedByInfo ? GroupRInfo : ReadSLEB(); + + if (GroupHasAddend) { + if (!GroupedByAddend) + Addend += ReadSLEB(); + R.r_addend = Addend; + } else { + R.r_addend = 0; + } + + Relocs.push_back(R); + + if (ErrStr) + return createError(ErrStr); + } + + if (ErrStr) + return createError(ErrStr); + } + + return Relocs; +} + +template class llvm::object::ELFFile<ELF32LE>; +template class llvm::object::ELFFile<ELF32BE>; +template class llvm::object::ELFFile<ELF64LE>; +template class llvm::object::ELFFile<ELF64BE>; diff --git a/contrib/llvm/lib/Object/ELFObjectFile.cpp b/contrib/llvm/lib/Object/ELFObjectFile.cpp index fa136d782b5a..0aad1c89a2d8 100644 --- a/contrib/llvm/lib/Object/ELFObjectFile.cpp +++ b/contrib/llvm/lib/Object/ELFObjectFile.cpp @@ -37,7 +37,16 @@ using namespace object; ELFObjectFileBase::ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source) : ObjectFile(Type, Source) {} -ErrorOr<std::unique_ptr<ObjectFile>> +template <class ELFT> +static Expected<std::unique_ptr<ELFObjectFile<ELFT>>> +createPtr(MemoryBufferRef Object) { + auto Ret = ELFObjectFile<ELFT>::create(Object); + if (Error E = Ret.takeError()) + return std::move(E); + return make_unique<ELFObjectFile<ELFT>>(std::move(*Ret)); +} + +Expected<std::unique_ptr<ObjectFile>> ObjectFile::createELFObjectFile(MemoryBufferRef Obj) { std::pair<unsigned char, unsigned char> Ident = getElfArchType(Obj.getBuffer()); @@ -45,31 +54,24 @@ ObjectFile::createELFObjectFile(MemoryBufferRef Obj) { 1ULL << countTrailingZeros(uintptr_t(Obj.getBufferStart())); if (MaxAlignment < 2) - return object_error::parse_failed; + return createError("Insufficient alignment"); - std::error_code EC; - std::unique_ptr<ObjectFile> R; if (Ident.first == ELF::ELFCLASS32) { if (Ident.second == ELF::ELFDATA2LSB) - R.reset(new ELFObjectFile<ELFType<support::little, false>>(Obj, EC)); + return createPtr<ELF32LE>(Obj); else if (Ident.second == ELF::ELFDATA2MSB) - R.reset(new ELFObjectFile<ELFType<support::big, false>>(Obj, EC)); + return createPtr<ELF32BE>(Obj); else - return object_error::parse_failed; + return createError("Invalid ELF data"); } else if (Ident.first == ELF::ELFCLASS64) { if (Ident.second == ELF::ELFDATA2LSB) - R.reset(new ELFObjectFile<ELFType<support::little, true>>(Obj, EC)); + return createPtr<ELF64LE>(Obj); else if (Ident.second == ELF::ELFDATA2MSB) - R.reset(new ELFObjectFile<ELFType<support::big, true>>(Obj, EC)); + return createPtr<ELF64BE>(Obj); else - return object_error::parse_failed; - } else { - return object_error::parse_failed; + return createError("Invalid ELF data"); } - - if (EC) - return EC; - return std::move(R); + return createError("Invalid ELF class"); } SubtargetFeatures ELFObjectFileBase::getMIPSFeatures() const { @@ -260,8 +262,7 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const { std::string Triple; // Default to ARM, but use the triple if it's been set. - if (TheTriple.getArch() == Triple::thumb || - TheTriple.getArch() == Triple::thumbeb) + if (TheTriple.isThumb()) Triple = "thumb"; else Triple = "arm"; diff --git a/contrib/llvm/lib/Object/IRObjectFile.cpp b/contrib/llvm/lib/Object/IRObjectFile.cpp index e7807b038335..1ecb26d60bce 100644 --- a/contrib/llvm/lib/Object/IRObjectFile.cpp +++ b/contrib/llvm/lib/Object/IRObjectFile.cpp @@ -12,7 +12,6 @@ //===----------------------------------------------------------------------===// #include "llvm/Object/IRObjectFile.h" -#include "RecordStreamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/BinaryFormat/Magic.h" #include "llvm/Bitcode/BitcodeReader.h" @@ -20,17 +19,8 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" -#include "llvm/MC/MCAsmInfo.h" -#include "llvm/MC/MCContext.h" -#include "llvm/MC/MCInstrInfo.h" -#include "llvm/MC/MCObjectFileInfo.h" -#include "llvm/MC/MCParser/MCAsmParser.h" -#include "llvm/MC/MCParser/MCTargetAsmParser.h" -#include "llvm/MC/MCRegisterInfo.h" -#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -82,20 +72,22 @@ StringRef IRObjectFile::getTargetTriple() const { return Mods[0]->getTargetTriple(); } -ErrorOr<MemoryBufferRef> IRObjectFile::findBitcodeInObject(const ObjectFile &Obj) { +Expected<MemoryBufferRef> +IRObjectFile::findBitcodeInObject(const ObjectFile &Obj) { for (const SectionRef &Sec : Obj.sections()) { if (Sec.isBitcode()) { StringRef SecContents; if (std::error_code EC = Sec.getContents(SecContents)) - return EC; + return errorCodeToError(EC); return MemoryBufferRef(SecContents, Obj.getFileName()); } } - return object_error::bitcode_section_not_found; + return errorCodeToError(object_error::bitcode_section_not_found); } -ErrorOr<MemoryBufferRef> IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) { +Expected<MemoryBufferRef> +IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) { file_magic Type = identify_magic(Object.getBuffer()); switch (Type) { case file_magic::bitcode: @@ -106,19 +98,19 @@ ErrorOr<MemoryBufferRef> IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Ob Expected<std::unique_ptr<ObjectFile>> ObjFile = ObjectFile::createObjectFile(Object, Type); if (!ObjFile) - return errorToErrorCode(ObjFile.takeError()); + return ObjFile.takeError(); return findBitcodeInObject(*ObjFile->get()); } default: - return object_error::invalid_file_type; + return errorCodeToError(object_error::invalid_file_type); } } Expected<std::unique_ptr<IRObjectFile>> IRObjectFile::create(MemoryBufferRef Object, LLVMContext &Context) { - ErrorOr<MemoryBufferRef> BCOrErr = findBitcodeInMemBuffer(Object); + Expected<MemoryBufferRef> BCOrErr = findBitcodeInMemBuffer(Object); if (!BCOrErr) - return errorCodeToError(BCOrErr.getError()); + return BCOrErr.takeError(); Expected<std::vector<BitcodeModule>> BMsOrErr = getBitcodeModuleList(*BCOrErr); @@ -142,10 +134,10 @@ IRObjectFile::create(MemoryBufferRef Object, LLVMContext &Context) { Expected<IRSymtabFile> object::readIRSymtab(MemoryBufferRef MBRef) { IRSymtabFile F; - ErrorOr<MemoryBufferRef> BCOrErr = + Expected<MemoryBufferRef> BCOrErr = IRObjectFile::findBitcodeInMemBuffer(MBRef); if (!BCOrErr) - return errorCodeToError(BCOrErr.getError()); + return BCOrErr.takeError(); Expected<BitcodeFileContents> BFCOrErr = getBitcodeFileContents(*BCOrErr); if (!BFCOrErr) diff --git a/contrib/llvm/lib/Object/IRSymtab.cpp b/contrib/llvm/lib/Object/IRSymtab.cpp index 7a6424a76a98..2d8d3f7c0878 100644 --- a/contrib/llvm/lib/Object/IRSymtab.cpp +++ b/contrib/llvm/lib/Object/IRSymtab.cpp @@ -72,7 +72,7 @@ struct Builder { BumpPtrAllocator &Alloc) : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc) {} - DenseMap<const Comdat *, unsigned> ComdatMap; + DenseMap<const Comdat *, int> ComdatMap; Mangler Mang; Triple TT; @@ -97,6 +97,8 @@ struct Builder { reinterpret_cast<const char *>(Objs.data() + Objs.size())); } + Expected<int> getComdatIndex(const Comdat *C, const Module *M); + Error addModule(Module *M); Error addSymbol(const ModuleSymbolTable &Msymtab, const SmallPtrSet<GlobalValue *, 8> &Used, @@ -140,6 +142,35 @@ Error Builder::addModule(Module *M) { return Error::success(); } +Expected<int> Builder::getComdatIndex(const Comdat *C, const Module *M) { + auto P = ComdatMap.insert(std::make_pair(C, Comdats.size())); + if (P.second) { + std::string Name; + if (TT.isOSBinFormatCOFF()) { + const GlobalValue *GV = M->getNamedValue(C->getName()); + if (!GV) + return make_error<StringError>("Could not find leader", + inconvertibleErrorCode()); + // Internal leaders do not affect symbol resolution, therefore they do not + // appear in the symbol table. + if (GV->hasLocalLinkage()) { + P.first->second = -1; + return -1; + } + llvm::raw_string_ostream OS(Name); + Mang.getNameWithPrefix(OS, GV, false); + } else { + Name = C->getName(); + } + + storage::Comdat Comdat; + setStr(Comdat.Name, Saver.save(Name)); + Comdats.push_back(Comdat); + } + + return P.first->second; +} + Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, const SmallPtrSet<GlobalValue *, 8> &Used, ModuleSymbolTable::Symbol Msym) { @@ -156,6 +187,7 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, Unc = &Uncommons.back(); *Unc = {}; setStr(Unc->COFFWeakExternFallbackName, ""); + setStr(Unc->SectionName, ""); return *Unc; }; @@ -215,14 +247,10 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, return make_error<StringError>("Unable to determine comdat of alias!", inconvertibleErrorCode()); if (const Comdat *C = Base->getComdat()) { - auto P = ComdatMap.insert(std::make_pair(C, Comdats.size())); - Sym.ComdatIndex = P.first->second; - - if (P.second) { - storage::Comdat Comdat; - setStr(Comdat.Name, C->getName()); - Comdats.push_back(Comdat); - } + Expected<int> ComdatIndexOrErr = getComdatIndex(C, GV->getParent()); + if (!ComdatIndexOrErr) + return ComdatIndexOrErr.takeError(); + Sym.ComdatIndex = *ComdatIndexOrErr; } if (TT.isOSBinFormatCOFF()) { @@ -230,16 +258,22 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, if ((Flags & object::BasicSymbolRef::SF_Weak) && (Flags & object::BasicSymbolRef::SF_Indirect)) { + auto *Fallback = dyn_cast<GlobalValue>( + cast<GlobalAlias>(GV)->getAliasee()->stripPointerCasts()); + if (!Fallback) + return make_error<StringError>("Invalid weak external", + inconvertibleErrorCode()); std::string FallbackName; raw_string_ostream OS(FallbackName); - Msymtab.printSymbolName( - OS, cast<GlobalValue>( - cast<GlobalAlias>(GV)->getAliasee()->stripPointerCasts())); + Msymtab.printSymbolName(OS, Fallback); OS.flush(); setStr(Uncommon().COFFWeakExternFallbackName, Saver.save(FallbackName)); } } + if (!Base->getSection().empty()) + setStr(Uncommon().SectionName, Saver.save(Base->getSection())); + return Error::success(); } diff --git a/contrib/llvm/lib/Object/MachOObjectFile.cpp b/contrib/llvm/lib/Object/MachOObjectFile.cpp index 2e4da9f15aa1..2e3415618e5f 100644 --- a/contrib/llvm/lib/Object/MachOObjectFile.cpp +++ b/contrib/llvm/lib/Object/MachOObjectFile.cpp @@ -16,7 +16,6 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Triple.h" @@ -59,10 +58,9 @@ namespace { } // end anonymous namespace -static Error -malformedError(Twine Msg) { - std::string StringMsg = "truncated or malformed object (" + Msg.str() + ")"; - return make_error<GenericBinaryError>(std::move(StringMsg), +static Error malformedError(const Twine &Msg) { + return make_error<GenericBinaryError>("truncated or malformed object (" + + Msg + ")", object_error::parse_failed); } @@ -185,6 +183,9 @@ static Expected<MachOObjectFile::LoadCommandInfo> getLoadCommandInfo(const MachOObjectFile &Obj, const char *Ptr, uint32_t LoadCommandIndex) { if (auto CmdOrErr = getStructOrErr<MachO::load_command>(Obj, Ptr)) { + if (CmdOrErr->cmdsize + Ptr > Obj.getData().end()) + return malformedError("load command " + Twine(LoadCommandIndex) + + " extends past end of file"); if (CmdOrErr->cmdsize < 8) return malformedError("load command " + Twine(LoadCommandIndex) + " with size less than 8 bytes"); @@ -476,8 +477,8 @@ static Error checkDysymtabCommand(const MachOObjectFile &Obj, "the file"); if (Error Err = checkOverlappingElement(Elements, Dysymtab.tocoff, Dysymtab.ntoc * sizeof(struct - MachO::dylib_table_of_contents), - "table of contents")) + MachO::dylib_table_of_contents), + "table of contents")) return Err; if (Dysymtab.modtaboff > FileSize) return malformedError("modtaboff field of LC_DYSYMTAB command " + @@ -502,7 +503,7 @@ static Error checkDysymtabCommand(const MachOObjectFile &Obj, "past the end of the file"); if (Error Err = checkOverlappingElement(Elements, Dysymtab.modtaboff, Dysymtab.nmodtab * sizeof_modtab, - "module table")) + "module table")) return Err; if (Dysymtab.extrefsymoff > FileSize) return malformedError("extrefsymoff field of LC_DYSYMTAB command " + @@ -518,8 +519,8 @@ static Error checkDysymtabCommand(const MachOObjectFile &Obj, "past the end of the file"); if (Error Err = checkOverlappingElement(Elements, Dysymtab.extrefsymoff, Dysymtab.nextrefsyms * - sizeof(MachO::dylib_reference), - "reference table")) + sizeof(MachO::dylib_reference), + "reference table")) return Err; if (Dysymtab.indirectsymoff > FileSize) return malformedError("indirectsymoff field of LC_DYSYMTAB command " + @@ -536,7 +537,7 @@ static Error checkDysymtabCommand(const MachOObjectFile &Obj, if (Error Err = checkOverlappingElement(Elements, Dysymtab.indirectsymoff, Dysymtab.nindirectsyms * sizeof(uint32_t), - "indirect table")) + "indirect table")) return Err; if (Dysymtab.extreloff > FileSize) return malformedError("extreloff field of LC_DYSYMTAB command " + @@ -552,8 +553,8 @@ static Error checkDysymtabCommand(const MachOObjectFile &Obj, "the file"); if (Error Err = checkOverlappingElement(Elements, Dysymtab.extreloff, Dysymtab.nextrel * - sizeof(MachO::relocation_info), - "external relocation table")) + sizeof(MachO::relocation_info), + "external relocation table")) return Err; if (Dysymtab.locreloff > FileSize) return malformedError("locreloff field of LC_DYSYMTAB command " + @@ -569,8 +570,8 @@ static Error checkDysymtabCommand(const MachOObjectFile &Obj, "the file"); if (Error Err = checkOverlappingElement(Elements, Dysymtab.locreloff, Dysymtab.nlocrel * - sizeof(MachO::relocation_info), - "local relocation table")) + sizeof(MachO::relocation_info), + "local relocation table")) return Err; *DysymtabLoadCmd = Load.Ptr; return Error::success(); @@ -802,7 +803,7 @@ static Error checkNoteCommand(const MachOObjectFile &Obj, uint32_t LoadCommandIndex, std::list<MachOElement> &Elements) { if (Load.C.cmdsize != sizeof(MachO::note_command)) - return malformedError("load command " + Twine(LoadCommandIndex) + + return malformedError("load command " + Twine(LoadCommandIndex) + " LC_NOTE has incorrect cmdsize"); MachO::note_command Nt = getStruct<MachO::note_command>(Obj, Load.Ptr); uint64_t FileSize = Obj.getData().size(); @@ -1114,7 +1115,7 @@ static Error checkTwoLevelHintsCommand(const MachOObjectFile &Obj, Twine(LoadCommandIndex) + " extends past the end of " "the file"); uint64_t BigSize = Hints.nhints; - BigSize *= Hints.nhints * sizeof(MachO::twolevel_hint); + BigSize *= sizeof(MachO::twolevel_hint); BigSize += Hints.offset; if (BigSize > FileSize) return malformedError("offset field plus nhints times sizeof(struct " @@ -1927,6 +1928,12 @@ bool MachOObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; } +bool MachOObjectFile::isSectionStripped(DataRefImpl Sec) const { + if (is64Bit()) + return getSection64(Sec).offset == 0; + return getSection(Sec).offset == 0; +} + relocation_iterator MachOObjectFile::section_rel_begin(DataRefImpl Sec) const { DataRefImpl Ret; Ret.d.a = Sec.d.a; @@ -1953,6 +1960,7 @@ MachOObjectFile::section_rel_end(DataRefImpl Sec) const { relocation_iterator MachOObjectFile::extrel_begin() const { DataRefImpl Ret; + // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations Ret.d.a = 0; // Would normally be a section index. Ret.d.b = 0; // Index into the external relocations return relocation_iterator(RelocationRef(Ret, this)); @@ -1961,11 +1969,29 @@ relocation_iterator MachOObjectFile::extrel_begin() const { relocation_iterator MachOObjectFile::extrel_end() const { MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); DataRefImpl Ret; + // for DYSYMTAB symbols, Ret.d.a == 0 for external relocations Ret.d.a = 0; // Would normally be a section index. Ret.d.b = DysymtabLoadCmd.nextrel; // Index into the external relocations return relocation_iterator(RelocationRef(Ret, this)); } +relocation_iterator MachOObjectFile::locrel_begin() const { + DataRefImpl Ret; + // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations + Ret.d.a = 1; // Would normally be a section index. + Ret.d.b = 0; // Index into the local relocations + return relocation_iterator(RelocationRef(Ret, this)); +} + +relocation_iterator MachOObjectFile::locrel_end() const { + MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); + DataRefImpl Ret; + // for DYSYMTAB symbols, Ret.d.a == 1 for local relocations + Ret.d.a = 1; // Would normally be a section index. + Ret.d.b = DysymtabLoadCmd.nlocrel; // Index into the local relocations + return relocation_iterator(RelocationRef(Ret, this)); +} + void MachOObjectFile::moveRelocationNext(DataRefImpl &Rel) const { ++Rel.d.b; } @@ -2566,7 +2592,7 @@ bool MachOObjectFile::isValidArch(StringRef ArchFlag) { .Default(false); } -unsigned MachOObjectFile::getArch() const { +Triple::ArchType MachOObjectFile::getArch() const { return getArch(getCPUType(*this)); } @@ -2607,10 +2633,14 @@ dice_iterator MachOObjectFile::end_dices() const { return dice_iterator(DiceRef(DRI, this)); } -ExportEntry::ExportEntry(ArrayRef<uint8_t> T) : Trie(T) {} +ExportEntry::ExportEntry(Error *E, const MachOObjectFile *O, + ArrayRef<uint8_t> T) : E(E), O(O), Trie(T) {} void ExportEntry::moveToFirst() { + ErrorAsOutParameter ErrAsOutParam(E); pushNode(0); + if (*E) + return; pushDownUntilBottom(); } @@ -2637,14 +2667,12 @@ bool ExportEntry::operator==(const ExportEntry &Other) const { return true; } -uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr) { +uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr, const char **error) { unsigned Count; - uint64_t Result = decodeULEB128(Ptr, &Count); + uint64_t Result = decodeULEB128(Ptr, &Count, Trie.end(), error); Ptr += Count; - if (Ptr > Trie.end()) { + if (Ptr > Trie.end()) Ptr = Trie.end(); - Malformed = true; - } return Result; } @@ -2679,24 +2707,134 @@ ExportEntry::NodeState::NodeState(const uint8_t *Ptr) : Start(Ptr), Current(Ptr) {} void ExportEntry::pushNode(uint64_t offset) { + ErrorAsOutParameter ErrAsOutParam(E); const uint8_t *Ptr = Trie.begin() + offset; NodeState State(Ptr); - uint64_t ExportInfoSize = readULEB128(State.Current); + const char *error; + uint64_t ExportInfoSize = readULEB128(State.Current, &error); + if (error) { + *E = malformedError("export info size " + Twine(error) + + " in export trie data at node: 0x" + + Twine::utohexstr(offset)); + moveToEnd(); + return; + } State.IsExportNode = (ExportInfoSize != 0); const uint8_t* Children = State.Current + ExportInfoSize; + if (Children > Trie.end()) { + *E = malformedError( + "export info size: 0x" + Twine::utohexstr(ExportInfoSize) + + " in export trie data at node: 0x" + Twine::utohexstr(offset) + + " too big and extends past end of trie data"); + moveToEnd(); + return; + } if (State.IsExportNode) { - State.Flags = readULEB128(State.Current); + const uint8_t *ExportStart = State.Current; + State.Flags = readULEB128(State.Current, &error); + if (error) { + *E = malformedError("flags " + Twine(error) + + " in export trie data at node: 0x" + + Twine::utohexstr(offset)); + moveToEnd(); + return; + } + uint64_t Kind = State.Flags & MachO::EXPORT_SYMBOL_FLAGS_KIND_MASK; + if (State.Flags != 0 && + (Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_REGULAR && + Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_ABSOLUTE && + Kind != MachO::EXPORT_SYMBOL_FLAGS_KIND_THREAD_LOCAL)) { + *E = malformedError( + "unsupported exported symbol kind: " + Twine((int)Kind) + + " in flags: 0x" + Twine::utohexstr(State.Flags) + + " in export trie data at node: 0x" + Twine::utohexstr(offset)); + moveToEnd(); + return; + } if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_REEXPORT) { State.Address = 0; - State.Other = readULEB128(State.Current); // dylib ordinal + State.Other = readULEB128(State.Current, &error); // dylib ordinal + if (error) { + *E = malformedError("dylib ordinal of re-export " + Twine(error) + + " in export trie data at node: 0x" + + Twine::utohexstr(offset)); + moveToEnd(); + return; + } + if (O != nullptr) { + if (State.Other > O->getLibraryCount()) { + *E = malformedError( + "bad library ordinal: " + Twine((int)State.Other) + " (max " + + Twine((int)O->getLibraryCount()) + + ") in export trie data at node: 0x" + Twine::utohexstr(offset)); + moveToEnd(); + return; + } + } State.ImportName = reinterpret_cast<const char*>(State.Current); + if (*State.ImportName == '\0') { + State.Current++; + } else { + const uint8_t *End = State.Current + 1; + if (End >= Trie.end()) { + *E = malformedError("import name of re-export in export trie data at " + "node: 0x" + + Twine::utohexstr(offset) + + " starts past end of trie data"); + moveToEnd(); + return; + } + while(*End != '\0' && End < Trie.end()) + End++; + if (*End != '\0') { + *E = malformedError("import name of re-export in export trie data at " + "node: 0x" + + Twine::utohexstr(offset) + + " extends past end of trie data"); + moveToEnd(); + return; + } + State.Current = End + 1; + } } else { - State.Address = readULEB128(State.Current); - if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) - State.Other = readULEB128(State.Current); + State.Address = readULEB128(State.Current, &error); + if (error) { + *E = malformedError("address " + Twine(error) + + " in export trie data at node: 0x" + + Twine::utohexstr(offset)); + moveToEnd(); + return; + } + if (State.Flags & MachO::EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) { + State.Other = readULEB128(State.Current, &error); + if (error) { + *E = malformedError("resolver of stub and resolver " + Twine(error) + + " in export trie data at node: 0x" + + Twine::utohexstr(offset)); + moveToEnd(); + return; + } + } + } + if(ExportStart + ExportInfoSize != State.Current) { + *E = malformedError( + "inconsistant export info size: 0x" + + Twine::utohexstr(ExportInfoSize) + " where actual size was: 0x" + + Twine::utohexstr(State.Current - ExportStart) + + " in export trie data at node: 0x" + Twine::utohexstr(offset)); + moveToEnd(); + return; } } State.ChildCount = *Children; + if (State.ChildCount != 0 && Children + 1 >= Trie.end()) { + *E = malformedError("byte for count of childern in export trie data at " + "node: 0x" + + Twine::utohexstr(offset) + + " extends past end of trie data"); + moveToEnd(); + return; + } State.Current = Children + 1; State.NextChildIndex = 0; State.ParentStringLength = CumulativeString.size(); @@ -2704,21 +2842,53 @@ void ExportEntry::pushNode(uint64_t offset) { } void ExportEntry::pushDownUntilBottom() { + ErrorAsOutParameter ErrAsOutParam(E); + const char *error; while (Stack.back().NextChildIndex < Stack.back().ChildCount) { NodeState &Top = Stack.back(); CumulativeString.resize(Top.ParentStringLength); - for (;*Top.Current != 0; Top.Current++) { + for (;*Top.Current != 0 && Top.Current < Trie.end(); Top.Current++) { char C = *Top.Current; CumulativeString.push_back(C); } + if (Top.Current >= Trie.end()) { + *E = malformedError("edge sub-string in export trie data at node: 0x" + + Twine::utohexstr(Top.Start - Trie.begin()) + + " for child #" + Twine((int)Top.NextChildIndex) + + " extends past end of trie data"); + moveToEnd(); + return; + } Top.Current += 1; - uint64_t childNodeIndex = readULEB128(Top.Current); + uint64_t childNodeIndex = readULEB128(Top.Current, &error); + if (error) { + *E = malformedError("child node offset " + Twine(error) + + " in export trie data at node: 0x" + + Twine::utohexstr(Top.Start - Trie.begin())); + moveToEnd(); + return; + } + for (const NodeState &node : nodes()) { + if (node.Start == Trie.begin() + childNodeIndex){ + *E = malformedError("loop in childern in export trie data at node: 0x" + + Twine::utohexstr(Top.Start - Trie.begin()) + + " back to node: 0x" + + Twine::utohexstr(childNodeIndex)); + moveToEnd(); + return; + } + } Top.NextChildIndex += 1; pushNode(childNodeIndex); + if (*E) + return; } if (!Stack.back().IsExportNode) { - Malformed = true; + *E = malformedError("node is not an export node in export trie data at " + "node: 0x" + + Twine::utohexstr(Stack.back().Start - Trie.begin())); moveToEnd(); + return; } } @@ -2738,8 +2908,11 @@ void ExportEntry::pushDownUntilBottom() { // stack ivar. If there is no more ways down, it pops up one and tries to go // down a sibling path until a childless node is reached. void ExportEntry::moveNext() { - if (Stack.empty() || !Stack.back().IsExportNode) { - Malformed = true; + assert(!Stack.empty() && "ExportEntry::moveNext() with empty node stack"); + if (!Stack.back().IsExportNode) { + *E = malformedError("node is not an export node in export trie data at " + "node: 0x" + + Twine::utohexstr(Stack.back().Start - Trie.begin())); moveToEnd(); return; } @@ -2764,21 +2937,22 @@ void ExportEntry::moveNext() { } iterator_range<export_iterator> -MachOObjectFile::exports(ArrayRef<uint8_t> Trie) { - ExportEntry Start(Trie); +MachOObjectFile::exports(Error &E, ArrayRef<uint8_t> Trie, + const MachOObjectFile *O) { + ExportEntry Start(&E, O, Trie); if (Trie.empty()) Start.moveToEnd(); else Start.moveToFirst(); - ExportEntry Finish(Trie); + ExportEntry Finish(&E, O, Trie); Finish.moveToEnd(); return make_range(export_iterator(Start), export_iterator(Finish)); } -iterator_range<export_iterator> MachOObjectFile::exports() const { - return exports(getDyldInfoExportsTrie()); +iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const { + return exports(Err, getDyldInfoExportsTrie(), this); } MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O, @@ -2831,11 +3005,11 @@ void MachORebaseEntry::moveNext() { case MachO::REBASE_OPCODE_SET_TYPE_IMM: RebaseType = ImmValue; if (RebaseType > MachO::REBASE_TYPE_TEXT_PCREL32) { - *E = malformedError("for REBASE_OPCODE_SET_TYPE_IMM bad bind type: " + - Twine((int)RebaseType) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; + *E = malformedError("for REBASE_OPCODE_SET_TYPE_IMM bad bind type: " + + Twine((int)RebaseType) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; } DEBUG_WITH_TYPE( "mach-o-rebase", @@ -2847,8 +3021,8 @@ void MachORebaseEntry::moveNext() { SegmentOffset = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -2856,8 +3030,8 @@ void MachORebaseEntry::moveNext() { true); if (error) { *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -2871,18 +3045,18 @@ void MachORebaseEntry::moveNext() { case MachO::REBASE_OPCODE_ADD_ADDR_ULEB: SegmentOffset += readULEB128(&error); if (error) { - *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) + + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { - *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) + + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -2896,8 +3070,8 @@ void MachORebaseEntry::moveNext() { true); if (error) { *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -2905,10 +3079,11 @@ void MachORebaseEntry::moveNext() { error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, false); if (error) { - *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " - " (after adding immediate times the pointer size) " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = + malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " + " (after adding immediate times the pointer size) " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -2922,8 +3097,8 @@ void MachORebaseEntry::moveNext() { true); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -2937,11 +3112,11 @@ void MachORebaseEntry::moveNext() { error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, SegmentIndex, SegmentOffset); if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " - + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); - return; + return; } DEBUG_WITH_TYPE( "mach-o-rebase", @@ -2956,8 +3131,8 @@ void MachORebaseEntry::moveNext() { true); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -2966,8 +3141,8 @@ void MachORebaseEntry::moveNext() { Count = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -2978,11 +3153,11 @@ void MachORebaseEntry::moveNext() { error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, SegmentIndex, SegmentOffset); if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " - + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); - return; + return; } DEBUG_WITH_TYPE( "mach-o-rebase", @@ -2997,16 +3172,16 @@ void MachORebaseEntry::moveNext() { true); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } Skip = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3016,11 +3191,11 @@ void MachORebaseEntry::moveNext() { error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, SegmentIndex, SegmentOffset); if (error) { - *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " - + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); - return; + return; } DEBUG_WITH_TYPE( "mach-o-rebase", @@ -3035,16 +3210,18 @@ void MachORebaseEntry::moveNext() { true); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" - "ULEB " + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "ULEB " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } Count = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" - "ULEB " + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "ULEB " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3055,8 +3232,9 @@ void MachORebaseEntry::moveNext() { Skip = readULEB128(&error); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" - "ULEB " + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "ULEB " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3066,10 +3244,11 @@ void MachORebaseEntry::moveNext() { SegmentIndex, SegmentOffset); if (error) { *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" - "ULEB " + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "ULEB " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); - return; + return; } DEBUG_WITH_TYPE( "mach-o-rebase", @@ -3081,8 +3260,8 @@ void MachORebaseEntry::moveNext() { return; default: *E = malformedError("bad rebase info (bad opcode value 0x" + - utohexstr(Opcode) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine::utohexstr(Opcode) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3224,8 +3403,8 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: if (TableKind == Kind::Weak) { *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM not allowed in " - "weak bind table for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "weak bind table for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3233,9 +3412,11 @@ void MachOBindEntry::moveNext() { LibraryOrdinalSet = true; if (ImmValue > O->getLibraryCount()) { *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad " - "library ordinal: " + Twine((int)ImmValue) + " (max " + - Twine((int)O->getLibraryCount()) + ") for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "library ordinal: " + + Twine((int)ImmValue) + " (max " + + Twine((int)O->getLibraryCount()) + + ") for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3247,8 +3428,8 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: if (TableKind == Kind::Weak) { *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB not allowed in " - "weak bind table for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "weak bind table for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3256,16 +3437,18 @@ void MachOBindEntry::moveNext() { LibraryOrdinalSet = true; if (error) { *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (Ordinal > (int)O->getLibraryCount()) { *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad " - "library ordinal: " + Twine((int)Ordinal) + " (max " + - Twine((int)O->getLibraryCount()) + ") for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "library ordinal: " + + Twine((int)Ordinal) + " (max " + + Twine((int)O->getLibraryCount()) + + ") for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3277,8 +3460,8 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: if (TableKind == Kind::Weak) { *E = malformedError("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM not allowed in " - "weak bind table for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "weak bind table for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3287,8 +3470,9 @@ void MachOBindEntry::moveNext() { Ordinal = SignExtended; if (Ordinal < MachO::BIND_SPECIAL_DYLIB_FLAT_LOOKUP) { *E = malformedError("for BIND_OPCODE_SET_DYLIB_SPECIAL_IMM unknown " - "special ordinal: " + Twine((int)Ordinal) + " for opcode at: " - "0x" + utohexstr(OpcodeStart - Opcodes.begin())); + "special ordinal: " + + Twine((int)Ordinal) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3307,11 +3491,12 @@ void MachOBindEntry::moveNext() { ++Ptr; } if (Ptr == Opcodes.end()) { - *E = malformedError("for BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM " - "symbol name extends past opcodes for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; + *E = malformedError( + "for BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM " + "symbol name extends past opcodes for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; } SymbolName = StringRef(reinterpret_cast<const char*>(SymStart), Ptr-SymStart); @@ -3328,11 +3513,11 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_SET_TYPE_IMM: BindType = ImmValue; if (ImmValue > MachO::BIND_TYPE_TEXT_PCREL32) { - *E = malformedError("for BIND_OPCODE_SET_TYPE_IMM bad bind type: " + - Twine((int)ImmValue) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); - moveToEnd(); - return; + *E = malformedError("for BIND_OPCODE_SET_TYPE_IMM bad bind type: " + + Twine((int)ImmValue) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; } DEBUG_WITH_TYPE( "mach-o-bind", @@ -3342,9 +3527,9 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_SET_ADDEND_SLEB: Addend = readSLEB128(&error); if (error) { - *E = malformedError("for BIND_OPCODE_SET_ADDEND_SLEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError("for BIND_OPCODE_SET_ADDEND_SLEB " + Twine(error) + + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3358,16 +3543,16 @@ void MachOBindEntry::moveNext() { SegmentOffset = readULEB128(&error); if (error) { *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3381,17 +3566,17 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_ADD_ADDR_ULEB: SegmentOffset += readULEB128(&error); if (error) { - *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) + + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { - *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) + + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3406,21 +3591,24 @@ void MachOBindEntry::moveNext() { error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND " + Twine(error) + - " for opcode at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (SymbolName == StringRef()) { - *E = malformedError("for BIND_OPCODE_DO_BIND missing preceding " - "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError( + "for BIND_OPCODE_DO_BIND missing preceding " + "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (!LibraryOrdinalSet && TableKind != Kind::Weak) { - *E = malformedError("for BIND_OPCODE_DO_BIND missing preceding " - "BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = + malformedError("for BIND_OPCODE_DO_BIND missing preceding " + "BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3432,38 +3620,41 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: if (TableKind == Kind::Lazy) { *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB not allowed in " - "lazy bind table for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "lazy bind table for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (SymbolName == StringRef()) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing " - "preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode " - "at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError( + "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing " + "preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for opcode " + "at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (!LibraryOrdinalSet && TableKind != Kind::Weak) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing " - "preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError( + "for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB missing " + "preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } AdvanceAmount = readULEB128(&error) + PointerSize; if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3474,8 +3665,9 @@ void MachOBindEntry::moveNext() { AdvanceAmount, false); if (error) { *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB (after adding " - "ULEB) " + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "ULEB) " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3491,30 +3683,34 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: if (TableKind == Kind::Lazy) { *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED not " - "allowed in lazy bind table for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "allowed in lazy bind table for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (SymbolName == StringRef()) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " - "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for " - "opcode at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError( + "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " + "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for " + "opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (!LibraryOrdinalSet && TableKind != Kind::Weak) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " - "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode " - "at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError( + "for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " + "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode " + "at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3523,10 +3719,11 @@ void MachOBindEntry::moveNext() { error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset + AdvanceAmount, false); if (error) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " - " (after adding immediate times the pointer size) " + - Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = + malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " + " (after adding immediate times the pointer size) " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3538,8 +3735,8 @@ void MachOBindEntry::moveNext() { case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: if (TableKind == Kind::Lazy) { *E = malformedError("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB not " - "allowed in lazy bind table for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + "allowed in lazy bind table for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3550,8 +3747,9 @@ void MachOBindEntry::moveNext() { RemainingLoopCount = 0; if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " - " (count value) " + Twine(error) + " for opcode at" - ": 0x" + utohexstr(OpcodeStart - Opcodes.begin())); + " (count value) " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -3559,41 +3757,48 @@ void MachOBindEntry::moveNext() { AdvanceAmount = Skip + PointerSize; if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " - " (skip value) " + Twine(error) + " for opcode at" - ": 0x" + utohexstr(OpcodeStart - Opcodes.begin())); + " (skip value) " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " - + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = + malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (SymbolName == StringRef()) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " - "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for " - "opcode at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError( + "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + "missing preceding BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM for " + "opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } if (!LibraryOrdinalSet && TableKind != Kind::Weak) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " - "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode " - "at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); + *E = malformedError( + "for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + "missing preceding BIND_OPCODE_SET_DYLIB_ORDINAL_* for opcode " + "at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } error = O->BindEntryCheckCountAndSkip(Count, Skip, PointerSize, SegmentIndex, SegmentOffset); if (error) { - *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " - + Twine(error) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + *E = + malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " + + Twine(error) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); - return; + return; } DEBUG_WITH_TYPE( "mach-o-bind", @@ -3605,8 +3810,8 @@ void MachOBindEntry::moveNext() { return; default: *E = malformedError("bad bind info (bad opcode value 0x" + - utohexstr(Opcode) + " for opcode at: 0x" + - utohexstr(OpcodeStart - Opcodes.begin())); + Twine::utohexstr(Opcode) + " for opcode at: 0x" + + Twine::utohexstr(OpcodeStart - Opcodes.begin())); moveToEnd(); return; } @@ -4115,7 +4320,10 @@ MachOObjectFile::getRelocation(DataRefImpl Rel) const { } } else { MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand(); - Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations + if (Rel.d.a == 0) + Offset = DysymtabLoadCmd.extreloff; // Offset to the external relocations + else + Offset = DysymtabLoadCmd.locreloff; // Offset to the local relocations } auto P = reinterpret_cast<const MachO::any_relocation_info *>( diff --git a/contrib/llvm/lib/Object/ModuleSymbolTable.cpp b/contrib/llvm/lib/Object/ModuleSymbolTable.cpp index f2e7a218c13a..64446525b916 100644 --- a/contrib/llvm/lib/Object/ModuleSymbolTable.cpp +++ b/contrib/llvm/lib/Object/ModuleSymbolTable.cpp @@ -175,7 +175,7 @@ void ModuleSymbolTable::CollectAsmSymbols( MCObjectFileInfo MOFI; MCContext MCCtx(MAI.get(), MRI.get(), &MOFI); - MOFI.InitMCObjectFileInfo(TT, /*PIC*/ false, CodeModel::Default, MCCtx); + MOFI.InitMCObjectFileInfo(TT, /*PIC*/ false, MCCtx); RecordStreamer Streamer(MCCtx); T->createNullTargetStreamer(Streamer); diff --git a/contrib/llvm/lib/Object/ObjectFile.cpp b/contrib/llvm/lib/Object/ObjectFile.cpp index 8377dd0d73fa..652a2b2497ef 100644 --- a/contrib/llvm/lib/Object/ObjectFile.cpp +++ b/contrib/llvm/lib/Object/ObjectFile.cpp @@ -75,10 +75,37 @@ bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; } +bool ObjectFile::isSectionStripped(DataRefImpl Sec) const { return false; } + section_iterator ObjectFile::getRelocatedSection(DataRefImpl Sec) const { return section_iterator(SectionRef(Sec, this)); } +Triple ObjectFile::makeTriple() const { + Triple TheTriple; + auto Arch = getArch(); + TheTriple.setArch(Triple::ArchType(Arch)); + + // For ARM targets, try to use the build attributes to build determine + // the build target. Target features are also added, but later during + // disassembly. + if (Arch == Triple::arm || Arch == Triple::armeb) + setARMSubArch(TheTriple); + + // TheTriple defaults to ELF, and COFF doesn't have an environment: + // the best we can do here is indicate that it is mach-o. + if (isMachO()) + TheTriple.setObjectFormat(Triple::MachO); + + if (isCOFF()) { + const auto COFFObj = dyn_cast<COFFObjectFile>(this); + if (COFFObj->getArch() == Triple::thumb) + TheTriple.setTriple("thumbv7-windows"); + } + + return TheTriple; +} + Expected<std::unique_ptr<ObjectFile>> ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) { StringRef Data = Object.getBuffer(); @@ -98,7 +125,7 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) { case file_magic::elf_executable: case file_magic::elf_shared_object: case file_magic::elf_core: - return errorOrToExpected(createELFObjectFile(Object)); + return createELFObjectFile(Object); case file_magic::macho_object: case file_magic::macho_executable: case file_magic::macho_fixed_virtual_memory_shared_lib: @@ -114,7 +141,7 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) { case file_magic::coff_object: case file_magic::coff_import_library: case file_magic::pecoff_executable: - return errorOrToExpected(createCOFFObjectFile(Object)); + return createCOFFObjectFile(Object); case file_magic::wasm_object: return createWasmObjectFile(Object); } diff --git a/contrib/llvm/lib/Object/SymbolicFile.cpp b/contrib/llvm/lib/Object/SymbolicFile.cpp index 1042d29d2350..2e7f2cc0d1d9 100644 --- a/contrib/llvm/lib/Object/SymbolicFile.cpp +++ b/contrib/llvm/lib/Object/SymbolicFile.cpp @@ -80,10 +80,12 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type, if (!Obj || !Context) return std::move(Obj); - ErrorOr<MemoryBufferRef> BCData = + Expected<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInObject(*Obj->get()); - if (!BCData) + if (!BCData) { + consumeError(BCData.takeError()); return std::move(Obj); + } return IRObjectFile::create( MemoryBufferRef(BCData->getBuffer(), Object.getBufferIdentifier()), diff --git a/contrib/llvm/lib/Object/WasmObjectFile.cpp b/contrib/llvm/lib/Object/WasmObjectFile.cpp index 7f80bf0b83a0..7a0c05ed8a15 100644 --- a/contrib/llvm/lib/Object/WasmObjectFile.cpp +++ b/contrib/llvm/lib/Object/WasmObjectFile.cpp @@ -178,14 +178,16 @@ static wasm::WasmTable readTable(const uint8_t *&Ptr) { } static Error readSection(WasmSection &Section, const uint8_t *&Ptr, - const uint8_t *Start) { - // TODO(sbc): Avoid reading past EOF in the case of malformed files. + const uint8_t *Start, const uint8_t *Eof) { Section.Offset = Ptr - Start; Section.Type = readVaruint7(Ptr); uint32_t Size = readVaruint32(Ptr); if (Size == 0) return make_error<StringError>("Zero length section", object_error::parse_failed); + if (Ptr + Size > Eof) + return make_error<StringError>("Section too large", + object_error::parse_failed); Section.Content = ArrayRef<uint8_t>(Ptr, Size); Ptr += Size; return Error::success(); @@ -193,7 +195,6 @@ static Error readSection(WasmSection &Section, const uint8_t *&Ptr, WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) : ObjectFile(Binary::ID_Wasm, Buffer) { - LinkingData.DataAlignment = 0; LinkingData.DataSize = 0; ErrorAsOutParameter ErrAsOutParam(&Err); @@ -203,7 +204,16 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) object_error::parse_failed); return; } + + const uint8_t *Eof = getPtr(getData().size()); const uint8_t *Ptr = getPtr(4); + + if (Ptr + 4 > Eof) { + Err = make_error<StringError>("Missing version number", + object_error::parse_failed); + return; + } + Header.Version = readUint32(Ptr); if (Header.Version != wasm::WasmVersion) { Err = make_error<StringError>("Bad version number", @@ -211,10 +221,9 @@ WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err) return; } - const uint8_t *Eof = getPtr(getData().size()); WasmSection Sec; while (Ptr < Eof) { - if ((Err = readSection(Sec, Ptr, getPtr(0)))) + if ((Err = readSection(Sec, Ptr, getPtr(0), Eof))) return; if ((Err = parseSection(Sec))) return; @@ -292,9 +301,61 @@ Error WasmObjectFile::parseNameSection(const uint8_t *Ptr, const uint8_t *End) { return Error::success(); } +void WasmObjectFile::populateSymbolTable() { + // Add imports to symbol table + size_t ImportIndex = 0; + size_t GlobalIndex = 0; + size_t FunctionIndex = 0; + for (const wasm::WasmImport& Import : Imports) { + switch (Import.Kind) { + case wasm::WASM_EXTERNAL_GLOBAL: + assert(Import.Global.Type == wasm::WASM_TYPE_I32); + SymbolMap.try_emplace(Import.Field, Symbols.size()); + Symbols.emplace_back(Import.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT, + ImportSection, GlobalIndex++, ImportIndex); + DEBUG(dbgs() << "Adding import: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); + break; + case wasm::WASM_EXTERNAL_FUNCTION: + SymbolMap.try_emplace(Import.Field, Symbols.size()); + Symbols.emplace_back(Import.Field, + WasmSymbol::SymbolType::FUNCTION_IMPORT, + ImportSection, FunctionIndex++, ImportIndex); + DEBUG(dbgs() << "Adding import: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); + break; + default: + break; + } + ImportIndex++; + } + + // Add exports to symbol table + for (const wasm::WasmExport& Export : Exports) { + if (Export.Kind == wasm::WASM_EXTERNAL_FUNCTION || + Export.Kind == wasm::WASM_EXTERNAL_GLOBAL) { + WasmSymbol::SymbolType ExportType = + Export.Kind == wasm::WASM_EXTERNAL_FUNCTION + ? WasmSymbol::SymbolType::FUNCTION_EXPORT + : WasmSymbol::SymbolType::GLOBAL_EXPORT; + SymbolMap.try_emplace(Export.Name, Symbols.size()); + Symbols.emplace_back(Export.Name, ExportType, + ExportSection, Export.Index); + DEBUG(dbgs() << "Adding export: " << Symbols.back() + << " sym index:" << Symbols.size() << "\n"); + } + } +} + Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, const uint8_t *End) { HasLinkingSection = true; + + // Only populate the symbol table with imports and exports if the object + // has a linking section (i.e. its a relocatable object file). Otherwise + // the global might not represent symbols at all. + populateSymbolTable(); + while (Ptr < End) { uint8_t Type = readVarint7(Ptr); uint32_t Size = readVaruint32(Ptr); @@ -317,7 +378,7 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, Symbols[SymIndex].Flags = Flags; DEBUG(dbgs() << "Set symbol flags index:" << SymIndex << " name:" - << Symbols[SymIndex].Name << " exptected:" + << Symbols[SymIndex].Name << " expected:" << Symbol << " flags: " << Flags << "\n"); } break; @@ -325,10 +386,33 @@ Error WasmObjectFile::parseLinkingSection(const uint8_t *Ptr, case wasm::WASM_DATA_SIZE: LinkingData.DataSize = readVaruint32(Ptr); break; - case wasm::WASM_DATA_ALIGNMENT: - LinkingData.DataAlignment = readVaruint32(Ptr); + case wasm::WASM_SEGMENT_INFO: { + uint32_t Count = readVaruint32(Ptr); + if (Count > DataSegments.size()) + return make_error<GenericBinaryError>("Too many segment names", + object_error::parse_failed); + for (uint32_t i = 0; i < Count; i++) { + DataSegments[i].Data.Name = readString(Ptr); + DataSegments[i].Data.Alignment = readVaruint32(Ptr); + DataSegments[i].Data.Flags = readVaruint32(Ptr); + } + break; + } + case wasm::WASM_INIT_FUNCS: { + uint32_t Count = readVaruint32(Ptr); + LinkingData.InitFunctions.reserve(Count); + for (uint32_t i = 0; i < Count; i++) { + wasm::WasmInitFunc Init; + Init.Priority = readVaruint32(Ptr); + Init.FunctionIndex = readVaruint32(Ptr); + if (!isValidFunctionIndex(Init.FunctionIndex)) + return make_error<GenericBinaryError>("Invalid function index: " + + Twine(Init.FunctionIndex), + object_error::parse_failed); + LinkingData.InitFunctions.emplace_back(Init); + } break; - case wasm::WASM_STACK_POINTER: + } default: Ptr += Size; break; @@ -387,9 +471,9 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, const uint8_t *Ptr, case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB: case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB: break; - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: - case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB: + case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32: Reloc.Addend = readVarint32(Ptr); break; default: @@ -455,6 +539,7 @@ Error WasmObjectFile::parseTypeSection(const uint8_t *Ptr, const uint8_t *End) { } Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) { + ImportSection = Sections.size(); uint32_t Count = readVaruint32(Ptr); Imports.reserve(Count); for (uint32_t i = 0; i < Count; i++) { @@ -464,31 +549,22 @@ Error WasmObjectFile::parseImportSection(const uint8_t *Ptr, const uint8_t *End) Im.Kind = readUint8(Ptr); switch (Im.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: + NumImportedFunctions++; Im.SigIndex = readVaruint32(Ptr); - SymbolMap.try_emplace(Im.Field, Symbols.size()); - Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::FUNCTION_IMPORT, - Sections.size(), i); - DEBUG(dbgs() << "Adding import: " << Symbols.back() - << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_GLOBAL: + NumImportedGlobals++; Im.Global.Type = readVarint7(Ptr); Im.Global.Mutable = readVaruint1(Ptr); - SymbolMap.try_emplace(Im.Field, Symbols.size()); - Symbols.emplace_back(Im.Field, WasmSymbol::SymbolType::GLOBAL_IMPORT, - Sections.size(), i); - DEBUG(dbgs() << "Adding import: " << Symbols.back() - << " sym index:" << Symbols.size() << "\n"); break; case wasm::WASM_EXTERNAL_MEMORY: Im.Memory = readLimits(Ptr); break; case wasm::WASM_EXTERNAL_TABLE: Im.Table = readTable(Ptr); - if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC) { + if (Im.Table.ElemType != wasm::WASM_TYPE_ANYFUNC) return make_error<GenericBinaryError>("Invalid table element type", object_error::parse_failed); - } break; default: return make_error<GenericBinaryError>( @@ -560,6 +636,7 @@ Error WasmObjectFile::parseGlobalSection(const uint8_t *Ptr, const uint8_t *End) } Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) { + ExportSection = Sections.size(); uint32_t Count = readVaruint32(Ptr); Exports.reserve(Count); for (uint32_t i = 0; i < Count; i++) { @@ -567,17 +644,18 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) Ex.Name = readString(Ptr); Ex.Kind = readUint8(Ptr); Ex.Index = readVaruint32(Ptr); - WasmSymbol::SymbolType ExportType; - bool MakeSymbol = false; switch (Ex.Kind) { case wasm::WASM_EXTERNAL_FUNCTION: - ExportType = WasmSymbol::SymbolType::FUNCTION_EXPORT; - MakeSymbol = true; + if (Ex.Index >= FunctionTypes.size() + NumImportedFunctions) + return make_error<GenericBinaryError>("Invalid function export", + object_error::parse_failed); break; - case wasm::WASM_EXTERNAL_GLOBAL: - ExportType = WasmSymbol::SymbolType::GLOBAL_EXPORT; - MakeSymbol = true; + case wasm::WASM_EXTERNAL_GLOBAL: { + if (Ex.Index >= Globals.size() + NumImportedGlobals) + return make_error<GenericBinaryError>("Invalid global export", + object_error::parse_failed); break; + } case wasm::WASM_EXTERNAL_MEMORY: case wasm::WASM_EXTERNAL_TABLE: break; @@ -585,20 +663,6 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) return make_error<GenericBinaryError>( "Unexpected export kind", object_error::parse_failed); } - if (MakeSymbol) { - auto Pair = SymbolMap.try_emplace(Ex.Name, Symbols.size()); - if (Pair.second) { - Symbols.emplace_back(Ex.Name, ExportType, - Sections.size(), i); - DEBUG(dbgs() << "Adding export: " << Symbols.back() - << " sym index:" << Symbols.size() << "\n"); - } else { - uint32_t SymIndex = Pair.first->second; - Symbols[SymIndex] = WasmSymbol(Ex.Name, ExportType, Sections.size(), i); - DEBUG(dbgs() << "Replacing existing symbol: " << Symbols[SymIndex] - << " sym index:" << SymIndex << "\n"); - } - } Exports.push_back(Ex); } if (Ptr != End) @@ -607,27 +671,34 @@ Error WasmObjectFile::parseExportSection(const uint8_t *Ptr, const uint8_t *End) return Error::success(); } +bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const { + return Index < FunctionTypes.size() + NumImportedFunctions; +} + Error WasmObjectFile::parseStartSection(const uint8_t *Ptr, const uint8_t *End) { StartFunction = readVaruint32(Ptr); - if (StartFunction >= FunctionTypes.size()) + if (!isValidFunctionIndex(StartFunction)) return make_error<GenericBinaryError>("Invalid start function", object_error::parse_failed); return Error::success(); } Error WasmObjectFile::parseCodeSection(const uint8_t *Ptr, const uint8_t *End) { + const uint8_t *CodeSectionStart = Ptr; uint32_t FunctionCount = readVaruint32(Ptr); if (FunctionCount != FunctionTypes.size()) { return make_error<GenericBinaryError>("Invalid function count", object_error::parse_failed); } - CodeSection = ArrayRef<uint8_t>(Ptr, End - Ptr); - while (FunctionCount--) { wasm::WasmFunction Function; - uint32_t FunctionSize = readVaruint32(Ptr); - const uint8_t *FunctionEnd = Ptr + FunctionSize; + const uint8_t *FunctionStart = Ptr; + uint32_t Size = readVaruint32(Ptr); + const uint8_t *FunctionEnd = Ptr + Size; + + Function.CodeSectionOffset = FunctionStart - CodeSectionStart; + Function.Size = FunctionEnd - FunctionStart; uint32_t NumLocalDecls = readVaruint32(Ptr); Function.Locals.reserve(NumLocalDecls); @@ -685,6 +756,8 @@ Error WasmObjectFile::parseDataSection(const uint8_t *Ptr, const uint8_t *End) { return Err; uint32_t Size = readVaruint32(Ptr); Segment.Data.Content = ArrayRef<uint8_t>(Ptr, Size); + Segment.Data.Alignment = 0; + Segment.Data.Flags = 0; Segment.SectionOffset = Ptr - Start; Ptr += Size; DataSegments.push_back(Segment); @@ -710,15 +783,19 @@ uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { const WasmSymbol &Sym = getWasmSymbol(Symb); DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n"); - if (Sym.Flags & wasm::WASM_SYMBOL_FLAG_WEAK) + if (Sym.isWeak()) Result |= SymbolRef::SF_Weak; + if (!Sym.isLocal()) + Result |= SymbolRef::SF_Global; + if (Sym.isHidden()) + Result |= SymbolRef::SF_Hidden; switch (Sym.Type) { case WasmSymbol::SymbolType::FUNCTION_IMPORT: Result |= SymbolRef::SF_Undefined | SymbolRef::SF_Executable; break; case WasmSymbol::SymbolType::FUNCTION_EXPORT: - Result |= SymbolRef::SF_Global | SymbolRef::SF_Executable; + Result |= SymbolRef::SF_Executable; break; case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: Result |= SymbolRef::SF_Executable; @@ -728,7 +805,6 @@ uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const { Result |= SymbolRef::SF_Undefined; break; case WasmSymbol::SymbolType::GLOBAL_EXPORT: - Result |= SymbolRef::SF_Global; break; } @@ -763,21 +839,29 @@ Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { return getSymbolValue(Symb); } -uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { - const WasmSymbol& Sym = getWasmSymbol(Symb); +uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol& Sym) const { switch (Sym.Type) { case WasmSymbol::SymbolType::FUNCTION_IMPORT: case WasmSymbol::SymbolType::GLOBAL_IMPORT: - return 0; case WasmSymbol::SymbolType::FUNCTION_EXPORT: - case WasmSymbol::SymbolType::GLOBAL_EXPORT: - return Exports[Sym.ElementIndex].Index; case WasmSymbol::SymbolType::DEBUG_FUNCTION_NAME: return Sym.ElementIndex; + case WasmSymbol::SymbolType::GLOBAL_EXPORT: { + uint32_t GlobalIndex = Sym.ElementIndex - NumImportedGlobals; + assert(GlobalIndex < Globals.size()); + const wasm::WasmGlobal& Global = Globals[GlobalIndex]; + // WasmSymbols correspond only to I32_CONST globals + assert(Global.InitExpr.Opcode == wasm::WASM_OPCODE_I32_CONST); + return Global.InitExpr.Value.Int32; + } } llvm_unreachable("invalid symbol type"); } +uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + return getWasmSymbolValue(getWasmSymbol(Symb)); +} + uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const { llvm_unreachable("not yet implemented"); return 0; @@ -957,7 +1041,7 @@ uint8_t WasmObjectFile::getBytesInAddress() const { return 4; } StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; } -unsigned WasmObjectFile::getArch() const { return Triple::wasm32; } +Triple::ArchType WasmObjectFile::getArch() const { return Triple::wasm32; } SubtargetFeatures WasmObjectFile::getFeatures() const { return SubtargetFeatures(); diff --git a/contrib/llvm/lib/Object/WindowsResource.cpp b/contrib/llvm/lib/Object/WindowsResource.cpp index 246eee5ddb31..9ca584a4a1ae 100644 --- a/contrib/llvm/lib/Object/WindowsResource.cpp +++ b/contrib/llvm/lib/Object/WindowsResource.cpp @@ -17,7 +17,6 @@ #include "llvm/Support/MathExtras.h" #include <ctime> #include <queue> -#include <sstream> #include <system_error> using namespace llvm; @@ -57,19 +56,22 @@ WindowsResource::createWindowsResource(MemoryBufferRef Source) { } Expected<ResourceEntryRef> WindowsResource::getHeadEntry() { - Error Err = Error::success(); - auto Ref = ResourceEntryRef(BinaryStreamRef(BBS), this, Err); - if (Err) - return std::move(Err); - return Ref; + if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix)) + return make_error<EmptyResError>(".res contains no entries", + object_error::unexpected_eof); + return ResourceEntryRef::create(BinaryStreamRef(BBS), this); } ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref, - const WindowsResource *Owner, Error &Err) - : Reader(Ref), OwningRes(Owner) { - if (loadNext()) - Err = make_error<GenericBinaryError>("Could not read first entry.\n", - object_error::unexpected_eof); + const WindowsResource *Owner) + : Reader(Ref) {} + +Expected<ResourceEntryRef> +ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) { + auto Ref = ResourceEntryRef(BSR, Owner); + if (auto E = Ref.loadNext()) + return std::move(E); + return Ref; } Error ResourceEntryRef::moveNext(bool &End) { @@ -127,8 +129,20 @@ WindowsResourceParser::WindowsResourceParser() : Root(false) {} Error WindowsResourceParser::parse(WindowsResource *WR) { auto EntryOrErr = WR->getHeadEntry(); - if (!EntryOrErr) - return EntryOrErr.takeError(); + if (!EntryOrErr) { + auto E = EntryOrErr.takeError(); + if (E.isA<EmptyResError>()) { + // Check if the .res file contains no entries. In this case we don't have + // to throw an error but can rather just return without parsing anything. + // This applies for files which have a valid PE header magic and the + // mandatory empty null resource entry. Files which do not fit this + // criteria would have already been filtered out by + // WindowsResource::createWindowsResource(). + consumeError(std::move(E)); + return Error::success(); + } + return E; + } ResourceEntryRef Entry = EntryOrErr.get(); bool End = false; @@ -426,19 +440,7 @@ std::unique_ptr<MemoryBuffer> WindowsResourceCOFFWriter::write() { void WindowsResourceCOFFWriter::writeCOFFHeader() { // Write the COFF header. auto *Header = reinterpret_cast<coff_file_header *>(BufferStart); - switch (MachineType) { - case COFF::IMAGE_FILE_MACHINE_ARMNT: - Header->Machine = COFF::IMAGE_FILE_MACHINE_ARMNT; - break; - case COFF::IMAGE_FILE_MACHINE_AMD64: - Header->Machine = COFF::IMAGE_FILE_MACHINE_AMD64; - break; - case COFF::IMAGE_FILE_MACHINE_I386: - Header->Machine = COFF::IMAGE_FILE_MACHINE_I386; - break; - default: - Header->Machine = COFF::IMAGE_FILE_MACHINE_UNKNOWN; - } + Header->Machine = MachineType; Header->NumberOfSections = 2; Header->TimeDateStamp = getTime(); Header->PointerToSymbolTable = SymbolTableOffset; @@ -699,8 +701,11 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { case COFF::IMAGE_FILE_MACHINE_I386: Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB; break; + case COFF::IMAGE_FILE_MACHINE_ARM64: + Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB; + break; default: - Reloc->Type = 0; + llvm_unreachable("unknown machine type"); } CurrentOffset += sizeof(coff_relocation); } |