aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/lib/Object
diff options
context:
space:
mode:
authororivej <orivej@yandex-team.ru>2022-02-10 16:45:01 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:45:01 +0300
commit2d37894b1b037cf24231090eda8589bbb44fb6fc (patch)
treebe835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/lib/Object
parent718c552901d703c502ccbefdfc3c9028d608b947 (diff)
downloadydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Object')
-rw-r--r--contrib/libs/llvm12/lib/Object/Archive.cpp1978
-rw-r--r--contrib/libs/llvm12/lib/Object/ArchiveWriter.cpp1186
-rw-r--r--contrib/libs/llvm12/lib/Object/Binary.cpp214
-rw-r--r--contrib/libs/llvm12/lib/Object/COFFImportFile.cpp1250
-rw-r--r--contrib/libs/llvm12/lib/Object/COFFModuleDefinition.cpp736
-rw-r--r--contrib/libs/llvm12/lib/Object/COFFObjectFile.cpp3654
-rw-r--r--contrib/libs/llvm12/lib/Object/Decompressor.cpp196
-rw-r--r--contrib/libs/llvm12/lib/Object/ELF.cpp1168
-rw-r--r--contrib/libs/llvm12/lib/Object/ELFObjectFile.cpp996
-rw-r--r--contrib/libs/llvm12/lib/Object/Error.cpp188
-rw-r--r--contrib/libs/llvm12/lib/Object/IRObjectFile.cpp312
-rw-r--r--contrib/libs/llvm12/lib/Object/IRSymtab.cpp826
-rw-r--r--contrib/libs/llvm12/lib/Object/MachOObjectFile.cpp9280
-rw-r--r--contrib/libs/llvm12/lib/Object/MachOUniversal.cpp486
-rw-r--r--contrib/libs/llvm12/lib/Object/Minidump.cpp310
-rw-r--r--contrib/libs/llvm12/lib/Object/ModuleSymbolTable.cpp454
-rw-r--r--contrib/libs/llvm12/lib/Object/Object.cpp712
-rw-r--r--contrib/libs/llvm12/lib/Object/ObjectFile.cpp394
-rw-r--r--contrib/libs/llvm12/lib/Object/RecordStreamer.cpp464
-rw-r--r--contrib/libs/llvm12/lib/Object/RecordStreamer.h170
-rw-r--r--contrib/libs/llvm12/lib/Object/RelocationResolver.cpp1164
-rw-r--r--contrib/libs/llvm12/lib/Object/SymbolSize.cpp210
-rw-r--r--contrib/libs/llvm12/lib/Object/SymbolicFile.cpp168
-rw-r--r--contrib/libs/llvm12/lib/Object/TapiFile.cpp204
-rw-r--r--contrib/libs/llvm12/lib/Object/TapiUniversal.cpp122
-rw-r--r--contrib/libs/llvm12/lib/Object/WasmObjectFile.cpp3264
-rw-r--r--contrib/libs/llvm12/lib/Object/WindowsMachineFlag.cpp88
-rw-r--r--contrib/libs/llvm12/lib/Object/WindowsResource.cpp2030
-rw-r--r--contrib/libs/llvm12/lib/Object/XCOFFObjectFile.cpp1670
-rw-r--r--contrib/libs/llvm12/lib/Object/ya.make90
30 files changed, 16992 insertions, 16992 deletions
diff --git a/contrib/libs/llvm12/lib/Object/Archive.cpp b/contrib/libs/llvm12/lib/Object/Archive.cpp
index 9023ac55ec..11c9de4455 100644
--- a/contrib/libs/llvm12/lib/Object/Archive.cpp
+++ b/contrib/libs/llvm12/lib/Object/Archive.cpp
@@ -1,991 +1,991 @@
-//===- Archive.cpp - ar File Format implementation ------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the ArchiveObjectFile class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/Archive.h"
-#include "llvm/ADT/Optional.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Support/Chrono.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <memory>
-#include <string>
-#include <system_error>
-
-using namespace llvm;
-using namespace object;
-using namespace llvm::support::endian;
-
+//===- Archive.cpp - ar File Format implementation ------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the ArchiveObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Archive.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+using namespace llvm::support::endian;
+
const char Magic[] = "!<arch>\n";
const char ThinMagic[] = "!<thin>\n";
-
-void Archive::anchor() {}
-
-static Error
-malformedError(Twine Msg) {
- std::string StringMsg = "truncated or malformed archive (" + Msg.str() + ")";
- return make_error<GenericBinaryError>(std::move(StringMsg),
- object_error::parse_failed);
-}
-
-ArchiveMemberHeader::ArchiveMemberHeader(const Archive *Parent,
- const char *RawHeaderPtr,
- uint64_t Size, Error *Err)
- : Parent(Parent),
- ArMemHdr(reinterpret_cast<const ArMemHdrType *>(RawHeaderPtr)) {
- if (RawHeaderPtr == nullptr)
- return;
- ErrorAsOutParameter ErrAsOutParam(Err);
-
- if (Size < sizeof(ArMemHdrType)) {
- if (Err) {
- std::string Msg("remaining size of archive too small for next archive "
- "member header ");
- Expected<StringRef> NameOrErr = getName(Size);
- if (!NameOrErr) {
- consumeError(NameOrErr.takeError());
- uint64_t Offset = RawHeaderPtr - Parent->getData().data();
- *Err = malformedError(Msg + "at offset " + Twine(Offset));
- } else
- *Err = malformedError(Msg + "for " + NameOrErr.get());
- }
- return;
- }
- if (ArMemHdr->Terminator[0] != '`' || ArMemHdr->Terminator[1] != '\n') {
- if (Err) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(StringRef(ArMemHdr->Terminator,
- sizeof(ArMemHdr->Terminator)));
- OS.flush();
- std::string Msg("terminator characters in archive member \"" + Buf +
- "\" not the correct \"`\\n\" values for the archive "
- "member header ");
- Expected<StringRef> NameOrErr = getName(Size);
- if (!NameOrErr) {
- consumeError(NameOrErr.takeError());
- uint64_t Offset = RawHeaderPtr - Parent->getData().data();
- *Err = malformedError(Msg + "at offset " + Twine(Offset));
- } else
- *Err = malformedError(Msg + "for " + NameOrErr.get());
- }
- return;
- }
-}
-
-// This gets the raw name from the ArMemHdr->Name field and checks that it is
-// valid for the kind of archive. If it is not valid it returns an Error.
-Expected<StringRef> ArchiveMemberHeader::getRawName() const {
- char EndCond;
- auto Kind = Parent->kind();
- if (Kind == Archive::K_BSD || Kind == Archive::K_DARWIN64) {
- if (ArMemHdr->Name[0] == ' ') {
- uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("name contains a leading space for archive member "
- "header at offset " + Twine(Offset));
- }
- EndCond = ' ';
- }
- else if (ArMemHdr->Name[0] == '/' || ArMemHdr->Name[0] == '#')
- EndCond = ' ';
- else
- EndCond = '/';
- StringRef::size_type end =
- StringRef(ArMemHdr->Name, sizeof(ArMemHdr->Name)).find(EndCond);
- if (end == StringRef::npos)
- end = sizeof(ArMemHdr->Name);
- assert(end <= sizeof(ArMemHdr->Name) && end > 0);
- // Don't include the EndCond if there is one.
- return StringRef(ArMemHdr->Name, end);
-}
-
-// This gets the name looking up long names. Size is the size of the archive
-// member including the header, so the size of any name following the header
-// is checked to make sure it does not overflow.
-Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const {
-
- // This can be called from the ArchiveMemberHeader constructor when the
- // archive header is truncated to produce an error message with the name.
- // Make sure the name field is not truncated.
- if (Size < offsetof(ArMemHdrType, Name) + sizeof(ArMemHdr->Name)) {
- uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("archive header truncated before the name field "
- "for archive member header at offset " +
- Twine(ArchiveOffset));
- }
-
- // The raw name itself can be invalid.
- Expected<StringRef> NameOrErr = getRawName();
- if (!NameOrErr)
- return NameOrErr.takeError();
- StringRef Name = NameOrErr.get();
-
- // Check if it's a special name.
- if (Name[0] == '/') {
- if (Name.size() == 1) // Linker member.
- return Name;
- if (Name.size() == 2 && Name[1] == '/') // String table.
- return Name;
- // It's a long name.
- // Get the string table offset.
- std::size_t StringOffset;
- if (Name.substr(1).rtrim(' ').getAsInteger(10, StringOffset)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(Name.substr(1).rtrim(' '));
- OS.flush();
- uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("long name offset characters after the '/' are "
- "not all decimal numbers: '" + Buf + "' for "
- "archive member header at offset " +
- Twine(ArchiveOffset));
- }
-
- // Verify it.
- if (StringOffset >= Parent->getStringTable().size()) {
- uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("long name offset " + Twine(StringOffset) + " past "
- "the end of the string table for archive member "
- "header at offset " + Twine(ArchiveOffset));
- }
-
- // GNU long file names end with a "/\n".
- if (Parent->kind() == Archive::K_GNU ||
- Parent->kind() == Archive::K_GNU64) {
- size_t End = Parent->getStringTable().find('\n', /*From=*/StringOffset);
- if (End == StringRef::npos || End < 1 ||
- Parent->getStringTable()[End - 1] != '/') {
- return malformedError("string table at long name offset " +
- Twine(StringOffset) + "not terminated");
- }
- return Parent->getStringTable().slice(StringOffset, End - 1);
- }
- return Parent->getStringTable().begin() + StringOffset;
- }
-
- if (Name.startswith("#1/")) {
- uint64_t NameLength;
- if (Name.substr(3).rtrim(' ').getAsInteger(10, NameLength)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(Name.substr(3).rtrim(' '));
- OS.flush();
- uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("long name length characters after the #1/ are "
- "not all decimal numbers: '" + Buf + "' for "
- "archive member header at offset " +
- Twine(ArchiveOffset));
- }
- if (getSizeOf() + NameLength > Size) {
- uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("long name length: " + Twine(NameLength) +
- " extends past the end of the member or archive "
- "for archive member header at offset " +
- Twine(ArchiveOffset));
- }
- return StringRef(reinterpret_cast<const char *>(ArMemHdr) + getSizeOf(),
- NameLength).rtrim('\0');
- }
-
- // It is not a long name so trim the blanks at the end of the name.
- if (Name[Name.size() - 1] != '/')
- return Name.rtrim(' ');
-
- // It's a simple name.
- return Name.drop_back(1);
-}
-
-Expected<uint64_t> ArchiveMemberHeader::getSize() const {
- uint64_t Ret;
- if (StringRef(ArMemHdr->Size,
- sizeof(ArMemHdr->Size)).rtrim(" ").getAsInteger(10, Ret)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(StringRef(ArMemHdr->Size,
- sizeof(ArMemHdr->Size)).rtrim(" "));
- OS.flush();
- uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("characters in size field in archive header are not "
- "all decimal numbers: '" + Buf + "' for archive "
- "member header at offset " + Twine(Offset));
- }
- return Ret;
-}
-
-Expected<sys::fs::perms> ArchiveMemberHeader::getAccessMode() const {
- unsigned Ret;
- if (StringRef(ArMemHdr->AccessMode,
- sizeof(ArMemHdr->AccessMode)).rtrim(' ').getAsInteger(8, Ret)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(StringRef(ArMemHdr->AccessMode,
- sizeof(ArMemHdr->AccessMode)).rtrim(" "));
- OS.flush();
- uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("characters in AccessMode field in archive header "
- "are not all decimal numbers: '" + Buf + "' for the "
- "archive member header at offset " + Twine(Offset));
- }
- return static_cast<sys::fs::perms>(Ret);
-}
-
-Expected<sys::TimePoint<std::chrono::seconds>>
-ArchiveMemberHeader::getLastModified() const {
- unsigned Seconds;
- if (StringRef(ArMemHdr->LastModified,
- sizeof(ArMemHdr->LastModified)).rtrim(' ')
- .getAsInteger(10, Seconds)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(StringRef(ArMemHdr->LastModified,
- sizeof(ArMemHdr->LastModified)).rtrim(" "));
- OS.flush();
- uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("characters in LastModified field in archive header "
- "are not all decimal numbers: '" + Buf + "' for the "
- "archive member header at offset " + Twine(Offset));
- }
-
- return sys::toTimePoint(Seconds);
-}
-
-Expected<unsigned> ArchiveMemberHeader::getUID() const {
- unsigned Ret;
- StringRef User = StringRef(ArMemHdr->UID, sizeof(ArMemHdr->UID)).rtrim(' ');
- if (User.empty())
- return 0;
- if (User.getAsInteger(10, Ret)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(User);
- OS.flush();
- uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("characters in UID field in archive header "
- "are not all decimal numbers: '" + Buf + "' for the "
- "archive member header at offset " + Twine(Offset));
- }
- return Ret;
-}
-
-Expected<unsigned> ArchiveMemberHeader::getGID() const {
- unsigned Ret;
- StringRef Group = StringRef(ArMemHdr->GID, sizeof(ArMemHdr->GID)).rtrim(' ');
- if (Group.empty())
- return 0;
- if (Group.getAsInteger(10, Ret)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(Group);
- OS.flush();
- uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
- Parent->getData().data();
- return malformedError("characters in GID field in archive header "
- "are not all decimal numbers: '" + Buf + "' for the "
- "archive member header at offset " + Twine(Offset));
- }
- return Ret;
-}
-
-Archive::Child::Child(const Archive *Parent, StringRef Data,
- uint16_t StartOfFile)
- : Parent(Parent), Header(Parent, Data.data(), Data.size(), nullptr),
- Data(Data), StartOfFile(StartOfFile) {
-}
-
-Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err)
- : Parent(Parent),
- Header(Parent, Start,
- Parent
- ? Parent->getData().size() - (Start - Parent->getData().data())
- : 0, Err) {
- if (!Start)
- return;
-
- // If we are pointed to real data, Start is not a nullptr, then there must be
- // a non-null Err pointer available to report malformed data on. Only in
- // the case sentinel value is being constructed is Err is permitted to be a
- // nullptr.
- assert(Err && "Err can't be nullptr if Start is not a nullptr");
-
- ErrorAsOutParameter ErrAsOutParam(Err);
-
- // If there was an error in the construction of the Header
- // then just return with the error now set.
- if (*Err)
- return;
-
- uint64_t Size = Header.getSizeOf();
- Data = StringRef(Start, Size);
- Expected<bool> isThinOrErr = isThinMember();
- if (!isThinOrErr) {
- *Err = isThinOrErr.takeError();
- return;
- }
- bool isThin = isThinOrErr.get();
- if (!isThin) {
- Expected<uint64_t> MemberSize = getRawSize();
- if (!MemberSize) {
- *Err = MemberSize.takeError();
- return;
- }
- Size += MemberSize.get();
- Data = StringRef(Start, Size);
- }
-
- // Setup StartOfFile and PaddingBytes.
- StartOfFile = Header.getSizeOf();
- // Don't include attached name.
- Expected<StringRef> NameOrErr = getRawName();
- if (!NameOrErr){
- *Err = NameOrErr.takeError();
- return;
- }
- StringRef Name = NameOrErr.get();
- if (Name.startswith("#1/")) {
- uint64_t NameSize;
- if (Name.substr(3).rtrim(' ').getAsInteger(10, NameSize)) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- OS.write_escaped(Name.substr(3).rtrim(' '));
- OS.flush();
- uint64_t Offset = Start - Parent->getData().data();
- *Err = malformedError("long name length characters after the #1/ are "
- "not all decimal numbers: '" + Buf + "' for "
- "archive member header at offset " +
- Twine(Offset));
- return;
- }
- StartOfFile += NameSize;
- }
-}
-
-Expected<uint64_t> Archive::Child::getSize() const {
- if (Parent->IsThin)
- return Header.getSize();
- return Data.size() - StartOfFile;
-}
-
-Expected<uint64_t> Archive::Child::getRawSize() const {
- return Header.getSize();
-}
-
-Expected<bool> Archive::Child::isThinMember() const {
- Expected<StringRef> NameOrErr = Header.getRawName();
- if (!NameOrErr)
- return NameOrErr.takeError();
- StringRef Name = NameOrErr.get();
- return Parent->IsThin && Name != "/" && Name != "//";
-}
-
-Expected<std::string> Archive::Child::getFullName() const {
- Expected<bool> isThin = isThinMember();
- if (!isThin)
- return isThin.takeError();
- assert(isThin.get());
- Expected<StringRef> NameOrErr = getName();
- if (!NameOrErr)
- return NameOrErr.takeError();
- StringRef Name = *NameOrErr;
- if (sys::path::is_absolute(Name))
- return std::string(Name);
-
- SmallString<128> FullName = sys::path::parent_path(
- Parent->getMemoryBufferRef().getBufferIdentifier());
- sys::path::append(FullName, Name);
- return std::string(FullName.str());
-}
-
-Expected<StringRef> Archive::Child::getBuffer() const {
- Expected<bool> isThinOrErr = isThinMember();
- if (!isThinOrErr)
- return isThinOrErr.takeError();
- bool isThin = isThinOrErr.get();
- if (!isThin) {
- Expected<uint64_t> Size = getSize();
- if (!Size)
- return Size.takeError();
- return StringRef(Data.data() + StartOfFile, Size.get());
- }
- Expected<std::string> FullNameOrErr = getFullName();
- if (!FullNameOrErr)
- return FullNameOrErr.takeError();
- const std::string &FullName = *FullNameOrErr;
- ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(FullName);
- if (std::error_code EC = Buf.getError())
- return errorCodeToError(EC);
- Parent->ThinBuffers.push_back(std::move(*Buf));
- return Parent->ThinBuffers.back()->getBuffer();
-}
-
-Expected<Archive::Child> Archive::Child::getNext() const {
- size_t SpaceToSkip = Data.size();
- // If it's odd, add 1 to make it even.
- if (SpaceToSkip & 1)
- ++SpaceToSkip;
-
- const char *NextLoc = Data.data() + SpaceToSkip;
-
- // Check to see if this is at the end of the archive.
- if (NextLoc == Parent->Data.getBufferEnd())
- return Child(nullptr, nullptr, nullptr);
-
- // Check to see if this is past the end of the archive.
- if (NextLoc > Parent->Data.getBufferEnd()) {
- std::string Msg("offset to next archive member past the end of the archive "
- "after member ");
- Expected<StringRef> NameOrErr = getName();
- if (!NameOrErr) {
- consumeError(NameOrErr.takeError());
- uint64_t Offset = Data.data() - Parent->getData().data();
- return malformedError(Msg + "at offset " + Twine(Offset));
- } else
- return malformedError(Msg + NameOrErr.get());
- }
-
- Error Err = Error::success();
- Child Ret(Parent, NextLoc, &Err);
- if (Err)
- return std::move(Err);
- return Ret;
-}
-
-uint64_t Archive::Child::getChildOffset() const {
- const char *a = Parent->Data.getBuffer().data();
- const char *c = Data.data();
- uint64_t offset = c - a;
- return offset;
-}
-
-Expected<StringRef> Archive::Child::getName() const {
- Expected<uint64_t> RawSizeOrErr = getRawSize();
- if (!RawSizeOrErr)
- return RawSizeOrErr.takeError();
- uint64_t RawSize = RawSizeOrErr.get();
- Expected<StringRef> NameOrErr = Header.getName(Header.getSizeOf() + RawSize);
- if (!NameOrErr)
- return NameOrErr.takeError();
- StringRef Name = NameOrErr.get();
- return Name;
-}
-
-Expected<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const {
- Expected<StringRef> NameOrErr = getName();
- if (!NameOrErr)
- return NameOrErr.takeError();
- StringRef Name = NameOrErr.get();
- Expected<StringRef> Buf = getBuffer();
- if (!Buf)
- return createFileError(Name, Buf.takeError());
- return MemoryBufferRef(*Buf, Name);
-}
-
-Expected<std::unique_ptr<Binary>>
-Archive::Child::getAsBinary(LLVMContext *Context) const {
- Expected<MemoryBufferRef> BuffOrErr = getMemoryBufferRef();
- if (!BuffOrErr)
- return BuffOrErr.takeError();
-
- auto BinaryOrErr = createBinary(BuffOrErr.get(), Context);
- if (BinaryOrErr)
- return std::move(*BinaryOrErr);
- return BinaryOrErr.takeError();
-}
-
-Expected<std::unique_ptr<Archive>> Archive::create(MemoryBufferRef Source) {
- Error Err = Error::success();
- std::unique_ptr<Archive> Ret(new Archive(Source, Err));
- if (Err)
- return std::move(Err);
- return std::move(Ret);
-}
-
-void Archive::setFirstRegular(const Child &C) {
- FirstRegularData = C.Data;
- FirstRegularStartOfFile = C.StartOfFile;
-}
-
-Archive::Archive(MemoryBufferRef Source, Error &Err)
- : Binary(Binary::ID_Archive, Source) {
- ErrorAsOutParameter ErrAsOutParam(&Err);
- StringRef Buffer = Data.getBuffer();
- // Check for sufficient magic.
- if (Buffer.startswith(ThinMagic)) {
- IsThin = true;
- } else if (Buffer.startswith(Magic)) {
- IsThin = false;
- } else {
- Err = make_error<GenericBinaryError>("file too small to be an archive",
- object_error::invalid_file_type);
- return;
- }
-
- // Make sure Format is initialized before any call to
- // ArchiveMemberHeader::getName() is made. This could be a valid empty
- // archive which is the same in all formats. So claiming it to be gnu to is
- // fine if not totally correct before we look for a string table or table of
- // contents.
- Format = K_GNU;
-
- // Get the special members.
- child_iterator I = child_begin(Err, false);
- if (Err)
- return;
- child_iterator E = child_end();
-
- // See if this is a valid empty archive and if so return.
- if (I == E) {
- Err = Error::success();
- return;
- }
- const Child *C = &*I;
-
- auto Increment = [&]() {
- ++I;
- if (Err)
- return true;
- C = &*I;
- return false;
- };
-
- Expected<StringRef> NameOrErr = C->getRawName();
- if (!NameOrErr) {
- Err = NameOrErr.takeError();
- return;
- }
- StringRef Name = NameOrErr.get();
-
- // Below is the pattern that is used to figure out the archive format
- // GNU archive format
- // First member : / (may exist, if it exists, points to the symbol table )
- // Second member : // (may exist, if it exists, points to the string table)
- // Note : The string table is used if the filename exceeds 15 characters
- // BSD archive format
- // First member : __.SYMDEF or "__.SYMDEF SORTED" (the symbol table)
- // There is no string table, if the filename exceeds 15 characters or has a
- // embedded space, the filename has #1/<size>, The size represents the size
- // of the filename that needs to be read after the archive header
- // COFF archive format
- // First member : /
- // Second member : / (provides a directory of symbols)
- // Third member : // (may exist, if it exists, contains the string table)
- // Note: Microsoft PE/COFF Spec 8.3 says that the third member is present
- // even if the string table is empty. However, lib.exe does not in fact
- // seem to create the third member if there's no member whose filename
- // exceeds 15 characters. So the third member is optional.
-
- if (Name == "__.SYMDEF" || Name == "__.SYMDEF_64") {
- if (Name == "__.SYMDEF")
- Format = K_BSD;
- else // Name == "__.SYMDEF_64"
- Format = K_DARWIN64;
- // We know that the symbol table is not an external file, but we still must
- // check any Expected<> return value.
- Expected<StringRef> BufOrErr = C->getBuffer();
- if (!BufOrErr) {
- Err = BufOrErr.takeError();
- return;
- }
- SymbolTable = BufOrErr.get();
- if (Increment())
- return;
- setFirstRegular(*C);
-
- Err = Error::success();
- return;
- }
-
- if (Name.startswith("#1/")) {
- Format = K_BSD;
- // We know this is BSD, so getName will work since there is no string table.
- Expected<StringRef> NameOrErr = C->getName();
- if (!NameOrErr) {
- Err = NameOrErr.takeError();
- return;
- }
- Name = NameOrErr.get();
- if (Name == "__.SYMDEF SORTED" || Name == "__.SYMDEF") {
- // We know that the symbol table is not an external file, but we still
- // must check any Expected<> return value.
- Expected<StringRef> BufOrErr = C->getBuffer();
- if (!BufOrErr) {
- Err = BufOrErr.takeError();
- return;
- }
- SymbolTable = BufOrErr.get();
- if (Increment())
- return;
- }
- else if (Name == "__.SYMDEF_64 SORTED" || Name == "__.SYMDEF_64") {
- Format = K_DARWIN64;
- // We know that the symbol table is not an external file, but we still
- // must check any Expected<> return value.
- Expected<StringRef> BufOrErr = C->getBuffer();
- if (!BufOrErr) {
- Err = BufOrErr.takeError();
- return;
- }
- SymbolTable = BufOrErr.get();
- if (Increment())
- return;
- }
- setFirstRegular(*C);
- return;
- }
-
- // MIPS 64-bit ELF archives use a special format of a symbol table.
- // This format is marked by `ar_name` field equals to "/SYM64/".
- // For detailed description see page 96 in the following document:
- // http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf
-
- bool has64SymTable = false;
- if (Name == "/" || Name == "/SYM64/") {
- // We know that the symbol table is not an external file, but we still
- // must check any Expected<> return value.
- Expected<StringRef> BufOrErr = C->getBuffer();
- if (!BufOrErr) {
- Err = BufOrErr.takeError();
- return;
- }
- SymbolTable = BufOrErr.get();
- if (Name == "/SYM64/")
- has64SymTable = true;
-
- if (Increment())
- return;
- if (I == E) {
- Err = Error::success();
- return;
- }
- Expected<StringRef> NameOrErr = C->getRawName();
- if (!NameOrErr) {
- Err = NameOrErr.takeError();
- return;
- }
- Name = NameOrErr.get();
- }
-
- if (Name == "//") {
- 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();
- if (!BufOrErr) {
- Err = BufOrErr.takeError();
- return;
- }
- StringTable = BufOrErr.get();
- if (Increment())
- return;
- setFirstRegular(*C);
- Err = Error::success();
- return;
- }
-
- if (Name[0] != '/') {
- Format = has64SymTable ? K_GNU64 : K_GNU;
- setFirstRegular(*C);
- Err = Error::success();
- return;
- }
-
- if (Name != "/") {
- Err = errorCodeToError(object_error::parse_failed);
- return;
- }
-
- Format = K_COFF;
- // We know that the symbol table is not an external file, but we still
- // must check any Expected<> return value.
- Expected<StringRef> BufOrErr = C->getBuffer();
- if (!BufOrErr) {
- Err = BufOrErr.takeError();
- return;
- }
- SymbolTable = BufOrErr.get();
-
- if (Increment())
- return;
-
- if (I == E) {
- setFirstRegular(*C);
- Err = Error::success();
- return;
- }
-
- NameOrErr = C->getRawName();
- if (!NameOrErr) {
- Err = NameOrErr.takeError();
- return;
- }
- Name = NameOrErr.get();
-
- if (Name == "//") {
- // The string table is never an external member, but we still
- // must check any Expected<> return value.
- Expected<StringRef> BufOrErr = C->getBuffer();
- if (!BufOrErr) {
- Err = BufOrErr.takeError();
- return;
- }
- StringTable = BufOrErr.get();
- if (Increment())
- return;
- }
-
- setFirstRegular(*C);
- Err = Error::success();
-}
-
-Archive::child_iterator Archive::child_begin(Error &Err,
- bool SkipInternal) const {
- if (isEmpty())
- return child_end();
-
- if (SkipInternal)
- return child_iterator::itr(
- Child(this, FirstRegularData, FirstRegularStartOfFile), Err);
-
- const char *Loc = Data.getBufferStart() + strlen(Magic);
- Child C(this, Loc, &Err);
- if (Err)
- return child_end();
- return child_iterator::itr(C, Err);
-}
-
-Archive::child_iterator Archive::child_end() const {
- return child_iterator::end(Child(nullptr, nullptr, nullptr));
-}
-
-StringRef Archive::Symbol::getName() const {
- return Parent->getSymbolTable().begin() + StringIndex;
-}
-
-Expected<Archive::Child> Archive::Symbol::getMember() const {
- const char *Buf = Parent->getSymbolTable().begin();
- const char *Offsets = Buf;
- if (Parent->kind() == K_GNU64 || Parent->kind() == K_DARWIN64)
- Offsets += sizeof(uint64_t);
- else
- Offsets += sizeof(uint32_t);
- uint64_t Offset = 0;
- if (Parent->kind() == K_GNU) {
- Offset = read32be(Offsets + SymbolIndex * 4);
- } 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
- // Offsets (the first uint32_t is the number of bytes of the ranlib
- // structs). The ranlib structs are a pair of uint32_t's the first
- // being a string table offset and the second being the offset into
- // the archive of the member that defines the symbol. Which is what
- // is needed here.
- Offset = read32le(Offsets + SymbolIndex * 8 + 4);
- } else if (Parent->kind() == K_DARWIN64) {
- // The SymbolIndex is an index into the ranlib_64 structs that start at
- // Offsets (the first uint64_t is the number of bytes of the ranlib_64
- // structs). The ranlib_64 structs are a pair of uint64_t's the first
- // being a string table offset and the second being the offset into
- // the archive of the member that defines the symbol. Which is what
- // is needed here.
- Offset = read64le(Offsets + SymbolIndex * 16 + 8);
- } else {
- // Skip offsets.
- uint32_t MemberCount = read32le(Buf);
- Buf += MemberCount * 4 + 4;
-
- uint32_t SymbolCount = read32le(Buf);
- if (SymbolIndex >= SymbolCount)
- return errorCodeToError(object_error::parse_failed);
-
- // Skip SymbolCount to get to the indices table.
- const char *Indices = Buf + 4;
-
- // Get the index of the offset in the file member offset table for this
- // symbol.
- uint16_t OffsetIndex = read16le(Indices + SymbolIndex * 2);
- // Subtract 1 since OffsetIndex is 1 based.
- --OffsetIndex;
-
- if (OffsetIndex >= MemberCount)
- return errorCodeToError(object_error::parse_failed);
-
- Offset = read32le(Offsets + OffsetIndex * 4);
- }
-
- const char *Loc = Parent->getData().begin() + Offset;
- Error Err = Error::success();
- Child C(Parent, Loc, &Err);
- if (Err)
- return std::move(Err);
- return C;
-}
-
-Archive::Symbol Archive::Symbol::getNext() const {
- Symbol t(*this);
- if (Parent->kind() == K_BSD) {
- // t.StringIndex is an offset from the start of the __.SYMDEF or
- // "__.SYMDEF SORTED" member into the string table for the ranlib
- // struct indexed by t.SymbolIndex . To change t.StringIndex to the
- // offset in the string table for t.SymbolIndex+1 we subtract the
- // its offset from the start of the string table for t.SymbolIndex
- // and add the offset of the string table for t.SymbolIndex+1.
-
- // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t
- // which is the number of bytes of ranlib structs that follow. The ranlib
- // structs are a pair of uint32_t's the first being a string table offset
- // and the second being the offset into the archive of the member that
- // define the symbol. After that the next uint32_t is the byte count of
- // the string table followed by the string table.
- const char *Buf = Parent->getSymbolTable().begin();
- uint32_t RanlibCount = 0;
- RanlibCount = read32le(Buf) / 8;
- // If t.SymbolIndex + 1 will be past the count of symbols (the RanlibCount)
- // don't change the t.StringIndex as we don't want to reference a ranlib
- // past RanlibCount.
- if (t.SymbolIndex + 1 < RanlibCount) {
- const char *Ranlibs = Buf + 4;
- uint32_t CurRanStrx = 0;
- uint32_t NextRanStrx = 0;
- CurRanStrx = read32le(Ranlibs + t.SymbolIndex * 8);
- NextRanStrx = read32le(Ranlibs + (t.SymbolIndex + 1) * 8);
- t.StringIndex -= CurRanStrx;
- t.StringIndex += NextRanStrx;
- }
- } else {
- // Go to one past next null.
- t.StringIndex = Parent->getSymbolTable().find('\0', t.StringIndex) + 1;
- }
- ++t.SymbolIndex;
- return t;
-}
-
-Archive::symbol_iterator Archive::symbol_begin() const {
- if (!hasSymbolTable())
- return symbol_iterator(Symbol(this, 0, 0));
-
- const char *buf = getSymbolTable().begin();
- if (kind() == K_GNU) {
- uint32_t symbol_count = 0;
- symbol_count = read32be(buf);
- buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t)));
- } 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) {
- // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t
- // which is the number of bytes of ranlib structs that follow. The ranlib
- // structs are a pair of uint32_t's the first being a string table offset
- // and the second being the offset into the archive of the member that
- // define the symbol. After that the next uint32_t is the byte count of
- // the string table followed by the string table.
- uint32_t ranlib_count = 0;
- ranlib_count = read32le(buf) / 8;
- const char *ranlibs = buf + 4;
- uint32_t ran_strx = 0;
- ran_strx = read32le(ranlibs);
- buf += sizeof(uint32_t) + (ranlib_count * (2 * (sizeof(uint32_t))));
- // Skip the byte count of the string table.
- buf += sizeof(uint32_t);
- buf += ran_strx;
- } else if (kind() == K_DARWIN64) {
- // The __.SYMDEF_64 or "__.SYMDEF_64 SORTED" member starts with a uint64_t
- // which is the number of bytes of ranlib_64 structs that follow. The
- // ranlib_64 structs are a pair of uint64_t's the first being a string
- // table offset and the second being the offset into the archive of the
- // member that define the symbol. After that the next uint64_t is the byte
- // count of the string table followed by the string table.
- uint64_t ranlib_count = 0;
- ranlib_count = read64le(buf) / 16;
- const char *ranlibs = buf + 8;
- uint64_t ran_strx = 0;
- ran_strx = read64le(ranlibs);
- buf += sizeof(uint64_t) + (ranlib_count * (2 * (sizeof(uint64_t))));
- // Skip the byte count of the string table.
- buf += sizeof(uint64_t);
- buf += ran_strx;
- } else {
- uint32_t member_count = 0;
- uint32_t symbol_count = 0;
- member_count = read32le(buf);
- buf += 4 + (member_count * 4); // Skip offsets.
- symbol_count = read32le(buf);
- buf += 4 + (symbol_count * 2); // Skip indices.
- }
- uint32_t string_start_offset = buf - getSymbolTable().begin();
- return symbol_iterator(Symbol(this, 0, string_start_offset));
-}
-
-Archive::symbol_iterator Archive::symbol_end() const {
- return symbol_iterator(Symbol(this, getNumberOfSymbols(), 0));
-}
-
-uint32_t Archive::getNumberOfSymbols() const {
- if (!hasSymbolTable())
- return 0;
- const char *buf = getSymbolTable().begin();
- if (kind() == K_GNU)
- return read32be(buf);
- if (kind() == K_GNU64)
- return read64be(buf);
- if (kind() == K_BSD)
- return read32le(buf) / 8;
- if (kind() == K_DARWIN64)
- return read64le(buf) / 16;
- uint32_t member_count = 0;
- member_count = read32le(buf);
- buf += 4 + (member_count * 4); // Skip offsets.
- return read32le(buf);
-}
-
-Expected<Optional<Archive::Child>> Archive::findSym(StringRef name) const {
- Archive::symbol_iterator bs = symbol_begin();
- Archive::symbol_iterator es = symbol_end();
-
- for (; bs != es; ++bs) {
- StringRef SymName = bs->getName();
- if (SymName == name) {
- if (auto MemberOrErr = bs->getMember())
- return Child(*MemberOrErr);
- else
- return MemberOrErr.takeError();
- }
- }
- return Optional<Child>();
-}
-
-// Returns true if archive file contains no member file.
-bool Archive::isEmpty() const { return Data.getBufferSize() == 8; }
-
-bool Archive::hasSymbolTable() const { return !SymbolTable.empty(); }
+
+void Archive::anchor() {}
+
+static Error
+malformedError(Twine Msg) {
+ std::string StringMsg = "truncated or malformed archive (" + Msg.str() + ")";
+ return make_error<GenericBinaryError>(std::move(StringMsg),
+ object_error::parse_failed);
+}
+
+ArchiveMemberHeader::ArchiveMemberHeader(const Archive *Parent,
+ const char *RawHeaderPtr,
+ uint64_t Size, Error *Err)
+ : Parent(Parent),
+ ArMemHdr(reinterpret_cast<const ArMemHdrType *>(RawHeaderPtr)) {
+ if (RawHeaderPtr == nullptr)
+ return;
+ ErrorAsOutParameter ErrAsOutParam(Err);
+
+ if (Size < sizeof(ArMemHdrType)) {
+ if (Err) {
+ std::string Msg("remaining size of archive too small for next archive "
+ "member header ");
+ Expected<StringRef> NameOrErr = getName(Size);
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
+ uint64_t Offset = RawHeaderPtr - Parent->getData().data();
+ *Err = malformedError(Msg + "at offset " + Twine(Offset));
+ } else
+ *Err = malformedError(Msg + "for " + NameOrErr.get());
+ }
+ return;
+ }
+ if (ArMemHdr->Terminator[0] != '`' || ArMemHdr->Terminator[1] != '\n') {
+ if (Err) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(StringRef(ArMemHdr->Terminator,
+ sizeof(ArMemHdr->Terminator)));
+ OS.flush();
+ std::string Msg("terminator characters in archive member \"" + Buf +
+ "\" not the correct \"`\\n\" values for the archive "
+ "member header ");
+ Expected<StringRef> NameOrErr = getName(Size);
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
+ uint64_t Offset = RawHeaderPtr - Parent->getData().data();
+ *Err = malformedError(Msg + "at offset " + Twine(Offset));
+ } else
+ *Err = malformedError(Msg + "for " + NameOrErr.get());
+ }
+ return;
+ }
+}
+
+// This gets the raw name from the ArMemHdr->Name field and checks that it is
+// valid for the kind of archive. If it is not valid it returns an Error.
+Expected<StringRef> ArchiveMemberHeader::getRawName() const {
+ char EndCond;
+ auto Kind = Parent->kind();
+ if (Kind == Archive::K_BSD || Kind == Archive::K_DARWIN64) {
+ if (ArMemHdr->Name[0] == ' ') {
+ uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("name contains a leading space for archive member "
+ "header at offset " + Twine(Offset));
+ }
+ EndCond = ' ';
+ }
+ else if (ArMemHdr->Name[0] == '/' || ArMemHdr->Name[0] == '#')
+ EndCond = ' ';
+ else
+ EndCond = '/';
+ StringRef::size_type end =
+ StringRef(ArMemHdr->Name, sizeof(ArMemHdr->Name)).find(EndCond);
+ if (end == StringRef::npos)
+ end = sizeof(ArMemHdr->Name);
+ assert(end <= sizeof(ArMemHdr->Name) && end > 0);
+ // Don't include the EndCond if there is one.
+ return StringRef(ArMemHdr->Name, end);
+}
+
+// This gets the name looking up long names. Size is the size of the archive
+// member including the header, so the size of any name following the header
+// is checked to make sure it does not overflow.
+Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const {
+
+ // This can be called from the ArchiveMemberHeader constructor when the
+ // archive header is truncated to produce an error message with the name.
+ // Make sure the name field is not truncated.
+ if (Size < offsetof(ArMemHdrType, Name) + sizeof(ArMemHdr->Name)) {
+ uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("archive header truncated before the name field "
+ "for archive member header at offset " +
+ Twine(ArchiveOffset));
+ }
+
+ // The raw name itself can be invalid.
+ Expected<StringRef> NameOrErr = getRawName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ StringRef Name = NameOrErr.get();
+
+ // Check if it's a special name.
+ if (Name[0] == '/') {
+ if (Name.size() == 1) // Linker member.
+ return Name;
+ if (Name.size() == 2 && Name[1] == '/') // String table.
+ return Name;
+ // It's a long name.
+ // Get the string table offset.
+ std::size_t StringOffset;
+ if (Name.substr(1).rtrim(' ').getAsInteger(10, StringOffset)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(Name.substr(1).rtrim(' '));
+ OS.flush();
+ uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("long name offset characters after the '/' are "
+ "not all decimal numbers: '" + Buf + "' for "
+ "archive member header at offset " +
+ Twine(ArchiveOffset));
+ }
+
+ // Verify it.
+ if (StringOffset >= Parent->getStringTable().size()) {
+ uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("long name offset " + Twine(StringOffset) + " past "
+ "the end of the string table for archive member "
+ "header at offset " + Twine(ArchiveOffset));
+ }
+
+ // GNU long file names end with a "/\n".
+ if (Parent->kind() == Archive::K_GNU ||
+ Parent->kind() == Archive::K_GNU64) {
+ size_t End = Parent->getStringTable().find('\n', /*From=*/StringOffset);
+ if (End == StringRef::npos || End < 1 ||
+ Parent->getStringTable()[End - 1] != '/') {
+ return malformedError("string table at long name offset " +
+ Twine(StringOffset) + "not terminated");
+ }
+ return Parent->getStringTable().slice(StringOffset, End - 1);
+ }
+ return Parent->getStringTable().begin() + StringOffset;
+ }
+
+ if (Name.startswith("#1/")) {
+ uint64_t NameLength;
+ if (Name.substr(3).rtrim(' ').getAsInteger(10, NameLength)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(Name.substr(3).rtrim(' '));
+ OS.flush();
+ uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("long name length characters after the #1/ are "
+ "not all decimal numbers: '" + Buf + "' for "
+ "archive member header at offset " +
+ Twine(ArchiveOffset));
+ }
+ if (getSizeOf() + NameLength > Size) {
+ uint64_t ArchiveOffset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("long name length: " + Twine(NameLength) +
+ " extends past the end of the member or archive "
+ "for archive member header at offset " +
+ Twine(ArchiveOffset));
+ }
+ return StringRef(reinterpret_cast<const char *>(ArMemHdr) + getSizeOf(),
+ NameLength).rtrim('\0');
+ }
+
+ // It is not a long name so trim the blanks at the end of the name.
+ if (Name[Name.size() - 1] != '/')
+ return Name.rtrim(' ');
+
+ // It's a simple name.
+ return Name.drop_back(1);
+}
+
+Expected<uint64_t> ArchiveMemberHeader::getSize() const {
+ uint64_t Ret;
+ if (StringRef(ArMemHdr->Size,
+ sizeof(ArMemHdr->Size)).rtrim(" ").getAsInteger(10, Ret)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(StringRef(ArMemHdr->Size,
+ sizeof(ArMemHdr->Size)).rtrim(" "));
+ OS.flush();
+ uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("characters in size field in archive header are not "
+ "all decimal numbers: '" + Buf + "' for archive "
+ "member header at offset " + Twine(Offset));
+ }
+ return Ret;
+}
+
+Expected<sys::fs::perms> ArchiveMemberHeader::getAccessMode() const {
+ unsigned Ret;
+ if (StringRef(ArMemHdr->AccessMode,
+ sizeof(ArMemHdr->AccessMode)).rtrim(' ').getAsInteger(8, Ret)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(StringRef(ArMemHdr->AccessMode,
+ sizeof(ArMemHdr->AccessMode)).rtrim(" "));
+ OS.flush();
+ uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("characters in AccessMode field in archive header "
+ "are not all decimal numbers: '" + Buf + "' for the "
+ "archive member header at offset " + Twine(Offset));
+ }
+ return static_cast<sys::fs::perms>(Ret);
+}
+
+Expected<sys::TimePoint<std::chrono::seconds>>
+ArchiveMemberHeader::getLastModified() const {
+ unsigned Seconds;
+ if (StringRef(ArMemHdr->LastModified,
+ sizeof(ArMemHdr->LastModified)).rtrim(' ')
+ .getAsInteger(10, Seconds)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(StringRef(ArMemHdr->LastModified,
+ sizeof(ArMemHdr->LastModified)).rtrim(" "));
+ OS.flush();
+ uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("characters in LastModified field in archive header "
+ "are not all decimal numbers: '" + Buf + "' for the "
+ "archive member header at offset " + Twine(Offset));
+ }
+
+ return sys::toTimePoint(Seconds);
+}
+
+Expected<unsigned> ArchiveMemberHeader::getUID() const {
+ unsigned Ret;
+ StringRef User = StringRef(ArMemHdr->UID, sizeof(ArMemHdr->UID)).rtrim(' ');
+ if (User.empty())
+ return 0;
+ if (User.getAsInteger(10, Ret)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(User);
+ OS.flush();
+ uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("characters in UID field in archive header "
+ "are not all decimal numbers: '" + Buf + "' for the "
+ "archive member header at offset " + Twine(Offset));
+ }
+ return Ret;
+}
+
+Expected<unsigned> ArchiveMemberHeader::getGID() const {
+ unsigned Ret;
+ StringRef Group = StringRef(ArMemHdr->GID, sizeof(ArMemHdr->GID)).rtrim(' ');
+ if (Group.empty())
+ return 0;
+ if (Group.getAsInteger(10, Ret)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(Group);
+ OS.flush();
+ uint64_t Offset = reinterpret_cast<const char *>(ArMemHdr) -
+ Parent->getData().data();
+ return malformedError("characters in GID field in archive header "
+ "are not all decimal numbers: '" + Buf + "' for the "
+ "archive member header at offset " + Twine(Offset));
+ }
+ return Ret;
+}
+
+Archive::Child::Child(const Archive *Parent, StringRef Data,
+ uint16_t StartOfFile)
+ : Parent(Parent), Header(Parent, Data.data(), Data.size(), nullptr),
+ Data(Data), StartOfFile(StartOfFile) {
+}
+
+Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err)
+ : Parent(Parent),
+ Header(Parent, Start,
+ Parent
+ ? Parent->getData().size() - (Start - Parent->getData().data())
+ : 0, Err) {
+ if (!Start)
+ return;
+
+ // If we are pointed to real data, Start is not a nullptr, then there must be
+ // a non-null Err pointer available to report malformed data on. Only in
+ // the case sentinel value is being constructed is Err is permitted to be a
+ // nullptr.
+ assert(Err && "Err can't be nullptr if Start is not a nullptr");
+
+ ErrorAsOutParameter ErrAsOutParam(Err);
+
+ // If there was an error in the construction of the Header
+ // then just return with the error now set.
+ if (*Err)
+ return;
+
+ uint64_t Size = Header.getSizeOf();
+ Data = StringRef(Start, Size);
+ Expected<bool> isThinOrErr = isThinMember();
+ if (!isThinOrErr) {
+ *Err = isThinOrErr.takeError();
+ return;
+ }
+ bool isThin = isThinOrErr.get();
+ if (!isThin) {
+ Expected<uint64_t> MemberSize = getRawSize();
+ if (!MemberSize) {
+ *Err = MemberSize.takeError();
+ return;
+ }
+ Size += MemberSize.get();
+ Data = StringRef(Start, Size);
+ }
+
+ // Setup StartOfFile and PaddingBytes.
+ StartOfFile = Header.getSizeOf();
+ // Don't include attached name.
+ Expected<StringRef> NameOrErr = getRawName();
+ if (!NameOrErr){
+ *Err = NameOrErr.takeError();
+ return;
+ }
+ StringRef Name = NameOrErr.get();
+ if (Name.startswith("#1/")) {
+ uint64_t NameSize;
+ if (Name.substr(3).rtrim(' ').getAsInteger(10, NameSize)) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ OS.write_escaped(Name.substr(3).rtrim(' '));
+ OS.flush();
+ uint64_t Offset = Start - Parent->getData().data();
+ *Err = malformedError("long name length characters after the #1/ are "
+ "not all decimal numbers: '" + Buf + "' for "
+ "archive member header at offset " +
+ Twine(Offset));
+ return;
+ }
+ StartOfFile += NameSize;
+ }
+}
+
+Expected<uint64_t> Archive::Child::getSize() const {
+ if (Parent->IsThin)
+ return Header.getSize();
+ return Data.size() - StartOfFile;
+}
+
+Expected<uint64_t> Archive::Child::getRawSize() const {
+ return Header.getSize();
+}
+
+Expected<bool> Archive::Child::isThinMember() const {
+ Expected<StringRef> NameOrErr = Header.getRawName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ StringRef Name = NameOrErr.get();
+ return Parent->IsThin && Name != "/" && Name != "//";
+}
+
+Expected<std::string> Archive::Child::getFullName() const {
+ Expected<bool> isThin = isThinMember();
+ if (!isThin)
+ return isThin.takeError();
+ assert(isThin.get());
+ Expected<StringRef> NameOrErr = getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ StringRef Name = *NameOrErr;
+ if (sys::path::is_absolute(Name))
+ return std::string(Name);
+
+ SmallString<128> FullName = sys::path::parent_path(
+ Parent->getMemoryBufferRef().getBufferIdentifier());
+ sys::path::append(FullName, Name);
+ return std::string(FullName.str());
+}
+
+Expected<StringRef> Archive::Child::getBuffer() const {
+ Expected<bool> isThinOrErr = isThinMember();
+ if (!isThinOrErr)
+ return isThinOrErr.takeError();
+ bool isThin = isThinOrErr.get();
+ if (!isThin) {
+ Expected<uint64_t> Size = getSize();
+ if (!Size)
+ return Size.takeError();
+ return StringRef(Data.data() + StartOfFile, Size.get());
+ }
+ Expected<std::string> FullNameOrErr = getFullName();
+ if (!FullNameOrErr)
+ return FullNameOrErr.takeError();
+ const std::string &FullName = *FullNameOrErr;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> Buf = MemoryBuffer::getFile(FullName);
+ if (std::error_code EC = Buf.getError())
+ return errorCodeToError(EC);
+ Parent->ThinBuffers.push_back(std::move(*Buf));
+ return Parent->ThinBuffers.back()->getBuffer();
+}
+
+Expected<Archive::Child> Archive::Child::getNext() const {
+ size_t SpaceToSkip = Data.size();
+ // If it's odd, add 1 to make it even.
+ if (SpaceToSkip & 1)
+ ++SpaceToSkip;
+
+ const char *NextLoc = Data.data() + SpaceToSkip;
+
+ // Check to see if this is at the end of the archive.
+ if (NextLoc == Parent->Data.getBufferEnd())
+ return Child(nullptr, nullptr, nullptr);
+
+ // Check to see if this is past the end of the archive.
+ if (NextLoc > Parent->Data.getBufferEnd()) {
+ std::string Msg("offset to next archive member past the end of the archive "
+ "after member ");
+ Expected<StringRef> NameOrErr = getName();
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
+ uint64_t Offset = Data.data() - Parent->getData().data();
+ return malformedError(Msg + "at offset " + Twine(Offset));
+ } else
+ return malformedError(Msg + NameOrErr.get());
+ }
+
+ Error Err = Error::success();
+ Child Ret(Parent, NextLoc, &Err);
+ if (Err)
+ return std::move(Err);
+ return Ret;
+}
+
+uint64_t Archive::Child::getChildOffset() const {
+ const char *a = Parent->Data.getBuffer().data();
+ const char *c = Data.data();
+ uint64_t offset = c - a;
+ return offset;
+}
+
+Expected<StringRef> Archive::Child::getName() const {
+ Expected<uint64_t> RawSizeOrErr = getRawSize();
+ if (!RawSizeOrErr)
+ return RawSizeOrErr.takeError();
+ uint64_t RawSize = RawSizeOrErr.get();
+ Expected<StringRef> NameOrErr = Header.getName(Header.getSizeOf() + RawSize);
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ StringRef Name = NameOrErr.get();
+ return Name;
+}
+
+Expected<MemoryBufferRef> Archive::Child::getMemoryBufferRef() const {
+ Expected<StringRef> NameOrErr = getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ StringRef Name = NameOrErr.get();
+ Expected<StringRef> Buf = getBuffer();
+ if (!Buf)
+ return createFileError(Name, Buf.takeError());
+ return MemoryBufferRef(*Buf, Name);
+}
+
+Expected<std::unique_ptr<Binary>>
+Archive::Child::getAsBinary(LLVMContext *Context) const {
+ Expected<MemoryBufferRef> BuffOrErr = getMemoryBufferRef();
+ if (!BuffOrErr)
+ return BuffOrErr.takeError();
+
+ auto BinaryOrErr = createBinary(BuffOrErr.get(), Context);
+ if (BinaryOrErr)
+ return std::move(*BinaryOrErr);
+ return BinaryOrErr.takeError();
+}
+
+Expected<std::unique_ptr<Archive>> Archive::create(MemoryBufferRef Source) {
+ Error Err = Error::success();
+ std::unique_ptr<Archive> Ret(new Archive(Source, Err));
+ if (Err)
+ return std::move(Err);
+ return std::move(Ret);
+}
+
+void Archive::setFirstRegular(const Child &C) {
+ FirstRegularData = C.Data;
+ FirstRegularStartOfFile = C.StartOfFile;
+}
+
+Archive::Archive(MemoryBufferRef Source, Error &Err)
+ : Binary(Binary::ID_Archive, Source) {
+ ErrorAsOutParameter ErrAsOutParam(&Err);
+ StringRef Buffer = Data.getBuffer();
+ // Check for sufficient magic.
+ if (Buffer.startswith(ThinMagic)) {
+ IsThin = true;
+ } else if (Buffer.startswith(Magic)) {
+ IsThin = false;
+ } else {
+ Err = make_error<GenericBinaryError>("file too small to be an archive",
+ object_error::invalid_file_type);
+ return;
+ }
+
+ // Make sure Format is initialized before any call to
+ // ArchiveMemberHeader::getName() is made. This could be a valid empty
+ // archive which is the same in all formats. So claiming it to be gnu to is
+ // fine if not totally correct before we look for a string table or table of
+ // contents.
+ Format = K_GNU;
+
+ // Get the special members.
+ child_iterator I = child_begin(Err, false);
+ if (Err)
+ return;
+ child_iterator E = child_end();
+
+ // See if this is a valid empty archive and if so return.
+ if (I == E) {
+ Err = Error::success();
+ return;
+ }
+ const Child *C = &*I;
+
+ auto Increment = [&]() {
+ ++I;
+ if (Err)
+ return true;
+ C = &*I;
+ return false;
+ };
+
+ Expected<StringRef> NameOrErr = C->getRawName();
+ if (!NameOrErr) {
+ Err = NameOrErr.takeError();
+ return;
+ }
+ StringRef Name = NameOrErr.get();
+
+ // Below is the pattern that is used to figure out the archive format
+ // GNU archive format
+ // First member : / (may exist, if it exists, points to the symbol table )
+ // Second member : // (may exist, if it exists, points to the string table)
+ // Note : The string table is used if the filename exceeds 15 characters
+ // BSD archive format
+ // First member : __.SYMDEF or "__.SYMDEF SORTED" (the symbol table)
+ // There is no string table, if the filename exceeds 15 characters or has a
+ // embedded space, the filename has #1/<size>, The size represents the size
+ // of the filename that needs to be read after the archive header
+ // COFF archive format
+ // First member : /
+ // Second member : / (provides a directory of symbols)
+ // Third member : // (may exist, if it exists, contains the string table)
+ // Note: Microsoft PE/COFF Spec 8.3 says that the third member is present
+ // even if the string table is empty. However, lib.exe does not in fact
+ // seem to create the third member if there's no member whose filename
+ // exceeds 15 characters. So the third member is optional.
+
+ if (Name == "__.SYMDEF" || Name == "__.SYMDEF_64") {
+ if (Name == "__.SYMDEF")
+ Format = K_BSD;
+ else // Name == "__.SYMDEF_64"
+ Format = K_DARWIN64;
+ // We know that the symbol table is not an external file, but we still must
+ // check any Expected<> return value.
+ Expected<StringRef> BufOrErr = C->getBuffer();
+ if (!BufOrErr) {
+ Err = BufOrErr.takeError();
+ return;
+ }
+ SymbolTable = BufOrErr.get();
+ if (Increment())
+ return;
+ setFirstRegular(*C);
+
+ Err = Error::success();
+ return;
+ }
+
+ if (Name.startswith("#1/")) {
+ Format = K_BSD;
+ // We know this is BSD, so getName will work since there is no string table.
+ Expected<StringRef> NameOrErr = C->getName();
+ if (!NameOrErr) {
+ Err = NameOrErr.takeError();
+ return;
+ }
+ Name = NameOrErr.get();
+ if (Name == "__.SYMDEF SORTED" || Name == "__.SYMDEF") {
+ // We know that the symbol table is not an external file, but we still
+ // must check any Expected<> return value.
+ Expected<StringRef> BufOrErr = C->getBuffer();
+ if (!BufOrErr) {
+ Err = BufOrErr.takeError();
+ return;
+ }
+ SymbolTable = BufOrErr.get();
+ if (Increment())
+ return;
+ }
+ else if (Name == "__.SYMDEF_64 SORTED" || Name == "__.SYMDEF_64") {
+ Format = K_DARWIN64;
+ // We know that the symbol table is not an external file, but we still
+ // must check any Expected<> return value.
+ Expected<StringRef> BufOrErr = C->getBuffer();
+ if (!BufOrErr) {
+ Err = BufOrErr.takeError();
+ return;
+ }
+ SymbolTable = BufOrErr.get();
+ if (Increment())
+ return;
+ }
+ setFirstRegular(*C);
+ return;
+ }
+
+ // MIPS 64-bit ELF archives use a special format of a symbol table.
+ // This format is marked by `ar_name` field equals to "/SYM64/".
+ // For detailed description see page 96 in the following document:
+ // http://techpubs.sgi.com/library/manuals/4000/007-4658-001/pdf/007-4658-001.pdf
+
+ bool has64SymTable = false;
+ if (Name == "/" || Name == "/SYM64/") {
+ // We know that the symbol table is not an external file, but we still
+ // must check any Expected<> return value.
+ Expected<StringRef> BufOrErr = C->getBuffer();
+ if (!BufOrErr) {
+ Err = BufOrErr.takeError();
+ return;
+ }
+ SymbolTable = BufOrErr.get();
+ if (Name == "/SYM64/")
+ has64SymTable = true;
+
+ if (Increment())
+ return;
+ if (I == E) {
+ Err = Error::success();
+ return;
+ }
+ Expected<StringRef> NameOrErr = C->getRawName();
+ if (!NameOrErr) {
+ Err = NameOrErr.takeError();
+ return;
+ }
+ Name = NameOrErr.get();
+ }
+
+ if (Name == "//") {
+ 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();
+ if (!BufOrErr) {
+ Err = BufOrErr.takeError();
+ return;
+ }
+ StringTable = BufOrErr.get();
+ if (Increment())
+ return;
+ setFirstRegular(*C);
+ Err = Error::success();
+ return;
+ }
+
+ if (Name[0] != '/') {
+ Format = has64SymTable ? K_GNU64 : K_GNU;
+ setFirstRegular(*C);
+ Err = Error::success();
+ return;
+ }
+
+ if (Name != "/") {
+ Err = errorCodeToError(object_error::parse_failed);
+ return;
+ }
+
+ Format = K_COFF;
+ // We know that the symbol table is not an external file, but we still
+ // must check any Expected<> return value.
+ Expected<StringRef> BufOrErr = C->getBuffer();
+ if (!BufOrErr) {
+ Err = BufOrErr.takeError();
+ return;
+ }
+ SymbolTable = BufOrErr.get();
+
+ if (Increment())
+ return;
+
+ if (I == E) {
+ setFirstRegular(*C);
+ Err = Error::success();
+ return;
+ }
+
+ NameOrErr = C->getRawName();
+ if (!NameOrErr) {
+ Err = NameOrErr.takeError();
+ return;
+ }
+ Name = NameOrErr.get();
+
+ if (Name == "//") {
+ // The string table is never an external member, but we still
+ // must check any Expected<> return value.
+ Expected<StringRef> BufOrErr = C->getBuffer();
+ if (!BufOrErr) {
+ Err = BufOrErr.takeError();
+ return;
+ }
+ StringTable = BufOrErr.get();
+ if (Increment())
+ return;
+ }
+
+ setFirstRegular(*C);
+ Err = Error::success();
+}
+
+Archive::child_iterator Archive::child_begin(Error &Err,
+ bool SkipInternal) const {
+ if (isEmpty())
+ return child_end();
+
+ if (SkipInternal)
+ return child_iterator::itr(
+ Child(this, FirstRegularData, FirstRegularStartOfFile), Err);
+
+ const char *Loc = Data.getBufferStart() + strlen(Magic);
+ Child C(this, Loc, &Err);
+ if (Err)
+ return child_end();
+ return child_iterator::itr(C, Err);
+}
+
+Archive::child_iterator Archive::child_end() const {
+ return child_iterator::end(Child(nullptr, nullptr, nullptr));
+}
+
+StringRef Archive::Symbol::getName() const {
+ return Parent->getSymbolTable().begin() + StringIndex;
+}
+
+Expected<Archive::Child> Archive::Symbol::getMember() const {
+ const char *Buf = Parent->getSymbolTable().begin();
+ const char *Offsets = Buf;
+ if (Parent->kind() == K_GNU64 || Parent->kind() == K_DARWIN64)
+ Offsets += sizeof(uint64_t);
+ else
+ Offsets += sizeof(uint32_t);
+ uint64_t Offset = 0;
+ if (Parent->kind() == K_GNU) {
+ Offset = read32be(Offsets + SymbolIndex * 4);
+ } 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
+ // Offsets (the first uint32_t is the number of bytes of the ranlib
+ // structs). The ranlib structs are a pair of uint32_t's the first
+ // being a string table offset and the second being the offset into
+ // the archive of the member that defines the symbol. Which is what
+ // is needed here.
+ Offset = read32le(Offsets + SymbolIndex * 8 + 4);
+ } else if (Parent->kind() == K_DARWIN64) {
+ // The SymbolIndex is an index into the ranlib_64 structs that start at
+ // Offsets (the first uint64_t is the number of bytes of the ranlib_64
+ // structs). The ranlib_64 structs are a pair of uint64_t's the first
+ // being a string table offset and the second being the offset into
+ // the archive of the member that defines the symbol. Which is what
+ // is needed here.
+ Offset = read64le(Offsets + SymbolIndex * 16 + 8);
+ } else {
+ // Skip offsets.
+ uint32_t MemberCount = read32le(Buf);
+ Buf += MemberCount * 4 + 4;
+
+ uint32_t SymbolCount = read32le(Buf);
+ if (SymbolIndex >= SymbolCount)
+ return errorCodeToError(object_error::parse_failed);
+
+ // Skip SymbolCount to get to the indices table.
+ const char *Indices = Buf + 4;
+
+ // Get the index of the offset in the file member offset table for this
+ // symbol.
+ uint16_t OffsetIndex = read16le(Indices + SymbolIndex * 2);
+ // Subtract 1 since OffsetIndex is 1 based.
+ --OffsetIndex;
+
+ if (OffsetIndex >= MemberCount)
+ return errorCodeToError(object_error::parse_failed);
+
+ Offset = read32le(Offsets + OffsetIndex * 4);
+ }
+
+ const char *Loc = Parent->getData().begin() + Offset;
+ Error Err = Error::success();
+ Child C(Parent, Loc, &Err);
+ if (Err)
+ return std::move(Err);
+ return C;
+}
+
+Archive::Symbol Archive::Symbol::getNext() const {
+ Symbol t(*this);
+ if (Parent->kind() == K_BSD) {
+ // t.StringIndex is an offset from the start of the __.SYMDEF or
+ // "__.SYMDEF SORTED" member into the string table for the ranlib
+ // struct indexed by t.SymbolIndex . To change t.StringIndex to the
+ // offset in the string table for t.SymbolIndex+1 we subtract the
+ // its offset from the start of the string table for t.SymbolIndex
+ // and add the offset of the string table for t.SymbolIndex+1.
+
+ // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t
+ // which is the number of bytes of ranlib structs that follow. The ranlib
+ // structs are a pair of uint32_t's the first being a string table offset
+ // and the second being the offset into the archive of the member that
+ // define the symbol. After that the next uint32_t is the byte count of
+ // the string table followed by the string table.
+ const char *Buf = Parent->getSymbolTable().begin();
+ uint32_t RanlibCount = 0;
+ RanlibCount = read32le(Buf) / 8;
+ // If t.SymbolIndex + 1 will be past the count of symbols (the RanlibCount)
+ // don't change the t.StringIndex as we don't want to reference a ranlib
+ // past RanlibCount.
+ if (t.SymbolIndex + 1 < RanlibCount) {
+ const char *Ranlibs = Buf + 4;
+ uint32_t CurRanStrx = 0;
+ uint32_t NextRanStrx = 0;
+ CurRanStrx = read32le(Ranlibs + t.SymbolIndex * 8);
+ NextRanStrx = read32le(Ranlibs + (t.SymbolIndex + 1) * 8);
+ t.StringIndex -= CurRanStrx;
+ t.StringIndex += NextRanStrx;
+ }
+ } else {
+ // Go to one past next null.
+ t.StringIndex = Parent->getSymbolTable().find('\0', t.StringIndex) + 1;
+ }
+ ++t.SymbolIndex;
+ return t;
+}
+
+Archive::symbol_iterator Archive::symbol_begin() const {
+ if (!hasSymbolTable())
+ return symbol_iterator(Symbol(this, 0, 0));
+
+ const char *buf = getSymbolTable().begin();
+ if (kind() == K_GNU) {
+ uint32_t symbol_count = 0;
+ symbol_count = read32be(buf);
+ buf += sizeof(uint32_t) + (symbol_count * (sizeof(uint32_t)));
+ } 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) {
+ // The __.SYMDEF or "__.SYMDEF SORTED" member starts with a uint32_t
+ // which is the number of bytes of ranlib structs that follow. The ranlib
+ // structs are a pair of uint32_t's the first being a string table offset
+ // and the second being the offset into the archive of the member that
+ // define the symbol. After that the next uint32_t is the byte count of
+ // the string table followed by the string table.
+ uint32_t ranlib_count = 0;
+ ranlib_count = read32le(buf) / 8;
+ const char *ranlibs = buf + 4;
+ uint32_t ran_strx = 0;
+ ran_strx = read32le(ranlibs);
+ buf += sizeof(uint32_t) + (ranlib_count * (2 * (sizeof(uint32_t))));
+ // Skip the byte count of the string table.
+ buf += sizeof(uint32_t);
+ buf += ran_strx;
+ } else if (kind() == K_DARWIN64) {
+ // The __.SYMDEF_64 or "__.SYMDEF_64 SORTED" member starts with a uint64_t
+ // which is the number of bytes of ranlib_64 structs that follow. The
+ // ranlib_64 structs are a pair of uint64_t's the first being a string
+ // table offset and the second being the offset into the archive of the
+ // member that define the symbol. After that the next uint64_t is the byte
+ // count of the string table followed by the string table.
+ uint64_t ranlib_count = 0;
+ ranlib_count = read64le(buf) / 16;
+ const char *ranlibs = buf + 8;
+ uint64_t ran_strx = 0;
+ ran_strx = read64le(ranlibs);
+ buf += sizeof(uint64_t) + (ranlib_count * (2 * (sizeof(uint64_t))));
+ // Skip the byte count of the string table.
+ buf += sizeof(uint64_t);
+ buf += ran_strx;
+ } else {
+ uint32_t member_count = 0;
+ uint32_t symbol_count = 0;
+ member_count = read32le(buf);
+ buf += 4 + (member_count * 4); // Skip offsets.
+ symbol_count = read32le(buf);
+ buf += 4 + (symbol_count * 2); // Skip indices.
+ }
+ uint32_t string_start_offset = buf - getSymbolTable().begin();
+ return symbol_iterator(Symbol(this, 0, string_start_offset));
+}
+
+Archive::symbol_iterator Archive::symbol_end() const {
+ return symbol_iterator(Symbol(this, getNumberOfSymbols(), 0));
+}
+
+uint32_t Archive::getNumberOfSymbols() const {
+ if (!hasSymbolTable())
+ return 0;
+ const char *buf = getSymbolTable().begin();
+ if (kind() == K_GNU)
+ return read32be(buf);
+ if (kind() == K_GNU64)
+ return read64be(buf);
+ if (kind() == K_BSD)
+ return read32le(buf) / 8;
+ if (kind() == K_DARWIN64)
+ return read64le(buf) / 16;
+ uint32_t member_count = 0;
+ member_count = read32le(buf);
+ buf += 4 + (member_count * 4); // Skip offsets.
+ return read32le(buf);
+}
+
+Expected<Optional<Archive::Child>> Archive::findSym(StringRef name) const {
+ Archive::symbol_iterator bs = symbol_begin();
+ Archive::symbol_iterator es = symbol_end();
+
+ for (; bs != es; ++bs) {
+ StringRef SymName = bs->getName();
+ if (SymName == name) {
+ if (auto MemberOrErr = bs->getMember())
+ return Child(*MemberOrErr);
+ else
+ return MemberOrErr.takeError();
+ }
+ }
+ return Optional<Child>();
+}
+
+// Returns true if archive file contains no member file.
+bool Archive::isEmpty() const { return Data.getBufferSize() == 8; }
+
+bool Archive::hasSymbolTable() const { return !SymbolTable.empty(); }
diff --git a/contrib/libs/llvm12/lib/Object/ArchiveWriter.cpp b/contrib/libs/llvm12/lib/Object/ArchiveWriter.cpp
index 3774fbdb7e..ce997464ca 100644
--- a/contrib/libs/llvm12/lib/Object/ArchiveWriter.cpp
+++ b/contrib/libs/llvm12/lib/Object/ArchiveWriter.cpp
@@ -1,327 +1,327 @@
-//===- ArchiveWriter.cpp - ar File Format implementation --------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the writeArchive function.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/ArchiveWriter.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/BinaryFormat/Magic.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Object/SymbolicFile.h"
-#include "llvm/Support/Alignment.h"
-#include "llvm/Support/EndianStream.h"
-#include "llvm/Support/Errc.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/Path.h"
+//===- ArchiveWriter.cpp - ar File Format implementation --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the writeArchive function.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/Alignment.h"
+#include "llvm/Support/EndianStream.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/SmallVectorMemoryBuffer.h"
-#include "llvm/Support/ToolOutputFile.h"
-#include "llvm/Support/raw_ostream.h"
-
-#include <map>
-
-#if !defined(_MSC_VER) && !defined(__MINGW32__)
-#include <unistd.h>
-#else
-#include <io.h>
-#endif
-
-using namespace llvm;
-
-NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
- : Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
- MemberName(BufRef.getBufferIdentifier()) {}
-
-Expected<NewArchiveMember>
-NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
- bool Deterministic) {
- Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef();
- if (!BufOrErr)
- return BufOrErr.takeError();
-
- NewArchiveMember M;
- M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
- M.MemberName = M.Buf->getBufferIdentifier();
- if (!Deterministic) {
- auto ModTimeOrErr = OldMember.getLastModified();
- if (!ModTimeOrErr)
- return ModTimeOrErr.takeError();
- M.ModTime = ModTimeOrErr.get();
- Expected<unsigned> UIDOrErr = OldMember.getUID();
- if (!UIDOrErr)
- return UIDOrErr.takeError();
- M.UID = UIDOrErr.get();
- Expected<unsigned> GIDOrErr = OldMember.getGID();
- if (!GIDOrErr)
- return GIDOrErr.takeError();
- M.GID = GIDOrErr.get();
- Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode();
- if (!AccessModeOrErr)
- return AccessModeOrErr.takeError();
- M.Perms = AccessModeOrErr.get();
- }
- return std::move(M);
-}
-
-Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
- bool Deterministic) {
- sys::fs::file_status Status;
- auto FDOrErr = sys::fs::openNativeFileForRead(FileName);
- if (!FDOrErr)
- return FDOrErr.takeError();
- sys::fs::file_t FD = *FDOrErr;
- assert(FD != sys::fs::kInvalidFile);
-
- if (auto EC = sys::fs::status(FD, Status))
- return errorCodeToError(EC);
-
- // Opening a directory doesn't make sense. Let it fail.
- // Linux cannot open directories with open(2), although
- // cygwin and *bsd can.
- if (Status.type() == sys::fs::file_type::directory_file)
- return errorCodeToError(make_error_code(errc::is_a_directory));
-
- ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
- MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false);
- if (!MemberBufferOrErr)
- return errorCodeToError(MemberBufferOrErr.getError());
-
- if (auto EC = sys::fs::closeFile(FD))
- return errorCodeToError(EC);
-
- NewArchiveMember M;
- M.Buf = std::move(*MemberBufferOrErr);
- M.MemberName = M.Buf->getBufferIdentifier();
- if (!Deterministic) {
- M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>(
- Status.getLastModificationTime());
- M.UID = Status.getUser();
- M.GID = Status.getGroup();
- M.Perms = Status.permissions();
- }
- return std::move(M);
-}
-
-template <typename T>
-static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
- uint64_t OldPos = OS.tell();
- OS << Data;
- unsigned SizeSoFar = OS.tell() - OldPos;
- assert(SizeSoFar <= Size && "Data doesn't fit in Size");
- OS.indent(Size - SizeSoFar);
-}
-
-static bool isDarwin(object::Archive::Kind Kind) {
- return Kind == object::Archive::K_DARWIN ||
- Kind == object::Archive::K_DARWIN64;
-}
-
-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:
- case object::Archive::K_DARWIN64:
- return true;
- case object::Archive::K_COFF:
- break;
- }
- llvm_unreachable("not supported for writting");
-}
-
-template <class T>
-static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
- support::endian::write(Out, Val,
- isBSDLike(Kind) ? support::little : support::big);
-}
-
-static void printRestOfMemberHeader(
- raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
- unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
- printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
-
- // 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_ostream &Out, StringRef Name,
- const sys::TimePoint<std::chrono::seconds> &ModTime,
- unsigned UID, unsigned GID, unsigned Perms,
- uint64_t Size) {
- printWithSpacePadding(Out, Twine(Name) + "/", 16);
- printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
-}
-
-static void
-printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
- const sys::TimePoint<std::chrono::seconds> &ModTime,
- unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
- uint64_t PosAfterHeader = Pos + 60 + Name.size();
- // Pad so that even 64 bit object files are aligned.
- unsigned Pad = offsetToAlignment(PosAfterHeader, Align(8));
- unsigned NameWithPadding = Name.size() + Pad;
- printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
- printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
- NameWithPadding + Size);
- Out << Name;
- while (Pad--)
- Out.write(uint8_t(0));
-}
-
-static bool useStringTable(bool Thin, StringRef Name) {
- return Thin || Name.size() >= 16 || Name.contains('/');
-}
-
-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");
-}
-
-static void
-printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
- StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
- bool Thin, const NewArchiveMember &M,
- sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) {
- if (isBSDLike(Kind))
- return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
- M.Perms, Size);
- if (!useStringTable(Thin, M.MemberName))
- return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
- M.Perms, Size);
- Out << '/';
- uint64_t NamePos;
- if (Thin) {
- NamePos = StringTable.tell();
- StringTable << M.MemberName << "/\n";
- } else {
- auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
- if (Insertion.second) {
- Insertion.first->second = StringTable.tell();
- StringTable << M.MemberName << "/\n";
- }
- NamePos = Insertion.first->second;
- }
- printWithSpacePadding(Out, NamePos, 15);
- printRestOfMemberHeader(Out, 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, Align(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) {
- using namespace std::chrono;
-
- if (!Deterministic)
- return time_point_cast<seconds>(system_clock::now());
- return sys::TimePoint<seconds>();
-}
-
-static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
- Expected<uint32_t> SymFlagsOrErr = S.getFlags();
- if (!SymFlagsOrErr)
- // TODO: Actually report errors helpfully.
- report_fatal_error(SymFlagsOrErr.takeError());
- if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
- return false;
- if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
- return false;
- if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
- return false;
- return true;
-}
-
-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);
-}
-
+#include "llvm/Support/ToolOutputFile.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <map>
+
+#if !defined(_MSC_VER) && !defined(__MINGW32__)
+#include <unistd.h>
+#else
+#include <io.h>
+#endif
+
+using namespace llvm;
+
+NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
+ : Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
+ MemberName(BufRef.getBufferIdentifier()) {}
+
+Expected<NewArchiveMember>
+NewArchiveMember::getOldMember(const object::Archive::Child &OldMember,
+ bool Deterministic) {
+ Expected<llvm::MemoryBufferRef> BufOrErr = OldMember.getMemoryBufferRef();
+ if (!BufOrErr)
+ return BufOrErr.takeError();
+
+ NewArchiveMember M;
+ M.Buf = MemoryBuffer::getMemBuffer(*BufOrErr, false);
+ M.MemberName = M.Buf->getBufferIdentifier();
+ if (!Deterministic) {
+ auto ModTimeOrErr = OldMember.getLastModified();
+ if (!ModTimeOrErr)
+ return ModTimeOrErr.takeError();
+ M.ModTime = ModTimeOrErr.get();
+ Expected<unsigned> UIDOrErr = OldMember.getUID();
+ if (!UIDOrErr)
+ return UIDOrErr.takeError();
+ M.UID = UIDOrErr.get();
+ Expected<unsigned> GIDOrErr = OldMember.getGID();
+ if (!GIDOrErr)
+ return GIDOrErr.takeError();
+ M.GID = GIDOrErr.get();
+ Expected<sys::fs::perms> AccessModeOrErr = OldMember.getAccessMode();
+ if (!AccessModeOrErr)
+ return AccessModeOrErr.takeError();
+ M.Perms = AccessModeOrErr.get();
+ }
+ return std::move(M);
+}
+
+Expected<NewArchiveMember> NewArchiveMember::getFile(StringRef FileName,
+ bool Deterministic) {
+ sys::fs::file_status Status;
+ auto FDOrErr = sys::fs::openNativeFileForRead(FileName);
+ if (!FDOrErr)
+ return FDOrErr.takeError();
+ sys::fs::file_t FD = *FDOrErr;
+ assert(FD != sys::fs::kInvalidFile);
+
+ if (auto EC = sys::fs::status(FD, Status))
+ return errorCodeToError(EC);
+
+ // Opening a directory doesn't make sense. Let it fail.
+ // Linux cannot open directories with open(2), although
+ // cygwin and *bsd can.
+ if (Status.type() == sys::fs::file_type::directory_file)
+ return errorCodeToError(make_error_code(errc::is_a_directory));
+
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MemberBufferOrErr =
+ MemoryBuffer::getOpenFile(FD, FileName, Status.getSize(), false);
+ if (!MemberBufferOrErr)
+ return errorCodeToError(MemberBufferOrErr.getError());
+
+ if (auto EC = sys::fs::closeFile(FD))
+ return errorCodeToError(EC);
+
+ NewArchiveMember M;
+ M.Buf = std::move(*MemberBufferOrErr);
+ M.MemberName = M.Buf->getBufferIdentifier();
+ if (!Deterministic) {
+ M.ModTime = std::chrono::time_point_cast<std::chrono::seconds>(
+ Status.getLastModificationTime());
+ M.UID = Status.getUser();
+ M.GID = Status.getGroup();
+ M.Perms = Status.permissions();
+ }
+ return std::move(M);
+}
+
+template <typename T>
+static void printWithSpacePadding(raw_ostream &OS, T Data, unsigned Size) {
+ uint64_t OldPos = OS.tell();
+ OS << Data;
+ unsigned SizeSoFar = OS.tell() - OldPos;
+ assert(SizeSoFar <= Size && "Data doesn't fit in Size");
+ OS.indent(Size - SizeSoFar);
+}
+
+static bool isDarwin(object::Archive::Kind Kind) {
+ return Kind == object::Archive::K_DARWIN ||
+ Kind == object::Archive::K_DARWIN64;
+}
+
+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:
+ case object::Archive::K_DARWIN64:
+ return true;
+ case object::Archive::K_COFF:
+ break;
+ }
+ llvm_unreachable("not supported for writting");
+}
+
+template <class T>
+static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
+ support::endian::write(Out, Val,
+ isBSDLike(Kind) ? support::little : support::big);
+}
+
+static void printRestOfMemberHeader(
+ raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
+ unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
+ printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
+
+ // 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_ostream &Out, StringRef Name,
+ const sys::TimePoint<std::chrono::seconds> &ModTime,
+ unsigned UID, unsigned GID, unsigned Perms,
+ uint64_t Size) {
+ printWithSpacePadding(Out, Twine(Name) + "/", 16);
+ printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
+}
+
+static void
+printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
+ const sys::TimePoint<std::chrono::seconds> &ModTime,
+ unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
+ uint64_t PosAfterHeader = Pos + 60 + Name.size();
+ // Pad so that even 64 bit object files are aligned.
+ unsigned Pad = offsetToAlignment(PosAfterHeader, Align(8));
+ unsigned NameWithPadding = Name.size() + Pad;
+ printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
+ printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
+ NameWithPadding + Size);
+ Out << Name;
+ while (Pad--)
+ Out.write(uint8_t(0));
+}
+
+static bool useStringTable(bool Thin, StringRef Name) {
+ return Thin || Name.size() >= 16 || Name.contains('/');
+}
+
+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");
+}
+
+static void
+printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
+ StringMap<uint64_t> &MemberNames, object::Archive::Kind Kind,
+ bool Thin, const NewArchiveMember &M,
+ sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) {
+ if (isBSDLike(Kind))
+ return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
+ M.Perms, Size);
+ if (!useStringTable(Thin, M.MemberName))
+ return printGNUSmallMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
+ M.Perms, Size);
+ Out << '/';
+ uint64_t NamePos;
+ if (Thin) {
+ NamePos = StringTable.tell();
+ StringTable << M.MemberName << "/\n";
+ } else {
+ auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
+ if (Insertion.second) {
+ Insertion.first->second = StringTable.tell();
+ StringTable << M.MemberName << "/\n";
+ }
+ NamePos = Insertion.first->second;
+ }
+ printWithSpacePadding(Out, NamePos, 15);
+ printRestOfMemberHeader(Out, 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, Align(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) {
+ using namespace std::chrono;
+
+ if (!Deterministic)
+ return time_point_cast<seconds>(system_clock::now());
+ return sys::TimePoint<seconds>();
+}
+
+static bool isArchiveSymbol(const object::BasicSymbolRef &S) {
+ Expected<uint32_t> SymFlagsOrErr = S.getFlags();
+ if (!SymFlagsOrErr)
+ // TODO: Actually report errors helpfully.
+ report_fatal_error(SymFlagsOrErr.takeError());
+ if (*SymFlagsOrErr & object::SymbolRef::SF_FormatSpecific)
+ return false;
+ if (!(*SymFlagsOrErr & object::SymbolRef::SF_Global))
+ return false;
+ if (*SymFlagsOrErr & object::SymbolRef::SF_Undefined)
+ return false;
+ return true;
+}
+
+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);
+}
+
static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
uint64_t NumSyms, uint64_t OffsetSize,
StringRef StringTable,
uint32_t *Padding = nullptr) {
assert((OffsetSize == 4 || OffsetSize == 8) && "Unsupported OffsetSize");
uint64_t Size = OffsetSize; // Number of entries
- if (isBSDLike(Kind))
- Size += NumSyms * OffsetSize * 2; // Table
- else
- Size += NumSyms * OffsetSize; // Table
- if (isBSDLike(Kind))
- Size += OffsetSize; // 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.
+ if (isBSDLike(Kind))
+ Size += NumSyms * OffsetSize * 2; // Table
+ else
+ Size += NumSyms * OffsetSize; // Table
+ if (isBSDLike(Kind))
+ Size += OffsetSize; // 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.
uint32_t Pad = offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
- Size += Pad;
+ Size += Pad;
if (Padding)
*Padding = Pad;
return Size;
}
-
+
static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
bool Deterministic, uint64_t Size) {
- if (isBSDLike(Kind)) {
- const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
- printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
- Size);
- } else {
- const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
- printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
- }
+ if (isBSDLike(Kind)) {
+ const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
+ printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
+ Size);
+ } else {
+ const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
+ printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
+ }
}
-
+
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
bool Deterministic, ArrayRef<MemberData> Members,
StringRef StringTable) {
@@ -339,173 +339,173 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize, StringTable, &Pad);
writeSymbolTableHeader(Out, Kind, Deterministic, Size);
- uint64_t Pos = Out.tell() + Size;
-
- if (isBSDLike(Kind))
- printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
- else
- printNBits(Out, Kind, NumSyms);
-
- for (const MemberData &M : Members) {
- for (unsigned StringOffset : M.Symbols) {
- if (isBSDLike(Kind))
- printNBits(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
- printNBits(Out, Kind, StringTable.size());
- Out << StringTable;
-
- while (Pad--)
- Out.write(uint8_t(0));
-}
-
-static Expected<std::vector<unsigned>>
-getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
- std::vector<unsigned> Ret;
-
- // In the scenario when LLVMContext is populated SymbolicFile will contain a
- // reference to it, thus SymbolicFile should be destroyed first.
- LLVMContext Context;
- std::unique_ptr<object::SymbolicFile> Obj;
+ uint64_t Pos = Out.tell() + Size;
+
+ if (isBSDLike(Kind))
+ printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
+ else
+ printNBits(Out, Kind, NumSyms);
+
+ for (const MemberData &M : Members) {
+ for (unsigned StringOffset : M.Symbols) {
+ if (isBSDLike(Kind))
+ printNBits(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
+ printNBits(Out, Kind, StringTable.size());
+ Out << StringTable;
+
+ while (Pad--)
+ Out.write(uint8_t(0));
+}
+
+static Expected<std::vector<unsigned>>
+getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
+ std::vector<unsigned> Ret;
+
+ // In the scenario when LLVMContext is populated SymbolicFile will contain a
+ // reference to it, thus SymbolicFile should be destroyed first.
+ LLVMContext Context;
+ std::unique_ptr<object::SymbolicFile> Obj;
const file_magic Type = identify_magic(Buf.getBuffer());
// Treat unsupported file types as having no symbols.
if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
return Ret;
if (Type == file_magic::bitcode) {
- auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
- Buf, file_magic::bitcode, &Context);
+ auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
+ Buf, file_magic::bitcode, &Context);
if (!ObjOrErr)
return ObjOrErr.takeError();
- Obj = std::move(*ObjOrErr);
- } else {
- auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
+ Obj = std::move(*ObjOrErr);
+ } else {
+ auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
if (!ObjOrErr)
return ObjOrErr.takeError();
- Obj = std::move(*ObjOrErr);
- }
-
- HasObject = true;
- for (const object::BasicSymbolRef &S : Obj->symbols()) {
- if (!isArchiveSymbol(S))
- continue;
- Ret.push_back(SymNames.tell());
- if (Error E = S.printName(SymNames))
- return std::move(E);
- SymNames << '\0';
- }
- return Ret;
-}
-
-static Expected<std::vector<MemberData>>
-computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
- object::Archive::Kind Kind, bool Thin, bool Deterministic,
+ Obj = std::move(*ObjOrErr);
+ }
+
+ HasObject = true;
+ for (const object::BasicSymbolRef &S : Obj->symbols()) {
+ if (!isArchiveSymbol(S))
+ continue;
+ Ret.push_back(SymNames.tell());
+ if (Error E = S.printName(SymNames))
+ return std::move(E);
+ SymNames << '\0';
+ }
+ return Ret;
+}
+
+static Expected<std::vector<MemberData>>
+computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
+ object::Archive::Kind Kind, bool Thin, bool Deterministic,
bool NeedSymbols, ArrayRef<NewArchiveMember> NewMembers) {
- static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
-
- // This ignores the symbol table, but we only need the value mod 8 and the
- // symbol table is aligned to be a multiple of 8 bytes
- uint64_t Pos = 0;
-
- std::vector<MemberData> Ret;
- bool HasObject = false;
-
- // Deduplicate long member names in the string table and reuse earlier name
- // offsets. This especially saves space for COFF Import libraries where all
- // members have the same name.
- StringMap<uint64_t> MemberNames;
-
- // UniqueTimestamps is a special case to improve debugging on Darwin:
- //
- // The Darwin linker does not link debug info into the final
- // binary. Instead, it emits entries of type N_OSO in in the output
- // binary's symbol table, containing references to the linked-in
- // object files. Using that reference, the debugger can read the
- // debug data directly from the object files. Alternatively, an
- // invocation of 'dsymutil' will link the debug data from the object
- // files into a dSYM bundle, which can be loaded by the debugger,
- // instead of the object files.
- //
- // For an object file, the N_OSO entries contain the absolute path
- // path to the file, and the file's timestamp. For an object
- // included in an archive, the path is formatted like
- // "/absolute/path/to/archive.a(member.o)", and the timestamp is the
- // archive member's timestamp, rather than the archive's timestamp.
- //
- // However, this doesn't always uniquely identify an object within
- // an archive -- an archive file can have multiple entries with the
- // same filename. (This will happen commonly if the original object
- // files started in different directories.) The only way they get
- // distinguished, then, is via the timestamp. But this process is
- // unable to find the correct object file in the archive when there
- // are two files of the same name and timestamp.
- //
- // Additionally, timestamp==0 is treated specially, and causes the
- // timestamp to be ignored as a match criteria.
- //
- // That will "usually" work out okay when creating an archive not in
- // deterministic timestamp mode, because the objects will probably
- // have been created at different timestamps.
- //
- // To ameliorate this problem, in deterministic archive mode (which
- // is the default), on Darwin we will emit a unique non-zero
- // timestamp for each entry with a duplicated name. This is still
- // deterministic: the only thing affecting that timestamp is the
- // order of the files in the resultant archive.
- //
- // See also the functions that handle the lookup:
- // in lldb: ObjectContainerBSDArchive::Archive::FindObject()
- // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
- bool UniqueTimestamps = Deterministic && isDarwin(Kind);
- std::map<StringRef, unsigned> FilenameCount;
- if (UniqueTimestamps) {
- for (const NewArchiveMember &M : NewMembers)
- FilenameCount[M.MemberName]++;
- for (auto &Entry : FilenameCount)
- Entry.second = Entry.second > 1 ? 1 : 0;
- }
-
- for (const NewArchiveMember &M : NewMembers) {
- std::string Header;
- raw_string_ostream Out(Header);
-
- 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.
- unsigned MemberPadding =
- isDarwin(Kind) ? offsetToAlignment(Data.size(), Align(8)) : 0;
- unsigned TailPadding =
- offsetToAlignment(Data.size() + MemberPadding, Align(2));
- StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
-
- sys::TimePoint<std::chrono::seconds> ModTime;
- if (UniqueTimestamps)
- // Increment timestamp for each file of a given name.
- ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
- else
- ModTime = M.ModTime;
-
- uint64_t Size = Buf.getBufferSize() + MemberPadding;
- if (Size > object::Archive::MaxMemberSize) {
- std::string StringMsg =
- "File " + M.MemberName.str() + " exceeds size limit";
- return make_error<object::GenericBinaryError>(
- std::move(StringMsg), object::object_error::parse_failed);
- }
-
- printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
- ModTime, Size);
- Out.flush();
-
+ static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
+
+ // This ignores the symbol table, but we only need the value mod 8 and the
+ // symbol table is aligned to be a multiple of 8 bytes
+ uint64_t Pos = 0;
+
+ std::vector<MemberData> Ret;
+ bool HasObject = false;
+
+ // Deduplicate long member names in the string table and reuse earlier name
+ // offsets. This especially saves space for COFF Import libraries where all
+ // members have the same name.
+ StringMap<uint64_t> MemberNames;
+
+ // UniqueTimestamps is a special case to improve debugging on Darwin:
+ //
+ // The Darwin linker does not link debug info into the final
+ // binary. Instead, it emits entries of type N_OSO in in the output
+ // binary's symbol table, containing references to the linked-in
+ // object files. Using that reference, the debugger can read the
+ // debug data directly from the object files. Alternatively, an
+ // invocation of 'dsymutil' will link the debug data from the object
+ // files into a dSYM bundle, which can be loaded by the debugger,
+ // instead of the object files.
+ //
+ // For an object file, the N_OSO entries contain the absolute path
+ // path to the file, and the file's timestamp. For an object
+ // included in an archive, the path is formatted like
+ // "/absolute/path/to/archive.a(member.o)", and the timestamp is the
+ // archive member's timestamp, rather than the archive's timestamp.
+ //
+ // However, this doesn't always uniquely identify an object within
+ // an archive -- an archive file can have multiple entries with the
+ // same filename. (This will happen commonly if the original object
+ // files started in different directories.) The only way they get
+ // distinguished, then, is via the timestamp. But this process is
+ // unable to find the correct object file in the archive when there
+ // are two files of the same name and timestamp.
+ //
+ // Additionally, timestamp==0 is treated specially, and causes the
+ // timestamp to be ignored as a match criteria.
+ //
+ // That will "usually" work out okay when creating an archive not in
+ // deterministic timestamp mode, because the objects will probably
+ // have been created at different timestamps.
+ //
+ // To ameliorate this problem, in deterministic archive mode (which
+ // is the default), on Darwin we will emit a unique non-zero
+ // timestamp for each entry with a duplicated name. This is still
+ // deterministic: the only thing affecting that timestamp is the
+ // order of the files in the resultant archive.
+ //
+ // See also the functions that handle the lookup:
+ // in lldb: ObjectContainerBSDArchive::Archive::FindObject()
+ // in llvm/tools/dsymutil: BinaryHolder::GetArchiveMemberBuffers().
+ bool UniqueTimestamps = Deterministic && isDarwin(Kind);
+ std::map<StringRef, unsigned> FilenameCount;
+ if (UniqueTimestamps) {
+ for (const NewArchiveMember &M : NewMembers)
+ FilenameCount[M.MemberName]++;
+ for (auto &Entry : FilenameCount)
+ Entry.second = Entry.second > 1 ? 1 : 0;
+ }
+
+ for (const NewArchiveMember &M : NewMembers) {
+ std::string Header;
+ raw_string_ostream Out(Header);
+
+ 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.
+ unsigned MemberPadding =
+ isDarwin(Kind) ? offsetToAlignment(Data.size(), Align(8)) : 0;
+ unsigned TailPadding =
+ offsetToAlignment(Data.size() + MemberPadding, Align(2));
+ StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
+
+ sys::TimePoint<std::chrono::seconds> ModTime;
+ if (UniqueTimestamps)
+ // Increment timestamp for each file of a given name.
+ ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
+ else
+ ModTime = M.ModTime;
+
+ uint64_t Size = Buf.getBufferSize() + MemberPadding;
+ if (Size > object::Archive::MaxMemberSize) {
+ std::string StringMsg =
+ "File " + M.MemberName.str() + " exceeds size limit";
+ return make_error<object::GenericBinaryError>(
+ std::move(StringMsg), object::object_error::parse_failed);
+ }
+
+ printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
+ ModTime, Size);
+ Out.flush();
+
std::vector<unsigned> Symbols;
if (NeedSymbols) {
Expected<std::vector<unsigned>> SymbolsOrErr =
@@ -514,95 +514,95 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
return std::move(E);
Symbols = std::move(*SymbolsOrErr);
}
-
- Pos += Header.size() + Data.size() + Padding.size();
+
+ 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;
-}
-
-namespace llvm {
-
-static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) {
- SmallString<128> Ret = P;
- std::error_code Err = sys::fs::make_absolute(Ret);
- if (Err)
- return Err;
- sys::path::remove_dots(Ret, /*removedotdot*/ true);
- return Ret;
-}
-
-// Compute the relative path from From to To.
-Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
- ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To);
- ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From);
- if (!PathToOrErr || !DirFromOrErr)
- return errorCodeToError(std::error_code(errno, std::generic_category()));
-
- const SmallString<128> &PathTo = *PathToOrErr;
- const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr);
-
- // Can't construct a relative path between different roots
- if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom))
- return sys::path::convert_to_slash(PathTo);
-
- // Skip common prefixes
- auto FromTo =
- std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom),
- sys::path::begin(PathTo));
- auto FromI = FromTo.first;
- auto ToI = FromTo.second;
-
- // Construct relative path
- SmallString<128> Relative;
- for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
- sys::path::append(Relative, sys::path::Style::posix, "..");
-
- for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI)
- sys::path::append(Relative, sys::path::Style::posix, *ToI);
-
- return std::string(Relative.str());
-}
-
+ }
+ // 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;
+}
+
+namespace llvm {
+
+static ErrorOr<SmallString<128>> canonicalizePath(StringRef P) {
+ SmallString<128> Ret = P;
+ std::error_code Err = sys::fs::make_absolute(Ret);
+ if (Err)
+ return Err;
+ sys::path::remove_dots(Ret, /*removedotdot*/ true);
+ return Ret;
+}
+
+// Compute the relative path from From to To.
+Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
+ ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To);
+ ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From);
+ if (!PathToOrErr || !DirFromOrErr)
+ return errorCodeToError(std::error_code(errno, std::generic_category()));
+
+ const SmallString<128> &PathTo = *PathToOrErr;
+ const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr);
+
+ // Can't construct a relative path between different roots
+ if (sys::path::root_name(PathTo) != sys::path::root_name(DirFrom))
+ return sys::path::convert_to_slash(PathTo);
+
+ // Skip common prefixes
+ auto FromTo =
+ std::mismatch(sys::path::begin(DirFrom), sys::path::end(DirFrom),
+ sys::path::begin(PathTo));
+ auto FromI = FromTo.first;
+ auto ToI = FromTo.second;
+
+ // Construct relative path
+ SmallString<128> Relative;
+ for (auto FromE = sys::path::end(DirFrom); FromI != FromE; ++FromI)
+ sys::path::append(Relative, sys::path::Style::posix, "..");
+
+ for (auto ToE = sys::path::end(PathTo); ToI != ToE; ++ToI)
+ sys::path::append(Relative, sys::path::Style::posix, *ToI);
+
+ return std::string(Relative.str());
+}
+
static Error writeArchiveToStream(raw_ostream &Out,
ArrayRef<NewArchiveMember> NewMembers,
bool WriteSymtab, object::Archive::Kind Kind,
bool Deterministic, bool Thin) {
- assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
-
- SmallString<0> SymNamesBuf;
- raw_svector_ostream SymNames(SymNamesBuf);
- SmallString<0> StringTableBuf;
- raw_svector_ostream StringTable(StringTableBuf);
-
+ assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
+
+ SmallString<0> SymNamesBuf;
+ raw_svector_ostream SymNames(SymNamesBuf);
+ SmallString<0> StringTableBuf;
+ raw_svector_ostream StringTable(StringTableBuf);
+
Expected<std::vector<MemberData>> DataOrErr =
computeMemberData(StringTable, SymNames, Kind, Thin, Deterministic,
WriteSymtab, NewMembers);
- if (Error E = DataOrErr.takeError())
- return E;
- std::vector<MemberData> &Data = *DataOrErr;
-
- 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) {
+ if (Error E = DataOrErr.takeError())
+ return E;
+ std::vector<MemberData> &Data = *DataOrErr;
+
+ 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 = 8; // For the file signature.
- uint64_t LastOffset = MaxOffset;
+ uint64_t LastOffset = MaxOffset;
uint64_t NumSyms = 0;
- for (const auto &M : Data) {
- // Record the start of the member's offset
- LastOffset = MaxOffset;
- // Account for the size of each part associated with the member.
- MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
+ for (const auto &M : Data) {
+ // Record the start of the member's offset
+ LastOffset = MaxOffset;
+ // Account for the size of each part associated with the member.
+ MaxOffset += M.Header.size() + M.Data.size() + M.Padding.size();
NumSyms += M.Symbols.size();
- }
-
+ }
+
// We assume 32-bit offsets to see if 32-bit symbols are possible or not.
uint64_t SymtabSize = computeSymbolTableSize(Kind, NumSyms, 4, SymNamesBuf);
auto computeSymbolTableHeaderSize =
@@ -614,44 +614,44 @@ static Error writeArchiveToStream(raw_ostream &Out,
};
LastOffset += computeSymbolTableHeaderSize() + SymtabSize;
- // The SYM64 format is used when an archive's member offsets are larger than
- // 32-bits can hold. The need for this shift in format is detected by
- // 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 environment variable to pretend like the
- // cutoff happens before 32-bits and instead happens at some much smaller
- // value.
+ // 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 environment variable to pretend like the
+ // cutoff happens before 32-bits and instead happens at some much smaller
+ // value.
uint64_t Sym64Threshold = 1ULL << 32;
- const char *Sym64Env = std::getenv("SYM64_THRESHOLD");
- if (Sym64Env)
- StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
-
- // If LastOffset isn't going to fit in a 32-bit varible we need to switch
- // to 64-bit. Note that the file can be larger than 4GB as long as the last
- // member starts before the 4GB offset.
+ const char *Sym64Env = std::getenv("SYM64_THRESHOLD");
+ if (Sym64Env)
+ StringRef(Sym64Env).getAsInteger(10, Sym64Threshold);
+
+ // If LastOffset isn't going to fit in a 32-bit varible we need to switch
+ // to 64-bit. Note that the file can be larger than 4GB as long as the last
+ // member starts before the 4GB offset.
if (LastOffset >= Sym64Threshold) {
- if (Kind == object::Archive::K_DARWIN)
- Kind = object::Archive::K_DARWIN64;
- else
- Kind = object::Archive::K_GNU64;
- }
- }
-
- 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();
+ if (Kind == object::Archive::K_DARWIN)
+ Kind = object::Archive::K_DARWIN64;
+ else
+ Kind = object::Archive::K_GNU64;
+ }
+ }
+
+ 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();
return Error::success();
}
-
+
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
bool WriteSymtab, object::Archive::Kind Kind,
bool Deterministic, bool Thin,
@@ -669,21 +669,21 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
return E;
}
- // At this point, we no longer need whatever backing memory
- // was used to generate the NewMembers. On Windows, this buffer
- // could be a mapped view of the file we want to replace (if
- // we're updating an existing archive, say). In that case, the
- // rename would still succeed, but it would leave behind a
- // temporary file (actually the original file renamed) because
- // a file cannot be deleted while there's a handle open on it,
- // only renamed. So by freeing this buffer, this ensures that
- // the last open handle on the destination file, if any, is
- // closed before we attempt to rename.
- OldArchiveBuf.reset();
-
- return Temp->keep(ArcName);
-}
-
+ // At this point, we no longer need whatever backing memory
+ // was used to generate the NewMembers. On Windows, this buffer
+ // could be a mapped view of the file we want to replace (if
+ // we're updating an existing archive, say). In that case, the
+ // rename would still succeed, but it would leave behind a
+ // temporary file (actually the original file renamed) because
+ // a file cannot be deleted while there's a handle open on it,
+ // only renamed. So by freeing this buffer, this ensures that
+ // the last open handle on the destination file, if any, is
+ // closed before we attempt to rename.
+ OldArchiveBuf.reset();
+
+ return Temp->keep(ArcName);
+}
+
Expected<std::unique_ptr<MemoryBuffer>>
writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab,
object::Archive::Kind Kind, bool Deterministic,
@@ -699,4 +699,4 @@ writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab,
std::move(ArchiveBufferVector));
}
-} // namespace llvm
+} // namespace llvm
diff --git a/contrib/libs/llvm12/lib/Object/Binary.cpp b/contrib/libs/llvm12/lib/Object/Binary.cpp
index 66a5abc0c8..e741cbba28 100644
--- a/contrib/libs/llvm12/lib/Object/Binary.cpp
+++ b/contrib/libs/llvm12/lib/Object/Binary.cpp
@@ -1,113 +1,113 @@
-//===- Binary.cpp - A generic binary file ---------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the Binary class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/Binary.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/BinaryFormat/Magic.h"
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/MachOUniversal.h"
-#include "llvm/Object/Minidump.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Object/TapiUniversal.h"
-#include "llvm/Object/WindowsResource.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include <algorithm>
-#include <memory>
-#include <system_error>
-
-using namespace llvm;
-using namespace object;
-
-Binary::~Binary() = default;
-
-Binary::Binary(unsigned int Type, MemoryBufferRef Source)
- : TypeID(Type), Data(Source) {}
-
-StringRef Binary::getData() const { return Data.getBuffer(); }
-
-StringRef Binary::getFileName() const { return Data.getBufferIdentifier(); }
-
-MemoryBufferRef Binary::getMemoryBufferRef() const { return Data; }
-
-Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
+//===- Binary.cpp - A generic binary file ---------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Binary class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Binary.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/Minidump.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/TapiUniversal.h"
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <memory>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+
+Binary::~Binary() = default;
+
+Binary::Binary(unsigned int Type, MemoryBufferRef Source)
+ : TypeID(Type), Data(Source) {}
+
+StringRef Binary::getData() const { return Data.getBuffer(); }
+
+StringRef Binary::getFileName() const { return Data.getBufferIdentifier(); }
+
+MemoryBufferRef Binary::getMemoryBufferRef() const { return Data; }
+
+Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
LLVMContext *Context,
bool InitContent) {
- file_magic Type = identify_magic(Buffer.getBuffer());
-
- switch (Type) {
- case file_magic::archive:
- return Archive::create(Buffer);
- case file_magic::elf:
- case file_magic::elf_relocatable:
- case file_magic::elf_executable:
- case file_magic::elf_shared_object:
- case file_magic::elf_core:
- case file_magic::macho_object:
- case file_magic::macho_executable:
- case file_magic::macho_fixed_virtual_memory_shared_lib:
- case file_magic::macho_core:
- case file_magic::macho_preload_executable:
- case file_magic::macho_dynamically_linked_shared_lib:
- case file_magic::macho_dynamic_linker:
- case file_magic::macho_bundle:
- case file_magic::macho_dynamically_linked_shared_lib_stub:
- case file_magic::macho_dsym_companion:
- case file_magic::macho_kext_bundle:
- case file_magic::coff_object:
- case file_magic::coff_import_library:
- case file_magic::pecoff_executable:
- case file_magic::bitcode:
- case file_magic::xcoff_object_32:
- case file_magic::xcoff_object_64:
- case file_magic::wasm_object:
+ file_magic Type = identify_magic(Buffer.getBuffer());
+
+ switch (Type) {
+ case file_magic::archive:
+ return Archive::create(Buffer);
+ case file_magic::elf:
+ case file_magic::elf_relocatable:
+ case file_magic::elf_executable:
+ case file_magic::elf_shared_object:
+ case file_magic::elf_core:
+ case file_magic::macho_object:
+ case file_magic::macho_executable:
+ case file_magic::macho_fixed_virtual_memory_shared_lib:
+ case file_magic::macho_core:
+ case file_magic::macho_preload_executable:
+ case file_magic::macho_dynamically_linked_shared_lib:
+ case file_magic::macho_dynamic_linker:
+ case file_magic::macho_bundle:
+ case file_magic::macho_dynamically_linked_shared_lib_stub:
+ case file_magic::macho_dsym_companion:
+ case file_magic::macho_kext_bundle:
+ case file_magic::coff_object:
+ case file_magic::coff_import_library:
+ case file_magic::pecoff_executable:
+ case file_magic::bitcode:
+ case file_magic::xcoff_object_32:
+ case file_magic::xcoff_object_64:
+ case file_magic::wasm_object:
return ObjectFile::createSymbolicFile(Buffer, Type, Context, InitContent);
- case file_magic::macho_universal_binary:
- return MachOUniversalBinary::create(Buffer);
- case file_magic::windows_resource:
- return WindowsResource::createWindowsResource(Buffer);
- case file_magic::pdb:
- // PDB does not support the Binary interface.
- return errorCodeToError(object_error::invalid_file_type);
- case file_magic::unknown:
- case file_magic::coff_cl_gl_object:
- // Unrecognized object file format.
- return errorCodeToError(object_error::invalid_file_type);
- case file_magic::minidump:
- return MinidumpFile::create(Buffer);
- case file_magic::tapi_file:
- return TapiUniversal::create(Buffer);
- }
- llvm_unreachable("Unexpected Binary File Type");
-}
-
+ case file_magic::macho_universal_binary:
+ return MachOUniversalBinary::create(Buffer);
+ case file_magic::windows_resource:
+ return WindowsResource::createWindowsResource(Buffer);
+ case file_magic::pdb:
+ // PDB does not support the Binary interface.
+ return errorCodeToError(object_error::invalid_file_type);
+ case file_magic::unknown:
+ case file_magic::coff_cl_gl_object:
+ // Unrecognized object file format.
+ return errorCodeToError(object_error::invalid_file_type);
+ case file_magic::minidump:
+ return MinidumpFile::create(Buffer);
+ case file_magic::tapi_file:
+ return TapiUniversal::create(Buffer);
+ }
+ llvm_unreachable("Unexpected Binary File Type");
+}
+
Expected<OwningBinary<Binary>>
object::createBinary(StringRef Path, LLVMContext *Context, bool InitContent) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
- MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
- /*RequiresNullTerminator=*/false);
- if (std::error_code EC = FileOrErr.getError())
- return errorCodeToError(EC);
- std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
-
- Expected<std::unique_ptr<Binary>> BinOrErr =
+ ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
+ MemoryBuffer::getFileOrSTDIN(Path, /*FileSize=*/-1,
+ /*RequiresNullTerminator=*/false);
+ if (std::error_code EC = FileOrErr.getError())
+ return errorCodeToError(EC);
+ std::unique_ptr<MemoryBuffer> &Buffer = FileOrErr.get();
+
+ Expected<std::unique_ptr<Binary>> BinOrErr =
createBinary(Buffer->getMemBufferRef(), Context, InitContent);
- if (!BinOrErr)
- return BinOrErr.takeError();
- std::unique_ptr<Binary> &Bin = BinOrErr.get();
-
- return OwningBinary<Binary>(std::move(Bin), std::move(Buffer));
-}
+ if (!BinOrErr)
+ return BinOrErr.takeError();
+ std::unique_ptr<Binary> &Bin = BinOrErr.get();
+
+ return OwningBinary<Binary>(std::move(Bin), std::move(Buffer));
+}
diff --git a/contrib/libs/llvm12/lib/Object/COFFImportFile.cpp b/contrib/libs/llvm12/lib/Object/COFFImportFile.cpp
index 1244cabe75..69bbf70b43 100644
--- a/contrib/libs/llvm12/lib/Object/COFFImportFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/COFFImportFile.cpp
@@ -1,625 +1,625 @@
-//===- COFFImportFile.cpp - COFF short import file implementation ---------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the writeImportLibrary function.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/COFFImportFile.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/Object/Archive.h"
-#include "llvm/Object/ArchiveWriter.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/Path.h"
-
-#include <cstdint>
-#include <string>
-#include <vector>
-
-using namespace llvm::COFF;
-using namespace llvm::object;
-using namespace llvm;
-
-namespace llvm {
-namespace object {
-
-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:
- case IMAGE_FILE_MACHINE_I386:
- return true;
- }
-}
-
-static uint16_t getImgRelRelocation(MachineTypes Machine) {
- switch (Machine) {
- default:
- llvm_unreachable("unsupported machine");
- case IMAGE_FILE_MACHINE_AMD64:
- 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;
- }
-}
-
-template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
- size_t S = B.size();
- B.resize(S + sizeof(T));
- memcpy(&B[S], &Data, sizeof(T));
-}
-
-static void writeStringTable(std::vector<uint8_t> &B,
- ArrayRef<const std::string> Strings) {
- // The COFF string table consists of a 4-byte value which is the size of the
- // table, including the length field itself. This value is followed by the
- // string content itself, which is an array of null-terminated C-style
- // strings. The termination is important as they are referenced to by offset
- // by the symbol entity in the file format.
-
- size_t Pos = B.size();
- size_t Offset = B.size();
-
- // Skip over the length field, we will fill it in later as we will have
- // computed the length while emitting the string content itself.
- Pos += sizeof(uint32_t);
-
- for (const auto &S : Strings) {
- B.resize(Pos + S.length() + 1);
- strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
- Pos += S.length() + 1;
- }
-
- // Backfill the length of the table now that it has been computed.
- support::ulittle32_t Length(B.size() - Offset);
- support::endian::write32le(&B[Offset], Length);
-}
-
-static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
- MachineTypes Machine, bool MinGW) {
- // A decorated stdcall function in MSVC is exported with the
- // type IMPORT_NAME, and the exported function name includes the
- // the leading underscore. In MinGW on the other hand, a decorated
- // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
- // See the comment in isDecorated in COFFModuleDefinition.cpp for more
- // details.
- if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW)
- return IMPORT_NAME;
- if (Sym != ExtName)
- return IMPORT_NAME_UNDECORATE;
- if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
- return IMPORT_NAME_NOPREFIX;
- return IMPORT_NAME;
-}
-
-static Expected<std::string> replace(StringRef S, StringRef From,
- StringRef To) {
- size_t Pos = S.find(From);
-
- // From and To may be mangled, but substrings in S may not.
- if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
- From = From.substr(1);
- To = To.substr(1);
- Pos = S.find(From);
- }
-
- if (Pos == StringRef::npos) {
- return make_error<StringError>(
- StringRef(Twine(S + ": replacing '" + From +
- "' with '" + To + "' failed").str()), object_error::parse_failed);
- }
-
- return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
-}
-
-static const std::string NullImportDescriptorSymbolName =
- "__NULL_IMPORT_DESCRIPTOR";
-
-namespace {
-// This class constructs various small object files necessary to support linking
-// symbols imported from a DLL. The contents are pretty strictly defined and
-// nearly entirely static. The details of the structures files are defined in
-// WINNT.h and the PE/COFF specification.
-class ObjectFactory {
- using u16 = support::ulittle16_t;
- using u32 = support::ulittle32_t;
- MachineTypes Machine;
- BumpPtrAllocator Alloc;
- StringRef ImportName;
- StringRef Library;
- std::string ImportDescriptorSymbolName;
- std::string NullThunkSymbolName;
-
-public:
- ObjectFactory(StringRef S, MachineTypes M)
- : Machine(M), ImportName(S), Library(S.drop_back(4)),
- ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
- NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
-
- // Creates an Import Descriptor. This is a small object file which contains a
- // reference to the terminators and contains the library name (entry) for the
- // import name table. It will force the linker to construct the necessary
- // structure to import symbols from the DLL.
- NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
-
- // Creates a NULL import descriptor. This is a small object file whcih
- // contains a NULL import descriptor. It is used to terminate the imports
- // from a specific DLL.
- NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
-
- // Create a NULL Thunk Entry. This is a small object file which contains a
- // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
- // is used to terminate the IAT and ILT.
- NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
-
- // Create a short import file which is described in PE/COFF spec 7. Import
- // Library Format.
- NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
- ImportType Type, ImportNameType NameType);
-
- // Create a weak external file which is described in PE/COFF Aux Format 3.
- NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
-};
-} // namespace
-
-NewArchiveMember
-ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
- const uint32_t NumberOfSections = 2;
- const uint32_t NumberOfSymbols = 7;
- const uint32_t NumberOfRelocations = 3;
-
- // COFF Header
- coff_file_header Header{
- u16(Machine),
- u16(NumberOfSections),
- u32(0),
- u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
- // .idata$2
- sizeof(coff_import_directory_table_entry) +
- NumberOfRelocations * sizeof(coff_relocation) +
- // .idata$4
- (ImportName.size() + 1)),
- u32(NumberOfSymbols),
- u16(0),
- u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
- };
- append(Buffer, Header);
-
- // Section Header Table
- const coff_section SectionTable[NumberOfSections] = {
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
- u32(0),
- u32(0),
- u32(sizeof(coff_import_directory_table_entry)),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
- sizeof(coff_import_directory_table_entry)),
- u32(0),
- u16(NumberOfRelocations),
- u16(0),
- u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
- IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
- u32(0),
- u32(0),
- u32(ImportName.size() + 1),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
- sizeof(coff_import_directory_table_entry) +
- NumberOfRelocations * sizeof(coff_relocation)),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
- IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
- };
- append(Buffer, SectionTable);
-
- // .idata$2
- const coff_import_directory_table_entry ImportDescriptor{
- u32(0), u32(0), u32(0), u32(0), u32(0),
- };
- append(Buffer, ImportDescriptor);
-
- const coff_relocation RelocationTable[NumberOfRelocations] = {
- {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
- u16(getImgRelRelocation(Machine))},
- {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
- u32(3), u16(getImgRelRelocation(Machine))},
- {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
- u32(4), u16(getImgRelRelocation(Machine))},
- };
- append(Buffer, RelocationTable);
-
- // .idata$6
- auto S = Buffer.size();
- Buffer.resize(S + ImportName.size() + 1);
- memcpy(&Buffer[S], ImportName.data(), ImportName.size());
- Buffer[S + ImportName.size()] = '\0';
-
- // Symbol Table
- coff_symbol16 SymbolTable[NumberOfSymbols] = {
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(1),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
- u32(0),
- u16(1),
- u16(0),
- IMAGE_SYM_CLASS_SECTION,
- 0},
- {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
- u32(0),
- u16(2),
- u16(0),
- IMAGE_SYM_CLASS_STATIC,
- 0},
- {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_SECTION,
- 0},
- {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_SECTION,
- 0},
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- };
- // TODO: Name.Offset.Offset here and in the all similar places below
- // suggests a names refactoring. Maybe StringTableOffset.Value?
- SymbolTable[0].Name.Offset.Offset =
- sizeof(uint32_t);
- SymbolTable[5].Name.Offset.Offset =
- sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
- SymbolTable[6].Name.Offset.Offset =
- sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
- NullImportDescriptorSymbolName.length() + 1;
- append(Buffer, SymbolTable);
-
- // String Table
- writeStringTable(Buffer,
- {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
- NullThunkSymbolName});
-
- StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
- return {MemoryBufferRef(F, ImportName)};
-}
-
-NewArchiveMember
-ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
- const uint32_t NumberOfSections = 1;
- const uint32_t NumberOfSymbols = 1;
-
- // COFF Header
- coff_file_header Header{
- u16(Machine),
- u16(NumberOfSections),
- u32(0),
- u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
- // .idata$3
- sizeof(coff_import_directory_table_entry)),
- u32(NumberOfSymbols),
- u16(0),
- u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
- };
- append(Buffer, Header);
-
- // Section Header Table
- const coff_section SectionTable[NumberOfSections] = {
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
- u32(0),
- u32(0),
- u32(sizeof(coff_import_directory_table_entry)),
- u32(sizeof(coff_file_header) +
- (NumberOfSections * sizeof(coff_section))),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
- IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
- };
- append(Buffer, SectionTable);
-
- // .idata$3
- const coff_import_directory_table_entry ImportDescriptor{
- u32(0), u32(0), u32(0), u32(0), u32(0),
- };
- append(Buffer, ImportDescriptor);
-
- // Symbol Table
- coff_symbol16 SymbolTable[NumberOfSymbols] = {
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(1),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- };
- SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
- append(Buffer, SymbolTable);
-
- // String Table
- writeStringTable(Buffer, {NullImportDescriptorSymbolName});
-
- StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
- return {MemoryBufferRef(F, ImportName)};
-}
-
-NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
- const uint32_t NumberOfSections = 2;
- const uint32_t NumberOfSymbols = 1;
- uint32_t VASize = is32bit(Machine) ? 4 : 8;
-
- // COFF Header
- coff_file_header Header{
- u16(Machine),
- u16(NumberOfSections),
- u32(0),
- u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
- // .idata$5
- VASize +
- // .idata$4
- VASize),
- u32(NumberOfSymbols),
- u16(0),
- u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
- };
- append(Buffer, Header);
-
- // Section Header Table
- const coff_section SectionTable[NumberOfSections] = {
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
- u32(0),
- u32(0),
- u32(VASize),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
- : IMAGE_SCN_ALIGN_8BYTES) |
- IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
- IMAGE_SCN_MEM_WRITE)},
- {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
- u32(0),
- u32(0),
- u32(VASize),
- u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
- VASize),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
- : IMAGE_SCN_ALIGN_8BYTES) |
- IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
- IMAGE_SCN_MEM_WRITE)},
- };
- append(Buffer, SectionTable);
-
- // .idata$5, ILT
- append(Buffer, u32(0));
- if (!is32bit(Machine))
- append(Buffer, u32(0));
-
- // .idata$4, IAT
- append(Buffer, u32(0));
- if (!is32bit(Machine))
- append(Buffer, u32(0));
-
- // Symbol Table
- coff_symbol16 SymbolTable[NumberOfSymbols] = {
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(1),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- };
- SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
- append(Buffer, SymbolTable);
-
- // String Table
- writeStringTable(Buffer, {NullThunkSymbolName});
-
- StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
- return {MemoryBufferRef{F, ImportName}};
-}
-
-NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
- uint16_t Ordinal,
- ImportType ImportType,
- ImportNameType NameType) {
- size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
- size_t Size = sizeof(coff_import_header) + ImpSize;
- char *Buf = Alloc.Allocate<char>(Size);
- memset(Buf, 0, Size);
- char *P = Buf;
-
- // Write short import library.
- auto *Imp = reinterpret_cast<coff_import_header *>(P);
- P += sizeof(*Imp);
- Imp->Sig2 = 0xFFFF;
- Imp->Machine = Machine;
- Imp->SizeOfData = ImpSize;
- if (Ordinal > 0)
- Imp->OrdinalHint = Ordinal;
- Imp->TypeInfo = (NameType << 2) | ImportType;
-
- // Write symbol name and DLL name.
- memcpy(P, Sym.data(), Sym.size());
- P += Sym.size() + 1;
- memcpy(P, ImportName.data(), ImportName.size());
-
- return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
-}
-
-NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
- StringRef Weak, bool Imp) {
- std::vector<uint8_t> Buffer;
- const uint32_t NumberOfSections = 1;
- const uint32_t NumberOfSymbols = 5;
-
- // COFF Header
- coff_file_header Header{
- u16(Machine),
- u16(NumberOfSections),
- u32(0),
- u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
- u32(NumberOfSymbols),
- u16(0),
- u16(0),
- };
- append(Buffer, Header);
-
- // Section Header Table
- const coff_section SectionTable[NumberOfSections] = {
- {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
- u32(0),
- u32(0),
- u32(0),
- u32(0),
- u32(0),
- u32(0),
- u16(0),
- u16(0),
- u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
- append(Buffer, SectionTable);
-
- // Symbol Table
- coff_symbol16 SymbolTable[NumberOfSymbols] = {
- {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
- u32(0),
- u16(0xFFFF),
- u16(0),
- IMAGE_SYM_CLASS_STATIC,
- 0},
- {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
- u32(0),
- u16(0xFFFF),
- u16(0),
- IMAGE_SYM_CLASS_STATIC,
- 0},
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_EXTERNAL,
- 0},
- {{{0, 0, 0, 0, 0, 0, 0, 0}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_WEAK_EXTERNAL,
- 1},
- {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
- u32(0),
- u16(0),
- u16(0),
- IMAGE_SYM_CLASS_NULL,
- 0},
- };
- SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
-
- //__imp_ String Table
- StringRef Prefix = Imp ? "__imp_" : "";
- SymbolTable[3].Name.Offset.Offset =
- sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
- append(Buffer, SymbolTable);
- writeStringTable(Buffer, {(Prefix + Sym).str(),
- (Prefix + Weak).str()});
-
- // Copied here so we can still use writeStringTable
- char *Buf = Alloc.Allocate<char>(Buffer.size());
- memcpy(Buf, Buffer.data(), Buffer.size());
- return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
-}
-
-Error writeImportLibrary(StringRef ImportName, StringRef Path,
- ArrayRef<COFFShortExport> Exports,
- MachineTypes Machine, bool MinGW) {
-
- std::vector<NewArchiveMember> Members;
- ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
-
- std::vector<uint8_t> ImportDescriptor;
- Members.push_back(OF.createImportDescriptor(ImportDescriptor));
-
- std::vector<uint8_t> NullImportDescriptor;
- Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
-
- std::vector<uint8_t> NullThunk;
- Members.push_back(OF.createNullThunk(NullThunk));
-
- for (COFFShortExport E : Exports) {
- if (E.Private)
- continue;
-
- ImportType ImportType = IMPORT_CODE;
- if (E.Data)
- ImportType = IMPORT_DATA;
- if (E.Constant)
- ImportType = IMPORT_CONST;
-
- StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
- ImportNameType NameType = E.Noname
- ? IMPORT_ORDINAL
- : getNameType(SymbolName, E.Name,
- Machine, MinGW);
- Expected<std::string> Name = E.ExtName.empty()
- ? std::string(SymbolName)
- : replace(SymbolName, E.Name, E.ExtName);
-
- if (!Name)
- return Name.takeError();
-
- if (!E.AliasTarget.empty() && *Name != E.AliasTarget) {
- Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false));
- Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true));
- continue;
- }
-
- Members.push_back(
- OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
- }
-
- return writeArchive(Path, Members, /*WriteSymtab*/ true,
- object::Archive::K_GNU,
- /*Deterministic*/ true, /*Thin*/ false);
-}
-
-} // namespace object
-} // namespace llvm
+//===- COFFImportFile.cpp - COFF short import file implementation ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the writeImportLibrary function.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Object/Archive.h"
+#include "llvm/Object/ArchiveWriter.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
+
+#include <cstdint>
+#include <string>
+#include <vector>
+
+using namespace llvm::COFF;
+using namespace llvm::object;
+using namespace llvm;
+
+namespace llvm {
+namespace object {
+
+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:
+ case IMAGE_FILE_MACHINE_I386:
+ return true;
+ }
+}
+
+static uint16_t getImgRelRelocation(MachineTypes Machine) {
+ switch (Machine) {
+ default:
+ llvm_unreachable("unsupported machine");
+ case IMAGE_FILE_MACHINE_AMD64:
+ 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;
+ }
+}
+
+template <class T> static void append(std::vector<uint8_t> &B, const T &Data) {
+ size_t S = B.size();
+ B.resize(S + sizeof(T));
+ memcpy(&B[S], &Data, sizeof(T));
+}
+
+static void writeStringTable(std::vector<uint8_t> &B,
+ ArrayRef<const std::string> Strings) {
+ // The COFF string table consists of a 4-byte value which is the size of the
+ // table, including the length field itself. This value is followed by the
+ // string content itself, which is an array of null-terminated C-style
+ // strings. The termination is important as they are referenced to by offset
+ // by the symbol entity in the file format.
+
+ size_t Pos = B.size();
+ size_t Offset = B.size();
+
+ // Skip over the length field, we will fill it in later as we will have
+ // computed the length while emitting the string content itself.
+ Pos += sizeof(uint32_t);
+
+ for (const auto &S : Strings) {
+ B.resize(Pos + S.length() + 1);
+ strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
+ Pos += S.length() + 1;
+ }
+
+ // Backfill the length of the table now that it has been computed.
+ support::ulittle32_t Length(B.size() - Offset);
+ support::endian::write32le(&B[Offset], Length);
+}
+
+static ImportNameType getNameType(StringRef Sym, StringRef ExtName,
+ MachineTypes Machine, bool MinGW) {
+ // A decorated stdcall function in MSVC is exported with the
+ // type IMPORT_NAME, and the exported function name includes the
+ // the leading underscore. In MinGW on the other hand, a decorated
+ // stdcall function still omits the underscore (IMPORT_NAME_NOPREFIX).
+ // See the comment in isDecorated in COFFModuleDefinition.cpp for more
+ // details.
+ if (ExtName.startswith("_") && ExtName.contains('@') && !MinGW)
+ return IMPORT_NAME;
+ if (Sym != ExtName)
+ return IMPORT_NAME_UNDECORATE;
+ if (Machine == IMAGE_FILE_MACHINE_I386 && Sym.startswith("_"))
+ return IMPORT_NAME_NOPREFIX;
+ return IMPORT_NAME;
+}
+
+static Expected<std::string> replace(StringRef S, StringRef From,
+ StringRef To) {
+ size_t Pos = S.find(From);
+
+ // From and To may be mangled, but substrings in S may not.
+ if (Pos == StringRef::npos && From.startswith("_") && To.startswith("_")) {
+ From = From.substr(1);
+ To = To.substr(1);
+ Pos = S.find(From);
+ }
+
+ if (Pos == StringRef::npos) {
+ return make_error<StringError>(
+ StringRef(Twine(S + ": replacing '" + From +
+ "' with '" + To + "' failed").str()), object_error::parse_failed);
+ }
+
+ return (Twine(S.substr(0, Pos)) + To + S.substr(Pos + From.size())).str();
+}
+
+static const std::string NullImportDescriptorSymbolName =
+ "__NULL_IMPORT_DESCRIPTOR";
+
+namespace {
+// This class constructs various small object files necessary to support linking
+// symbols imported from a DLL. The contents are pretty strictly defined and
+// nearly entirely static. The details of the structures files are defined in
+// WINNT.h and the PE/COFF specification.
+class ObjectFactory {
+ using u16 = support::ulittle16_t;
+ using u32 = support::ulittle32_t;
+ MachineTypes Machine;
+ BumpPtrAllocator Alloc;
+ StringRef ImportName;
+ StringRef Library;
+ std::string ImportDescriptorSymbolName;
+ std::string NullThunkSymbolName;
+
+public:
+ ObjectFactory(StringRef S, MachineTypes M)
+ : Machine(M), ImportName(S), Library(S.drop_back(4)),
+ ImportDescriptorSymbolName(("__IMPORT_DESCRIPTOR_" + Library).str()),
+ NullThunkSymbolName(("\x7f" + Library + "_NULL_THUNK_DATA").str()) {}
+
+ // Creates an Import Descriptor. This is a small object file which contains a
+ // reference to the terminators and contains the library name (entry) for the
+ // import name table. It will force the linker to construct the necessary
+ // structure to import symbols from the DLL.
+ NewArchiveMember createImportDescriptor(std::vector<uint8_t> &Buffer);
+
+ // Creates a NULL import descriptor. This is a small object file whcih
+ // contains a NULL import descriptor. It is used to terminate the imports
+ // from a specific DLL.
+ NewArchiveMember createNullImportDescriptor(std::vector<uint8_t> &Buffer);
+
+ // Create a NULL Thunk Entry. This is a small object file which contains a
+ // NULL Import Address Table entry and a NULL Import Lookup Table Entry. It
+ // is used to terminate the IAT and ILT.
+ NewArchiveMember createNullThunk(std::vector<uint8_t> &Buffer);
+
+ // Create a short import file which is described in PE/COFF spec 7. Import
+ // Library Format.
+ NewArchiveMember createShortImport(StringRef Sym, uint16_t Ordinal,
+ ImportType Type, ImportNameType NameType);
+
+ // Create a weak external file which is described in PE/COFF Aux Format 3.
+ NewArchiveMember createWeakExternal(StringRef Sym, StringRef Weak, bool Imp);
+};
+} // namespace
+
+NewArchiveMember
+ObjectFactory::createImportDescriptor(std::vector<uint8_t> &Buffer) {
+ const uint32_t NumberOfSections = 2;
+ const uint32_t NumberOfSymbols = 7;
+ const uint32_t NumberOfRelocations = 3;
+
+ // COFF Header
+ coff_file_header Header{
+ u16(Machine),
+ u16(NumberOfSections),
+ u32(0),
+ u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+ // .idata$2
+ sizeof(coff_import_directory_table_entry) +
+ NumberOfRelocations * sizeof(coff_relocation) +
+ // .idata$4
+ (ImportName.size() + 1)),
+ u32(NumberOfSymbols),
+ u16(0),
+ u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
+ };
+ append(Buffer, Header);
+
+ // Section Header Table
+ const coff_section SectionTable[NumberOfSections] = {
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '2'},
+ u32(0),
+ u32(0),
+ u32(sizeof(coff_import_directory_table_entry)),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+ sizeof(coff_import_directory_table_entry)),
+ u32(0),
+ u16(NumberOfRelocations),
+ u16(0),
+ u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '6'},
+ u32(0),
+ u32(0),
+ u32(ImportName.size() + 1),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+ sizeof(coff_import_directory_table_entry) +
+ NumberOfRelocations * sizeof(coff_relocation)),
+ u32(0),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32(IMAGE_SCN_ALIGN_2BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+ };
+ append(Buffer, SectionTable);
+
+ // .idata$2
+ const coff_import_directory_table_entry ImportDescriptor{
+ u32(0), u32(0), u32(0), u32(0), u32(0),
+ };
+ append(Buffer, ImportDescriptor);
+
+ const coff_relocation RelocationTable[NumberOfRelocations] = {
+ {u32(offsetof(coff_import_directory_table_entry, NameRVA)), u32(2),
+ u16(getImgRelRelocation(Machine))},
+ {u32(offsetof(coff_import_directory_table_entry, ImportLookupTableRVA)),
+ u32(3), u16(getImgRelRelocation(Machine))},
+ {u32(offsetof(coff_import_directory_table_entry, ImportAddressTableRVA)),
+ u32(4), u16(getImgRelRelocation(Machine))},
+ };
+ append(Buffer, RelocationTable);
+
+ // .idata$6
+ auto S = Buffer.size();
+ Buffer.resize(S + ImportName.size() + 1);
+ memcpy(&Buffer[S], ImportName.data(), ImportName.size());
+ Buffer[S + ImportName.size()] = '\0';
+
+ // Symbol Table
+ coff_symbol16 SymbolTable[NumberOfSymbols] = {
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(1),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ {{{'.', 'i', 'd', 'a', 't', 'a', '$', '2'}},
+ u32(0),
+ u16(1),
+ u16(0),
+ IMAGE_SYM_CLASS_SECTION,
+ 0},
+ {{{'.', 'i', 'd', 'a', 't', 'a', '$', '6'}},
+ u32(0),
+ u16(2),
+ u16(0),
+ IMAGE_SYM_CLASS_STATIC,
+ 0},
+ {{{'.', 'i', 'd', 'a', 't', 'a', '$', '4'}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_SECTION,
+ 0},
+ {{{'.', 'i', 'd', 'a', 't', 'a', '$', '5'}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_SECTION,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ };
+ // TODO: Name.Offset.Offset here and in the all similar places below
+ // suggests a names refactoring. Maybe StringTableOffset.Value?
+ SymbolTable[0].Name.Offset.Offset =
+ sizeof(uint32_t);
+ SymbolTable[5].Name.Offset.Offset =
+ sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1;
+ SymbolTable[6].Name.Offset.Offset =
+ sizeof(uint32_t) + ImportDescriptorSymbolName.length() + 1 +
+ NullImportDescriptorSymbolName.length() + 1;
+ append(Buffer, SymbolTable);
+
+ // String Table
+ writeStringTable(Buffer,
+ {ImportDescriptorSymbolName, NullImportDescriptorSymbolName,
+ NullThunkSymbolName});
+
+ StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+ return {MemoryBufferRef(F, ImportName)};
+}
+
+NewArchiveMember
+ObjectFactory::createNullImportDescriptor(std::vector<uint8_t> &Buffer) {
+ const uint32_t NumberOfSections = 1;
+ const uint32_t NumberOfSymbols = 1;
+
+ // COFF Header
+ coff_file_header Header{
+ u16(Machine),
+ u16(NumberOfSections),
+ u32(0),
+ u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+ // .idata$3
+ sizeof(coff_import_directory_table_entry)),
+ u32(NumberOfSymbols),
+ u16(0),
+ u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
+ };
+ append(Buffer, Header);
+
+ // Section Header Table
+ const coff_section SectionTable[NumberOfSections] = {
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '3'},
+ u32(0),
+ u32(0),
+ u32(sizeof(coff_import_directory_table_entry)),
+ u32(sizeof(coff_file_header) +
+ (NumberOfSections * sizeof(coff_section))),
+ u32(0),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32(IMAGE_SCN_ALIGN_4BYTES | IMAGE_SCN_CNT_INITIALIZED_DATA |
+ IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE)},
+ };
+ append(Buffer, SectionTable);
+
+ // .idata$3
+ const coff_import_directory_table_entry ImportDescriptor{
+ u32(0), u32(0), u32(0), u32(0), u32(0),
+ };
+ append(Buffer, ImportDescriptor);
+
+ // Symbol Table
+ coff_symbol16 SymbolTable[NumberOfSymbols] = {
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(1),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ };
+ SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
+ append(Buffer, SymbolTable);
+
+ // String Table
+ writeStringTable(Buffer, {NullImportDescriptorSymbolName});
+
+ StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+ return {MemoryBufferRef(F, ImportName)};
+}
+
+NewArchiveMember ObjectFactory::createNullThunk(std::vector<uint8_t> &Buffer) {
+ const uint32_t NumberOfSections = 2;
+ const uint32_t NumberOfSymbols = 1;
+ uint32_t VASize = is32bit(Machine) ? 4 : 8;
+
+ // COFF Header
+ coff_file_header Header{
+ u16(Machine),
+ u16(NumberOfSections),
+ u32(0),
+ u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section)) +
+ // .idata$5
+ VASize +
+ // .idata$4
+ VASize),
+ u32(NumberOfSymbols),
+ u16(0),
+ u16(is32bit(Machine) ? IMAGE_FILE_32BIT_MACHINE : C_Invalid),
+ };
+ append(Buffer, Header);
+
+ // Section Header Table
+ const coff_section SectionTable[NumberOfSections] = {
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '5'},
+ u32(0),
+ u32(0),
+ u32(VASize),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section)),
+ u32(0),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
+ : IMAGE_SCN_ALIGN_8BYTES) |
+ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
+ IMAGE_SCN_MEM_WRITE)},
+ {{'.', 'i', 'd', 'a', 't', 'a', '$', '4'},
+ u32(0),
+ u32(0),
+ u32(VASize),
+ u32(sizeof(coff_file_header) + NumberOfSections * sizeof(coff_section) +
+ VASize),
+ u32(0),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32((is32bit(Machine) ? IMAGE_SCN_ALIGN_4BYTES
+ : IMAGE_SCN_ALIGN_8BYTES) |
+ IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ |
+ IMAGE_SCN_MEM_WRITE)},
+ };
+ append(Buffer, SectionTable);
+
+ // .idata$5, ILT
+ append(Buffer, u32(0));
+ if (!is32bit(Machine))
+ append(Buffer, u32(0));
+
+ // .idata$4, IAT
+ append(Buffer, u32(0));
+ if (!is32bit(Machine))
+ append(Buffer, u32(0));
+
+ // Symbol Table
+ coff_symbol16 SymbolTable[NumberOfSymbols] = {
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(1),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ };
+ SymbolTable[0].Name.Offset.Offset = sizeof(uint32_t);
+ append(Buffer, SymbolTable);
+
+ // String Table
+ writeStringTable(Buffer, {NullThunkSymbolName});
+
+ StringRef F{reinterpret_cast<const char *>(Buffer.data()), Buffer.size()};
+ return {MemoryBufferRef{F, ImportName}};
+}
+
+NewArchiveMember ObjectFactory::createShortImport(StringRef Sym,
+ uint16_t Ordinal,
+ ImportType ImportType,
+ ImportNameType NameType) {
+ size_t ImpSize = ImportName.size() + Sym.size() + 2; // +2 for NULs
+ size_t Size = sizeof(coff_import_header) + ImpSize;
+ char *Buf = Alloc.Allocate<char>(Size);
+ memset(Buf, 0, Size);
+ char *P = Buf;
+
+ // Write short import library.
+ auto *Imp = reinterpret_cast<coff_import_header *>(P);
+ P += sizeof(*Imp);
+ Imp->Sig2 = 0xFFFF;
+ Imp->Machine = Machine;
+ Imp->SizeOfData = ImpSize;
+ if (Ordinal > 0)
+ Imp->OrdinalHint = Ordinal;
+ Imp->TypeInfo = (NameType << 2) | ImportType;
+
+ // Write symbol name and DLL name.
+ memcpy(P, Sym.data(), Sym.size());
+ P += Sym.size() + 1;
+ memcpy(P, ImportName.data(), ImportName.size());
+
+ return {MemoryBufferRef(StringRef(Buf, Size), ImportName)};
+}
+
+NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym,
+ StringRef Weak, bool Imp) {
+ std::vector<uint8_t> Buffer;
+ const uint32_t NumberOfSections = 1;
+ const uint32_t NumberOfSymbols = 5;
+
+ // COFF Header
+ coff_file_header Header{
+ u16(Machine),
+ u16(NumberOfSections),
+ u32(0),
+ u32(sizeof(Header) + (NumberOfSections * sizeof(coff_section))),
+ u32(NumberOfSymbols),
+ u16(0),
+ u16(0),
+ };
+ append(Buffer, Header);
+
+ // Section Header Table
+ const coff_section SectionTable[NumberOfSections] = {
+ {{'.', 'd', 'r', 'e', 'c', 't', 'v', 'e'},
+ u32(0),
+ u32(0),
+ u32(0),
+ u32(0),
+ u32(0),
+ u32(0),
+ u16(0),
+ u16(0),
+ u32(IMAGE_SCN_LNK_INFO | IMAGE_SCN_LNK_REMOVE)}};
+ append(Buffer, SectionTable);
+
+ // Symbol Table
+ coff_symbol16 SymbolTable[NumberOfSymbols] = {
+ {{{'@', 'c', 'o', 'm', 'p', '.', 'i', 'd'}},
+ u32(0),
+ u16(0xFFFF),
+ u16(0),
+ IMAGE_SYM_CLASS_STATIC,
+ 0},
+ {{{'@', 'f', 'e', 'a', 't', '.', '0', '0'}},
+ u32(0),
+ u16(0xFFFF),
+ u16(0),
+ IMAGE_SYM_CLASS_STATIC,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_EXTERNAL,
+ 0},
+ {{{0, 0, 0, 0, 0, 0, 0, 0}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_WEAK_EXTERNAL,
+ 1},
+ {{{2, 0, 0, 0, IMAGE_WEAK_EXTERN_SEARCH_ALIAS, 0, 0, 0}},
+ u32(0),
+ u16(0),
+ u16(0),
+ IMAGE_SYM_CLASS_NULL,
+ 0},
+ };
+ SymbolTable[2].Name.Offset.Offset = sizeof(uint32_t);
+
+ //__imp_ String Table
+ StringRef Prefix = Imp ? "__imp_" : "";
+ SymbolTable[3].Name.Offset.Offset =
+ sizeof(uint32_t) + Sym.size() + Prefix.size() + 1;
+ append(Buffer, SymbolTable);
+ writeStringTable(Buffer, {(Prefix + Sym).str(),
+ (Prefix + Weak).str()});
+
+ // Copied here so we can still use writeStringTable
+ char *Buf = Alloc.Allocate<char>(Buffer.size());
+ memcpy(Buf, Buffer.data(), Buffer.size());
+ return {MemoryBufferRef(StringRef(Buf, Buffer.size()), ImportName)};
+}
+
+Error writeImportLibrary(StringRef ImportName, StringRef Path,
+ ArrayRef<COFFShortExport> Exports,
+ MachineTypes Machine, bool MinGW) {
+
+ std::vector<NewArchiveMember> Members;
+ ObjectFactory OF(llvm::sys::path::filename(ImportName), Machine);
+
+ std::vector<uint8_t> ImportDescriptor;
+ Members.push_back(OF.createImportDescriptor(ImportDescriptor));
+
+ std::vector<uint8_t> NullImportDescriptor;
+ Members.push_back(OF.createNullImportDescriptor(NullImportDescriptor));
+
+ std::vector<uint8_t> NullThunk;
+ Members.push_back(OF.createNullThunk(NullThunk));
+
+ for (COFFShortExport E : Exports) {
+ if (E.Private)
+ continue;
+
+ ImportType ImportType = IMPORT_CODE;
+ if (E.Data)
+ ImportType = IMPORT_DATA;
+ if (E.Constant)
+ ImportType = IMPORT_CONST;
+
+ StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName;
+ ImportNameType NameType = E.Noname
+ ? IMPORT_ORDINAL
+ : getNameType(SymbolName, E.Name,
+ Machine, MinGW);
+ Expected<std::string> Name = E.ExtName.empty()
+ ? std::string(SymbolName)
+ : replace(SymbolName, E.Name, E.ExtName);
+
+ if (!Name)
+ return Name.takeError();
+
+ if (!E.AliasTarget.empty() && *Name != E.AliasTarget) {
+ Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, false));
+ Members.push_back(OF.createWeakExternal(E.AliasTarget, *Name, true));
+ continue;
+ }
+
+ Members.push_back(
+ OF.createShortImport(*Name, E.Ordinal, ImportType, NameType));
+ }
+
+ return writeArchive(Path, Members, /*WriteSymtab*/ true,
+ object::Archive::K_GNU,
+ /*Deterministic*/ true, /*Thin*/ false);
+}
+
+} // namespace object
+} // namespace llvm
diff --git a/contrib/libs/llvm12/lib/Object/COFFModuleDefinition.cpp b/contrib/libs/llvm12/lib/Object/COFFModuleDefinition.cpp
index f9e897fbe5..8f29f7a658 100644
--- a/contrib/libs/llvm12/lib/Object/COFFModuleDefinition.cpp
+++ b/contrib/libs/llvm12/lib/Object/COFFModuleDefinition.cpp
@@ -1,368 +1,368 @@
-//===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Windows-specific.
-// A parser for the module-definition file (.def file).
-//
-// The format of module-definition files are described in this document:
-// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/COFFModuleDefinition.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Object/COFFImportFile.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace llvm::COFF;
-using namespace llvm;
-
-namespace llvm {
-namespace object {
-
-enum Kind {
- Unknown,
- Eof,
- Identifier,
- Comma,
- Equal,
- EqualEqual,
- KwBase,
- KwConstant,
- KwData,
- KwExports,
- KwHeapsize,
- KwLibrary,
- KwName,
- KwNoname,
- KwPrivate,
- KwStacksize,
- KwVersion,
-};
-
-struct Token {
- explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
- Kind K;
- StringRef Value;
-};
-
-static bool isDecorated(StringRef Sym, bool MingwDef) {
- // 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) {
- return make_error<StringError>(StringRef(Err.str()),
- object_error::parse_failed);
-}
-
-class Lexer {
-public:
- Lexer(StringRef S) : Buf(S) {}
-
- Token lex() {
- Buf = Buf.trim();
- if (Buf.empty())
- return Token(Eof);
-
- switch (Buf[0]) {
- case '\0':
- return Token(Eof);
- case ';': {
- size_t End = Buf.find('\n');
- Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
- return lex();
- }
- case '=':
- Buf = Buf.drop_front();
- if (Buf.startswith("=")) {
- Buf = Buf.drop_front();
- return Token(EqualEqual, "==");
- }
- return Token(Equal, "=");
- case ',':
- Buf = Buf.drop_front();
- return Token(Comma, ",");
- case '"': {
- StringRef S;
- std::tie(S, Buf) = Buf.substr(1).split('"');
- return Token(Identifier, S);
- }
- default: {
- 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)
- .Case("CONSTANT", KwConstant)
- .Case("DATA", KwData)
- .Case("EXPORTS", KwExports)
- .Case("HEAPSIZE", KwHeapsize)
- .Case("LIBRARY", KwLibrary)
- .Case("NAME", KwName)
- .Case("NONAME", KwNoname)
- .Case("PRIVATE", KwPrivate)
- .Case("STACKSIZE", KwStacksize)
- .Case("VERSION", KwVersion)
- .Default(Identifier);
- Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
- return Token(K, Word);
- }
- }
- }
-
-private:
- StringRef Buf;
-};
-
-class Parser {
-public:
- explicit Parser(StringRef S, MachineTypes M, bool B)
- : Lex(S), Machine(M), MingwDef(B) {}
-
- Expected<COFFModuleDefinition> parse() {
- do {
- if (Error Err = parseOne())
- return std::move(Err);
- } while (Tok.K != Eof);
- return Info;
- }
-
-private:
- void read() {
- if (Stack.empty()) {
- Tok = Lex.lex();
- return;
- }
- Tok = Stack.back();
- Stack.pop_back();
- }
-
- Error readAsInt(uint64_t *I) {
- read();
- if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
- return createError("integer expected");
- return Error::success();
- }
-
- Error expect(Kind Expected, StringRef Msg) {
- read();
- if (Tok.K != Expected)
- return createError(Msg);
- return Error::success();
- }
-
- void unget() { Stack.push_back(Tok); }
-
- Error parseOne() {
- read();
- switch (Tok.K) {
- case Eof:
- return Error::success();
- case KwExports:
- for (;;) {
- read();
- if (Tok.K != Identifier) {
- unget();
- return Error::success();
- }
- if (Error Err = parseExport())
- return Err;
- }
- case KwHeapsize:
- return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
- case KwStacksize:
- return parseNumbers(&Info.StackReserve, &Info.StackCommit);
- case KwLibrary:
- case KwName: {
- bool IsDll = Tok.K == KwLibrary; // Check before parseName.
- std::string Name;
- if (Error Err = parseName(&Name, &Info.ImageBase))
- return Err;
-
- Info.ImportName = Name;
-
- // Set the output file, but don't override /out if it was already passed.
- if (Info.OutputFile.empty()) {
- Info.OutputFile = Name;
- // Append the appropriate file extension if not already present.
- if (!sys::path::has_extension(Name))
- Info.OutputFile += IsDll ? ".dll" : ".exe";
- }
-
- return Error::success();
- }
- case KwVersion:
- return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
- default:
- return createError("unknown directive: " + Tok.Value);
- }
- }
-
- Error parseExport() {
- COFFShortExport E;
- E.Name = std::string(Tok.Value);
- read();
- if (Tok.K == Equal) {
- read();
- if (Tok.K != Identifier)
- return createError("identifier expected, but got " + Tok.Value);
- E.ExtName = E.Name;
- E.Name = std::string(Tok.Value);
- } else {
- unget();
- }
-
- if (Machine == IMAGE_FILE_MACHINE_I386) {
- if (!isDecorated(E.Name, MingwDef))
- E.Name = (std::string("_").append(E.Name));
- if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
- E.ExtName = (std::string("_").append(E.ExtName));
- }
-
- for (;;) {
- read();
- if (Tok.K == Identifier && Tok.Value[0] == '@') {
- 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;
- } else {
- unget();
- }
- continue;
- }
- if (Tok.K == KwData) {
- E.Data = true;
- continue;
- }
- if (Tok.K == KwConstant) {
- E.Constant = true;
- continue;
- }
- if (Tok.K == KwPrivate) {
- E.Private = true;
- continue;
- }
- if (Tok.K == EqualEqual) {
- read();
- E.AliasTarget = std::string(Tok.Value);
- if (Machine == IMAGE_FILE_MACHINE_I386 && !isDecorated(E.AliasTarget, MingwDef))
- E.AliasTarget = std::string("_").append(E.AliasTarget);
- continue;
- }
- unget();
- Info.Exports.push_back(E);
- return Error::success();
- }
- }
-
- // HEAPSIZE/STACKSIZE reserve[,commit]
- Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
- if (Error Err = readAsInt(Reserve))
- return Err;
- read();
- if (Tok.K != Comma) {
- unget();
- Commit = nullptr;
- return Error::success();
- }
- if (Error Err = readAsInt(Commit))
- return Err;
- return Error::success();
- }
-
- // NAME outputPath [BASE=address]
- Error parseName(std::string *Out, uint64_t *Baseaddr) {
- read();
- if (Tok.K == Identifier) {
- *Out = std::string(Tok.Value);
- } else {
- *Out = "";
- unget();
- return Error::success();
- }
- read();
- if (Tok.K == KwBase) {
- if (Error Err = expect(Equal, "'=' expected"))
- return Err;
- if (Error Err = readAsInt(Baseaddr))
- return Err;
- } else {
- unget();
- *Baseaddr = 0;
- }
- return Error::success();
- }
-
- // VERSION major[.minor]
- Error parseVersion(uint32_t *Major, uint32_t *Minor) {
- read();
- if (Tok.K != Identifier)
- return createError("identifier expected, but got " + Tok.Value);
- StringRef V1, V2;
- std::tie(V1, V2) = Tok.Value.split('.');
- if (V1.getAsInteger(10, *Major))
- return createError("integer expected, but got " + Tok.Value);
- if (V2.empty())
- *Minor = 0;
- else if (V2.getAsInteger(10, *Minor))
- return createError("integer expected, but got " + Tok.Value);
- return Error::success();
- }
-
- Lexer Lex;
- Token Tok;
- std::vector<Token> Stack;
- MachineTypes Machine;
- COFFModuleDefinition Info;
- bool MingwDef;
-};
-
-Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
- MachineTypes Machine,
- bool MingwDef) {
- return Parser(MB.getBuffer(), Machine, MingwDef).parse();
-}
-
-} // namespace object
-} // namespace llvm
+//===--- COFFModuleDefinition.cpp - Simple DEF parser ---------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Windows-specific.
+// A parser for the module-definition file (.def file).
+//
+// The format of module-definition files are described in this document:
+// https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/COFFModuleDefinition.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm::COFF;
+using namespace llvm;
+
+namespace llvm {
+namespace object {
+
+enum Kind {
+ Unknown,
+ Eof,
+ Identifier,
+ Comma,
+ Equal,
+ EqualEqual,
+ KwBase,
+ KwConstant,
+ KwData,
+ KwExports,
+ KwHeapsize,
+ KwLibrary,
+ KwName,
+ KwNoname,
+ KwPrivate,
+ KwStacksize,
+ KwVersion,
+};
+
+struct Token {
+ explicit Token(Kind T = Unknown, StringRef S = "") : K(T), Value(S) {}
+ Kind K;
+ StringRef Value;
+};
+
+static bool isDecorated(StringRef Sym, bool MingwDef) {
+ // 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) {
+ return make_error<StringError>(StringRef(Err.str()),
+ object_error::parse_failed);
+}
+
+class Lexer {
+public:
+ Lexer(StringRef S) : Buf(S) {}
+
+ Token lex() {
+ Buf = Buf.trim();
+ if (Buf.empty())
+ return Token(Eof);
+
+ switch (Buf[0]) {
+ case '\0':
+ return Token(Eof);
+ case ';': {
+ size_t End = Buf.find('\n');
+ Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
+ return lex();
+ }
+ case '=':
+ Buf = Buf.drop_front();
+ if (Buf.startswith("=")) {
+ Buf = Buf.drop_front();
+ return Token(EqualEqual, "==");
+ }
+ return Token(Equal, "=");
+ case ',':
+ Buf = Buf.drop_front();
+ return Token(Comma, ",");
+ case '"': {
+ StringRef S;
+ std::tie(S, Buf) = Buf.substr(1).split('"');
+ return Token(Identifier, S);
+ }
+ default: {
+ 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)
+ .Case("CONSTANT", KwConstant)
+ .Case("DATA", KwData)
+ .Case("EXPORTS", KwExports)
+ .Case("HEAPSIZE", KwHeapsize)
+ .Case("LIBRARY", KwLibrary)
+ .Case("NAME", KwName)
+ .Case("NONAME", KwNoname)
+ .Case("PRIVATE", KwPrivate)
+ .Case("STACKSIZE", KwStacksize)
+ .Case("VERSION", KwVersion)
+ .Default(Identifier);
+ Buf = (End == Buf.npos) ? "" : Buf.drop_front(End);
+ return Token(K, Word);
+ }
+ }
+ }
+
+private:
+ StringRef Buf;
+};
+
+class Parser {
+public:
+ explicit Parser(StringRef S, MachineTypes M, bool B)
+ : Lex(S), Machine(M), MingwDef(B) {}
+
+ Expected<COFFModuleDefinition> parse() {
+ do {
+ if (Error Err = parseOne())
+ return std::move(Err);
+ } while (Tok.K != Eof);
+ return Info;
+ }
+
+private:
+ void read() {
+ if (Stack.empty()) {
+ Tok = Lex.lex();
+ return;
+ }
+ Tok = Stack.back();
+ Stack.pop_back();
+ }
+
+ Error readAsInt(uint64_t *I) {
+ read();
+ if (Tok.K != Identifier || Tok.Value.getAsInteger(10, *I))
+ return createError("integer expected");
+ return Error::success();
+ }
+
+ Error expect(Kind Expected, StringRef Msg) {
+ read();
+ if (Tok.K != Expected)
+ return createError(Msg);
+ return Error::success();
+ }
+
+ void unget() { Stack.push_back(Tok); }
+
+ Error parseOne() {
+ read();
+ switch (Tok.K) {
+ case Eof:
+ return Error::success();
+ case KwExports:
+ for (;;) {
+ read();
+ if (Tok.K != Identifier) {
+ unget();
+ return Error::success();
+ }
+ if (Error Err = parseExport())
+ return Err;
+ }
+ case KwHeapsize:
+ return parseNumbers(&Info.HeapReserve, &Info.HeapCommit);
+ case KwStacksize:
+ return parseNumbers(&Info.StackReserve, &Info.StackCommit);
+ case KwLibrary:
+ case KwName: {
+ bool IsDll = Tok.K == KwLibrary; // Check before parseName.
+ std::string Name;
+ if (Error Err = parseName(&Name, &Info.ImageBase))
+ return Err;
+
+ Info.ImportName = Name;
+
+ // Set the output file, but don't override /out if it was already passed.
+ if (Info.OutputFile.empty()) {
+ Info.OutputFile = Name;
+ // Append the appropriate file extension if not already present.
+ if (!sys::path::has_extension(Name))
+ Info.OutputFile += IsDll ? ".dll" : ".exe";
+ }
+
+ return Error::success();
+ }
+ case KwVersion:
+ return parseVersion(&Info.MajorImageVersion, &Info.MinorImageVersion);
+ default:
+ return createError("unknown directive: " + Tok.Value);
+ }
+ }
+
+ Error parseExport() {
+ COFFShortExport E;
+ E.Name = std::string(Tok.Value);
+ read();
+ if (Tok.K == Equal) {
+ read();
+ if (Tok.K != Identifier)
+ return createError("identifier expected, but got " + Tok.Value);
+ E.ExtName = E.Name;
+ E.Name = std::string(Tok.Value);
+ } else {
+ unget();
+ }
+
+ if (Machine == IMAGE_FILE_MACHINE_I386) {
+ if (!isDecorated(E.Name, MingwDef))
+ E.Name = (std::string("_").append(E.Name));
+ if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
+ E.ExtName = (std::string("_").append(E.ExtName));
+ }
+
+ for (;;) {
+ read();
+ if (Tok.K == Identifier && Tok.Value[0] == '@') {
+ 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;
+ } else {
+ unget();
+ }
+ continue;
+ }
+ if (Tok.K == KwData) {
+ E.Data = true;
+ continue;
+ }
+ if (Tok.K == KwConstant) {
+ E.Constant = true;
+ continue;
+ }
+ if (Tok.K == KwPrivate) {
+ E.Private = true;
+ continue;
+ }
+ if (Tok.K == EqualEqual) {
+ read();
+ E.AliasTarget = std::string(Tok.Value);
+ if (Machine == IMAGE_FILE_MACHINE_I386 && !isDecorated(E.AliasTarget, MingwDef))
+ E.AliasTarget = std::string("_").append(E.AliasTarget);
+ continue;
+ }
+ unget();
+ Info.Exports.push_back(E);
+ return Error::success();
+ }
+ }
+
+ // HEAPSIZE/STACKSIZE reserve[,commit]
+ Error parseNumbers(uint64_t *Reserve, uint64_t *Commit) {
+ if (Error Err = readAsInt(Reserve))
+ return Err;
+ read();
+ if (Tok.K != Comma) {
+ unget();
+ Commit = nullptr;
+ return Error::success();
+ }
+ if (Error Err = readAsInt(Commit))
+ return Err;
+ return Error::success();
+ }
+
+ // NAME outputPath [BASE=address]
+ Error parseName(std::string *Out, uint64_t *Baseaddr) {
+ read();
+ if (Tok.K == Identifier) {
+ *Out = std::string(Tok.Value);
+ } else {
+ *Out = "";
+ unget();
+ return Error::success();
+ }
+ read();
+ if (Tok.K == KwBase) {
+ if (Error Err = expect(Equal, "'=' expected"))
+ return Err;
+ if (Error Err = readAsInt(Baseaddr))
+ return Err;
+ } else {
+ unget();
+ *Baseaddr = 0;
+ }
+ return Error::success();
+ }
+
+ // VERSION major[.minor]
+ Error parseVersion(uint32_t *Major, uint32_t *Minor) {
+ read();
+ if (Tok.K != Identifier)
+ return createError("identifier expected, but got " + Tok.Value);
+ StringRef V1, V2;
+ std::tie(V1, V2) = Tok.Value.split('.');
+ if (V1.getAsInteger(10, *Major))
+ return createError("integer expected, but got " + Tok.Value);
+ if (V2.empty())
+ *Minor = 0;
+ else if (V2.getAsInteger(10, *Minor))
+ return createError("integer expected, but got " + Tok.Value);
+ return Error::success();
+ }
+
+ Lexer Lex;
+ Token Tok;
+ std::vector<Token> Stack;
+ MachineTypes Machine;
+ COFFModuleDefinition Info;
+ bool MingwDef;
+};
+
+Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
+ MachineTypes Machine,
+ bool MingwDef) {
+ return Parser(MB.getBuffer(), Machine, MingwDef).parse();
+}
+
+} // namespace object
+} // namespace llvm
diff --git a/contrib/libs/llvm12/lib/Object/COFFObjectFile.cpp b/contrib/libs/llvm12/lib/Object/COFFObjectFile.cpp
index aca654e9c3..6e9a8eb35d 100644
--- a/contrib/libs/llvm12/lib/Object/COFFObjectFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/COFFObjectFile.cpp
@@ -1,657 +1,657 @@
-//===- COFFObjectFile.cpp - COFF object file implementation ---------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file declares the COFFObjectFile class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/ADT/iterator_range.h"
-#include "llvm/BinaryFormat/COFF.h"
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/BinaryStreamReader.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include <algorithm>
-#include <cassert>
+//===- COFFObjectFile.cpp - COFF object file implementation ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the COFFObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <cassert>
#include <cinttypes>
-#include <cstddef>
-#include <cstring>
-#include <limits>
-#include <memory>
-#include <system_error>
-
-using namespace llvm;
-using namespace object;
-
-using support::ulittle16_t;
-using support::ulittle32_t;
-using support::ulittle64_t;
-using support::little16_t;
-
-// Returns false if size is greater than the buffer size. And sets ec.
-static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) {
- if (M.getBufferSize() < Size) {
- EC = object_error::unexpected_eof;
- return false;
- }
- return true;
-}
-
-// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
-// Returns unexpected_eof if error.
-template <typename T>
-static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr,
- const uint64_t Size = sizeof(T)) {
+#include <cstddef>
+#include <cstring>
+#include <limits>
+#include <memory>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+
+using support::ulittle16_t;
+using support::ulittle32_t;
+using support::ulittle64_t;
+using support::little16_t;
+
+// Returns false if size is greater than the buffer size. And sets ec.
+static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size) {
+ if (M.getBufferSize() < Size) {
+ EC = object_error::unexpected_eof;
+ return false;
+ }
+ return true;
+}
+
+// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m.
+// Returns unexpected_eof if error.
+template <typename T>
+static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr,
+ const uint64_t Size = sizeof(T)) {
uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);
- if (Error E = Binary::checkOffset(M, Addr, Size))
- return E;
- Obj = reinterpret_cast<const T *>(Addr);
- return Error::success();
-}
-
-// Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without
-// prefixed slashes.
-static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {
- assert(Str.size() <= 6 && "String too long, possible overflow.");
- if (Str.size() > 6)
- return true;
-
- uint64_t Value = 0;
- while (!Str.empty()) {
- unsigned CharVal;
- if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..25
- CharVal = Str[0] - 'A';
- else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..51
- CharVal = Str[0] - 'a' + 26;
- else if (Str[0] >= '0' && Str[0] <= '9') // 52..61
- CharVal = Str[0] - '0' + 52;
- else if (Str[0] == '+') // 62
- CharVal = 62;
- else if (Str[0] == '/') // 63
- CharVal = 63;
- else
- return true;
-
- Value = (Value * 64) + CharVal;
- Str = Str.substr(1);
- }
-
- if (Value > std::numeric_limits<uint32_t>::max())
- return true;
-
- Result = static_cast<uint32_t>(Value);
- return false;
-}
-
-template <typename coff_symbol_type>
-const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {
- const coff_symbol_type *Addr =
- reinterpret_cast<const coff_symbol_type *>(Ref.p);
-
+ if (Error E = Binary::checkOffset(M, Addr, Size))
+ return E;
+ Obj = reinterpret_cast<const T *>(Addr);
+ return Error::success();
+}
+
+// Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without
+// prefixed slashes.
+static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result) {
+ assert(Str.size() <= 6 && "String too long, possible overflow.");
+ if (Str.size() > 6)
+ return true;
+
+ uint64_t Value = 0;
+ while (!Str.empty()) {
+ unsigned CharVal;
+ if (Str[0] >= 'A' && Str[0] <= 'Z') // 0..25
+ CharVal = Str[0] - 'A';
+ else if (Str[0] >= 'a' && Str[0] <= 'z') // 26..51
+ CharVal = Str[0] - 'a' + 26;
+ else if (Str[0] >= '0' && Str[0] <= '9') // 52..61
+ CharVal = Str[0] - '0' + 52;
+ else if (Str[0] == '+') // 62
+ CharVal = 62;
+ else if (Str[0] == '/') // 63
+ CharVal = 63;
+ else
+ return true;
+
+ Value = (Value * 64) + CharVal;
+ Str = Str.substr(1);
+ }
+
+ if (Value > std::numeric_limits<uint32_t>::max())
+ return true;
+
+ Result = static_cast<uint32_t>(Value);
+ return false;
+}
+
+template <typename coff_symbol_type>
+const coff_symbol_type *COFFObjectFile::toSymb(DataRefImpl Ref) const {
+ const coff_symbol_type *Addr =
+ reinterpret_cast<const coff_symbol_type *>(Ref.p);
+
assert(!checkOffset(Data, reinterpret_cast<uintptr_t>(Addr), sizeof(*Addr)));
-#ifndef NDEBUG
- // Verify that the symbol points to a valid entry in the symbol table.
+#ifndef NDEBUG
+ // Verify that the symbol points to a valid entry in the symbol table.
uintptr_t Offset =
reinterpret_cast<uintptr_t>(Addr) - reinterpret_cast<uintptr_t>(base());
-
- assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&
- "Symbol did not point to the beginning of a symbol");
-#endif
-
- return Addr;
-}
-
-const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {
- const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p);
-
-#ifndef NDEBUG
- // Verify that the section points to a valid entry in the section table.
- if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))
- report_fatal_error("Section was outside of section table.");
-
+
+ assert((Offset - getPointerToSymbolTable()) % sizeof(coff_symbol_type) == 0 &&
+ "Symbol did not point to the beginning of a symbol");
+#endif
+
+ return Addr;
+}
+
+const coff_section *COFFObjectFile::toSec(DataRefImpl Ref) const {
+ const coff_section *Addr = reinterpret_cast<const coff_section*>(Ref.p);
+
+#ifndef NDEBUG
+ // Verify that the section points to a valid entry in the section table.
+ if (Addr < SectionTable || Addr >= (SectionTable + getNumberOfSections()))
+ report_fatal_error("Section was outside of section table.");
+
uintptr_t Offset = reinterpret_cast<uintptr_t>(Addr) -
reinterpret_cast<uintptr_t>(SectionTable);
- assert(Offset % sizeof(coff_section) == 0 &&
- "Section did not point to the beginning of a section");
-#endif
-
- return Addr;
-}
-
-void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {
- auto End = reinterpret_cast<uintptr_t>(StringTable);
- if (SymbolTable16) {
- const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);
- Symb += 1 + Symb->NumberOfAuxSymbols;
- Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
- } else if (SymbolTable32) {
- const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);
- Symb += 1 + Symb->NumberOfAuxSymbols;
- Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
- } else {
- llvm_unreachable("no symbol table pointer!");
- }
-}
-
-Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {
- return getSymbolName(getCOFFSymbol(Ref));
-}
-
-uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {
- return getCOFFSymbol(Ref).getValue();
-}
-
-uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const {
- // MSVC/link.exe seems to align symbols to the next-power-of-2
- // up to 32 bytes.
- COFFSymbolRef Symb = getCOFFSymbol(Ref);
- return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));
-}
-
-Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {
- uint64_t Result = cantFail(getSymbolValue(Ref));
- COFFSymbolRef Symb = getCOFFSymbol(Ref);
- int32_t SectionNumber = Symb.getSectionNumber();
-
- if (Symb.isAnyUndefined() || Symb.isCommon() ||
- COFF::isReservedSectionNumber(SectionNumber))
- return Result;
-
- Expected<const coff_section *> Section = getSection(SectionNumber);
- if (!Section)
- return Section.takeError();
- Result += (*Section)->VirtualAddress;
-
- // The section VirtualAddress does not include ImageBase, and we want to
- // return virtual addresses.
- Result += getImageBase();
-
- return Result;
-}
-
-Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {
- COFFSymbolRef Symb = getCOFFSymbol(Ref);
- int32_t SectionNumber = Symb.getSectionNumber();
-
- if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
- return SymbolRef::ST_Function;
- if (Symb.isAnyUndefined())
- return SymbolRef::ST_Unknown;
- if (Symb.isCommon())
- return SymbolRef::ST_Data;
- if (Symb.isFileRecord())
- return SymbolRef::ST_File;
-
- // TODO: perhaps we need a new symbol type ST_Section.
- if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())
- return SymbolRef::ST_Debug;
-
- if (!COFF::isReservedSectionNumber(SectionNumber))
- return SymbolRef::ST_Data;
-
- return SymbolRef::ST_Other;
-}
-
-Expected<uint32_t> COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {
- COFFSymbolRef Symb = getCOFFSymbol(Ref);
- uint32_t Result = SymbolRef::SF_None;
-
- if (Symb.isExternal() || Symb.isWeakExternal())
- Result |= SymbolRef::SF_Global;
-
- if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {
- Result |= SymbolRef::SF_Weak;
- if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)
- Result |= SymbolRef::SF_Undefined;
- }
-
- if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)
- Result |= SymbolRef::SF_Absolute;
-
- if (Symb.isFileRecord())
- Result |= SymbolRef::SF_FormatSpecific;
-
- if (Symb.isSectionDefinition())
- Result |= SymbolRef::SF_FormatSpecific;
-
- if (Symb.isCommon())
- Result |= SymbolRef::SF_Common;
-
- if (Symb.isUndefined())
- Result |= SymbolRef::SF_Undefined;
-
- return Result;
-}
-
-uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {
- COFFSymbolRef Symb = getCOFFSymbol(Ref);
- return Symb.getValue();
-}
-
-Expected<section_iterator>
-COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {
- COFFSymbolRef Symb = getCOFFSymbol(Ref);
- if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))
- return section_end();
- Expected<const coff_section *> Sec = getSection(Symb.getSectionNumber());
- if (!Sec)
- return Sec.takeError();
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(*Sec);
- return section_iterator(SectionRef(Ret, this));
-}
-
-unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {
- COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());
- return Symb.getSectionNumber();
-}
-
-void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {
- const coff_section *Sec = toSec(Ref);
- Sec += 1;
- Ref.p = reinterpret_cast<uintptr_t>(Sec);
-}
-
-Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- return getSectionName(Sec);
-}
-
-uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- uint64_t Result = Sec->VirtualAddress;
-
- // The section VirtualAddress does not include ImageBase, and we want to
- // return virtual addresses.
- Result += getImageBase();
- return Result;
-}
-
-uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
- return toSec(Sec) - SectionTable;
-}
-
-uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {
- return getSectionSize(toSec(Ref));
-}
-
-Expected<ArrayRef<uint8_t>>
-COFFObjectFile::getSectionContents(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- ArrayRef<uint8_t> Res;
- if (Error E = getSectionContents(Sec, Res))
- return std::move(E);
- return Res;
-}
-
-uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- return Sec->getAlignment();
-}
-
-bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
- return false;
-}
-
-bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;
-}
-
-bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
-}
-
-bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
- COFF::IMAGE_SCN_MEM_READ |
- COFF::IMAGE_SCN_MEM_WRITE;
- return (Sec->Characteristics & BssFlags) == BssFlags;
-}
-
-// The .debug sections are the only debug sections for COFF
-// (\see MCObjectFileInfo.cpp).
-bool COFFObjectFile::isDebugSection(StringRef SectionName) const {
- return SectionName.startswith(".debug");
-}
-
-unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {
- uintptr_t Offset =
+ assert(Offset % sizeof(coff_section) == 0 &&
+ "Section did not point to the beginning of a section");
+#endif
+
+ return Addr;
+}
+
+void COFFObjectFile::moveSymbolNext(DataRefImpl &Ref) const {
+ auto End = reinterpret_cast<uintptr_t>(StringTable);
+ if (SymbolTable16) {
+ const coff_symbol16 *Symb = toSymb<coff_symbol16>(Ref);
+ Symb += 1 + Symb->NumberOfAuxSymbols;
+ Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
+ } else if (SymbolTable32) {
+ const coff_symbol32 *Symb = toSymb<coff_symbol32>(Ref);
+ Symb += 1 + Symb->NumberOfAuxSymbols;
+ Ref.p = std::min(reinterpret_cast<uintptr_t>(Symb), End);
+ } else {
+ llvm_unreachable("no symbol table pointer!");
+ }
+}
+
+Expected<StringRef> COFFObjectFile::getSymbolName(DataRefImpl Ref) const {
+ return getSymbolName(getCOFFSymbol(Ref));
+}
+
+uint64_t COFFObjectFile::getSymbolValueImpl(DataRefImpl Ref) const {
+ return getCOFFSymbol(Ref).getValue();
+}
+
+uint32_t COFFObjectFile::getSymbolAlignment(DataRefImpl Ref) const {
+ // MSVC/link.exe seems to align symbols to the next-power-of-2
+ // up to 32 bytes.
+ COFFSymbolRef Symb = getCOFFSymbol(Ref);
+ return std::min(uint64_t(32), PowerOf2Ceil(Symb.getValue()));
+}
+
+Expected<uint64_t> COFFObjectFile::getSymbolAddress(DataRefImpl Ref) const {
+ uint64_t Result = cantFail(getSymbolValue(Ref));
+ COFFSymbolRef Symb = getCOFFSymbol(Ref);
+ int32_t SectionNumber = Symb.getSectionNumber();
+
+ if (Symb.isAnyUndefined() || Symb.isCommon() ||
+ COFF::isReservedSectionNumber(SectionNumber))
+ return Result;
+
+ Expected<const coff_section *> Section = getSection(SectionNumber);
+ if (!Section)
+ return Section.takeError();
+ Result += (*Section)->VirtualAddress;
+
+ // The section VirtualAddress does not include ImageBase, and we want to
+ // return virtual addresses.
+ Result += getImageBase();
+
+ return Result;
+}
+
+Expected<SymbolRef::Type> COFFObjectFile::getSymbolType(DataRefImpl Ref) const {
+ COFFSymbolRef Symb = getCOFFSymbol(Ref);
+ int32_t SectionNumber = Symb.getSectionNumber();
+
+ if (Symb.getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION)
+ return SymbolRef::ST_Function;
+ if (Symb.isAnyUndefined())
+ return SymbolRef::ST_Unknown;
+ if (Symb.isCommon())
+ return SymbolRef::ST_Data;
+ if (Symb.isFileRecord())
+ return SymbolRef::ST_File;
+
+ // TODO: perhaps we need a new symbol type ST_Section.
+ if (SectionNumber == COFF::IMAGE_SYM_DEBUG || Symb.isSectionDefinition())
+ return SymbolRef::ST_Debug;
+
+ if (!COFF::isReservedSectionNumber(SectionNumber))
+ return SymbolRef::ST_Data;
+
+ return SymbolRef::ST_Other;
+}
+
+Expected<uint32_t> COFFObjectFile::getSymbolFlags(DataRefImpl Ref) const {
+ COFFSymbolRef Symb = getCOFFSymbol(Ref);
+ uint32_t Result = SymbolRef::SF_None;
+
+ if (Symb.isExternal() || Symb.isWeakExternal())
+ Result |= SymbolRef::SF_Global;
+
+ if (const coff_aux_weak_external *AWE = Symb.getWeakExternal()) {
+ Result |= SymbolRef::SF_Weak;
+ if (AWE->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)
+ Result |= SymbolRef::SF_Undefined;
+ }
+
+ if (Symb.getSectionNumber() == COFF::IMAGE_SYM_ABSOLUTE)
+ Result |= SymbolRef::SF_Absolute;
+
+ if (Symb.isFileRecord())
+ Result |= SymbolRef::SF_FormatSpecific;
+
+ if (Symb.isSectionDefinition())
+ Result |= SymbolRef::SF_FormatSpecific;
+
+ if (Symb.isCommon())
+ Result |= SymbolRef::SF_Common;
+
+ if (Symb.isUndefined())
+ Result |= SymbolRef::SF_Undefined;
+
+ return Result;
+}
+
+uint64_t COFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Ref) const {
+ COFFSymbolRef Symb = getCOFFSymbol(Ref);
+ return Symb.getValue();
+}
+
+Expected<section_iterator>
+COFFObjectFile::getSymbolSection(DataRefImpl Ref) const {
+ COFFSymbolRef Symb = getCOFFSymbol(Ref);
+ if (COFF::isReservedSectionNumber(Symb.getSectionNumber()))
+ return section_end();
+ Expected<const coff_section *> Sec = getSection(Symb.getSectionNumber());
+ if (!Sec)
+ return Sec.takeError();
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(*Sec);
+ return section_iterator(SectionRef(Ret, this));
+}
+
+unsigned COFFObjectFile::getSymbolSectionID(SymbolRef Sym) const {
+ COFFSymbolRef Symb = getCOFFSymbol(Sym.getRawDataRefImpl());
+ return Symb.getSectionNumber();
+}
+
+void COFFObjectFile::moveSectionNext(DataRefImpl &Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ Sec += 1;
+ Ref.p = reinterpret_cast<uintptr_t>(Sec);
+}
+
+Expected<StringRef> COFFObjectFile::getSectionName(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ return getSectionName(Sec);
+}
+
+uint64_t COFFObjectFile::getSectionAddress(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ uint64_t Result = Sec->VirtualAddress;
+
+ // The section VirtualAddress does not include ImageBase, and we want to
+ // return virtual addresses.
+ Result += getImageBase();
+ return Result;
+}
+
+uint64_t COFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
+ return toSec(Sec) - SectionTable;
+}
+
+uint64_t COFFObjectFile::getSectionSize(DataRefImpl Ref) const {
+ return getSectionSize(toSec(Ref));
+}
+
+Expected<ArrayRef<uint8_t>>
+COFFObjectFile::getSectionContents(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ ArrayRef<uint8_t> Res;
+ if (Error E = getSectionContents(Sec, Res))
+ return std::move(E);
+ return Res;
+}
+
+uint64_t COFFObjectFile::getSectionAlignment(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ return Sec->getAlignment();
+}
+
+bool COFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
+ return false;
+}
+
+bool COFFObjectFile::isSectionText(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ return Sec->Characteristics & COFF::IMAGE_SCN_CNT_CODE;
+}
+
+bool COFFObjectFile::isSectionData(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ return Sec->Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
+}
+
+bool COFFObjectFile::isSectionBSS(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ const uint32_t BssFlags = COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA |
+ COFF::IMAGE_SCN_MEM_READ |
+ COFF::IMAGE_SCN_MEM_WRITE;
+ return (Sec->Characteristics & BssFlags) == BssFlags;
+}
+
+// The .debug sections are the only debug sections for COFF
+// (\see MCObjectFileInfo.cpp).
+bool COFFObjectFile::isDebugSection(StringRef SectionName) const {
+ return SectionName.startswith(".debug");
+}
+
+unsigned COFFObjectFile::getSectionID(SectionRef Sec) const {
+ uintptr_t Offset =
Sec.getRawDataRefImpl().p - reinterpret_cast<uintptr_t>(SectionTable);
- assert((Offset % sizeof(coff_section)) == 0);
- return (Offset / sizeof(coff_section)) + 1;
-}
-
-bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- // In COFF, a virtual section won't have any in-file
- // content, so the file pointer to the content will be zero.
- return Sec->PointerToRawData == 0;
-}
-
-static uint32_t getNumberOfRelocations(const coff_section *Sec,
- MemoryBufferRef M, const uint8_t *base) {
- // The field for the number of relocations in COFF section table is only
- // 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to
- // NumberOfRelocations field, and the actual relocation count is stored in the
- // VirtualAddress field in the first relocation entry.
- if (Sec->hasExtendedRelocations()) {
- const coff_relocation *FirstReloc;
- if (Error E = getObject(FirstReloc, M,
- reinterpret_cast<const coff_relocation *>(
- base + Sec->PointerToRelocations))) {
- consumeError(std::move(E));
- return 0;
- }
- // -1 to exclude this first relocation entry.
- return FirstReloc->VirtualAddress - 1;
- }
- return Sec->NumberOfRelocations;
-}
-
-static const coff_relocation *
-getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {
- uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);
- if (!NumRelocs)
- return nullptr;
- auto begin = reinterpret_cast<const coff_relocation *>(
- Base + Sec->PointerToRelocations);
- if (Sec->hasExtendedRelocations()) {
- // Skip the first relocation entry repurposed to store the number of
- // relocations.
- begin++;
- }
+ assert((Offset % sizeof(coff_section)) == 0);
+ return (Offset / sizeof(coff_section)) + 1;
+}
+
+bool COFFObjectFile::isSectionVirtual(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ // In COFF, a virtual section won't have any in-file
+ // content, so the file pointer to the content will be zero.
+ return Sec->PointerToRawData == 0;
+}
+
+static uint32_t getNumberOfRelocations(const coff_section *Sec,
+ MemoryBufferRef M, const uint8_t *base) {
+ // The field for the number of relocations in COFF section table is only
+ // 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to
+ // NumberOfRelocations field, and the actual relocation count is stored in the
+ // VirtualAddress field in the first relocation entry.
+ if (Sec->hasExtendedRelocations()) {
+ const coff_relocation *FirstReloc;
+ if (Error E = getObject(FirstReloc, M,
+ reinterpret_cast<const coff_relocation *>(
+ base + Sec->PointerToRelocations))) {
+ consumeError(std::move(E));
+ return 0;
+ }
+ // -1 to exclude this first relocation entry.
+ return FirstReloc->VirtualAddress - 1;
+ }
+ return Sec->NumberOfRelocations;
+}
+
+static const coff_relocation *
+getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base) {
+ uint64_t NumRelocs = getNumberOfRelocations(Sec, M, Base);
+ if (!NumRelocs)
+ return nullptr;
+ auto begin = reinterpret_cast<const coff_relocation *>(
+ Base + Sec->PointerToRelocations);
+ if (Sec->hasExtendedRelocations()) {
+ // Skip the first relocation entry repurposed to store the number of
+ // relocations.
+ begin++;
+ }
if (auto E = Binary::checkOffset(M, reinterpret_cast<uintptr_t>(begin),
- sizeof(coff_relocation) * NumRelocs)) {
- consumeError(std::move(E));
- return nullptr;
- }
- return begin;
-}
-
-relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- const coff_relocation *begin = getFirstReloc(Sec, Data, base());
- if (begin && Sec->VirtualAddress != 0)
- report_fatal_error("Sections with relocations should have an address of 0");
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(begin);
- return relocation_iterator(RelocationRef(Ret, this));
-}
-
-relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {
- const coff_section *Sec = toSec(Ref);
- const coff_relocation *I = getFirstReloc(Sec, Data, base());
- if (I)
- I += getNumberOfRelocations(Sec, Data, base());
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(I);
- return relocation_iterator(RelocationRef(Ret, this));
-}
-
-// Initialize the pointer to the symbol table.
-Error COFFObjectFile::initSymbolTablePtr() {
- if (COFFHeader)
- if (Error E = getObject(
- SymbolTable16, Data, base() + getPointerToSymbolTable(),
- (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
- return E;
-
- if (COFFBigObjHeader)
- if (Error E = getObject(
- SymbolTable32, Data, base() + getPointerToSymbolTable(),
- (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
- return E;
-
- // Find string table. The first four byte of the string table contains the
- // total size of the string table, including the size field itself. If the
- // string table is empty, the value of the first four byte would be 4.
- uint32_t StringTableOffset = getPointerToSymbolTable() +
- getNumberOfSymbols() * getSymbolTableEntrySize();
- const uint8_t *StringTableAddr = base() + StringTableOffset;
- const ulittle32_t *StringTableSizePtr;
- if (Error E = getObject(StringTableSizePtr, Data, StringTableAddr))
- return E;
- StringTableSize = *StringTableSizePtr;
- if (Error E = getObject(StringTable, Data, StringTableAddr, StringTableSize))
- return E;
-
- // Treat table sizes < 4 as empty because contrary to the PECOFF spec, some
- // tools like cvtres write a size of 0 for an empty table instead of 4.
- if (StringTableSize < 4)
- StringTableSize = 4;
-
- // Check that the string table is null terminated if has any in it.
- if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)
- return errorCodeToError(object_error::parse_failed);
- return Error::success();
-}
-
-uint64_t COFFObjectFile::getImageBase() const {
- if (PE32Header)
- return PE32Header->ImageBase;
- else if (PE32PlusHeader)
- return PE32PlusHeader->ImageBase;
- // This actually comes up in practice.
- return 0;
-}
-
-// Returns the file offset for the given VA.
-Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
- uint64_t ImageBase = getImageBase();
- uint64_t Rva = Addr - ImageBase;
- assert(Rva <= UINT32_MAX);
- return getRvaPtr((uint32_t)Rva, Res);
-}
-
-// Returns the file offset for the given RVA.
-Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const {
- for (const SectionRef &S : sections()) {
- const coff_section *Section = getCOFFSection(S);
- uint32_t SectionStart = Section->VirtualAddress;
- uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
- if (SectionStart <= Addr && Addr < SectionEnd) {
- uint32_t Offset = Addr - SectionStart;
+ sizeof(coff_relocation) * NumRelocs)) {
+ consumeError(std::move(E));
+ return nullptr;
+ }
+ return begin;
+}
+
+relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ const coff_relocation *begin = getFirstReloc(Sec, Data, base());
+ if (begin && Sec->VirtualAddress != 0)
+ report_fatal_error("Sections with relocations should have an address of 0");
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(begin);
+ return relocation_iterator(RelocationRef(Ret, this));
+}
+
+relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {
+ const coff_section *Sec = toSec(Ref);
+ const coff_relocation *I = getFirstReloc(Sec, Data, base());
+ if (I)
+ I += getNumberOfRelocations(Sec, Data, base());
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(I);
+ return relocation_iterator(RelocationRef(Ret, this));
+}
+
+// Initialize the pointer to the symbol table.
+Error COFFObjectFile::initSymbolTablePtr() {
+ if (COFFHeader)
+ if (Error E = getObject(
+ SymbolTable16, Data, base() + getPointerToSymbolTable(),
+ (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
+ return E;
+
+ if (COFFBigObjHeader)
+ if (Error E = getObject(
+ SymbolTable32, Data, base() + getPointerToSymbolTable(),
+ (uint64_t)getNumberOfSymbols() * getSymbolTableEntrySize()))
+ return E;
+
+ // Find string table. The first four byte of the string table contains the
+ // total size of the string table, including the size field itself. If the
+ // string table is empty, the value of the first four byte would be 4.
+ uint32_t StringTableOffset = getPointerToSymbolTable() +
+ getNumberOfSymbols() * getSymbolTableEntrySize();
+ const uint8_t *StringTableAddr = base() + StringTableOffset;
+ const ulittle32_t *StringTableSizePtr;
+ if (Error E = getObject(StringTableSizePtr, Data, StringTableAddr))
+ return E;
+ StringTableSize = *StringTableSizePtr;
+ if (Error E = getObject(StringTable, Data, StringTableAddr, StringTableSize))
+ return E;
+
+ // Treat table sizes < 4 as empty because contrary to the PECOFF spec, some
+ // tools like cvtres write a size of 0 for an empty table instead of 4.
+ if (StringTableSize < 4)
+ StringTableSize = 4;
+
+ // Check that the string table is null terminated if has any in it.
+ if (StringTableSize > 4 && StringTable[StringTableSize - 1] != 0)
+ return errorCodeToError(object_error::parse_failed);
+ return Error::success();
+}
+
+uint64_t COFFObjectFile::getImageBase() const {
+ if (PE32Header)
+ return PE32Header->ImageBase;
+ else if (PE32PlusHeader)
+ return PE32PlusHeader->ImageBase;
+ // This actually comes up in practice.
+ return 0;
+}
+
+// Returns the file offset for the given VA.
+Error COFFObjectFile::getVaPtr(uint64_t Addr, uintptr_t &Res) const {
+ uint64_t ImageBase = getImageBase();
+ uint64_t Rva = Addr - ImageBase;
+ assert(Rva <= UINT32_MAX);
+ return getRvaPtr((uint32_t)Rva, Res);
+}
+
+// Returns the file offset for the given RVA.
+Error COFFObjectFile::getRvaPtr(uint32_t Addr, uintptr_t &Res) const {
+ for (const SectionRef &S : sections()) {
+ const coff_section *Section = getCOFFSection(S);
+ uint32_t SectionStart = Section->VirtualAddress;
+ uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
+ if (SectionStart <= Addr && Addr < SectionEnd) {
+ uint32_t Offset = Addr - SectionStart;
Res = reinterpret_cast<uintptr_t>(base()) + Section->PointerToRawData +
Offset;
- return Error::success();
- }
- }
- return errorCodeToError(object_error::parse_failed);
-}
-
-Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
- ArrayRef<uint8_t> &Contents) const {
- for (const SectionRef &S : sections()) {
- const coff_section *Section = getCOFFSection(S);
- uint32_t SectionStart = Section->VirtualAddress;
- // Check if this RVA is within the section bounds. Be careful about integer
- // overflow.
- uint32_t OffsetIntoSection = RVA - SectionStart;
- if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
- Size <= Section->VirtualSize - OffsetIntoSection) {
+ return Error::success();
+ }
+ }
+ return errorCodeToError(object_error::parse_failed);
+}
+
+Error COFFObjectFile::getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size,
+ ArrayRef<uint8_t> &Contents) const {
+ for (const SectionRef &S : sections()) {
+ const coff_section *Section = getCOFFSection(S);
+ uint32_t SectionStart = Section->VirtualAddress;
+ // Check if this RVA is within the section bounds. Be careful about integer
+ // overflow.
+ uint32_t OffsetIntoSection = RVA - SectionStart;
+ if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
+ Size <= Section->VirtualSize - OffsetIntoSection) {
uintptr_t Begin = reinterpret_cast<uintptr_t>(base()) +
Section->PointerToRawData + OffsetIntoSection;
- Contents =
- ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);
- return Error::success();
- }
- }
- return errorCodeToError(object_error::parse_failed);
-}
-
-// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
-// table entry.
-Error COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
- StringRef &Name) const {
- uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(Rva, IntPtr))
- return E;
- const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);
- Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);
- Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));
- return Error::success();
-}
-
-Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
- const codeview::DebugInfo *&PDBInfo,
- StringRef &PDBFileName) const {
- ArrayRef<uint8_t> InfoBytes;
- if (Error E = getRvaAndSizeAsBytes(
- DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes))
- return E;
- if (InfoBytes.size() < sizeof(*PDBInfo) + 1)
- return errorCodeToError(object_error::parse_failed);
- PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());
- InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));
- PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
- InfoBytes.size());
- // Truncate the name at the first null byte. Ignore any padding.
- PDBFileName = PDBFileName.split('\0').first;
- return Error::success();
-}
-
-Error COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,
- StringRef &PDBFileName) const {
- for (const debug_directory &D : debug_directories())
- if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
- return getDebugPDBInfo(&D, PDBInfo, PDBFileName);
- // If we get here, there is no PDB info to return.
- PDBInfo = nullptr;
- PDBFileName = StringRef();
- return Error::success();
-}
-
-// Find the import table.
-Error COFFObjectFile::initImportTablePtr() {
- // First, we get the RVA of the import table. If the file lacks a pointer to
- // the import table, do nothing.
- const data_directory *DataEntry = getDataDirectory(COFF::IMPORT_TABLE);
- if (!DataEntry)
- return Error::success();
-
- // Do nothing if the pointer to import table is NULL.
- if (DataEntry->RelativeVirtualAddress == 0)
- return Error::success();
-
- uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;
-
- // Find the section that contains the RVA. This is needed because the RVA is
- // the import table's memory address which is different from its file offset.
- uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(ImportTableRva, IntPtr))
- return E;
- if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
- return E;
- ImportDirectory = reinterpret_cast<
- const coff_import_directory_table_entry *>(IntPtr);
- return Error::success();
-}
-
-// Initializes DelayImportDirectory and NumberOfDelayImportDirectory.
-Error COFFObjectFile::initDelayImportTablePtr() {
- const data_directory *DataEntry =
- getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR);
- if (!DataEntry)
- return Error::success();
- if (DataEntry->RelativeVirtualAddress == 0)
- return Error::success();
-
- uint32_t RVA = DataEntry->RelativeVirtualAddress;
- NumberOfDelayImportDirectory = DataEntry->Size /
- sizeof(delay_import_directory_table_entry) - 1;
-
- uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(RVA, IntPtr))
- return E;
- DelayImportDirectory = reinterpret_cast<
- const delay_import_directory_table_entry *>(IntPtr);
- return Error::success();
-}
-
-// Find the export table.
-Error COFFObjectFile::initExportTablePtr() {
- // First, we get the RVA of the export table. If the file lacks a pointer to
- // the export table, do nothing.
- const data_directory *DataEntry = getDataDirectory(COFF::EXPORT_TABLE);
- if (!DataEntry)
- return Error::success();
-
- // Do nothing if the pointer to export table is NULL.
- if (DataEntry->RelativeVirtualAddress == 0)
- return Error::success();
-
- uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
- uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(ExportTableRva, IntPtr))
- return E;
- ExportDirectory =
- reinterpret_cast<const export_directory_table_entry *>(IntPtr);
- return Error::success();
-}
-
-Error COFFObjectFile::initBaseRelocPtr() {
- const data_directory *DataEntry =
- getDataDirectory(COFF::BASE_RELOCATION_TABLE);
- if (!DataEntry)
- return Error::success();
- if (DataEntry->RelativeVirtualAddress == 0)
- return Error::success();
-
- uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
- return E;
- BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(
- IntPtr);
- BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(
- IntPtr + DataEntry->Size);
- // FIXME: Verify the section containing BaseRelocHeader has at least
- // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
- return Error::success();
-}
-
-Error COFFObjectFile::initDebugDirectoryPtr() {
- // Get the RVA of the debug directory. Do nothing if it does not exist.
- const data_directory *DataEntry = getDataDirectory(COFF::DEBUG_DIRECTORY);
- if (!DataEntry)
- return Error::success();
-
- // Do nothing if the RVA is NULL.
- if (DataEntry->RelativeVirtualAddress == 0)
- return Error::success();
-
- // Check that the size is a multiple of the entry size.
- if (DataEntry->Size % sizeof(debug_directory) != 0)
- return errorCodeToError(object_error::parse_failed);
-
- uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
- return E;
- DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
- DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(
- IntPtr + DataEntry->Size);
- // FIXME: Verify the section containing DebugDirectoryBegin has at least
- // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
- return Error::success();
-}
-
+ Contents =
+ ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(Begin), Size);
+ return Error::success();
+ }
+ }
+ return errorCodeToError(object_error::parse_failed);
+}
+
+// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name
+// table entry.
+Error COFFObjectFile::getHintName(uint32_t Rva, uint16_t &Hint,
+ StringRef &Name) const {
+ uintptr_t IntPtr = 0;
+ if (Error E = getRvaPtr(Rva, IntPtr))
+ return E;
+ const uint8_t *Ptr = reinterpret_cast<const uint8_t *>(IntPtr);
+ Hint = *reinterpret_cast<const ulittle16_t *>(Ptr);
+ Name = StringRef(reinterpret_cast<const char *>(Ptr + 2));
+ return Error::success();
+}
+
+Error COFFObjectFile::getDebugPDBInfo(const debug_directory *DebugDir,
+ const codeview::DebugInfo *&PDBInfo,
+ StringRef &PDBFileName) const {
+ ArrayRef<uint8_t> InfoBytes;
+ if (Error E = getRvaAndSizeAsBytes(
+ DebugDir->AddressOfRawData, DebugDir->SizeOfData, InfoBytes))
+ return E;
+ if (InfoBytes.size() < sizeof(*PDBInfo) + 1)
+ return errorCodeToError(object_error::parse_failed);
+ PDBInfo = reinterpret_cast<const codeview::DebugInfo *>(InfoBytes.data());
+ InfoBytes = InfoBytes.drop_front(sizeof(*PDBInfo));
+ PDBFileName = StringRef(reinterpret_cast<const char *>(InfoBytes.data()),
+ InfoBytes.size());
+ // Truncate the name at the first null byte. Ignore any padding.
+ PDBFileName = PDBFileName.split('\0').first;
+ return Error::success();
+}
+
+Error COFFObjectFile::getDebugPDBInfo(const codeview::DebugInfo *&PDBInfo,
+ StringRef &PDBFileName) const {
+ for (const debug_directory &D : debug_directories())
+ if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
+ return getDebugPDBInfo(&D, PDBInfo, PDBFileName);
+ // If we get here, there is no PDB info to return.
+ PDBInfo = nullptr;
+ PDBFileName = StringRef();
+ return Error::success();
+}
+
+// Find the import table.
+Error COFFObjectFile::initImportTablePtr() {
+ // First, we get the RVA of the import table. If the file lacks a pointer to
+ // the import table, do nothing.
+ const data_directory *DataEntry = getDataDirectory(COFF::IMPORT_TABLE);
+ if (!DataEntry)
+ return Error::success();
+
+ // Do nothing if the pointer to import table is NULL.
+ if (DataEntry->RelativeVirtualAddress == 0)
+ return Error::success();
+
+ uint32_t ImportTableRva = DataEntry->RelativeVirtualAddress;
+
+ // Find the section that contains the RVA. This is needed because the RVA is
+ // the import table's memory address which is different from its file offset.
+ uintptr_t IntPtr = 0;
+ if (Error E = getRvaPtr(ImportTableRva, IntPtr))
+ return E;
+ if (Error E = checkOffset(Data, IntPtr, DataEntry->Size))
+ return E;
+ ImportDirectory = reinterpret_cast<
+ const coff_import_directory_table_entry *>(IntPtr);
+ return Error::success();
+}
+
+// Initializes DelayImportDirectory and NumberOfDelayImportDirectory.
+Error COFFObjectFile::initDelayImportTablePtr() {
+ const data_directory *DataEntry =
+ getDataDirectory(COFF::DELAY_IMPORT_DESCRIPTOR);
+ if (!DataEntry)
+ return Error::success();
+ if (DataEntry->RelativeVirtualAddress == 0)
+ return Error::success();
+
+ uint32_t RVA = DataEntry->RelativeVirtualAddress;
+ NumberOfDelayImportDirectory = DataEntry->Size /
+ sizeof(delay_import_directory_table_entry) - 1;
+
+ uintptr_t IntPtr = 0;
+ if (Error E = getRvaPtr(RVA, IntPtr))
+ return E;
+ DelayImportDirectory = reinterpret_cast<
+ const delay_import_directory_table_entry *>(IntPtr);
+ return Error::success();
+}
+
+// Find the export table.
+Error COFFObjectFile::initExportTablePtr() {
+ // First, we get the RVA of the export table. If the file lacks a pointer to
+ // the export table, do nothing.
+ const data_directory *DataEntry = getDataDirectory(COFF::EXPORT_TABLE);
+ if (!DataEntry)
+ return Error::success();
+
+ // Do nothing if the pointer to export table is NULL.
+ if (DataEntry->RelativeVirtualAddress == 0)
+ return Error::success();
+
+ uint32_t ExportTableRva = DataEntry->RelativeVirtualAddress;
+ uintptr_t IntPtr = 0;
+ if (Error E = getRvaPtr(ExportTableRva, IntPtr))
+ return E;
+ ExportDirectory =
+ reinterpret_cast<const export_directory_table_entry *>(IntPtr);
+ return Error::success();
+}
+
+Error COFFObjectFile::initBaseRelocPtr() {
+ const data_directory *DataEntry =
+ getDataDirectory(COFF::BASE_RELOCATION_TABLE);
+ if (!DataEntry)
+ return Error::success();
+ if (DataEntry->RelativeVirtualAddress == 0)
+ return Error::success();
+
+ uintptr_t IntPtr = 0;
+ if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+ return E;
+ BaseRelocHeader = reinterpret_cast<const coff_base_reloc_block_header *>(
+ IntPtr);
+ BaseRelocEnd = reinterpret_cast<coff_base_reloc_block_header *>(
+ IntPtr + DataEntry->Size);
+ // FIXME: Verify the section containing BaseRelocHeader has at least
+ // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
+ return Error::success();
+}
+
+Error COFFObjectFile::initDebugDirectoryPtr() {
+ // Get the RVA of the debug directory. Do nothing if it does not exist.
+ const data_directory *DataEntry = getDataDirectory(COFF::DEBUG_DIRECTORY);
+ if (!DataEntry)
+ return Error::success();
+
+ // Do nothing if the RVA is NULL.
+ if (DataEntry->RelativeVirtualAddress == 0)
+ return Error::success();
+
+ // Check that the size is a multiple of the entry size.
+ if (DataEntry->Size % sizeof(debug_directory) != 0)
+ return errorCodeToError(object_error::parse_failed);
+
+ uintptr_t IntPtr = 0;
+ if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+ return E;
+ DebugDirectoryBegin = reinterpret_cast<const debug_directory *>(IntPtr);
+ DebugDirectoryEnd = reinterpret_cast<const debug_directory *>(
+ IntPtr + DataEntry->Size);
+ // FIXME: Verify the section containing DebugDirectoryBegin has at least
+ // DataEntry->Size bytes after DataEntry->RelativeVirtualAddress.
+ return Error::success();
+}
+
Error COFFObjectFile::initTLSDirectoryPtr() {
// Get the RVA of the TLS directory. Do nothing if it does not exist.
const data_directory *DataEntry = getDataDirectory(COFF::TLS_TABLE);
@@ -684,1201 +684,1201 @@ Error COFFObjectFile::initTLSDirectoryPtr() {
return Error::success();
}
-Error COFFObjectFile::initLoadConfigPtr() {
- // Get the RVA of the debug directory. Do nothing if it does not exist.
- const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);
- if (!DataEntry)
- return Error::success();
-
- // Do nothing if the RVA is NULL.
- if (DataEntry->RelativeVirtualAddress == 0)
- return Error::success();
- uintptr_t IntPtr = 0;
- if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
- return E;
-
- LoadConfig = (const void *)IntPtr;
- return Error::success();
-}
-
-Expected<std::unique_ptr<COFFObjectFile>>
-COFFObjectFile::create(MemoryBufferRef Object) {
- std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object)));
- if (Error E = Obj->initialize())
- return std::move(E);
- return std::move(Obj);
-}
-
-COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)
- : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
- COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
- DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),
- SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),
- ImportDirectory(nullptr), DelayImportDirectory(nullptr),
- NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),
- BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
+Error COFFObjectFile::initLoadConfigPtr() {
+ // Get the RVA of the debug directory. Do nothing if it does not exist.
+ const data_directory *DataEntry = getDataDirectory(COFF::LOAD_CONFIG_TABLE);
+ if (!DataEntry)
+ return Error::success();
+
+ // Do nothing if the RVA is NULL.
+ if (DataEntry->RelativeVirtualAddress == 0)
+ return Error::success();
+ uintptr_t IntPtr = 0;
+ if (Error E = getRvaPtr(DataEntry->RelativeVirtualAddress, IntPtr))
+ return E;
+
+ LoadConfig = (const void *)IntPtr;
+ return Error::success();
+}
+
+Expected<std::unique_ptr<COFFObjectFile>>
+COFFObjectFile::create(MemoryBufferRef Object) {
+ std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object)));
+ if (Error E = Obj->initialize())
+ return std::move(E);
+ return std::move(Obj);
+}
+
+COFFObjectFile::COFFObjectFile(MemoryBufferRef Object)
+ : ObjectFile(Binary::ID_COFF, Object), COFFHeader(nullptr),
+ COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
+ DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),
+ SymbolTable32(nullptr), StringTable(nullptr), StringTableSize(0),
+ ImportDirectory(nullptr), DelayImportDirectory(nullptr),
+ NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),
+ BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),
TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}
-
-Error COFFObjectFile::initialize() {
- // Check that we at least have enough room for a header.
- std::error_code EC;
- if (!checkSize(Data, EC, sizeof(coff_file_header)))
- return errorCodeToError(EC);
-
- // The current location in the file where we are looking at.
- uint64_t CurPtr = 0;
-
- // PE header is optional and is present only in executables. If it exists,
- // it is placed right after COFF header.
- bool HasPEHeader = false;
-
- // Check if this is a PE/COFF file.
- if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {
- // PE/COFF, seek through MS-DOS compatibility stub and 4-byte
- // PE signature to find 'normal' COFF header.
- const auto *DH = reinterpret_cast<const dos_header *>(base());
- if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {
- CurPtr = DH->AddressOfNewExeHeader;
- // Check the PE magic bytes. ("PE\0\0")
- if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {
- return errorCodeToError(object_error::parse_failed);
- }
- CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.
- HasPEHeader = true;
- }
- }
-
- if (Error E = getObject(COFFHeader, Data, base() + CurPtr))
- return E;
-
- // It might be a bigobj file, let's check. Note that COFF bigobj and COFF
- // import libraries share a common prefix but bigobj is more restrictive.
- if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
- COFFHeader->NumberOfSections == uint16_t(0xffff) &&
- checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {
- if (Error E = getObject(COFFBigObjHeader, Data, base() + CurPtr))
- return E;
-
- // Verify that we are dealing with bigobj.
- if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&
- std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,
- sizeof(COFF::BigObjMagic)) == 0) {
- COFFHeader = nullptr;
- CurPtr += sizeof(coff_bigobj_file_header);
- } else {
- // It's not a bigobj.
- COFFBigObjHeader = nullptr;
- }
- }
- if (COFFHeader) {
- // The prior checkSize call may have failed. This isn't a hard error
- // because we were just trying to sniff out bigobj.
- EC = std::error_code();
- CurPtr += sizeof(coff_file_header);
-
- if (COFFHeader->isImportLibrary())
- return errorCodeToError(EC);
- }
-
- if (HasPEHeader) {
- const pe32_header *Header;
- if (Error E = getObject(Header, Data, base() + CurPtr))
- return E;
-
- const uint8_t *DataDirAddr;
- uint64_t DataDirSize;
- if (Header->Magic == COFF::PE32Header::PE32) {
- PE32Header = Header;
- DataDirAddr = base() + CurPtr + sizeof(pe32_header);
- DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;
- } else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {
- PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);
- DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);
- DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
- } else {
- // It's neither PE32 nor PE32+.
- return errorCodeToError(object_error::parse_failed);
- }
- if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))
- return E;
- }
-
- if (COFFHeader)
- CurPtr += COFFHeader->SizeOfOptionalHeader;
-
- assert(COFFHeader || COFFBigObjHeader);
-
- if (Error E =
- getObject(SectionTable, Data, base() + CurPtr,
- (uint64_t)getNumberOfSections() * sizeof(coff_section)))
- return E;
-
- // Initialize the pointer to the symbol table.
- if (getPointerToSymbolTable() != 0) {
- if (Error E = initSymbolTablePtr()) {
- // Recover from errors reading the symbol table.
- consumeError(std::move(E));
- SymbolTable16 = nullptr;
- SymbolTable32 = nullptr;
- StringTable = nullptr;
- StringTableSize = 0;
- }
- } else {
- // We had better not have any symbols if we don't have a symbol table.
- if (getNumberOfSymbols() != 0) {
- return errorCodeToError(object_error::parse_failed);
- }
- }
-
- // Initialize the pointer to the beginning of the import table.
- if (Error E = initImportTablePtr())
- return E;
- if (Error E = initDelayImportTablePtr())
- return E;
-
- // Initialize the pointer to the export table.
- if (Error E = initExportTablePtr())
- return E;
-
- // Initialize the pointer to the base relocation table.
- if (Error E = initBaseRelocPtr())
- return E;
-
+
+Error COFFObjectFile::initialize() {
+ // Check that we at least have enough room for a header.
+ std::error_code EC;
+ if (!checkSize(Data, EC, sizeof(coff_file_header)))
+ return errorCodeToError(EC);
+
+ // The current location in the file where we are looking at.
+ uint64_t CurPtr = 0;
+
+ // PE header is optional and is present only in executables. If it exists,
+ // it is placed right after COFF header.
+ bool HasPEHeader = false;
+
+ // Check if this is a PE/COFF file.
+ if (checkSize(Data, EC, sizeof(dos_header) + sizeof(COFF::PEMagic))) {
+ // PE/COFF, seek through MS-DOS compatibility stub and 4-byte
+ // PE signature to find 'normal' COFF header.
+ const auto *DH = reinterpret_cast<const dos_header *>(base());
+ if (DH->Magic[0] == 'M' && DH->Magic[1] == 'Z') {
+ CurPtr = DH->AddressOfNewExeHeader;
+ // Check the PE magic bytes. ("PE\0\0")
+ if (memcmp(base() + CurPtr, COFF::PEMagic, sizeof(COFF::PEMagic)) != 0) {
+ return errorCodeToError(object_error::parse_failed);
+ }
+ CurPtr += sizeof(COFF::PEMagic); // Skip the PE magic bytes.
+ HasPEHeader = true;
+ }
+ }
+
+ if (Error E = getObject(COFFHeader, Data, base() + CurPtr))
+ return E;
+
+ // It might be a bigobj file, let's check. Note that COFF bigobj and COFF
+ // import libraries share a common prefix but bigobj is more restrictive.
+ if (!HasPEHeader && COFFHeader->Machine == COFF::IMAGE_FILE_MACHINE_UNKNOWN &&
+ COFFHeader->NumberOfSections == uint16_t(0xffff) &&
+ checkSize(Data, EC, sizeof(coff_bigobj_file_header))) {
+ if (Error E = getObject(COFFBigObjHeader, Data, base() + CurPtr))
+ return E;
+
+ // Verify that we are dealing with bigobj.
+ if (COFFBigObjHeader->Version >= COFF::BigObjHeader::MinBigObjectVersion &&
+ std::memcmp(COFFBigObjHeader->UUID, COFF::BigObjMagic,
+ sizeof(COFF::BigObjMagic)) == 0) {
+ COFFHeader = nullptr;
+ CurPtr += sizeof(coff_bigobj_file_header);
+ } else {
+ // It's not a bigobj.
+ COFFBigObjHeader = nullptr;
+ }
+ }
+ if (COFFHeader) {
+ // The prior checkSize call may have failed. This isn't a hard error
+ // because we were just trying to sniff out bigobj.
+ EC = std::error_code();
+ CurPtr += sizeof(coff_file_header);
+
+ if (COFFHeader->isImportLibrary())
+ return errorCodeToError(EC);
+ }
+
+ if (HasPEHeader) {
+ const pe32_header *Header;
+ if (Error E = getObject(Header, Data, base() + CurPtr))
+ return E;
+
+ const uint8_t *DataDirAddr;
+ uint64_t DataDirSize;
+ if (Header->Magic == COFF::PE32Header::PE32) {
+ PE32Header = Header;
+ DataDirAddr = base() + CurPtr + sizeof(pe32_header);
+ DataDirSize = sizeof(data_directory) * PE32Header->NumberOfRvaAndSize;
+ } else if (Header->Magic == COFF::PE32Header::PE32_PLUS) {
+ PE32PlusHeader = reinterpret_cast<const pe32plus_header *>(Header);
+ DataDirAddr = base() + CurPtr + sizeof(pe32plus_header);
+ DataDirSize = sizeof(data_directory) * PE32PlusHeader->NumberOfRvaAndSize;
+ } else {
+ // It's neither PE32 nor PE32+.
+ return errorCodeToError(object_error::parse_failed);
+ }
+ if (Error E = getObject(DataDirectory, Data, DataDirAddr, DataDirSize))
+ return E;
+ }
+
+ if (COFFHeader)
+ CurPtr += COFFHeader->SizeOfOptionalHeader;
+
+ assert(COFFHeader || COFFBigObjHeader);
+
+ if (Error E =
+ getObject(SectionTable, Data, base() + CurPtr,
+ (uint64_t)getNumberOfSections() * sizeof(coff_section)))
+ return E;
+
+ // Initialize the pointer to the symbol table.
+ if (getPointerToSymbolTable() != 0) {
+ if (Error E = initSymbolTablePtr()) {
+ // Recover from errors reading the symbol table.
+ consumeError(std::move(E));
+ SymbolTable16 = nullptr;
+ SymbolTable32 = nullptr;
+ StringTable = nullptr;
+ StringTableSize = 0;
+ }
+ } else {
+ // We had better not have any symbols if we don't have a symbol table.
+ if (getNumberOfSymbols() != 0) {
+ return errorCodeToError(object_error::parse_failed);
+ }
+ }
+
+ // Initialize the pointer to the beginning of the import table.
+ if (Error E = initImportTablePtr())
+ return E;
+ if (Error E = initDelayImportTablePtr())
+ return E;
+
+ // Initialize the pointer to the export table.
+ if (Error E = initExportTablePtr())
+ return E;
+
+ // Initialize the pointer to the base relocation table.
+ if (Error E = initBaseRelocPtr())
+ return E;
+
// Initialize the pointer to the debug directory.
- if (Error E = initDebugDirectoryPtr())
- return E;
-
+ if (Error E = initDebugDirectoryPtr())
+ return E;
+
// Initialize the pointer to the TLS directory.
if (Error E = initTLSDirectoryPtr())
return E;
- if (Error E = initLoadConfigPtr())
- return E;
-
- return Error::success();
-}
-
-basic_symbol_iterator COFFObjectFile::symbol_begin() const {
- DataRefImpl Ret;
- Ret.p = getSymbolTable();
- return basic_symbol_iterator(SymbolRef(Ret, this));
-}
-
-basic_symbol_iterator COFFObjectFile::symbol_end() const {
- // The symbol table ends where the string table begins.
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(StringTable);
- return basic_symbol_iterator(SymbolRef(Ret, this));
-}
-
-import_directory_iterator COFFObjectFile::import_directory_begin() const {
- if (!ImportDirectory)
- return import_directory_end();
- if (ImportDirectory->isNull())
- return import_directory_end();
- return import_directory_iterator(
- ImportDirectoryEntryRef(ImportDirectory, 0, this));
-}
-
-import_directory_iterator COFFObjectFile::import_directory_end() const {
- return import_directory_iterator(
- ImportDirectoryEntryRef(nullptr, -1, this));
-}
-
-delay_import_directory_iterator
-COFFObjectFile::delay_import_directory_begin() const {
- return delay_import_directory_iterator(
- DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));
-}
-
-delay_import_directory_iterator
-COFFObjectFile::delay_import_directory_end() const {
- return delay_import_directory_iterator(
- DelayImportDirectoryEntryRef(
- DelayImportDirectory, NumberOfDelayImportDirectory, this));
-}
-
-export_directory_iterator COFFObjectFile::export_directory_begin() const {
- return export_directory_iterator(
- ExportDirectoryEntryRef(ExportDirectory, 0, this));
-}
-
-export_directory_iterator COFFObjectFile::export_directory_end() const {
- if (!ExportDirectory)
- return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));
- ExportDirectoryEntryRef Ref(ExportDirectory,
- ExportDirectory->AddressTableEntries, this);
- return export_directory_iterator(Ref);
-}
-
-section_iterator COFFObjectFile::section_begin() const {
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(SectionTable);
- return section_iterator(SectionRef(Ret, this));
-}
-
-section_iterator COFFObjectFile::section_end() const {
- DataRefImpl Ret;
- int NumSections =
- COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();
- Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);
- return section_iterator(SectionRef(Ret, this));
-}
-
-base_reloc_iterator COFFObjectFile::base_reloc_begin() const {
- return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));
-}
-
-base_reloc_iterator COFFObjectFile::base_reloc_end() const {
- return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));
-}
-
-uint8_t COFFObjectFile::getBytesInAddress() const {
- return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;
-}
-
-StringRef COFFObjectFile::getFileFormatName() const {
- switch(getMachine()) {
- case COFF::IMAGE_FILE_MACHINE_I386:
- return "COFF-i386";
- case COFF::IMAGE_FILE_MACHINE_AMD64:
- return "COFF-x86-64";
- case COFF::IMAGE_FILE_MACHINE_ARMNT:
- return "COFF-ARM";
- case COFF::IMAGE_FILE_MACHINE_ARM64:
- return "COFF-ARM64";
- default:
- return "COFF-<unknown arch>";
- }
-}
-
-Triple::ArchType COFFObjectFile::getArch() const {
- switch (getMachine()) {
- case COFF::IMAGE_FILE_MACHINE_I386:
- return Triple::x86;
- case COFF::IMAGE_FILE_MACHINE_AMD64:
- return Triple::x86_64;
- case COFF::IMAGE_FILE_MACHINE_ARMNT:
- return Triple::thumb;
- case COFF::IMAGE_FILE_MACHINE_ARM64:
- return Triple::aarch64;
- default:
- return Triple::UnknownArch;
- }
-}
-
-Expected<uint64_t> COFFObjectFile::getStartAddress() const {
- if (PE32Header)
- return PE32Header->AddressOfEntryPoint;
- return 0;
-}
-
-iterator_range<import_directory_iterator>
-COFFObjectFile::import_directories() const {
- return make_range(import_directory_begin(), import_directory_end());
-}
-
-iterator_range<delay_import_directory_iterator>
-COFFObjectFile::delay_import_directories() const {
- return make_range(delay_import_directory_begin(),
- delay_import_directory_end());
-}
-
-iterator_range<export_directory_iterator>
-COFFObjectFile::export_directories() const {
- return make_range(export_directory_begin(), export_directory_end());
-}
-
-iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {
- return make_range(base_reloc_begin(), base_reloc_end());
-}
-
-const data_directory *COFFObjectFile::getDataDirectory(uint32_t Index) const {
- if (!DataDirectory)
- return nullptr;
- assert(PE32Header || PE32PlusHeader);
- uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize
- : PE32PlusHeader->NumberOfRvaAndSize;
- if (Index >= NumEnt)
- return nullptr;
- return &DataDirectory[Index];
-}
-
-Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {
- // Perhaps getting the section of a reserved section index should be an error,
- // but callers rely on this to return null.
- if (COFF::isReservedSectionNumber(Index))
- return (const coff_section *)nullptr;
- if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {
- // We already verified the section table data, so no need to check again.
- return SectionTable + (Index - 1);
- }
- return errorCodeToError(object_error::parse_failed);
-}
-
-Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {
- if (StringTableSize <= 4)
- // Tried to get a string from an empty string table.
- return errorCodeToError(object_error::parse_failed);
- if (Offset >= StringTableSize)
- return errorCodeToError(object_error::unexpected_eof);
- return StringRef(StringTable + Offset);
-}
-
-Expected<StringRef> COFFObjectFile::getSymbolName(COFFSymbolRef Symbol) const {
- return getSymbolName(Symbol.getGeneric());
-}
-
-Expected<StringRef>
-COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol) const {
- // Check for string table entry. First 4 bytes are 0.
- if (Symbol->Name.Offset.Zeroes == 0)
- return getString(Symbol->Name.Offset.Offset);
-
- // Null terminated, let ::strlen figure out the length.
- if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)
- return StringRef(Symbol->Name.ShortName);
-
- // Not null terminated, use all 8 bytes.
- return StringRef(Symbol->Name.ShortName, COFF::NameSize);
-}
-
-ArrayRef<uint8_t>
-COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {
- const uint8_t *Aux = nullptr;
-
- size_t SymbolSize = getSymbolTableEntrySize();
- if (Symbol.getNumberOfAuxSymbols() > 0) {
- // AUX data comes immediately after the symbol in COFF
- Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;
-#ifndef NDEBUG
- // Verify that the Aux symbol points to a valid entry in the symbol table.
- uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());
- if (Offset < getPointerToSymbolTable() ||
- Offset >=
- getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))
- report_fatal_error("Aux Symbol data was outside of symbol table.");
-
- assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&
- "Aux Symbol data did not point to the beginning of a symbol");
-#endif
- }
- return makeArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);
-}
-
-uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {
- uintptr_t Offset =
- reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();
- assert(Offset % getSymbolTableEntrySize() == 0 &&
- "Symbol did not point to the beginning of a symbol");
- size_t Index = Offset / getSymbolTableEntrySize();
- assert(Index < getNumberOfSymbols());
- return Index;
-}
-
-Expected<StringRef>
-COFFObjectFile::getSectionName(const coff_section *Sec) const {
- StringRef Name;
- if (Sec->Name[COFF::NameSize - 1] == 0)
- // Null terminated, let ::strlen figure out the length.
- Name = Sec->Name;
- else
- // Not null terminated, use all 8 bytes.
- Name = StringRef(Sec->Name, COFF::NameSize);
-
- // Check for string table entry. First byte is '/'.
- if (Name.startswith("/")) {
- uint32_t Offset;
- if (Name.startswith("//")) {
- if (decodeBase64StringEntry(Name.substr(2), Offset))
- return createStringError(object_error::parse_failed,
- "invalid section name");
- } else {
- if (Name.substr(1).getAsInteger(10, Offset))
- return createStringError(object_error::parse_failed,
- "invalid section name");
- }
- return getString(Offset);
- }
-
- return Name;
-}
-
-uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {
- // SizeOfRawData and VirtualSize change what they represent depending on
- // whether or not we have an executable image.
- //
- // For object files, SizeOfRawData contains the size of section's data;
- // VirtualSize should be zero but isn't due to buggy COFF writers.
- //
- // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the
- // actual section size is in VirtualSize. It is possible for VirtualSize to
- // be greater than SizeOfRawData; the contents past that point should be
- // considered to be zero.
- if (getDOSHeader())
- return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
- return Sec->SizeOfRawData;
-}
-
-Error COFFObjectFile::getSectionContents(const coff_section *Sec,
- ArrayRef<uint8_t> &Res) const {
- // In COFF, a virtual section won't have any in-file
- // content, so the file pointer to the content will be zero.
- if (Sec->PointerToRawData == 0)
- return Error::success();
- // The only thing that we need to verify is that the contents is contained
- // within the file bounds. We don't need to make sure it doesn't cover other
- // data, as there's nothing that says that is not allowed.
+ if (Error E = initLoadConfigPtr())
+ return E;
+
+ return Error::success();
+}
+
+basic_symbol_iterator COFFObjectFile::symbol_begin() const {
+ DataRefImpl Ret;
+ Ret.p = getSymbolTable();
+ return basic_symbol_iterator(SymbolRef(Ret, this));
+}
+
+basic_symbol_iterator COFFObjectFile::symbol_end() const {
+ // The symbol table ends where the string table begins.
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(StringTable);
+ return basic_symbol_iterator(SymbolRef(Ret, this));
+}
+
+import_directory_iterator COFFObjectFile::import_directory_begin() const {
+ if (!ImportDirectory)
+ return import_directory_end();
+ if (ImportDirectory->isNull())
+ return import_directory_end();
+ return import_directory_iterator(
+ ImportDirectoryEntryRef(ImportDirectory, 0, this));
+}
+
+import_directory_iterator COFFObjectFile::import_directory_end() const {
+ return import_directory_iterator(
+ ImportDirectoryEntryRef(nullptr, -1, this));
+}
+
+delay_import_directory_iterator
+COFFObjectFile::delay_import_directory_begin() const {
+ return delay_import_directory_iterator(
+ DelayImportDirectoryEntryRef(DelayImportDirectory, 0, this));
+}
+
+delay_import_directory_iterator
+COFFObjectFile::delay_import_directory_end() const {
+ return delay_import_directory_iterator(
+ DelayImportDirectoryEntryRef(
+ DelayImportDirectory, NumberOfDelayImportDirectory, this));
+}
+
+export_directory_iterator COFFObjectFile::export_directory_begin() const {
+ return export_directory_iterator(
+ ExportDirectoryEntryRef(ExportDirectory, 0, this));
+}
+
+export_directory_iterator COFFObjectFile::export_directory_end() const {
+ if (!ExportDirectory)
+ return export_directory_iterator(ExportDirectoryEntryRef(nullptr, 0, this));
+ ExportDirectoryEntryRef Ref(ExportDirectory,
+ ExportDirectory->AddressTableEntries, this);
+ return export_directory_iterator(Ref);
+}
+
+section_iterator COFFObjectFile::section_begin() const {
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(SectionTable);
+ return section_iterator(SectionRef(Ret, this));
+}
+
+section_iterator COFFObjectFile::section_end() const {
+ DataRefImpl Ret;
+ int NumSections =
+ COFFHeader && COFFHeader->isImportLibrary() ? 0 : getNumberOfSections();
+ Ret.p = reinterpret_cast<uintptr_t>(SectionTable + NumSections);
+ return section_iterator(SectionRef(Ret, this));
+}
+
+base_reloc_iterator COFFObjectFile::base_reloc_begin() const {
+ return base_reloc_iterator(BaseRelocRef(BaseRelocHeader, this));
+}
+
+base_reloc_iterator COFFObjectFile::base_reloc_end() const {
+ return base_reloc_iterator(BaseRelocRef(BaseRelocEnd, this));
+}
+
+uint8_t COFFObjectFile::getBytesInAddress() const {
+ return getArch() == Triple::x86_64 || getArch() == Triple::aarch64 ? 8 : 4;
+}
+
+StringRef COFFObjectFile::getFileFormatName() const {
+ switch(getMachine()) {
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ return "COFF-i386";
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ return "COFF-x86-64";
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ return "COFF-ARM";
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ return "COFF-ARM64";
+ default:
+ return "COFF-<unknown arch>";
+ }
+}
+
+Triple::ArchType COFFObjectFile::getArch() const {
+ switch (getMachine()) {
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ return Triple::x86;
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ return Triple::x86_64;
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ return Triple::thumb;
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ return Triple::aarch64;
+ default:
+ return Triple::UnknownArch;
+ }
+}
+
+Expected<uint64_t> COFFObjectFile::getStartAddress() const {
+ if (PE32Header)
+ return PE32Header->AddressOfEntryPoint;
+ return 0;
+}
+
+iterator_range<import_directory_iterator>
+COFFObjectFile::import_directories() const {
+ return make_range(import_directory_begin(), import_directory_end());
+}
+
+iterator_range<delay_import_directory_iterator>
+COFFObjectFile::delay_import_directories() const {
+ return make_range(delay_import_directory_begin(),
+ delay_import_directory_end());
+}
+
+iterator_range<export_directory_iterator>
+COFFObjectFile::export_directories() const {
+ return make_range(export_directory_begin(), export_directory_end());
+}
+
+iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {
+ return make_range(base_reloc_begin(), base_reloc_end());
+}
+
+const data_directory *COFFObjectFile::getDataDirectory(uint32_t Index) const {
+ if (!DataDirectory)
+ return nullptr;
+ assert(PE32Header || PE32PlusHeader);
+ uint32_t NumEnt = PE32Header ? PE32Header->NumberOfRvaAndSize
+ : PE32PlusHeader->NumberOfRvaAndSize;
+ if (Index >= NumEnt)
+ return nullptr;
+ return &DataDirectory[Index];
+}
+
+Expected<const coff_section *> COFFObjectFile::getSection(int32_t Index) const {
+ // Perhaps getting the section of a reserved section index should be an error,
+ // but callers rely on this to return null.
+ if (COFF::isReservedSectionNumber(Index))
+ return (const coff_section *)nullptr;
+ if (static_cast<uint32_t>(Index) <= getNumberOfSections()) {
+ // We already verified the section table data, so no need to check again.
+ return SectionTable + (Index - 1);
+ }
+ return errorCodeToError(object_error::parse_failed);
+}
+
+Expected<StringRef> COFFObjectFile::getString(uint32_t Offset) const {
+ if (StringTableSize <= 4)
+ // Tried to get a string from an empty string table.
+ return errorCodeToError(object_error::parse_failed);
+ if (Offset >= StringTableSize)
+ return errorCodeToError(object_error::unexpected_eof);
+ return StringRef(StringTable + Offset);
+}
+
+Expected<StringRef> COFFObjectFile::getSymbolName(COFFSymbolRef Symbol) const {
+ return getSymbolName(Symbol.getGeneric());
+}
+
+Expected<StringRef>
+COFFObjectFile::getSymbolName(const coff_symbol_generic *Symbol) const {
+ // Check for string table entry. First 4 bytes are 0.
+ if (Symbol->Name.Offset.Zeroes == 0)
+ return getString(Symbol->Name.Offset.Offset);
+
+ // Null terminated, let ::strlen figure out the length.
+ if (Symbol->Name.ShortName[COFF::NameSize - 1] == 0)
+ return StringRef(Symbol->Name.ShortName);
+
+ // Not null terminated, use all 8 bytes.
+ return StringRef(Symbol->Name.ShortName, COFF::NameSize);
+}
+
+ArrayRef<uint8_t>
+COFFObjectFile::getSymbolAuxData(COFFSymbolRef Symbol) const {
+ const uint8_t *Aux = nullptr;
+
+ size_t SymbolSize = getSymbolTableEntrySize();
+ if (Symbol.getNumberOfAuxSymbols() > 0) {
+ // AUX data comes immediately after the symbol in COFF
+ Aux = reinterpret_cast<const uint8_t *>(Symbol.getRawPtr()) + SymbolSize;
+#ifndef NDEBUG
+ // Verify that the Aux symbol points to a valid entry in the symbol table.
+ uintptr_t Offset = uintptr_t(Aux) - uintptr_t(base());
+ if (Offset < getPointerToSymbolTable() ||
+ Offset >=
+ getPointerToSymbolTable() + (getNumberOfSymbols() * SymbolSize))
+ report_fatal_error("Aux Symbol data was outside of symbol table.");
+
+ assert((Offset - getPointerToSymbolTable()) % SymbolSize == 0 &&
+ "Aux Symbol data did not point to the beginning of a symbol");
+#endif
+ }
+ return makeArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);
+}
+
+uint32_t COFFObjectFile::getSymbolIndex(COFFSymbolRef Symbol) const {
+ uintptr_t Offset =
+ reinterpret_cast<uintptr_t>(Symbol.getRawPtr()) - getSymbolTable();
+ assert(Offset % getSymbolTableEntrySize() == 0 &&
+ "Symbol did not point to the beginning of a symbol");
+ size_t Index = Offset / getSymbolTableEntrySize();
+ assert(Index < getNumberOfSymbols());
+ return Index;
+}
+
+Expected<StringRef>
+COFFObjectFile::getSectionName(const coff_section *Sec) const {
+ StringRef Name;
+ if (Sec->Name[COFF::NameSize - 1] == 0)
+ // Null terminated, let ::strlen figure out the length.
+ Name = Sec->Name;
+ else
+ // Not null terminated, use all 8 bytes.
+ Name = StringRef(Sec->Name, COFF::NameSize);
+
+ // Check for string table entry. First byte is '/'.
+ if (Name.startswith("/")) {
+ uint32_t Offset;
+ if (Name.startswith("//")) {
+ if (decodeBase64StringEntry(Name.substr(2), Offset))
+ return createStringError(object_error::parse_failed,
+ "invalid section name");
+ } else {
+ if (Name.substr(1).getAsInteger(10, Offset))
+ return createStringError(object_error::parse_failed,
+ "invalid section name");
+ }
+ return getString(Offset);
+ }
+
+ return Name;
+}
+
+uint64_t COFFObjectFile::getSectionSize(const coff_section *Sec) const {
+ // SizeOfRawData and VirtualSize change what they represent depending on
+ // whether or not we have an executable image.
+ //
+ // For object files, SizeOfRawData contains the size of section's data;
+ // VirtualSize should be zero but isn't due to buggy COFF writers.
+ //
+ // For executables, SizeOfRawData *must* be a multiple of FileAlignment; the
+ // actual section size is in VirtualSize. It is possible for VirtualSize to
+ // be greater than SizeOfRawData; the contents past that point should be
+ // considered to be zero.
+ if (getDOSHeader())
+ return std::min(Sec->VirtualSize, Sec->SizeOfRawData);
+ return Sec->SizeOfRawData;
+}
+
+Error COFFObjectFile::getSectionContents(const coff_section *Sec,
+ ArrayRef<uint8_t> &Res) const {
+ // In COFF, a virtual section won't have any in-file
+ // content, so the file pointer to the content will be zero.
+ if (Sec->PointerToRawData == 0)
+ return Error::success();
+ // The only thing that we need to verify is that the contents is contained
+ // within the file bounds. We don't need to make sure it doesn't cover other
+ // data, as there's nothing that says that is not allowed.
uintptr_t ConStart =
reinterpret_cast<uintptr_t>(base()) + Sec->PointerToRawData;
- uint32_t SectionSize = getSectionSize(Sec);
- if (Error E = checkOffset(Data, ConStart, SectionSize))
- return E;
- Res = makeArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);
- return Error::success();
-}
-
-const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {
- return reinterpret_cast<const coff_relocation*>(Rel.p);
-}
-
-void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
- Rel.p = reinterpret_cast<uintptr_t>(
- reinterpret_cast<const coff_relocation*>(Rel.p) + 1);
-}
-
-uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
- const coff_relocation *R = toRel(Rel);
- return R->VirtualAddress;
-}
-
-symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
- const coff_relocation *R = toRel(Rel);
- DataRefImpl Ref;
- if (R->SymbolTableIndex >= getNumberOfSymbols())
- return symbol_end();
- if (SymbolTable16)
- Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);
- else if (SymbolTable32)
- Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);
- else
- llvm_unreachable("no symbol table pointer!");
- return symbol_iterator(SymbolRef(Ref, this));
-}
-
-uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {
- const coff_relocation* R = toRel(Rel);
- return R->Type;
-}
-
-const coff_section *
-COFFObjectFile::getCOFFSection(const SectionRef &Section) const {
- return toSec(Section.getRawDataRefImpl());
-}
-
-COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {
- if (SymbolTable16)
- return toSymb<coff_symbol16>(Ref);
- if (SymbolTable32)
- return toSymb<coff_symbol32>(Ref);
- llvm_unreachable("no symbol table pointer!");
-}
-
-COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {
- return getCOFFSymbol(Symbol.getRawDataRefImpl());
-}
-
-const coff_relocation *
-COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {
- return toRel(Reloc.getRawDataRefImpl());
-}
-
-ArrayRef<coff_relocation>
-COFFObjectFile::getRelocations(const coff_section *Sec) const {
- return {getFirstReloc(Sec, Data, base()),
- getNumberOfRelocations(Sec, Data, base())};
-}
-
-#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \
- case COFF::reloc_type: \
- return #reloc_type;
-
-StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
- switch (getMachine()) {
- case COFF::IMAGE_FILE_MACHINE_AMD64:
- switch (Type) {
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);
- default:
- return "Unknown";
- }
- break;
- case COFF::IMAGE_FILE_MACHINE_ARMNT:
- switch (Type) {
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR);
- default:
- return "Unknown";
- }
- break;
- case COFF::IMAGE_FILE_MACHINE_ARM64:
- switch (Type) {
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32);
- default:
- return "Unknown";
- }
- break;
- case COFF::IMAGE_FILE_MACHINE_I386:
- switch (Type) {
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);
- LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);
- default:
- return "Unknown";
- }
- break;
- default:
- return "Unknown";
- }
-}
-
-#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME
-
-void COFFObjectFile::getRelocationTypeName(
- DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
- const coff_relocation *Reloc = toRel(Rel);
- StringRef Res = getRelocationTypeName(Reloc->Type);
- Result.append(Res.begin(), Res.end());
-}
-
-bool COFFObjectFile::isRelocatableObject() const {
- return !DataDirectory;
-}
-
-StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {
- return StringSwitch<StringRef>(Name)
- .Case("eh_fram", "eh_frame")
- .Default(Name);
-}
-
-bool ImportDirectoryEntryRef::
-operator==(const ImportDirectoryEntryRef &Other) const {
- return ImportTable == Other.ImportTable && Index == Other.Index;
-}
-
-void ImportDirectoryEntryRef::moveNext() {
- ++Index;
- if (ImportTable[Index].isNull()) {
- Index = -1;
- ImportTable = nullptr;
- }
-}
-
-Error ImportDirectoryEntryRef::getImportTableEntry(
- const coff_import_directory_table_entry *&Result) const {
- return getObject(Result, OwningObject->Data, ImportTable + Index);
-}
-
-static imported_symbol_iterator
-makeImportedSymbolIterator(const COFFObjectFile *Object,
- uintptr_t Ptr, int Index) {
- if (Object->getBytesInAddress() == 4) {
- auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);
- return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
- }
- auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);
- return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
-}
-
-static imported_symbol_iterator
-importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {
- uintptr_t IntPtr = 0;
- // FIXME: Handle errors.
- cantFail(Object->getRvaPtr(RVA, IntPtr));
- return makeImportedSymbolIterator(Object, IntPtr, 0);
-}
-
-static imported_symbol_iterator
-importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {
- uintptr_t IntPtr = 0;
- // FIXME: Handle errors.
- cantFail(Object->getRvaPtr(RVA, IntPtr));
- // Forward the pointer to the last entry which is null.
- int Index = 0;
- if (Object->getBytesInAddress() == 4) {
- auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);
- while (*Entry++)
- ++Index;
- } else {
- auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);
- while (*Entry++)
- ++Index;
- }
- return makeImportedSymbolIterator(Object, IntPtr, Index);
-}
-
-imported_symbol_iterator
-ImportDirectoryEntryRef::imported_symbol_begin() const {
- return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,
- OwningObject);
-}
-
-imported_symbol_iterator
-ImportDirectoryEntryRef::imported_symbol_end() const {
- return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,
- OwningObject);
-}
-
-iterator_range<imported_symbol_iterator>
-ImportDirectoryEntryRef::imported_symbols() const {
- return make_range(imported_symbol_begin(), imported_symbol_end());
-}
-
-imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {
- return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,
- OwningObject);
-}
-
-imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {
- return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,
- OwningObject);
-}
-
-iterator_range<imported_symbol_iterator>
-ImportDirectoryEntryRef::lookup_table_symbols() const {
- return make_range(lookup_table_begin(), lookup_table_end());
-}
-
-Error ImportDirectoryEntryRef::getName(StringRef &Result) const {
- uintptr_t IntPtr = 0;
- if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr))
- return E;
- Result = StringRef(reinterpret_cast<const char *>(IntPtr));
- return Error::success();
-}
-
-Error
-ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {
- Result = ImportTable[Index].ImportLookupTableRVA;
- return Error::success();
-}
-
-Error ImportDirectoryEntryRef::getImportAddressTableRVA(
- uint32_t &Result) const {
- Result = ImportTable[Index].ImportAddressTableRVA;
- return Error::success();
-}
-
-bool DelayImportDirectoryEntryRef::
-operator==(const DelayImportDirectoryEntryRef &Other) const {
- return Table == Other.Table && Index == Other.Index;
-}
-
-void DelayImportDirectoryEntryRef::moveNext() {
- ++Index;
-}
-
-imported_symbol_iterator
-DelayImportDirectoryEntryRef::imported_symbol_begin() const {
- return importedSymbolBegin(Table[Index].DelayImportNameTable,
- OwningObject);
-}
-
-imported_symbol_iterator
-DelayImportDirectoryEntryRef::imported_symbol_end() const {
- return importedSymbolEnd(Table[Index].DelayImportNameTable,
- OwningObject);
-}
-
-iterator_range<imported_symbol_iterator>
-DelayImportDirectoryEntryRef::imported_symbols() const {
- return make_range(imported_symbol_begin(), imported_symbol_end());
-}
-
-Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {
- uintptr_t IntPtr = 0;
- if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr))
- return E;
- Result = StringRef(reinterpret_cast<const char *>(IntPtr));
- return Error::success();
-}
-
-Error DelayImportDirectoryEntryRef::getDelayImportTable(
- const delay_import_directory_table_entry *&Result) const {
- Result = &Table[Index];
- return Error::success();
-}
-
-Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,
- uint64_t &Result) const {
- uint32_t RVA = Table[Index].DelayImportAddressTable +
- AddrIndex * (OwningObject->is64() ? 8 : 4);
- uintptr_t IntPtr = 0;
- if (Error E = OwningObject->getRvaPtr(RVA, IntPtr))
- return E;
- if (OwningObject->is64())
- Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);
- else
- Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);
- return Error::success();
-}
-
-bool ExportDirectoryEntryRef::
-operator==(const ExportDirectoryEntryRef &Other) const {
- return ExportTable == Other.ExportTable && Index == Other.Index;
-}
-
-void ExportDirectoryEntryRef::moveNext() {
- ++Index;
-}
-
-// Returns the name of the current export symbol. If the symbol is exported only
-// by ordinal, the empty string is set as a result.
-Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {
- uintptr_t IntPtr = 0;
- if (Error E = OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr))
- return E;
- Result = StringRef(reinterpret_cast<const char *>(IntPtr));
- return Error::success();
-}
-
-// Returns the starting ordinal number.
-Error ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {
- Result = ExportTable->OrdinalBase;
- return Error::success();
-}
-
-// Returns the export ordinal of the current export symbol.
-Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
- Result = ExportTable->OrdinalBase + Index;
- return Error::success();
-}
-
-// Returns the address of the current export symbol.
-Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
- uintptr_t IntPtr = 0;
- if (Error EC =
- OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr))
- return EC;
- const export_address_table_entry *entry =
- reinterpret_cast<const export_address_table_entry *>(IntPtr);
- Result = entry[Index].ExportRVA;
- return Error::success();
-}
-
-// Returns the name of the current export symbol. If the symbol is exported only
-// by ordinal, the empty string is set as a result.
-Error
-ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
- uintptr_t IntPtr = 0;
- if (Error EC =
- OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr))
- return EC;
- const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
-
- uint32_t NumEntries = ExportTable->NumberOfNamePointers;
- int Offset = 0;
- for (const ulittle16_t *I = Start, *E = Start + NumEntries;
- I < E; ++I, ++Offset) {
- if (*I != Index)
- continue;
- if (Error EC =
- OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr))
- return EC;
- const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
- if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr))
- return EC;
- Result = StringRef(reinterpret_cast<const char *>(IntPtr));
- return Error::success();
- }
- Result = "";
- return Error::success();
-}
-
-Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {
- const data_directory *DataEntry =
- OwningObject->getDataDirectory(COFF::EXPORT_TABLE);
- if (!DataEntry)
- return errorCodeToError(object_error::parse_failed);
- uint32_t RVA;
- if (auto EC = getExportRVA(RVA))
- return EC;
- uint32_t Begin = DataEntry->RelativeVirtualAddress;
- uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;
- Result = (Begin <= RVA && RVA < End);
- return Error::success();
-}
-
-Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
- uint32_t RVA;
- if (auto EC = getExportRVA(RVA))
- return EC;
- uintptr_t IntPtr = 0;
- if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr))
- return EC;
- Result = StringRef(reinterpret_cast<const char *>(IntPtr));
- return Error::success();
-}
-
-bool ImportedSymbolRef::
-operator==(const ImportedSymbolRef &Other) const {
- return Entry32 == Other.Entry32 && Entry64 == Other.Entry64
- && Index == Other.Index;
-}
-
-void ImportedSymbolRef::moveNext() {
- ++Index;
-}
-
-Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {
- uint32_t RVA;
- if (Entry32) {
- // If a symbol is imported only by ordinal, it has no name.
- if (Entry32[Index].isOrdinal())
- return Error::success();
- RVA = Entry32[Index].getHintNameRVA();
- } else {
- if (Entry64[Index].isOrdinal())
- return Error::success();
- RVA = Entry64[Index].getHintNameRVA();
- }
- uintptr_t IntPtr = 0;
- if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
- return EC;
- // +2 because the first two bytes is hint.
- Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));
- return Error::success();
-}
-
-Error ImportedSymbolRef::isOrdinal(bool &Result) const {
- if (Entry32)
- Result = Entry32[Index].isOrdinal();
- else
- Result = Entry64[Index].isOrdinal();
- return Error::success();
-}
-
-Error ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {
- if (Entry32)
- Result = Entry32[Index].getHintNameRVA();
- else
- Result = Entry64[Index].getHintNameRVA();
- return Error::success();
-}
-
-Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {
- uint32_t RVA;
- if (Entry32) {
- if (Entry32[Index].isOrdinal()) {
- Result = Entry32[Index].getOrdinal();
- return Error::success();
- }
- RVA = Entry32[Index].getHintNameRVA();
- } else {
- if (Entry64[Index].isOrdinal()) {
- Result = Entry64[Index].getOrdinal();
- return Error::success();
- }
- RVA = Entry64[Index].getHintNameRVA();
- }
- uintptr_t IntPtr = 0;
- if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
- return EC;
- Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);
- return Error::success();
-}
-
-Expected<std::unique_ptr<COFFObjectFile>>
-ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {
- return COFFObjectFile::create(Object);
-}
-
-bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {
- return Header == Other.Header && Index == Other.Index;
-}
-
-void BaseRelocRef::moveNext() {
- // Header->BlockSize is the size of the current block, including the
- // size of the header itself.
- uint32_t Size = sizeof(*Header) +
- sizeof(coff_base_reloc_block_entry) * (Index + 1);
- if (Size == Header->BlockSize) {
- // .reloc contains a list of base relocation blocks. Each block
- // consists of the header followed by entries. The header contains
- // how many entories will follow. When we reach the end of the
- // current block, proceed to the next block.
- Header = reinterpret_cast<const coff_base_reloc_block_header *>(
- reinterpret_cast<const uint8_t *>(Header) + Size);
- Index = 0;
- } else {
- ++Index;
- }
-}
-
-Error BaseRelocRef::getType(uint8_t &Type) const {
- auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
- Type = Entry[Index].getType();
- return Error::success();
-}
-
-Error BaseRelocRef::getRVA(uint32_t &Result) const {
- auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
- Result = Header->PageRVA + Entry[Index].getOffset();
- return Error::success();
-}
-
-#define RETURN_IF_ERROR(Expr) \
- do { \
- Error E = (Expr); \
- if (E) \
- return std::move(E); \
- } while (0)
-
-Expected<ArrayRef<UTF16>>
-ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {
- BinaryStreamReader Reader = BinaryStreamReader(BBS);
- Reader.setOffset(Offset);
- uint16_t Length;
- RETURN_IF_ERROR(Reader.readInteger(Length));
- ArrayRef<UTF16> RawDirString;
- RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));
- return RawDirString;
-}
-
-Expected<ArrayRef<UTF16>>
-ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {
- return getDirStringAtOffset(Entry.Identifier.getNameOffset());
-}
-
-Expected<const coff_resource_dir_table &>
-ResourceSectionRef::getTableAtOffset(uint32_t Offset) {
- const coff_resource_dir_table *Table = nullptr;
-
- BinaryStreamReader Reader(BBS);
- Reader.setOffset(Offset);
- RETURN_IF_ERROR(Reader.readObject(Table));
- assert(Table != nullptr);
- return *Table;
-}
-
-Expected<const coff_resource_dir_entry &>
-ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {
- const coff_resource_dir_entry *Entry = nullptr;
-
- BinaryStreamReader Reader(BBS);
- Reader.setOffset(Offset);
- RETURN_IF_ERROR(Reader.readObject(Entry));
- assert(Entry != nullptr);
- return *Entry;
-}
-
-Expected<const coff_resource_data_entry &>
-ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {
- const coff_resource_data_entry *Entry = nullptr;
-
- BinaryStreamReader Reader(BBS);
- Reader.setOffset(Offset);
- RETURN_IF_ERROR(Reader.readObject(Entry));
- assert(Entry != nullptr);
- return *Entry;
-}
-
-Expected<const coff_resource_dir_table &>
-ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {
- assert(Entry.Offset.isSubDir());
- return getTableAtOffset(Entry.Offset.value());
-}
-
-Expected<const coff_resource_data_entry &>
-ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {
- assert(!Entry.Offset.isSubDir());
- return getDataEntryAtOffset(Entry.Offset.value());
-}
-
-Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {
- return getTableAtOffset(0);
-}
-
-Expected<const coff_resource_dir_entry &>
-ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,
- uint32_t Index) {
- if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))
- return createStringError(object_error::parse_failed, "index out of range");
- const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);
- ptrdiff_t TableOffset = TablePtr - BBS.data().data();
- return getTableEntryAtOffset(TableOffset + sizeof(Table) +
- Index * sizeof(coff_resource_dir_entry));
-}
-
-Error ResourceSectionRef::load(const COFFObjectFile *O) {
- for (const SectionRef &S : O->sections()) {
- Expected<StringRef> Name = S.getName();
- if (!Name)
- return Name.takeError();
-
- if (*Name == ".rsrc" || *Name == ".rsrc$01")
- return load(O, S);
- }
- return createStringError(object_error::parse_failed,
- "no resource section found");
-}
-
-Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {
- Obj = O;
- Section = S;
- Expected<StringRef> Contents = Section.getContents();
- if (!Contents)
- return Contents.takeError();
- BBS = BinaryByteStream(*Contents, support::little);
- const coff_section *COFFSect = Obj->getCOFFSection(Section);
- ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);
- Relocs.reserve(OrigRelocs.size());
- for (const coff_relocation &R : OrigRelocs)
- Relocs.push_back(&R);
+ uint32_t SectionSize = getSectionSize(Sec);
+ if (Error E = checkOffset(Data, ConStart, SectionSize))
+ return E;
+ Res = makeArrayRef(reinterpret_cast<const uint8_t *>(ConStart), SectionSize);
+ return Error::success();
+}
+
+const coff_relocation *COFFObjectFile::toRel(DataRefImpl Rel) const {
+ return reinterpret_cast<const coff_relocation*>(Rel.p);
+}
+
+void COFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
+ Rel.p = reinterpret_cast<uintptr_t>(
+ reinterpret_cast<const coff_relocation*>(Rel.p) + 1);
+}
+
+uint64_t COFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
+ const coff_relocation *R = toRel(Rel);
+ return R->VirtualAddress;
+}
+
+symbol_iterator COFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
+ const coff_relocation *R = toRel(Rel);
+ DataRefImpl Ref;
+ if (R->SymbolTableIndex >= getNumberOfSymbols())
+ return symbol_end();
+ if (SymbolTable16)
+ Ref.p = reinterpret_cast<uintptr_t>(SymbolTable16 + R->SymbolTableIndex);
+ else if (SymbolTable32)
+ Ref.p = reinterpret_cast<uintptr_t>(SymbolTable32 + R->SymbolTableIndex);
+ else
+ llvm_unreachable("no symbol table pointer!");
+ return symbol_iterator(SymbolRef(Ref, this));
+}
+
+uint64_t COFFObjectFile::getRelocationType(DataRefImpl Rel) const {
+ const coff_relocation* R = toRel(Rel);
+ return R->Type;
+}
+
+const coff_section *
+COFFObjectFile::getCOFFSection(const SectionRef &Section) const {
+ return toSec(Section.getRawDataRefImpl());
+}
+
+COFFSymbolRef COFFObjectFile::getCOFFSymbol(const DataRefImpl &Ref) const {
+ if (SymbolTable16)
+ return toSymb<coff_symbol16>(Ref);
+ if (SymbolTable32)
+ return toSymb<coff_symbol32>(Ref);
+ llvm_unreachable("no symbol table pointer!");
+}
+
+COFFSymbolRef COFFObjectFile::getCOFFSymbol(const SymbolRef &Symbol) const {
+ return getCOFFSymbol(Symbol.getRawDataRefImpl());
+}
+
+const coff_relocation *
+COFFObjectFile::getCOFFRelocation(const RelocationRef &Reloc) const {
+ return toRel(Reloc.getRawDataRefImpl());
+}
+
+ArrayRef<coff_relocation>
+COFFObjectFile::getRelocations(const coff_section *Sec) const {
+ return {getFirstReloc(Sec, Data, base()),
+ getNumberOfRelocations(Sec, Data, base())};
+}
+
+#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \
+ case COFF::reloc_type: \
+ return #reloc_type;
+
+StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
+ switch (getMachine()) {
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ switch (Type) {
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR32NB);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_1);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_2);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_3);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_4);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_REL32_5);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECTION);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SECREL7);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_TOKEN);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SREL32);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_PAIR);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_SSPAN32);
+ default:
+ return "Unknown";
+ }
+ break;
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ switch (Type) {
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32NB);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH11);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_TOKEN);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX24);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX11);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_REL32);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECTION);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_SECREL);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32A);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_MOV32T);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH20T);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BRANCH24T);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_BLX23T);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_PAIR);
+ default:
+ return "Unknown";
+ }
+ break;
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ switch (Type) {
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32NB);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH26);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEBASE_REL21);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL21);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12A);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_PAGEOFFSET_12L);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12A);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_HIGH12A);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECREL_LOW12L);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_TOKEN);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_SECTION);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR64);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH19);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_BRANCH14);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_REL32);
+ default:
+ return "Unknown";
+ }
+ break;
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ switch (Type) {
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL16);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR32NB);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SEG12);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECTION);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_TOKEN);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_SECREL7);
+ LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_REL32);
+ default:
+ return "Unknown";
+ }
+ break;
+ default:
+ return "Unknown";
+ }
+}
+
+#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME
+
+void COFFObjectFile::getRelocationTypeName(
+ DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
+ const coff_relocation *Reloc = toRel(Rel);
+ StringRef Res = getRelocationTypeName(Reloc->Type);
+ Result.append(Res.begin(), Res.end());
+}
+
+bool COFFObjectFile::isRelocatableObject() const {
+ return !DataDirectory;
+}
+
+StringRef COFFObjectFile::mapDebugSectionName(StringRef Name) const {
+ return StringSwitch<StringRef>(Name)
+ .Case("eh_fram", "eh_frame")
+ .Default(Name);
+}
+
+bool ImportDirectoryEntryRef::
+operator==(const ImportDirectoryEntryRef &Other) const {
+ return ImportTable == Other.ImportTable && Index == Other.Index;
+}
+
+void ImportDirectoryEntryRef::moveNext() {
+ ++Index;
+ if (ImportTable[Index].isNull()) {
+ Index = -1;
+ ImportTable = nullptr;
+ }
+}
+
+Error ImportDirectoryEntryRef::getImportTableEntry(
+ const coff_import_directory_table_entry *&Result) const {
+ return getObject(Result, OwningObject->Data, ImportTable + Index);
+}
+
+static imported_symbol_iterator
+makeImportedSymbolIterator(const COFFObjectFile *Object,
+ uintptr_t Ptr, int Index) {
+ if (Object->getBytesInAddress() == 4) {
+ auto *P = reinterpret_cast<const import_lookup_table_entry32 *>(Ptr);
+ return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
+ }
+ auto *P = reinterpret_cast<const import_lookup_table_entry64 *>(Ptr);
+ return imported_symbol_iterator(ImportedSymbolRef(P, Index, Object));
+}
+
+static imported_symbol_iterator
+importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object) {
+ uintptr_t IntPtr = 0;
+ // FIXME: Handle errors.
+ cantFail(Object->getRvaPtr(RVA, IntPtr));
+ return makeImportedSymbolIterator(Object, IntPtr, 0);
+}
+
+static imported_symbol_iterator
+importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object) {
+ uintptr_t IntPtr = 0;
+ // FIXME: Handle errors.
+ cantFail(Object->getRvaPtr(RVA, IntPtr));
+ // Forward the pointer to the last entry which is null.
+ int Index = 0;
+ if (Object->getBytesInAddress() == 4) {
+ auto *Entry = reinterpret_cast<ulittle32_t *>(IntPtr);
+ while (*Entry++)
+ ++Index;
+ } else {
+ auto *Entry = reinterpret_cast<ulittle64_t *>(IntPtr);
+ while (*Entry++)
+ ++Index;
+ }
+ return makeImportedSymbolIterator(Object, IntPtr, Index);
+}
+
+imported_symbol_iterator
+ImportDirectoryEntryRef::imported_symbol_begin() const {
+ return importedSymbolBegin(ImportTable[Index].ImportAddressTableRVA,
+ OwningObject);
+}
+
+imported_symbol_iterator
+ImportDirectoryEntryRef::imported_symbol_end() const {
+ return importedSymbolEnd(ImportTable[Index].ImportAddressTableRVA,
+ OwningObject);
+}
+
+iterator_range<imported_symbol_iterator>
+ImportDirectoryEntryRef::imported_symbols() const {
+ return make_range(imported_symbol_begin(), imported_symbol_end());
+}
+
+imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_begin() const {
+ return importedSymbolBegin(ImportTable[Index].ImportLookupTableRVA,
+ OwningObject);
+}
+
+imported_symbol_iterator ImportDirectoryEntryRef::lookup_table_end() const {
+ return importedSymbolEnd(ImportTable[Index].ImportLookupTableRVA,
+ OwningObject);
+}
+
+iterator_range<imported_symbol_iterator>
+ImportDirectoryEntryRef::lookup_table_symbols() const {
+ return make_range(lookup_table_begin(), lookup_table_end());
+}
+
+Error ImportDirectoryEntryRef::getName(StringRef &Result) const {
+ uintptr_t IntPtr = 0;
+ if (Error E = OwningObject->getRvaPtr(ImportTable[Index].NameRVA, IntPtr))
+ return E;
+ Result = StringRef(reinterpret_cast<const char *>(IntPtr));
+ return Error::success();
+}
+
+Error
+ImportDirectoryEntryRef::getImportLookupTableRVA(uint32_t &Result) const {
+ Result = ImportTable[Index].ImportLookupTableRVA;
+ return Error::success();
+}
+
+Error ImportDirectoryEntryRef::getImportAddressTableRVA(
+ uint32_t &Result) const {
+ Result = ImportTable[Index].ImportAddressTableRVA;
+ return Error::success();
+}
+
+bool DelayImportDirectoryEntryRef::
+operator==(const DelayImportDirectoryEntryRef &Other) const {
+ return Table == Other.Table && Index == Other.Index;
+}
+
+void DelayImportDirectoryEntryRef::moveNext() {
+ ++Index;
+}
+
+imported_symbol_iterator
+DelayImportDirectoryEntryRef::imported_symbol_begin() const {
+ return importedSymbolBegin(Table[Index].DelayImportNameTable,
+ OwningObject);
+}
+
+imported_symbol_iterator
+DelayImportDirectoryEntryRef::imported_symbol_end() const {
+ return importedSymbolEnd(Table[Index].DelayImportNameTable,
+ OwningObject);
+}
+
+iterator_range<imported_symbol_iterator>
+DelayImportDirectoryEntryRef::imported_symbols() const {
+ return make_range(imported_symbol_begin(), imported_symbol_end());
+}
+
+Error DelayImportDirectoryEntryRef::getName(StringRef &Result) const {
+ uintptr_t IntPtr = 0;
+ if (Error E = OwningObject->getRvaPtr(Table[Index].Name, IntPtr))
+ return E;
+ Result = StringRef(reinterpret_cast<const char *>(IntPtr));
+ return Error::success();
+}
+
+Error DelayImportDirectoryEntryRef::getDelayImportTable(
+ const delay_import_directory_table_entry *&Result) const {
+ Result = &Table[Index];
+ return Error::success();
+}
+
+Error DelayImportDirectoryEntryRef::getImportAddress(int AddrIndex,
+ uint64_t &Result) const {
+ uint32_t RVA = Table[Index].DelayImportAddressTable +
+ AddrIndex * (OwningObject->is64() ? 8 : 4);
+ uintptr_t IntPtr = 0;
+ if (Error E = OwningObject->getRvaPtr(RVA, IntPtr))
+ return E;
+ if (OwningObject->is64())
+ Result = *reinterpret_cast<const ulittle64_t *>(IntPtr);
+ else
+ Result = *reinterpret_cast<const ulittle32_t *>(IntPtr);
+ return Error::success();
+}
+
+bool ExportDirectoryEntryRef::
+operator==(const ExportDirectoryEntryRef &Other) const {
+ return ExportTable == Other.ExportTable && Index == Other.Index;
+}
+
+void ExportDirectoryEntryRef::moveNext() {
+ ++Index;
+}
+
+// Returns the name of the current export symbol. If the symbol is exported only
+// by ordinal, the empty string is set as a result.
+Error ExportDirectoryEntryRef::getDllName(StringRef &Result) const {
+ uintptr_t IntPtr = 0;
+ if (Error E = OwningObject->getRvaPtr(ExportTable->NameRVA, IntPtr))
+ return E;
+ Result = StringRef(reinterpret_cast<const char *>(IntPtr));
+ return Error::success();
+}
+
+// Returns the starting ordinal number.
+Error ExportDirectoryEntryRef::getOrdinalBase(uint32_t &Result) const {
+ Result = ExportTable->OrdinalBase;
+ return Error::success();
+}
+
+// Returns the export ordinal of the current export symbol.
+Error ExportDirectoryEntryRef::getOrdinal(uint32_t &Result) const {
+ Result = ExportTable->OrdinalBase + Index;
+ return Error::success();
+}
+
+// Returns the address of the current export symbol.
+Error ExportDirectoryEntryRef::getExportRVA(uint32_t &Result) const {
+ uintptr_t IntPtr = 0;
+ if (Error EC =
+ OwningObject->getRvaPtr(ExportTable->ExportAddressTableRVA, IntPtr))
+ return EC;
+ const export_address_table_entry *entry =
+ reinterpret_cast<const export_address_table_entry *>(IntPtr);
+ Result = entry[Index].ExportRVA;
+ return Error::success();
+}
+
+// Returns the name of the current export symbol. If the symbol is exported only
+// by ordinal, the empty string is set as a result.
+Error
+ExportDirectoryEntryRef::getSymbolName(StringRef &Result) const {
+ uintptr_t IntPtr = 0;
+ if (Error EC =
+ OwningObject->getRvaPtr(ExportTable->OrdinalTableRVA, IntPtr))
+ return EC;
+ const ulittle16_t *Start = reinterpret_cast<const ulittle16_t *>(IntPtr);
+
+ uint32_t NumEntries = ExportTable->NumberOfNamePointers;
+ int Offset = 0;
+ for (const ulittle16_t *I = Start, *E = Start + NumEntries;
+ I < E; ++I, ++Offset) {
+ if (*I != Index)
+ continue;
+ if (Error EC =
+ OwningObject->getRvaPtr(ExportTable->NamePointerRVA, IntPtr))
+ return EC;
+ const ulittle32_t *NamePtr = reinterpret_cast<const ulittle32_t *>(IntPtr);
+ if (Error EC = OwningObject->getRvaPtr(NamePtr[Offset], IntPtr))
+ return EC;
+ Result = StringRef(reinterpret_cast<const char *>(IntPtr));
+ return Error::success();
+ }
+ Result = "";
+ return Error::success();
+}
+
+Error ExportDirectoryEntryRef::isForwarder(bool &Result) const {
+ const data_directory *DataEntry =
+ OwningObject->getDataDirectory(COFF::EXPORT_TABLE);
+ if (!DataEntry)
+ return errorCodeToError(object_error::parse_failed);
+ uint32_t RVA;
+ if (auto EC = getExportRVA(RVA))
+ return EC;
+ uint32_t Begin = DataEntry->RelativeVirtualAddress;
+ uint32_t End = DataEntry->RelativeVirtualAddress + DataEntry->Size;
+ Result = (Begin <= RVA && RVA < End);
+ return Error::success();
+}
+
+Error ExportDirectoryEntryRef::getForwardTo(StringRef &Result) const {
+ uint32_t RVA;
+ if (auto EC = getExportRVA(RVA))
+ return EC;
+ uintptr_t IntPtr = 0;
+ if (auto EC = OwningObject->getRvaPtr(RVA, IntPtr))
+ return EC;
+ Result = StringRef(reinterpret_cast<const char *>(IntPtr));
+ return Error::success();
+}
+
+bool ImportedSymbolRef::
+operator==(const ImportedSymbolRef &Other) const {
+ return Entry32 == Other.Entry32 && Entry64 == Other.Entry64
+ && Index == Other.Index;
+}
+
+void ImportedSymbolRef::moveNext() {
+ ++Index;
+}
+
+Error ImportedSymbolRef::getSymbolName(StringRef &Result) const {
+ uint32_t RVA;
+ if (Entry32) {
+ // If a symbol is imported only by ordinal, it has no name.
+ if (Entry32[Index].isOrdinal())
+ return Error::success();
+ RVA = Entry32[Index].getHintNameRVA();
+ } else {
+ if (Entry64[Index].isOrdinal())
+ return Error::success();
+ RVA = Entry64[Index].getHintNameRVA();
+ }
+ uintptr_t IntPtr = 0;
+ if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
+ return EC;
+ // +2 because the first two bytes is hint.
+ Result = StringRef(reinterpret_cast<const char *>(IntPtr + 2));
+ return Error::success();
+}
+
+Error ImportedSymbolRef::isOrdinal(bool &Result) const {
+ if (Entry32)
+ Result = Entry32[Index].isOrdinal();
+ else
+ Result = Entry64[Index].isOrdinal();
+ return Error::success();
+}
+
+Error ImportedSymbolRef::getHintNameRVA(uint32_t &Result) const {
+ if (Entry32)
+ Result = Entry32[Index].getHintNameRVA();
+ else
+ Result = Entry64[Index].getHintNameRVA();
+ return Error::success();
+}
+
+Error ImportedSymbolRef::getOrdinal(uint16_t &Result) const {
+ uint32_t RVA;
+ if (Entry32) {
+ if (Entry32[Index].isOrdinal()) {
+ Result = Entry32[Index].getOrdinal();
+ return Error::success();
+ }
+ RVA = Entry32[Index].getHintNameRVA();
+ } else {
+ if (Entry64[Index].isOrdinal()) {
+ Result = Entry64[Index].getOrdinal();
+ return Error::success();
+ }
+ RVA = Entry64[Index].getHintNameRVA();
+ }
+ uintptr_t IntPtr = 0;
+ if (Error EC = OwningObject->getRvaPtr(RVA, IntPtr))
+ return EC;
+ Result = *reinterpret_cast<const ulittle16_t *>(IntPtr);
+ return Error::success();
+}
+
+Expected<std::unique_ptr<COFFObjectFile>>
+ObjectFile::createCOFFObjectFile(MemoryBufferRef Object) {
+ return COFFObjectFile::create(Object);
+}
+
+bool BaseRelocRef::operator==(const BaseRelocRef &Other) const {
+ return Header == Other.Header && Index == Other.Index;
+}
+
+void BaseRelocRef::moveNext() {
+ // Header->BlockSize is the size of the current block, including the
+ // size of the header itself.
+ uint32_t Size = sizeof(*Header) +
+ sizeof(coff_base_reloc_block_entry) * (Index + 1);
+ if (Size == Header->BlockSize) {
+ // .reloc contains a list of base relocation blocks. Each block
+ // consists of the header followed by entries. The header contains
+ // how many entories will follow. When we reach the end of the
+ // current block, proceed to the next block.
+ Header = reinterpret_cast<const coff_base_reloc_block_header *>(
+ reinterpret_cast<const uint8_t *>(Header) + Size);
+ Index = 0;
+ } else {
+ ++Index;
+ }
+}
+
+Error BaseRelocRef::getType(uint8_t &Type) const {
+ auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
+ Type = Entry[Index].getType();
+ return Error::success();
+}
+
+Error BaseRelocRef::getRVA(uint32_t &Result) const {
+ auto *Entry = reinterpret_cast<const coff_base_reloc_block_entry *>(Header + 1);
+ Result = Header->PageRVA + Entry[Index].getOffset();
+ return Error::success();
+}
+
+#define RETURN_IF_ERROR(Expr) \
+ do { \
+ Error E = (Expr); \
+ if (E) \
+ return std::move(E); \
+ } while (0)
+
+Expected<ArrayRef<UTF16>>
+ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {
+ BinaryStreamReader Reader = BinaryStreamReader(BBS);
+ Reader.setOffset(Offset);
+ uint16_t Length;
+ RETURN_IF_ERROR(Reader.readInteger(Length));
+ ArrayRef<UTF16> RawDirString;
+ RETURN_IF_ERROR(Reader.readArray(RawDirString, Length));
+ return RawDirString;
+}
+
+Expected<ArrayRef<UTF16>>
+ResourceSectionRef::getEntryNameString(const coff_resource_dir_entry &Entry) {
+ return getDirStringAtOffset(Entry.Identifier.getNameOffset());
+}
+
+Expected<const coff_resource_dir_table &>
+ResourceSectionRef::getTableAtOffset(uint32_t Offset) {
+ const coff_resource_dir_table *Table = nullptr;
+
+ BinaryStreamReader Reader(BBS);
+ Reader.setOffset(Offset);
+ RETURN_IF_ERROR(Reader.readObject(Table));
+ assert(Table != nullptr);
+ return *Table;
+}
+
+Expected<const coff_resource_dir_entry &>
+ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {
+ const coff_resource_dir_entry *Entry = nullptr;
+
+ BinaryStreamReader Reader(BBS);
+ Reader.setOffset(Offset);
+ RETURN_IF_ERROR(Reader.readObject(Entry));
+ assert(Entry != nullptr);
+ return *Entry;
+}
+
+Expected<const coff_resource_data_entry &>
+ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {
+ const coff_resource_data_entry *Entry = nullptr;
+
+ BinaryStreamReader Reader(BBS);
+ Reader.setOffset(Offset);
+ RETURN_IF_ERROR(Reader.readObject(Entry));
+ assert(Entry != nullptr);
+ return *Entry;
+}
+
+Expected<const coff_resource_dir_table &>
+ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {
+ assert(Entry.Offset.isSubDir());
+ return getTableAtOffset(Entry.Offset.value());
+}
+
+Expected<const coff_resource_data_entry &>
+ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {
+ assert(!Entry.Offset.isSubDir());
+ return getDataEntryAtOffset(Entry.Offset.value());
+}
+
+Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {
+ return getTableAtOffset(0);
+}
+
+Expected<const coff_resource_dir_entry &>
+ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,
+ uint32_t Index) {
+ if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))
+ return createStringError(object_error::parse_failed, "index out of range");
+ const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);
+ ptrdiff_t TableOffset = TablePtr - BBS.data().data();
+ return getTableEntryAtOffset(TableOffset + sizeof(Table) +
+ Index * sizeof(coff_resource_dir_entry));
+}
+
+Error ResourceSectionRef::load(const COFFObjectFile *O) {
+ for (const SectionRef &S : O->sections()) {
+ Expected<StringRef> Name = S.getName();
+ if (!Name)
+ return Name.takeError();
+
+ if (*Name == ".rsrc" || *Name == ".rsrc$01")
+ return load(O, S);
+ }
+ return createStringError(object_error::parse_failed,
+ "no resource section found");
+}
+
+Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {
+ Obj = O;
+ Section = S;
+ Expected<StringRef> Contents = Section.getContents();
+ if (!Contents)
+ return Contents.takeError();
+ BBS = BinaryByteStream(*Contents, support::little);
+ const coff_section *COFFSect = Obj->getCOFFSection(Section);
+ ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);
+ Relocs.reserve(OrigRelocs.size());
+ for (const coff_relocation &R : OrigRelocs)
+ Relocs.push_back(&R);
llvm::sort(Relocs, [](const coff_relocation *A, const coff_relocation *B) {
return A->VirtualAddress < B->VirtualAddress;
});
- return Error::success();
-}
-
-Expected<StringRef>
-ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
- if (!Obj)
- return createStringError(object_error::parse_failed, "no object provided");
-
- // Find a potential relocation at the DataRVA field (first member of
- // the coff_resource_data_entry struct).
- const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);
- ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();
- coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),
- ulittle16_t(0)};
- auto RelocsForOffset =
- std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,
- [](const coff_relocation *A, const coff_relocation *B) {
- return A->VirtualAddress < B->VirtualAddress;
- });
-
- if (RelocsForOffset.first != RelocsForOffset.second) {
- // We found a relocation with the right offset. Check that it does have
- // the expected type.
- const coff_relocation &R = **RelocsForOffset.first;
- uint16_t RVAReloc;
- switch (Obj->getMachine()) {
- case COFF::IMAGE_FILE_MACHINE_I386:
- RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;
- break;
- case COFF::IMAGE_FILE_MACHINE_AMD64:
- RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;
- break;
- case COFF::IMAGE_FILE_MACHINE_ARMNT:
- RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;
- break;
- case COFF::IMAGE_FILE_MACHINE_ARM64:
- RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
- break;
- default:
- return createStringError(object_error::parse_failed,
- "unsupported architecture");
- }
- if (R.Type != RVAReloc)
- return createStringError(object_error::parse_failed,
- "unexpected relocation type");
- // Get the relocation's symbol
- Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);
- if (!Sym)
- return Sym.takeError();
- // And the symbol's section
- Expected<const coff_section *> Section =
- Obj->getSection(Sym->getSectionNumber());
- if (!Section)
- return Section.takeError();
- // Add the initial value of DataRVA to the symbol's offset to find the
- // data it points at.
- uint64_t Offset = Entry.DataRVA + Sym->getValue();
- ArrayRef<uint8_t> Contents;
- if (Error E = Obj->getSectionContents(*Section, Contents))
- return std::move(E);
- if (Offset + Entry.DataSize > Contents.size())
- return createStringError(object_error::parse_failed,
- "data outside of section");
- // Return a reference to the data inside the section.
- return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,
- Entry.DataSize);
- } else {
- // Relocatable objects need a relocation for the DataRVA field.
- if (Obj->isRelocatableObject())
- return createStringError(object_error::parse_failed,
- "no relocation found for DataRVA");
-
- // Locate the section that contains the address that DataRVA points at.
- uint64_t VA = Entry.DataRVA + Obj->getImageBase();
- for (const SectionRef &S : Obj->sections()) {
- if (VA >= S.getAddress() &&
- VA + Entry.DataSize <= S.getAddress() + S.getSize()) {
- uint64_t Offset = VA - S.getAddress();
- Expected<StringRef> Contents = S.getContents();
- if (!Contents)
- return Contents.takeError();
- return Contents->slice(Offset, Offset + Entry.DataSize);
- }
- }
- return createStringError(object_error::parse_failed,
- "address not found in image");
- }
-}
+ return Error::success();
+}
+
+Expected<StringRef>
+ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
+ if (!Obj)
+ return createStringError(object_error::parse_failed, "no object provided");
+
+ // Find a potential relocation at the DataRVA field (first member of
+ // the coff_resource_data_entry struct).
+ const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);
+ ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();
+ coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),
+ ulittle16_t(0)};
+ auto RelocsForOffset =
+ std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,
+ [](const coff_relocation *A, const coff_relocation *B) {
+ return A->VirtualAddress < B->VirtualAddress;
+ });
+
+ if (RelocsForOffset.first != RelocsForOffset.second) {
+ // We found a relocation with the right offset. Check that it does have
+ // the expected type.
+ const coff_relocation &R = **RelocsForOffset.first;
+ uint16_t RVAReloc;
+ switch (Obj->getMachine()) {
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;
+ break;
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;
+ break;
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;
+ break;
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
+ break;
+ default:
+ return createStringError(object_error::parse_failed,
+ "unsupported architecture");
+ }
+ if (R.Type != RVAReloc)
+ return createStringError(object_error::parse_failed,
+ "unexpected relocation type");
+ // Get the relocation's symbol
+ Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);
+ if (!Sym)
+ return Sym.takeError();
+ // And the symbol's section
+ Expected<const coff_section *> Section =
+ Obj->getSection(Sym->getSectionNumber());
+ if (!Section)
+ return Section.takeError();
+ // Add the initial value of DataRVA to the symbol's offset to find the
+ // data it points at.
+ uint64_t Offset = Entry.DataRVA + Sym->getValue();
+ ArrayRef<uint8_t> Contents;
+ if (Error E = Obj->getSectionContents(*Section, Contents))
+ return std::move(E);
+ if (Offset + Entry.DataSize > Contents.size())
+ return createStringError(object_error::parse_failed,
+ "data outside of section");
+ // Return a reference to the data inside the section.
+ return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,
+ Entry.DataSize);
+ } else {
+ // Relocatable objects need a relocation for the DataRVA field.
+ if (Obj->isRelocatableObject())
+ return createStringError(object_error::parse_failed,
+ "no relocation found for DataRVA");
+
+ // Locate the section that contains the address that DataRVA points at.
+ uint64_t VA = Entry.DataRVA + Obj->getImageBase();
+ for (const SectionRef &S : Obj->sections()) {
+ if (VA >= S.getAddress() &&
+ VA + Entry.DataSize <= S.getAddress() + S.getSize()) {
+ uint64_t Offset = VA - S.getAddress();
+ Expected<StringRef> Contents = S.getContents();
+ if (!Contents)
+ return Contents.takeError();
+ return Contents->slice(Offset, Offset + Entry.DataSize);
+ }
+ }
+ return createStringError(object_error::parse_failed,
+ "address not found in image");
+ }
+}
diff --git a/contrib/libs/llvm12/lib/Object/Decompressor.cpp b/contrib/libs/llvm12/lib/Object/Decompressor.cpp
index 359d554d40..11efd857d1 100644
--- a/contrib/libs/llvm12/lib/Object/Decompressor.cpp
+++ b/contrib/libs/llvm12/lib/Object/Decompressor.cpp
@@ -1,98 +1,98 @@
-//===-- Decompressor.cpp --------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/Decompressor.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/Support/Compression.h"
-#include "llvm/Support/DataExtractor.h"
-#include "llvm/Support/Endian.h"
-
-using namespace llvm;
-using namespace llvm::support::endian;
-using namespace object;
-
-Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data,
- bool IsLE, bool Is64Bit) {
- if (!zlib::isAvailable())
- return createError("zlib is not available");
-
- Decompressor D(Data);
- Error Err = isGnuStyle(Name) ? D.consumeCompressedGnuHeader()
- : D.consumeCompressedZLibHeader(Is64Bit, IsLE);
- if (Err)
- return std::move(Err);
- return D;
-}
-
-Decompressor::Decompressor(StringRef Data)
- : SectionData(Data), DecompressedSize(0) {}
-
-Error Decompressor::consumeCompressedGnuHeader() {
- if (!SectionData.startswith("ZLIB"))
- return createError("corrupted compressed section header");
-
- SectionData = SectionData.substr(4);
-
- // Consume uncompressed section size (big-endian 8 bytes).
- if (SectionData.size() < 8)
- return createError("corrupted uncompressed section size");
- DecompressedSize = read64be(SectionData.data());
- SectionData = SectionData.substr(8);
-
- return Error::success();
-}
-
-Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
- bool IsLittleEndian) {
- using namespace ELF;
- uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
- if (SectionData.size() < HdrSize)
- return createError("corrupted compressed section header");
-
- DataExtractor Extractor(SectionData, IsLittleEndian, 0);
- uint64_t Offset = 0;
- if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
- : sizeof(Elf32_Word)) !=
- ELFCOMPRESS_ZLIB)
- return createError("unsupported compression type");
-
- // Skip Elf64_Chdr::ch_reserved field.
- if (Is64Bit)
- Offset += sizeof(Elf64_Word);
-
- DecompressedSize = Extractor.getUnsigned(
- &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word));
- SectionData = SectionData.substr(HdrSize);
- return Error::success();
-}
-
-bool Decompressor::isGnuStyle(StringRef Name) {
- return Name.startswith(".zdebug");
-}
-
-bool Decompressor::isCompressed(const object::SectionRef &Section) {
- if (Section.isCompressed())
- return true;
-
- Expected<StringRef> SecNameOrErr = Section.getName();
- if (SecNameOrErr)
- return isGnuStyle(*SecNameOrErr);
-
- consumeError(SecNameOrErr.takeError());
- return false;
-}
-
-bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) {
- return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name);
-}
-
-Error Decompressor::decompress(MutableArrayRef<char> Buffer) {
- size_t Size = Buffer.size();
- return zlib::uncompress(SectionData, Buffer.data(), Size);
-}
+//===-- Decompressor.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Decompressor.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support::endian;
+using namespace object;
+
+Expected<Decompressor> Decompressor::create(StringRef Name, StringRef Data,
+ bool IsLE, bool Is64Bit) {
+ if (!zlib::isAvailable())
+ return createError("zlib is not available");
+
+ Decompressor D(Data);
+ Error Err = isGnuStyle(Name) ? D.consumeCompressedGnuHeader()
+ : D.consumeCompressedZLibHeader(Is64Bit, IsLE);
+ if (Err)
+ return std::move(Err);
+ return D;
+}
+
+Decompressor::Decompressor(StringRef Data)
+ : SectionData(Data), DecompressedSize(0) {}
+
+Error Decompressor::consumeCompressedGnuHeader() {
+ if (!SectionData.startswith("ZLIB"))
+ return createError("corrupted compressed section header");
+
+ SectionData = SectionData.substr(4);
+
+ // Consume uncompressed section size (big-endian 8 bytes).
+ if (SectionData.size() < 8)
+ return createError("corrupted uncompressed section size");
+ DecompressedSize = read64be(SectionData.data());
+ SectionData = SectionData.substr(8);
+
+ return Error::success();
+}
+
+Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
+ bool IsLittleEndian) {
+ using namespace ELF;
+ uint64_t HdrSize = Is64Bit ? sizeof(Elf64_Chdr) : sizeof(Elf32_Chdr);
+ if (SectionData.size() < HdrSize)
+ return createError("corrupted compressed section header");
+
+ DataExtractor Extractor(SectionData, IsLittleEndian, 0);
+ uint64_t Offset = 0;
+ if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
+ : sizeof(Elf32_Word)) !=
+ ELFCOMPRESS_ZLIB)
+ return createError("unsupported compression type");
+
+ // Skip Elf64_Chdr::ch_reserved field.
+ if (Is64Bit)
+ Offset += sizeof(Elf64_Word);
+
+ DecompressedSize = Extractor.getUnsigned(
+ &Offset, Is64Bit ? sizeof(Elf64_Xword) : sizeof(Elf32_Word));
+ SectionData = SectionData.substr(HdrSize);
+ return Error::success();
+}
+
+bool Decompressor::isGnuStyle(StringRef Name) {
+ return Name.startswith(".zdebug");
+}
+
+bool Decompressor::isCompressed(const object::SectionRef &Section) {
+ if (Section.isCompressed())
+ return true;
+
+ Expected<StringRef> SecNameOrErr = Section.getName();
+ if (SecNameOrErr)
+ return isGnuStyle(*SecNameOrErr);
+
+ consumeError(SecNameOrErr.takeError());
+ return false;
+}
+
+bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) {
+ return (Flags & ELF::SHF_COMPRESSED) || isGnuStyle(Name);
+}
+
+Error Decompressor::decompress(MutableArrayRef<char> Buffer) {
+ size_t Size = Buffer.size();
+ return zlib::uncompress(SectionData, Buffer.data(), Size);
+}
diff --git a/contrib/libs/llvm12/lib/Object/ELF.cpp b/contrib/libs/llvm12/lib/Object/ELF.cpp
index cd480c1254..264f115ddb 100644
--- a/contrib/libs/llvm12/lib/Object/ELF.cpp
+++ b/contrib/libs/llvm12/lib/Object/ELF.cpp
@@ -1,157 +1,157 @@
-//===- ELF.cpp - ELF object file implementation ---------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/ELF.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/Support/LEB128.h"
-
-using namespace llvm;
-using namespace object;
-
-#define STRINGIFY_ENUM_CASE(ns, name) \
- case ns::name: \
- return #name;
-
-#define ELF_RELOC(name, value) STRINGIFY_ENUM_CASE(ELF, name)
-
-StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine,
- uint32_t Type) {
- switch (Machine) {
- case ELF::EM_X86_64:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/x86_64.def"
- default:
- break;
- }
- break;
- case ELF::EM_386:
- case ELF::EM_IAMCU:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/i386.def"
- default:
- break;
- }
- break;
- case ELF::EM_MIPS:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/Mips.def"
- default:
- break;
- }
- break;
- case ELF::EM_AARCH64:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/AArch64.def"
- default:
- break;
- }
- break;
- case ELF::EM_ARM:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/ARM.def"
- default:
- 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"
- default:
- break;
- }
- break;
- case ELF::EM_HEXAGON:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/Hexagon.def"
- default:
- break;
- }
- break;
- case ELF::EM_LANAI:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/Lanai.def"
- default:
- break;
- }
- break;
- case ELF::EM_PPC:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/PowerPC.def"
- default:
- break;
- }
- break;
- case ELF::EM_PPC64:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"
- default:
- break;
- }
- break;
- case ELF::EM_RISCV:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/RISCV.def"
- default:
- break;
- }
- break;
- case ELF::EM_S390:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/SystemZ.def"
- default:
- break;
- }
- break;
- case ELF::EM_SPARC:
- case ELF::EM_SPARC32PLUS:
- case ELF::EM_SPARCV9:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/Sparc.def"
- default:
- break;
- }
- break;
- case ELF::EM_AMDGPU:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/AMDGPU.def"
- default:
- break;
- }
- break;
- case ELF::EM_BPF:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/BPF.def"
- default:
- break;
- }
- break;
- case ELF::EM_MSP430:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/MSP430.def"
- default:
- break;
- }
- break;
- case ELF::EM_VE:
- switch (Type) {
-#include "llvm/BinaryFormat/ELFRelocs/VE.def"
- default:
- break;
- }
- break;
+//===- ELF.cpp - ELF object file implementation ---------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ELF.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Support/LEB128.h"
+
+using namespace llvm;
+using namespace object;
+
+#define STRINGIFY_ENUM_CASE(ns, name) \
+ case ns::name: \
+ return #name;
+
+#define ELF_RELOC(name, value) STRINGIFY_ENUM_CASE(ELF, name)
+
+StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine,
+ uint32_t Type) {
+ switch (Machine) {
+ case ELF::EM_X86_64:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/x86_64.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_386:
+ case ELF::EM_IAMCU:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/i386.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_MIPS:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/Mips.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_AARCH64:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/AArch64.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_ARM:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/ARM.def"
+ default:
+ 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"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_HEXAGON:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/Hexagon.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_LANAI:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/Lanai.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_PPC:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/PowerPC.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_PPC64:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_RISCV:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/RISCV.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_S390:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/SystemZ.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_SPARC:
+ case ELF::EM_SPARC32PLUS:
+ case ELF::EM_SPARCV9:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/Sparc.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_AMDGPU:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/AMDGPU.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_BPF:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/BPF.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_MSP430:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/MSP430.def"
+ default:
+ break;
+ }
+ break;
+ case ELF::EM_VE:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/VE.def"
+ default:
+ break;
+ }
+ break;
case ELF::EM_CSKY:
switch (Type) {
#include "llvm/BinaryFormat/ELFRelocs/CSKY.def"
@@ -159,425 +159,425 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine,
break;
}
break;
- default:
- break;
- }
- return "Unknown";
-}
-
-#undef ELF_RELOC
-
-uint32_t llvm::object::getELFRelativeRelocationType(uint32_t Machine) {
- switch (Machine) {
- case ELF::EM_X86_64:
- return ELF::R_X86_64_RELATIVE;
- case ELF::EM_386:
- case ELF::EM_IAMCU:
- return ELF::R_386_RELATIVE;
- case ELF::EM_MIPS:
- break;
- case ELF::EM_AARCH64:
- return ELF::R_AARCH64_RELATIVE;
- case ELF::EM_ARM:
- return ELF::R_ARM_RELATIVE;
- case ELF::EM_ARC_COMPACT:
- case ELF::EM_ARC_COMPACT2:
- return ELF::R_ARC_RELATIVE;
- case ELF::EM_AVR:
- break;
- case ELF::EM_HEXAGON:
- return ELF::R_HEX_RELATIVE;
- case ELF::EM_LANAI:
- break;
- case ELF::EM_PPC:
- break;
- case ELF::EM_PPC64:
- return ELF::R_PPC64_RELATIVE;
- case ELF::EM_RISCV:
- return ELF::R_RISCV_RELATIVE;
- case ELF::EM_S390:
- return ELF::R_390_RELATIVE;
- case ELF::EM_SPARC:
- case ELF::EM_SPARC32PLUS:
- case ELF::EM_SPARCV9:
- return ELF::R_SPARC_RELATIVE;
+ default:
+ break;
+ }
+ return "Unknown";
+}
+
+#undef ELF_RELOC
+
+uint32_t llvm::object::getELFRelativeRelocationType(uint32_t Machine) {
+ switch (Machine) {
+ case ELF::EM_X86_64:
+ return ELF::R_X86_64_RELATIVE;
+ case ELF::EM_386:
+ case ELF::EM_IAMCU:
+ return ELF::R_386_RELATIVE;
+ case ELF::EM_MIPS:
+ break;
+ case ELF::EM_AARCH64:
+ return ELF::R_AARCH64_RELATIVE;
+ case ELF::EM_ARM:
+ return ELF::R_ARM_RELATIVE;
+ case ELF::EM_ARC_COMPACT:
+ case ELF::EM_ARC_COMPACT2:
+ return ELF::R_ARC_RELATIVE;
+ case ELF::EM_AVR:
+ break;
+ case ELF::EM_HEXAGON:
+ return ELF::R_HEX_RELATIVE;
+ case ELF::EM_LANAI:
+ break;
+ case ELF::EM_PPC:
+ break;
+ case ELF::EM_PPC64:
+ return ELF::R_PPC64_RELATIVE;
+ case ELF::EM_RISCV:
+ return ELF::R_RISCV_RELATIVE;
+ case ELF::EM_S390:
+ return ELF::R_390_RELATIVE;
+ case ELF::EM_SPARC:
+ case ELF::EM_SPARC32PLUS:
+ case ELF::EM_SPARCV9:
+ return ELF::R_SPARC_RELATIVE;
case ELF::EM_CSKY:
return ELF::R_CKCORE_RELATIVE;
- case ELF::EM_AMDGPU:
- break;
- case ELF::EM_BPF:
- break;
- default:
- break;
- }
- return 0;
-}
-
-StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
- switch (Machine) {
- case ELF::EM_ARM:
- switch (Type) {
- STRINGIFY_ENUM_CASE(ELF, SHT_ARM_EXIDX);
- STRINGIFY_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP);
- STRINGIFY_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES);
- STRINGIFY_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY);
- STRINGIFY_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION);
- }
- break;
- case ELF::EM_HEXAGON:
- switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_HEX_ORDERED); }
- break;
- case ELF::EM_X86_64:
- switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_X86_64_UNWIND); }
- break;
- case ELF::EM_MIPS:
- case ELF::EM_MIPS_RS3_LE:
- switch (Type) {
- STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
- STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
- STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_DWARF);
- STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS);
- }
- break;
- case ELF::EM_RISCV:
- switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_RISCV_ATTRIBUTES); }
- break;
- default:
- break;
- }
-
- switch (Type) {
- STRINGIFY_ENUM_CASE(ELF, SHT_NULL);
- STRINGIFY_ENUM_CASE(ELF, SHT_PROGBITS);
- STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB);
- STRINGIFY_ENUM_CASE(ELF, SHT_STRTAB);
- STRINGIFY_ENUM_CASE(ELF, SHT_RELA);
- STRINGIFY_ENUM_CASE(ELF, SHT_HASH);
- STRINGIFY_ENUM_CASE(ELF, SHT_DYNAMIC);
- STRINGIFY_ENUM_CASE(ELF, SHT_NOTE);
- STRINGIFY_ENUM_CASE(ELF, SHT_NOBITS);
- STRINGIFY_ENUM_CASE(ELF, SHT_REL);
- STRINGIFY_ENUM_CASE(ELF, SHT_SHLIB);
- STRINGIFY_ENUM_CASE(ELF, SHT_DYNSYM);
- STRINGIFY_ENUM_CASE(ELF, SHT_INIT_ARRAY);
- STRINGIFY_ENUM_CASE(ELF, SHT_FINI_ARRAY);
- 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_RELR);
- STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL);
- STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA);
- STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELR);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LINKER_OPTIONS);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_DEPENDENT_LIBRARIES);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_EHDR);
- STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_PHDR);
+ case ELF::EM_AMDGPU:
+ break;
+ case ELF::EM_BPF:
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
+ switch (Machine) {
+ case ELF::EM_ARM:
+ switch (Type) {
+ STRINGIFY_ENUM_CASE(ELF, SHT_ARM_EXIDX);
+ STRINGIFY_ENUM_CASE(ELF, SHT_ARM_PREEMPTMAP);
+ STRINGIFY_ENUM_CASE(ELF, SHT_ARM_ATTRIBUTES);
+ STRINGIFY_ENUM_CASE(ELF, SHT_ARM_DEBUGOVERLAY);
+ STRINGIFY_ENUM_CASE(ELF, SHT_ARM_OVERLAYSECTION);
+ }
+ break;
+ case ELF::EM_HEXAGON:
+ switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_HEX_ORDERED); }
+ break;
+ case ELF::EM_X86_64:
+ switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_X86_64_UNWIND); }
+ break;
+ case ELF::EM_MIPS:
+ case ELF::EM_MIPS_RS3_LE:
+ switch (Type) {
+ STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_REGINFO);
+ STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_OPTIONS);
+ STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_DWARF);
+ STRINGIFY_ENUM_CASE(ELF, SHT_MIPS_ABIFLAGS);
+ }
+ break;
+ case ELF::EM_RISCV:
+ switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_RISCV_ATTRIBUTES); }
+ break;
+ default:
+ break;
+ }
+
+ switch (Type) {
+ STRINGIFY_ENUM_CASE(ELF, SHT_NULL);
+ STRINGIFY_ENUM_CASE(ELF, SHT_PROGBITS);
+ STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB);
+ STRINGIFY_ENUM_CASE(ELF, SHT_STRTAB);
+ STRINGIFY_ENUM_CASE(ELF, SHT_RELA);
+ STRINGIFY_ENUM_CASE(ELF, SHT_HASH);
+ STRINGIFY_ENUM_CASE(ELF, SHT_DYNAMIC);
+ STRINGIFY_ENUM_CASE(ELF, SHT_NOTE);
+ STRINGIFY_ENUM_CASE(ELF, SHT_NOBITS);
+ STRINGIFY_ENUM_CASE(ELF, SHT_REL);
+ STRINGIFY_ENUM_CASE(ELF, SHT_SHLIB);
+ STRINGIFY_ENUM_CASE(ELF, SHT_DYNSYM);
+ STRINGIFY_ENUM_CASE(ELF, SHT_INIT_ARRAY);
+ STRINGIFY_ENUM_CASE(ELF, SHT_FINI_ARRAY);
+ 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_RELR);
+ STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL);
+ STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA);
+ STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELR);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ODRTAB);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LINKER_OPTIONS);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_CALL_GRAPH_PROFILE);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_DEPENDENT_LIBRARIES);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_EHDR);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_PHDR);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP);
- STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
- STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
- STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
- STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verneed);
- STRINGIFY_ENUM_CASE(ELF, SHT_GNU_versym);
- default:
- return "Unknown";
- }
-}
-
-template <class ELFT>
+ STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
+ STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
+ STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
+ STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verneed);
+ STRINGIFY_ENUM_CASE(ELF, SHT_GNU_versym);
+ default:
+ return "Unknown";
+ }
+}
+
+template <class ELFT>
std::vector<typename ELFT::Rel>
-ELFFile<ELFT>::decode_relrs(Elf_Relr_Range relrs) const {
- // This function decodes the contents of an SHT_RELR packed relocation
- // section.
- //
- // Proposal for adding SHT_RELR sections to generic-abi is here:
- // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
- //
- // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
- // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
- //
- // i.e. start with an address, followed by any number of bitmaps. The address
- // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
- // relocations each, at subsequent offsets following the last address entry.
- //
- // The bitmap entries must have 1 in the least significant bit. The assumption
- // here is that an address cannot have 1 in lsb. Odd addresses are not
- // supported.
- //
- // Excluding the least significant bit in the bitmap, each non-zero bit in
- // the bitmap represents a relocation to be applied to a corresponding machine
- // word that follows the base address word. The second least significant bit
- // represents the machine word immediately following the initial address, and
- // each bit that follows represents the next word, in linear order. As such,
- // a single bitmap can encode up to 31 relocations in a 32-bit object, and
- // 63 relocations in a 64-bit object.
- //
- // This encoding has a couple of interesting properties:
- // 1. Looking at any entry, it is clear whether it's an address or a bitmap:
- // even means address, odd means bitmap.
- // 2. Just a simple list of addresses is a valid encoding.
-
+ELFFile<ELFT>::decode_relrs(Elf_Relr_Range relrs) const {
+ // This function decodes the contents of an SHT_RELR packed relocation
+ // section.
+ //
+ // Proposal for adding SHT_RELR sections to generic-abi is here:
+ // https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
+ //
+ // The encoded sequence of Elf64_Relr entries in a SHT_RELR section looks
+ // like [ AAAAAAAA BBBBBBB1 BBBBBBB1 ... AAAAAAAA BBBBBB1 ... ]
+ //
+ // i.e. start with an address, followed by any number of bitmaps. The address
+ // entry encodes 1 relocation. The subsequent bitmap entries encode up to 63
+ // relocations each, at subsequent offsets following the last address entry.
+ //
+ // The bitmap entries must have 1 in the least significant bit. The assumption
+ // here is that an address cannot have 1 in lsb. Odd addresses are not
+ // supported.
+ //
+ // Excluding the least significant bit in the bitmap, each non-zero bit in
+ // the bitmap represents a relocation to be applied to a corresponding machine
+ // word that follows the base address word. The second least significant bit
+ // represents the machine word immediately following the initial address, and
+ // each bit that follows represents the next word, in linear order. As such,
+ // a single bitmap can encode up to 31 relocations in a 32-bit object, and
+ // 63 relocations in a 64-bit object.
+ //
+ // This encoding has a couple of interesting properties:
+ // 1. Looking at any entry, it is clear whether it's an address or a bitmap:
+ // even means address, odd means bitmap.
+ // 2. Just a simple list of addresses is a valid encoding.
+
Elf_Rel Rel;
Rel.r_info = 0;
Rel.setType(getRelativeRelocationType(), false);
std::vector<Elf_Rel> Relocs;
-
- // Word type: uint32_t for Elf32, and uint64_t for Elf64.
- typedef typename ELFT::uint Word;
-
- // Word size in number of bytes.
- const size_t WordSize = sizeof(Word);
-
- // Number of bits used for the relocation offsets bitmap.
- // These many relative relocations can be encoded in a single entry.
- const size_t NBits = 8*WordSize - 1;
-
- Word Base = 0;
- for (const Elf_Relr &R : relrs) {
- Word Entry = R;
- if ((Entry&1) == 0) {
- // Even entry: encodes the offset for next relocation.
+
+ // Word type: uint32_t for Elf32, and uint64_t for Elf64.
+ typedef typename ELFT::uint Word;
+
+ // Word size in number of bytes.
+ const size_t WordSize = sizeof(Word);
+
+ // Number of bits used for the relocation offsets bitmap.
+ // These many relative relocations can be encoded in a single entry.
+ const size_t NBits = 8*WordSize - 1;
+
+ Word Base = 0;
+ for (const Elf_Relr &R : relrs) {
+ Word Entry = R;
+ if ((Entry&1) == 0) {
+ // Even entry: encodes the offset for next relocation.
Rel.r_offset = Entry;
Relocs.push_back(Rel);
- // Set base offset for subsequent bitmap entries.
- Base = Entry + WordSize;
- continue;
- }
-
- // Odd entry: encodes bitmap for relocations starting at base.
- Word Offset = Base;
- while (Entry != 0) {
- Entry >>= 1;
- if ((Entry&1) != 0) {
+ // Set base offset for subsequent bitmap entries.
+ Base = Entry + WordSize;
+ continue;
+ }
+
+ // Odd entry: encodes bitmap for relocations starting at base.
+ Word Offset = Base;
+ while (Entry != 0) {
+ Entry >>= 1;
+ if ((Entry&1) != 0) {
Rel.r_offset = Offset;
Relocs.push_back(Rel);
- }
- Offset += WordSize;
- }
-
- // Advance base offset by NBits words.
- Base += NBits * WordSize;
- }
-
- return Relocs;
-}
-
-template <class ELFT>
-Expected<std::vector<typename ELFT::Rela>>
+ }
+ Offset += WordSize;
+ }
+
+ // Advance base offset by NBits words.
+ Base += NBits * WordSize;
+ }
+
+ return Relocs;
+}
+
+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();
-
- if (!GroupHasAddend)
- Addend = 0;
-
- 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 && !GroupedByAddend)
- Addend += ReadSLEB();
- R.r_addend = Addend;
- Relocs.push_back(R);
-
- if (ErrStr)
- return createError(ErrStr);
- }
-
- if (ErrStr)
- return createError(ErrStr);
- }
-
- return Relocs;
-}
-
-template <class ELFT>
-std::string ELFFile<ELFT>::getDynamicTagAsString(unsigned Arch,
- uint64_t Type) const {
-#define DYNAMIC_STRINGIFY_ENUM(tag, value) \
- case value: \
- return #tag;
-
-#define DYNAMIC_TAG(n, v)
- switch (Arch) {
- case ELF::EM_AARCH64:
- switch (Type) {
-#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef AARCH64_DYNAMIC_TAG
- }
- break;
-
- case ELF::EM_HEXAGON:
- switch (Type) {
-#define HEXAGON_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef HEXAGON_DYNAMIC_TAG
- }
- break;
-
- case ELF::EM_MIPS:
- switch (Type) {
-#define MIPS_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef MIPS_DYNAMIC_TAG
- }
- break;
-
- case ELF::EM_PPC64:
- switch (Type) {
-#define PPC64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef PPC64_DYNAMIC_TAG
- }
- break;
- }
-#undef DYNAMIC_TAG
- switch (Type) {
-// Now handle all dynamic tags except the architecture specific ones
-#define AARCH64_DYNAMIC_TAG(name, value)
-#define MIPS_DYNAMIC_TAG(name, value)
-#define HEXAGON_DYNAMIC_TAG(name, value)
-#define PPC64_DYNAMIC_TAG(name, value)
-// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc.
-#define DYNAMIC_TAG_MARKER(name, value)
-#define DYNAMIC_TAG(name, value) case value: return #name;
-#include "llvm/BinaryFormat/DynamicTags.def"
-#undef DYNAMIC_TAG
-#undef AARCH64_DYNAMIC_TAG
-#undef MIPS_DYNAMIC_TAG
-#undef HEXAGON_DYNAMIC_TAG
-#undef PPC64_DYNAMIC_TAG
-#undef DYNAMIC_TAG_MARKER
-#undef DYNAMIC_STRINGIFY_ENUM
- default:
- return "<unknown:>0x" + utohexstr(Type, true);
- }
-}
-
-template <class ELFT>
-std::string ELFFile<ELFT>::getDynamicTagAsString(uint64_t Type) 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();
+
+ if (!GroupHasAddend)
+ Addend = 0;
+
+ 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 && !GroupedByAddend)
+ Addend += ReadSLEB();
+ R.r_addend = Addend;
+ Relocs.push_back(R);
+
+ if (ErrStr)
+ return createError(ErrStr);
+ }
+
+ if (ErrStr)
+ return createError(ErrStr);
+ }
+
+ return Relocs;
+}
+
+template <class ELFT>
+std::string ELFFile<ELFT>::getDynamicTagAsString(unsigned Arch,
+ uint64_t Type) const {
+#define DYNAMIC_STRINGIFY_ENUM(tag, value) \
+ case value: \
+ return #tag;
+
+#define DYNAMIC_TAG(n, v)
+ switch (Arch) {
+ case ELF::EM_AARCH64:
+ switch (Type) {
+#define AARCH64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef AARCH64_DYNAMIC_TAG
+ }
+ break;
+
+ case ELF::EM_HEXAGON:
+ switch (Type) {
+#define HEXAGON_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef HEXAGON_DYNAMIC_TAG
+ }
+ break;
+
+ case ELF::EM_MIPS:
+ switch (Type) {
+#define MIPS_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef MIPS_DYNAMIC_TAG
+ }
+ break;
+
+ case ELF::EM_PPC64:
+ switch (Type) {
+#define PPC64_DYNAMIC_TAG(name, value) DYNAMIC_STRINGIFY_ENUM(name, value)
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef PPC64_DYNAMIC_TAG
+ }
+ break;
+ }
+#undef DYNAMIC_TAG
+ switch (Type) {
+// Now handle all dynamic tags except the architecture specific ones
+#define AARCH64_DYNAMIC_TAG(name, value)
+#define MIPS_DYNAMIC_TAG(name, value)
+#define HEXAGON_DYNAMIC_TAG(name, value)
+#define PPC64_DYNAMIC_TAG(name, value)
+// Also ignore marker tags such as DT_HIOS (maps to DT_VERNEEDNUM), etc.
+#define DYNAMIC_TAG_MARKER(name, value)
+#define DYNAMIC_TAG(name, value) case value: return #name;
+#include "llvm/BinaryFormat/DynamicTags.def"
+#undef DYNAMIC_TAG
+#undef AARCH64_DYNAMIC_TAG
+#undef MIPS_DYNAMIC_TAG
+#undef HEXAGON_DYNAMIC_TAG
+#undef PPC64_DYNAMIC_TAG
+#undef DYNAMIC_TAG_MARKER
+#undef DYNAMIC_STRINGIFY_ENUM
+ default:
+ return "<unknown:>0x" + utohexstr(Type, true);
+ }
+}
+
+template <class ELFT>
+std::string ELFFile<ELFT>::getDynamicTagAsString(uint64_t Type) const {
return getDynamicTagAsString(getHeader().e_machine, Type);
-}
-
-template <class ELFT>
-Expected<typename ELFT::DynRange> ELFFile<ELFT>::dynamicEntries() const {
- ArrayRef<Elf_Dyn> Dyn;
-
- auto ProgramHeadersOrError = program_headers();
- if (!ProgramHeadersOrError)
- return ProgramHeadersOrError.takeError();
-
- for (const Elf_Phdr &Phdr : *ProgramHeadersOrError) {
- if (Phdr.p_type == ELF::PT_DYNAMIC) {
- Dyn = makeArrayRef(
- reinterpret_cast<const Elf_Dyn *>(base() + Phdr.p_offset),
- Phdr.p_filesz / sizeof(Elf_Dyn));
- break;
- }
- }
-
- // If we can't find the dynamic section in the program headers, we just fall
- // back on the sections.
- if (Dyn.empty()) {
- auto SectionsOrError = sections();
- if (!SectionsOrError)
- return SectionsOrError.takeError();
-
- for (const Elf_Shdr &Sec : *SectionsOrError) {
- if (Sec.sh_type == ELF::SHT_DYNAMIC) {
- Expected<ArrayRef<Elf_Dyn>> DynOrError =
+}
+
+template <class ELFT>
+Expected<typename ELFT::DynRange> ELFFile<ELFT>::dynamicEntries() const {
+ ArrayRef<Elf_Dyn> Dyn;
+
+ auto ProgramHeadersOrError = program_headers();
+ if (!ProgramHeadersOrError)
+ return ProgramHeadersOrError.takeError();
+
+ for (const Elf_Phdr &Phdr : *ProgramHeadersOrError) {
+ if (Phdr.p_type == ELF::PT_DYNAMIC) {
+ Dyn = makeArrayRef(
+ reinterpret_cast<const Elf_Dyn *>(base() + Phdr.p_offset),
+ Phdr.p_filesz / sizeof(Elf_Dyn));
+ break;
+ }
+ }
+
+ // If we can't find the dynamic section in the program headers, we just fall
+ // back on the sections.
+ if (Dyn.empty()) {
+ auto SectionsOrError = sections();
+ if (!SectionsOrError)
+ return SectionsOrError.takeError();
+
+ for (const Elf_Shdr &Sec : *SectionsOrError) {
+ if (Sec.sh_type == ELF::SHT_DYNAMIC) {
+ Expected<ArrayRef<Elf_Dyn>> DynOrError =
getSectionContentsAsArray<Elf_Dyn>(Sec);
- if (!DynOrError)
- return DynOrError.takeError();
- Dyn = *DynOrError;
- break;
- }
- }
-
- if (!Dyn.data())
- return ArrayRef<Elf_Dyn>();
- }
-
- if (Dyn.empty())
- // TODO: this error is untested.
- return createError("invalid empty dynamic section");
-
- if (Dyn.back().d_tag != ELF::DT_NULL)
- // TODO: this error is untested.
- return createError("dynamic sections must be DT_NULL terminated");
-
- return Dyn;
-}
-
-template <class ELFT>
+ if (!DynOrError)
+ return DynOrError.takeError();
+ Dyn = *DynOrError;
+ break;
+ }
+ }
+
+ if (!Dyn.data())
+ return ArrayRef<Elf_Dyn>();
+ }
+
+ if (Dyn.empty())
+ // TODO: this error is untested.
+ return createError("invalid empty dynamic section");
+
+ if (Dyn.back().d_tag != ELF::DT_NULL)
+ // TODO: this error is untested.
+ return createError("dynamic sections must be DT_NULL terminated");
+
+ return Dyn;
+}
+
+template <class ELFT>
Expected<const uint8_t *>
ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
- auto ProgramHeadersOrError = program_headers();
- if (!ProgramHeadersOrError)
- return ProgramHeadersOrError.takeError();
-
- llvm::SmallVector<Elf_Phdr *, 4> LoadSegments;
-
- for (const Elf_Phdr &Phdr : *ProgramHeadersOrError)
- if (Phdr.p_type == ELF::PT_LOAD)
- LoadSegments.push_back(const_cast<Elf_Phdr *>(&Phdr));
-
+ auto ProgramHeadersOrError = program_headers();
+ if (!ProgramHeadersOrError)
+ return ProgramHeadersOrError.takeError();
+
+ llvm::SmallVector<Elf_Phdr *, 4> LoadSegments;
+
+ for (const Elf_Phdr &Phdr : *ProgramHeadersOrError)
+ if (Phdr.p_type == ELF::PT_LOAD)
+ LoadSegments.push_back(const_cast<Elf_Phdr *>(&Phdr));
+
auto SortPred = [](const Elf_Phdr_Impl<ELFT> *A,
const Elf_Phdr_Impl<ELFT> *B) {
return A->p_vaddr < B->p_vaddr;
@@ -588,36 +588,36 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
return std::move(E);
llvm::stable_sort(LoadSegments, SortPred);
}
-
+
const Elf_Phdr *const *I = llvm::upper_bound(
LoadSegments, VAddr, [](uint64_t VAddr, const Elf_Phdr_Impl<ELFT> *Phdr) {
return VAddr < Phdr->p_vaddr;
});
- if (I == LoadSegments.begin())
- return createError("virtual address is not in any segment: 0x" +
- Twine::utohexstr(VAddr));
- --I;
- const Elf_Phdr &Phdr = **I;
- uint64_t Delta = VAddr - Phdr.p_vaddr;
- if (Delta >= Phdr.p_filesz)
- return createError("virtual address is not in any segment: 0x" +
- Twine::utohexstr(VAddr));
-
- uint64_t Offset = Phdr.p_offset + Delta;
- if (Offset >= getBufSize())
- return createError("can't map virtual address 0x" +
- Twine::utohexstr(VAddr) + " to the segment with index " +
- Twine(&Phdr - (*ProgramHeadersOrError).data() + 1) +
- ": the segment ends at 0x" +
- Twine::utohexstr(Phdr.p_offset + Phdr.p_filesz) +
- ", which is greater than the file size (0x" +
- Twine::utohexstr(getBufSize()) + ")");
-
- return base() + Offset;
-}
-
-template class llvm::object::ELFFile<ELF32LE>;
-template class llvm::object::ELFFile<ELF32BE>;
-template class llvm::object::ELFFile<ELF64LE>;
-template class llvm::object::ELFFile<ELF64BE>;
+ if (I == LoadSegments.begin())
+ return createError("virtual address is not in any segment: 0x" +
+ Twine::utohexstr(VAddr));
+ --I;
+ const Elf_Phdr &Phdr = **I;
+ uint64_t Delta = VAddr - Phdr.p_vaddr;
+ if (Delta >= Phdr.p_filesz)
+ return createError("virtual address is not in any segment: 0x" +
+ Twine::utohexstr(VAddr));
+
+ uint64_t Offset = Phdr.p_offset + Delta;
+ if (Offset >= getBufSize())
+ return createError("can't map virtual address 0x" +
+ Twine::utohexstr(VAddr) + " to the segment with index " +
+ Twine(&Phdr - (*ProgramHeadersOrError).data() + 1) +
+ ": the segment ends at 0x" +
+ Twine::utohexstr(Phdr.p_offset + Phdr.p_filesz) +
+ ", which is greater than the file size (0x" +
+ Twine::utohexstr(getBufSize()) + ")");
+
+ return base() + Offset;
+}
+
+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/libs/llvm12/lib/Object/ELFObjectFile.cpp b/contrib/libs/llvm12/lib/Object/ELFObjectFile.cpp
index 81037e1259..91871a6255 100644
--- a/contrib/libs/llvm12/lib/Object/ELFObjectFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/ELFObjectFile.cpp
@@ -1,361 +1,361 @@
-//===- ELFObjectFile.cpp - ELF object file implementation -----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Part of the ELFObjectFile class implementation.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/BinaryFormat/ELF.h"
-#include "llvm/MC/MCInstrAnalysis.h"
-#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/Object/ELF.h"
-#include "llvm/Object/ELFTypes.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Support/ARMAttributeParser.h"
-#include "llvm/Support/ARMBuildAttributes.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/RISCVAttributeParser.h"
-#include "llvm/Support/RISCVAttributes.h"
-#include "llvm/Support/TargetRegistry.h"
-#include <algorithm>
-#include <cstddef>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <system_error>
-#include <utility>
-
-using namespace llvm;
-using namespace object;
-
-const EnumEntry<unsigned> llvm::object::ElfSymbolTypes[NumElfSymbolTypes] = {
- {"None", "NOTYPE", ELF::STT_NOTYPE},
- {"Object", "OBJECT", ELF::STT_OBJECT},
- {"Function", "FUNC", ELF::STT_FUNC},
- {"Section", "SECTION", ELF::STT_SECTION},
- {"File", "FILE", ELF::STT_FILE},
- {"Common", "COMMON", ELF::STT_COMMON},
- {"TLS", "TLS", ELF::STT_TLS},
- {"Unknown", "<unknown>: 7", 7},
- {"Unknown", "<unknown>: 8", 8},
- {"Unknown", "<unknown>: 9", 9},
- {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC},
- {"OS Specific", "<OS specific>: 11", 11},
- {"OS Specific", "<OS specific>: 12", 12},
- {"Proc Specific", "<processor specific>: 13", 13},
- {"Proc Specific", "<processor specific>: 14", 14},
- {"Proc Specific", "<processor specific>: 15", 15}
-};
-
-ELFObjectFileBase::ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source)
- : ObjectFile(Type, Source) {}
-
-template <class ELFT>
-static Expected<std::unique_ptr<ELFObjectFile<ELFT>>>
+//===- ELFObjectFile.cpp - ELF object file implementation -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the ELFObjectFile class implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/MC/MCInstrAnalysis.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/ELF.h"
+#include "llvm/Object/ELFTypes.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/ARMAttributeParser.h"
+#include "llvm/Support/ARMBuildAttributes.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/RISCVAttributeParser.h"
+#include "llvm/Support/RISCVAttributes.h"
+#include "llvm/Support/TargetRegistry.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <system_error>
+#include <utility>
+
+using namespace llvm;
+using namespace object;
+
+const EnumEntry<unsigned> llvm::object::ElfSymbolTypes[NumElfSymbolTypes] = {
+ {"None", "NOTYPE", ELF::STT_NOTYPE},
+ {"Object", "OBJECT", ELF::STT_OBJECT},
+ {"Function", "FUNC", ELF::STT_FUNC},
+ {"Section", "SECTION", ELF::STT_SECTION},
+ {"File", "FILE", ELF::STT_FILE},
+ {"Common", "COMMON", ELF::STT_COMMON},
+ {"TLS", "TLS", ELF::STT_TLS},
+ {"Unknown", "<unknown>: 7", 7},
+ {"Unknown", "<unknown>: 8", 8},
+ {"Unknown", "<unknown>: 9", 9},
+ {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC},
+ {"OS Specific", "<OS specific>: 11", 11},
+ {"OS Specific", "<OS specific>: 12", 12},
+ {"Proc Specific", "<processor specific>: 13", 13},
+ {"Proc Specific", "<processor specific>: 14", 14},
+ {"Proc Specific", "<processor specific>: 15", 15}
+};
+
+ELFObjectFileBase::ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source)
+ : ObjectFile(Type, Source) {}
+
+template <class ELFT>
+static Expected<std::unique_ptr<ELFObjectFile<ELFT>>>
createPtr(MemoryBufferRef Object, bool InitContent) {
auto Ret = ELFObjectFile<ELFT>::create(Object, InitContent);
- if (Error E = Ret.takeError())
- return std::move(E);
- return std::make_unique<ELFObjectFile<ELFT>>(std::move(*Ret));
-}
-
-Expected<std::unique_ptr<ObjectFile>>
+ if (Error E = Ret.takeError())
+ return std::move(E);
+ return std::make_unique<ELFObjectFile<ELFT>>(std::move(*Ret));
+}
+
+Expected<std::unique_ptr<ObjectFile>>
ObjectFile::createELFObjectFile(MemoryBufferRef Obj, bool InitContent) {
- std::pair<unsigned char, unsigned char> Ident =
- getElfArchType(Obj.getBuffer());
- std::size_t MaxAlignment =
+ std::pair<unsigned char, unsigned char> Ident =
+ getElfArchType(Obj.getBuffer());
+ std::size_t MaxAlignment =
1ULL << countTrailingZeros(
reinterpret_cast<uintptr_t>(Obj.getBufferStart()));
-
- if (MaxAlignment < 2)
- return createError("Insufficient alignment");
-
- if (Ident.first == ELF::ELFCLASS32) {
- if (Ident.second == ELF::ELFDATA2LSB)
+
+ if (MaxAlignment < 2)
+ return createError("Insufficient alignment");
+
+ if (Ident.first == ELF::ELFCLASS32) {
+ if (Ident.second == ELF::ELFDATA2LSB)
return createPtr<ELF32LE>(Obj, InitContent);
- else if (Ident.second == ELF::ELFDATA2MSB)
+ else if (Ident.second == ELF::ELFDATA2MSB)
return createPtr<ELF32BE>(Obj, InitContent);
- else
- return createError("Invalid ELF data");
- } else if (Ident.first == ELF::ELFCLASS64) {
- if (Ident.second == ELF::ELFDATA2LSB)
+ else
+ return createError("Invalid ELF data");
+ } else if (Ident.first == ELF::ELFCLASS64) {
+ if (Ident.second == ELF::ELFDATA2LSB)
return createPtr<ELF64LE>(Obj, InitContent);
- else if (Ident.second == ELF::ELFDATA2MSB)
+ else if (Ident.second == ELF::ELFDATA2MSB)
return createPtr<ELF64BE>(Obj, InitContent);
- else
- return createError("Invalid ELF data");
- }
- return createError("Invalid ELF class");
-}
-
-SubtargetFeatures ELFObjectFileBase::getMIPSFeatures() const {
- SubtargetFeatures Features;
- unsigned PlatformFlags = getPlatformFlags();
-
- switch (PlatformFlags & ELF::EF_MIPS_ARCH) {
- case ELF::EF_MIPS_ARCH_1:
- break;
- case ELF::EF_MIPS_ARCH_2:
- Features.AddFeature("mips2");
- break;
- case ELF::EF_MIPS_ARCH_3:
- Features.AddFeature("mips3");
- break;
- case ELF::EF_MIPS_ARCH_4:
- Features.AddFeature("mips4");
- break;
- case ELF::EF_MIPS_ARCH_5:
- Features.AddFeature("mips5");
- break;
- case ELF::EF_MIPS_ARCH_32:
- Features.AddFeature("mips32");
- break;
- case ELF::EF_MIPS_ARCH_64:
- Features.AddFeature("mips64");
- break;
- case ELF::EF_MIPS_ARCH_32R2:
- Features.AddFeature("mips32r2");
- break;
- case ELF::EF_MIPS_ARCH_64R2:
- Features.AddFeature("mips64r2");
- break;
- case ELF::EF_MIPS_ARCH_32R6:
- Features.AddFeature("mips32r6");
- break;
- case ELF::EF_MIPS_ARCH_64R6:
- Features.AddFeature("mips64r6");
- break;
- default:
- llvm_unreachable("Unknown EF_MIPS_ARCH value");
- }
-
- switch (PlatformFlags & ELF::EF_MIPS_MACH) {
- case ELF::EF_MIPS_MACH_NONE:
- // No feature associated with this value.
- break;
- case ELF::EF_MIPS_MACH_OCTEON:
- Features.AddFeature("cnmips");
- break;
- default:
- llvm_unreachable("Unknown EF_MIPS_ARCH value");
- }
-
- if (PlatformFlags & ELF::EF_MIPS_ARCH_ASE_M16)
- Features.AddFeature("mips16");
- if (PlatformFlags & ELF::EF_MIPS_MICROMIPS)
- Features.AddFeature("micromips");
-
- return Features;
-}
-
-SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
- SubtargetFeatures Features;
- ARMAttributeParser Attributes;
- if (Error E = getBuildAttributes(Attributes)) {
- consumeError(std::move(E));
- return SubtargetFeatures();
- }
-
- // both ARMv7-M and R have to support thumb hardware div
- bool isV7 = false;
- Optional<unsigned> Attr =
- Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
- if (Attr.hasValue())
- isV7 = Attr.getValue() == ARMBuildAttrs::v7;
-
- Attr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile);
- if (Attr.hasValue()) {
- switch (Attr.getValue()) {
- case ARMBuildAttrs::ApplicationProfile:
- Features.AddFeature("aclass");
- break;
- case ARMBuildAttrs::RealTimeProfile:
- Features.AddFeature("rclass");
- if (isV7)
- Features.AddFeature("hwdiv");
- break;
- case ARMBuildAttrs::MicroControllerProfile:
- Features.AddFeature("mclass");
- if (isV7)
- Features.AddFeature("hwdiv");
- break;
- }
- }
-
- Attr = Attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use);
- if (Attr.hasValue()) {
- switch (Attr.getValue()) {
- default:
- break;
- case ARMBuildAttrs::Not_Allowed:
- Features.AddFeature("thumb", false);
- Features.AddFeature("thumb2", false);
- break;
- case ARMBuildAttrs::AllowThumb32:
- Features.AddFeature("thumb2");
- break;
- }
- }
-
- Attr = Attributes.getAttributeValue(ARMBuildAttrs::FP_arch);
- if (Attr.hasValue()) {
- switch (Attr.getValue()) {
- default:
- break;
- case ARMBuildAttrs::Not_Allowed:
- Features.AddFeature("vfp2sp", false);
- Features.AddFeature("vfp3d16sp", false);
- Features.AddFeature("vfp4d16sp", false);
- break;
- case ARMBuildAttrs::AllowFPv2:
- Features.AddFeature("vfp2");
- break;
- case ARMBuildAttrs::AllowFPv3A:
- case ARMBuildAttrs::AllowFPv3B:
- Features.AddFeature("vfp3");
- break;
- case ARMBuildAttrs::AllowFPv4A:
- case ARMBuildAttrs::AllowFPv4B:
- Features.AddFeature("vfp4");
- break;
- }
- }
-
- Attr = Attributes.getAttributeValue(ARMBuildAttrs::Advanced_SIMD_arch);
- if (Attr.hasValue()) {
- switch (Attr.getValue()) {
- default:
- break;
- case ARMBuildAttrs::Not_Allowed:
- Features.AddFeature("neon", false);
- Features.AddFeature("fp16", false);
- break;
- case ARMBuildAttrs::AllowNeon:
- Features.AddFeature("neon");
- break;
- case ARMBuildAttrs::AllowNeon2:
- Features.AddFeature("neon");
- Features.AddFeature("fp16");
- break;
- }
- }
-
- Attr = Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch);
- if (Attr.hasValue()) {
- switch (Attr.getValue()) {
- default:
- break;
- case ARMBuildAttrs::Not_Allowed:
- Features.AddFeature("mve", false);
- Features.AddFeature("mve.fp", false);
- break;
- case ARMBuildAttrs::AllowMVEInteger:
- Features.AddFeature("mve.fp", false);
- Features.AddFeature("mve");
- break;
- case ARMBuildAttrs::AllowMVEIntegerAndFloat:
- Features.AddFeature("mve.fp");
- break;
- }
- }
-
- Attr = Attributes.getAttributeValue(ARMBuildAttrs::DIV_use);
- if (Attr.hasValue()) {
- switch (Attr.getValue()) {
- default:
- break;
- case ARMBuildAttrs::DisallowDIV:
- Features.AddFeature("hwdiv", false);
- Features.AddFeature("hwdiv-arm", false);
- break;
- case ARMBuildAttrs::AllowDIVExt:
- Features.AddFeature("hwdiv");
- Features.AddFeature("hwdiv-arm");
- break;
- }
- }
-
- return Features;
-}
-
-SubtargetFeatures ELFObjectFileBase::getRISCVFeatures() const {
- SubtargetFeatures Features;
- unsigned PlatformFlags = getPlatformFlags();
-
- if (PlatformFlags & ELF::EF_RISCV_RVC) {
- Features.AddFeature("c");
- }
-
- // Add features according to the ELF attribute section.
- // If there are any unrecognized features, ignore them.
- RISCVAttributeParser Attributes;
- if (Error E = getBuildAttributes(Attributes)) {
- // TODO Propagate Error.
- consumeError(std::move(E));
- return Features; // Keep "c" feature if there is one in PlatformFlags.
- }
-
- Optional<StringRef> Attr = Attributes.getAttributeString(RISCVAttrs::ARCH);
- if (Attr.hasValue()) {
- // The Arch pattern is [rv32|rv64][i|e]version(_[m|a|f|d|c]version)*
- // Version string pattern is (major)p(minor). Major and minor are optional.
- // For example, a version number could be 2p0, 2, or p92.
- StringRef Arch = Attr.getValue();
- if (Arch.consume_front("rv32"))
- Features.AddFeature("64bit", false);
- else if (Arch.consume_front("rv64"))
- Features.AddFeature("64bit");
-
- while (!Arch.empty()) {
- switch (Arch[0]) {
- default:
- break; // Ignore unexpected features.
- case 'i':
- Features.AddFeature("e", false);
- break;
- case 'd':
- Features.AddFeature("f"); // D-ext will imply F-ext.
- LLVM_FALLTHROUGH;
- case 'e':
- case 'm':
- case 'a':
- case 'f':
- case 'c':
- Features.AddFeature(Arch.take_front());
- break;
- }
-
- // FIXME: Handle version numbers.
- Arch = Arch.drop_until([](char c) { return c == '_' || c == '\0'; });
- Arch = Arch.drop_while([](char c) { return c == '_'; });
- }
- }
-
- return Features;
-}
-
-SubtargetFeatures ELFObjectFileBase::getFeatures() const {
- switch (getEMachine()) {
- case ELF::EM_MIPS:
- return getMIPSFeatures();
- case ELF::EM_ARM:
- return getARMFeatures();
- case ELF::EM_RISCV:
- return getRISCVFeatures();
- default:
- return SubtargetFeatures();
- }
-}
-
+ else
+ return createError("Invalid ELF data");
+ }
+ return createError("Invalid ELF class");
+}
+
+SubtargetFeatures ELFObjectFileBase::getMIPSFeatures() const {
+ SubtargetFeatures Features;
+ unsigned PlatformFlags = getPlatformFlags();
+
+ switch (PlatformFlags & ELF::EF_MIPS_ARCH) {
+ case ELF::EF_MIPS_ARCH_1:
+ break;
+ case ELF::EF_MIPS_ARCH_2:
+ Features.AddFeature("mips2");
+ break;
+ case ELF::EF_MIPS_ARCH_3:
+ Features.AddFeature("mips3");
+ break;
+ case ELF::EF_MIPS_ARCH_4:
+ Features.AddFeature("mips4");
+ break;
+ case ELF::EF_MIPS_ARCH_5:
+ Features.AddFeature("mips5");
+ break;
+ case ELF::EF_MIPS_ARCH_32:
+ Features.AddFeature("mips32");
+ break;
+ case ELF::EF_MIPS_ARCH_64:
+ Features.AddFeature("mips64");
+ break;
+ case ELF::EF_MIPS_ARCH_32R2:
+ Features.AddFeature("mips32r2");
+ break;
+ case ELF::EF_MIPS_ARCH_64R2:
+ Features.AddFeature("mips64r2");
+ break;
+ case ELF::EF_MIPS_ARCH_32R6:
+ Features.AddFeature("mips32r6");
+ break;
+ case ELF::EF_MIPS_ARCH_64R6:
+ Features.AddFeature("mips64r6");
+ break;
+ default:
+ llvm_unreachable("Unknown EF_MIPS_ARCH value");
+ }
+
+ switch (PlatformFlags & ELF::EF_MIPS_MACH) {
+ case ELF::EF_MIPS_MACH_NONE:
+ // No feature associated with this value.
+ break;
+ case ELF::EF_MIPS_MACH_OCTEON:
+ Features.AddFeature("cnmips");
+ break;
+ default:
+ llvm_unreachable("Unknown EF_MIPS_ARCH value");
+ }
+
+ if (PlatformFlags & ELF::EF_MIPS_ARCH_ASE_M16)
+ Features.AddFeature("mips16");
+ if (PlatformFlags & ELF::EF_MIPS_MICROMIPS)
+ Features.AddFeature("micromips");
+
+ return Features;
+}
+
+SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
+ SubtargetFeatures Features;
+ ARMAttributeParser Attributes;
+ if (Error E = getBuildAttributes(Attributes)) {
+ consumeError(std::move(E));
+ return SubtargetFeatures();
+ }
+
+ // both ARMv7-M and R have to support thumb hardware div
+ bool isV7 = false;
+ Optional<unsigned> Attr =
+ Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+ if (Attr.hasValue())
+ isV7 = Attr.getValue() == ARMBuildAttrs::v7;
+
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch_profile);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
+ case ARMBuildAttrs::ApplicationProfile:
+ Features.AddFeature("aclass");
+ break;
+ case ARMBuildAttrs::RealTimeProfile:
+ Features.AddFeature("rclass");
+ if (isV7)
+ Features.AddFeature("hwdiv");
+ break;
+ case ARMBuildAttrs::MicroControllerProfile:
+ Features.AddFeature("mclass");
+ if (isV7)
+ Features.AddFeature("hwdiv");
+ break;
+ }
+ }
+
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::THUMB_ISA_use);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
+ default:
+ break;
+ case ARMBuildAttrs::Not_Allowed:
+ Features.AddFeature("thumb", false);
+ Features.AddFeature("thumb2", false);
+ break;
+ case ARMBuildAttrs::AllowThumb32:
+ Features.AddFeature("thumb2");
+ break;
+ }
+ }
+
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::FP_arch);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
+ default:
+ break;
+ case ARMBuildAttrs::Not_Allowed:
+ Features.AddFeature("vfp2sp", false);
+ Features.AddFeature("vfp3d16sp", false);
+ Features.AddFeature("vfp4d16sp", false);
+ break;
+ case ARMBuildAttrs::AllowFPv2:
+ Features.AddFeature("vfp2");
+ break;
+ case ARMBuildAttrs::AllowFPv3A:
+ case ARMBuildAttrs::AllowFPv3B:
+ Features.AddFeature("vfp3");
+ break;
+ case ARMBuildAttrs::AllowFPv4A:
+ case ARMBuildAttrs::AllowFPv4B:
+ Features.AddFeature("vfp4");
+ break;
+ }
+ }
+
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::Advanced_SIMD_arch);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
+ default:
+ break;
+ case ARMBuildAttrs::Not_Allowed:
+ Features.AddFeature("neon", false);
+ Features.AddFeature("fp16", false);
+ break;
+ case ARMBuildAttrs::AllowNeon:
+ Features.AddFeature("neon");
+ break;
+ case ARMBuildAttrs::AllowNeon2:
+ Features.AddFeature("neon");
+ Features.AddFeature("fp16");
+ break;
+ }
+ }
+
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::MVE_arch);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
+ default:
+ break;
+ case ARMBuildAttrs::Not_Allowed:
+ Features.AddFeature("mve", false);
+ Features.AddFeature("mve.fp", false);
+ break;
+ case ARMBuildAttrs::AllowMVEInteger:
+ Features.AddFeature("mve.fp", false);
+ Features.AddFeature("mve");
+ break;
+ case ARMBuildAttrs::AllowMVEIntegerAndFloat:
+ Features.AddFeature("mve.fp");
+ break;
+ }
+ }
+
+ Attr = Attributes.getAttributeValue(ARMBuildAttrs::DIV_use);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
+ default:
+ break;
+ case ARMBuildAttrs::DisallowDIV:
+ Features.AddFeature("hwdiv", false);
+ Features.AddFeature("hwdiv-arm", false);
+ break;
+ case ARMBuildAttrs::AllowDIVExt:
+ Features.AddFeature("hwdiv");
+ Features.AddFeature("hwdiv-arm");
+ break;
+ }
+ }
+
+ return Features;
+}
+
+SubtargetFeatures ELFObjectFileBase::getRISCVFeatures() const {
+ SubtargetFeatures Features;
+ unsigned PlatformFlags = getPlatformFlags();
+
+ if (PlatformFlags & ELF::EF_RISCV_RVC) {
+ Features.AddFeature("c");
+ }
+
+ // Add features according to the ELF attribute section.
+ // If there are any unrecognized features, ignore them.
+ RISCVAttributeParser Attributes;
+ if (Error E = getBuildAttributes(Attributes)) {
+ // TODO Propagate Error.
+ consumeError(std::move(E));
+ return Features; // Keep "c" feature if there is one in PlatformFlags.
+ }
+
+ Optional<StringRef> Attr = Attributes.getAttributeString(RISCVAttrs::ARCH);
+ if (Attr.hasValue()) {
+ // The Arch pattern is [rv32|rv64][i|e]version(_[m|a|f|d|c]version)*
+ // Version string pattern is (major)p(minor). Major and minor are optional.
+ // For example, a version number could be 2p0, 2, or p92.
+ StringRef Arch = Attr.getValue();
+ if (Arch.consume_front("rv32"))
+ Features.AddFeature("64bit", false);
+ else if (Arch.consume_front("rv64"))
+ Features.AddFeature("64bit");
+
+ while (!Arch.empty()) {
+ switch (Arch[0]) {
+ default:
+ break; // Ignore unexpected features.
+ case 'i':
+ Features.AddFeature("e", false);
+ break;
+ case 'd':
+ Features.AddFeature("f"); // D-ext will imply F-ext.
+ LLVM_FALLTHROUGH;
+ case 'e':
+ case 'm':
+ case 'a':
+ case 'f':
+ case 'c':
+ Features.AddFeature(Arch.take_front());
+ break;
+ }
+
+ // FIXME: Handle version numbers.
+ Arch = Arch.drop_until([](char c) { return c == '_' || c == '\0'; });
+ Arch = Arch.drop_while([](char c) { return c == '_'; });
+ }
+ }
+
+ return Features;
+}
+
+SubtargetFeatures ELFObjectFileBase::getFeatures() const {
+ switch (getEMachine()) {
+ case ELF::EM_MIPS:
+ return getMIPSFeatures();
+ case ELF::EM_ARM:
+ return getARMFeatures();
+ case ELF::EM_RISCV:
+ return getRISCVFeatures();
+ default:
+ return SubtargetFeatures();
+ }
+}
+
Optional<StringRef> ELFObjectFileBase::tryGetCPUName() const {
switch (getEMachine()) {
case ELF::EM_AMDGPU:
@@ -480,154 +480,154 @@ StringRef ELFObjectFileBase::getAMDGPUCPUName() const {
}
}
-// FIXME Encode from a tablegen description or target parser.
-void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const {
- if (TheTriple.getSubArch() != Triple::NoSubArch)
- return;
-
- ARMAttributeParser Attributes;
- if (Error E = getBuildAttributes(Attributes)) {
- // TODO Propagate Error.
- consumeError(std::move(E));
- return;
- }
-
- std::string Triple;
- // Default to ARM, but use the triple if it's been set.
- if (TheTriple.isThumb())
- Triple = "thumb";
- else
- Triple = "arm";
-
- Optional<unsigned> Attr =
- Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
- if (Attr.hasValue()) {
- switch (Attr.getValue()) {
- case ARMBuildAttrs::v4:
- Triple += "v4";
- break;
- case ARMBuildAttrs::v4T:
- Triple += "v4t";
- break;
- case ARMBuildAttrs::v5T:
- Triple += "v5t";
- break;
- case ARMBuildAttrs::v5TE:
- Triple += "v5te";
- break;
- case ARMBuildAttrs::v5TEJ:
- Triple += "v5tej";
- break;
- case ARMBuildAttrs::v6:
- Triple += "v6";
- break;
- case ARMBuildAttrs::v6KZ:
- Triple += "v6kz";
- break;
- case ARMBuildAttrs::v6T2:
- Triple += "v6t2";
- break;
- case ARMBuildAttrs::v6K:
- Triple += "v6k";
- break;
- case ARMBuildAttrs::v7:
- Triple += "v7";
- break;
- case ARMBuildAttrs::v6_M:
- Triple += "v6m";
- break;
- case ARMBuildAttrs::v6S_M:
- Triple += "v6sm";
- break;
- case ARMBuildAttrs::v7E_M:
- Triple += "v7em";
- break;
- case ARMBuildAttrs::v8_A:
- Triple += "v8a";
- break;
- case ARMBuildAttrs::v8_R:
- Triple += "v8r";
- break;
- case ARMBuildAttrs::v8_M_Base:
- Triple += "v8m.base";
- break;
- case ARMBuildAttrs::v8_M_Main:
- Triple += "v8m.main";
- break;
- case ARMBuildAttrs::v8_1_M_Main:
- Triple += "v8.1m.main";
- break;
- }
- }
- if (!isLittleEndian())
- Triple += "eb";
-
- TheTriple.setArchName(Triple);
-}
-
+// FIXME Encode from a tablegen description or target parser.
+void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const {
+ if (TheTriple.getSubArch() != Triple::NoSubArch)
+ return;
+
+ ARMAttributeParser Attributes;
+ if (Error E = getBuildAttributes(Attributes)) {
+ // TODO Propagate Error.
+ consumeError(std::move(E));
+ return;
+ }
+
+ std::string Triple;
+ // Default to ARM, but use the triple if it's been set.
+ if (TheTriple.isThumb())
+ Triple = "thumb";
+ else
+ Triple = "arm";
+
+ Optional<unsigned> Attr =
+ Attributes.getAttributeValue(ARMBuildAttrs::CPU_arch);
+ if (Attr.hasValue()) {
+ switch (Attr.getValue()) {
+ case ARMBuildAttrs::v4:
+ Triple += "v4";
+ break;
+ case ARMBuildAttrs::v4T:
+ Triple += "v4t";
+ break;
+ case ARMBuildAttrs::v5T:
+ Triple += "v5t";
+ break;
+ case ARMBuildAttrs::v5TE:
+ Triple += "v5te";
+ break;
+ case ARMBuildAttrs::v5TEJ:
+ Triple += "v5tej";
+ break;
+ case ARMBuildAttrs::v6:
+ Triple += "v6";
+ break;
+ case ARMBuildAttrs::v6KZ:
+ Triple += "v6kz";
+ break;
+ case ARMBuildAttrs::v6T2:
+ Triple += "v6t2";
+ break;
+ case ARMBuildAttrs::v6K:
+ Triple += "v6k";
+ break;
+ case ARMBuildAttrs::v7:
+ Triple += "v7";
+ break;
+ case ARMBuildAttrs::v6_M:
+ Triple += "v6m";
+ break;
+ case ARMBuildAttrs::v6S_M:
+ Triple += "v6sm";
+ break;
+ case ARMBuildAttrs::v7E_M:
+ Triple += "v7em";
+ break;
+ case ARMBuildAttrs::v8_A:
+ Triple += "v8a";
+ break;
+ case ARMBuildAttrs::v8_R:
+ Triple += "v8r";
+ break;
+ case ARMBuildAttrs::v8_M_Base:
+ Triple += "v8m.base";
+ break;
+ case ARMBuildAttrs::v8_M_Main:
+ Triple += "v8m.main";
+ break;
+ case ARMBuildAttrs::v8_1_M_Main:
+ Triple += "v8.1m.main";
+ break;
+ }
+ }
+ if (!isLittleEndian())
+ Triple += "eb";
+
+ TheTriple.setArchName(Triple);
+}
+
std::vector<std::pair<Optional<DataRefImpl>, uint64_t>>
-ELFObjectFileBase::getPltAddresses() const {
- std::string Err;
- const auto Triple = makeTriple();
- const auto *T = TargetRegistry::lookupTarget(Triple.str(), Err);
- if (!T)
- return {};
- uint64_t JumpSlotReloc = 0;
- switch (Triple.getArch()) {
- case Triple::x86:
- JumpSlotReloc = ELF::R_386_JUMP_SLOT;
- break;
- case Triple::x86_64:
- JumpSlotReloc = ELF::R_X86_64_JUMP_SLOT;
- break;
- case Triple::aarch64:
- JumpSlotReloc = ELF::R_AARCH64_JUMP_SLOT;
- break;
- default:
- return {};
- }
- std::unique_ptr<const MCInstrInfo> MII(T->createMCInstrInfo());
- std::unique_ptr<const MCInstrAnalysis> MIA(
- T->createMCInstrAnalysis(MII.get()));
- if (!MIA)
- return {};
- Optional<SectionRef> Plt = None, RelaPlt = None, GotPlt = None;
- for (const SectionRef &Section : sections()) {
- Expected<StringRef> NameOrErr = Section.getName();
- if (!NameOrErr) {
- consumeError(NameOrErr.takeError());
- continue;
- }
- StringRef Name = *NameOrErr;
-
- if (Name == ".plt")
- Plt = Section;
- else if (Name == ".rela.plt" || Name == ".rel.plt")
- RelaPlt = Section;
- else if (Name == ".got.plt")
- GotPlt = Section;
- }
- if (!Plt || !RelaPlt || !GotPlt)
- return {};
- Expected<StringRef> PltContents = Plt->getContents();
- if (!PltContents) {
- consumeError(PltContents.takeError());
- return {};
- }
- auto PltEntries = MIA->findPltEntries(Plt->getAddress(),
- arrayRefFromStringRef(*PltContents),
- GotPlt->getAddress(), Triple);
- // Build a map from GOT entry virtual address to PLT entry virtual address.
- DenseMap<uint64_t, uint64_t> GotToPlt;
- for (const auto &Entry : PltEntries)
- GotToPlt.insert(std::make_pair(Entry.second, Entry.first));
- // Find the relocations in the dynamic relocation table that point to
- // locations in the GOT for which we know the corresponding PLT entry.
+ELFObjectFileBase::getPltAddresses() const {
+ std::string Err;
+ const auto Triple = makeTriple();
+ const auto *T = TargetRegistry::lookupTarget(Triple.str(), Err);
+ if (!T)
+ return {};
+ uint64_t JumpSlotReloc = 0;
+ switch (Triple.getArch()) {
+ case Triple::x86:
+ JumpSlotReloc = ELF::R_386_JUMP_SLOT;
+ break;
+ case Triple::x86_64:
+ JumpSlotReloc = ELF::R_X86_64_JUMP_SLOT;
+ break;
+ case Triple::aarch64:
+ JumpSlotReloc = ELF::R_AARCH64_JUMP_SLOT;
+ break;
+ default:
+ return {};
+ }
+ std::unique_ptr<const MCInstrInfo> MII(T->createMCInstrInfo());
+ std::unique_ptr<const MCInstrAnalysis> MIA(
+ T->createMCInstrAnalysis(MII.get()));
+ if (!MIA)
+ return {};
+ Optional<SectionRef> Plt = None, RelaPlt = None, GotPlt = None;
+ for (const SectionRef &Section : sections()) {
+ Expected<StringRef> NameOrErr = Section.getName();
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
+ continue;
+ }
+ StringRef Name = *NameOrErr;
+
+ if (Name == ".plt")
+ Plt = Section;
+ else if (Name == ".rela.plt" || Name == ".rel.plt")
+ RelaPlt = Section;
+ else if (Name == ".got.plt")
+ GotPlt = Section;
+ }
+ if (!Plt || !RelaPlt || !GotPlt)
+ return {};
+ Expected<StringRef> PltContents = Plt->getContents();
+ if (!PltContents) {
+ consumeError(PltContents.takeError());
+ return {};
+ }
+ auto PltEntries = MIA->findPltEntries(Plt->getAddress(),
+ arrayRefFromStringRef(*PltContents),
+ GotPlt->getAddress(), Triple);
+ // Build a map from GOT entry virtual address to PLT entry virtual address.
+ DenseMap<uint64_t, uint64_t> GotToPlt;
+ for (const auto &Entry : PltEntries)
+ GotToPlt.insert(std::make_pair(Entry.second, Entry.first));
+ // Find the relocations in the dynamic relocation table that point to
+ // locations in the GOT for which we know the corresponding PLT entry.
std::vector<std::pair<Optional<DataRefImpl>, uint64_t>> Result;
- for (const auto &Relocation : RelaPlt->relocations()) {
- if (Relocation.getType() != JumpSlotReloc)
- continue;
- auto PltEntryIter = GotToPlt.find(Relocation.getOffset());
+ for (const auto &Relocation : RelaPlt->relocations()) {
+ if (Relocation.getType() != JumpSlotReloc)
+ continue;
+ auto PltEntryIter = GotToPlt.find(Relocation.getOffset());
if (PltEntryIter != GotToPlt.end()) {
symbol_iterator Sym = Relocation.getSymbol();
if (Sym == symbol_end())
@@ -635,6 +635,6 @@ ELFObjectFileBase::getPltAddresses() const {
else
Result.emplace_back(Sym->getRawDataRefImpl(), PltEntryIter->second);
}
- }
- return Result;
-}
+ }
+ return Result;
+}
diff --git a/contrib/libs/llvm12/lib/Object/Error.cpp b/contrib/libs/llvm12/lib/Object/Error.cpp
index e79d670c86..bc75bc6c04 100644
--- a/contrib/libs/llvm12/lib/Object/Error.cpp
+++ b/contrib/libs/llvm12/lib/Object/Error.cpp
@@ -1,94 +1,94 @@
-//===- Error.cpp - system_error extensions for Object -----------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This defines a new error_category for the Object library.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/Error.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ManagedStatic.h"
-
-using namespace llvm;
-using namespace object;
-
-namespace {
-// FIXME: This class is only here to support the transition to llvm::Error. It
-// will be removed once this transition is complete. Clients should prefer to
-// deal with the Error value directly, rather than converting to error_code.
-class _object_error_category : public std::error_category {
-public:
- const char* name() const noexcept override;
- std::string message(int ev) const override;
-};
-}
-
-const char *_object_error_category::name() const noexcept {
- return "llvm.object";
-}
-
-std::string _object_error_category::message(int EV) const {
- object_error E = static_cast<object_error>(EV);
- switch (E) {
- case object_error::arch_not_found:
- return "No object file for requested architecture";
- case object_error::invalid_file_type:
- return "The file was not recognized as a valid object file";
- case object_error::parse_failed:
- return "Invalid data was encountered while parsing the file";
- case object_error::unexpected_eof:
- return "The end of the file was unexpectedly encountered";
- case object_error::string_table_non_null_end:
- return "String table must end with a null terminator";
- case object_error::invalid_section_index:
- return "Invalid section index";
- case object_error::bitcode_section_not_found:
- return "Bitcode section not found in object file";
- case object_error::invalid_symbol_index:
- return "Invalid symbol index";
- }
- llvm_unreachable("An enumerator of object_error does not have a message "
- "defined.");
-}
-
-void BinaryError::anchor() {}
-char BinaryError::ID = 0;
-char GenericBinaryError::ID = 0;
-
-GenericBinaryError::GenericBinaryError(const Twine &Msg) : Msg(Msg.str()) {}
-
-GenericBinaryError::GenericBinaryError(const Twine &Msg,
- object_error ECOverride)
- : Msg(Msg.str()) {
- setErrorCode(make_error_code(ECOverride));
-}
-
-void GenericBinaryError::log(raw_ostream &OS) const {
- OS << Msg;
-}
-
-static ManagedStatic<_object_error_category> error_category;
-
-const std::error_category &object::object_category() {
- return *error_category;
-}
-
-llvm::Error llvm::object::isNotObjectErrorInvalidFileType(llvm::Error Err) {
- return handleErrors(std::move(Err), [](std::unique_ptr<ECError> M) -> Error {
- // Try to handle 'M'. If successful, return a success value from
- // the handler.
- if (M->convertToErrorCode() == object_error::invalid_file_type)
- return Error::success();
-
- // We failed to handle 'M' - return it from the handler.
- // This value will be passed back from catchErrors and
- // wind up in Err2, where it will be returned from this function.
- return Error(std::move(M));
- });
-}
+//===- Error.cpp - system_error extensions for Object -----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This defines a new error_category for the Object library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Error.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class _object_error_category : public std::error_category {
+public:
+ const char* name() const noexcept override;
+ std::string message(int ev) const override;
+};
+}
+
+const char *_object_error_category::name() const noexcept {
+ return "llvm.object";
+}
+
+std::string _object_error_category::message(int EV) const {
+ object_error E = static_cast<object_error>(EV);
+ switch (E) {
+ case object_error::arch_not_found:
+ return "No object file for requested architecture";
+ case object_error::invalid_file_type:
+ return "The file was not recognized as a valid object file";
+ case object_error::parse_failed:
+ return "Invalid data was encountered while parsing the file";
+ case object_error::unexpected_eof:
+ return "The end of the file was unexpectedly encountered";
+ case object_error::string_table_non_null_end:
+ return "String table must end with a null terminator";
+ case object_error::invalid_section_index:
+ return "Invalid section index";
+ case object_error::bitcode_section_not_found:
+ return "Bitcode section not found in object file";
+ case object_error::invalid_symbol_index:
+ return "Invalid symbol index";
+ }
+ llvm_unreachable("An enumerator of object_error does not have a message "
+ "defined.");
+}
+
+void BinaryError::anchor() {}
+char BinaryError::ID = 0;
+char GenericBinaryError::ID = 0;
+
+GenericBinaryError::GenericBinaryError(const Twine &Msg) : Msg(Msg.str()) {}
+
+GenericBinaryError::GenericBinaryError(const Twine &Msg,
+ object_error ECOverride)
+ : Msg(Msg.str()) {
+ setErrorCode(make_error_code(ECOverride));
+}
+
+void GenericBinaryError::log(raw_ostream &OS) const {
+ OS << Msg;
+}
+
+static ManagedStatic<_object_error_category> error_category;
+
+const std::error_category &object::object_category() {
+ return *error_category;
+}
+
+llvm::Error llvm::object::isNotObjectErrorInvalidFileType(llvm::Error Err) {
+ return handleErrors(std::move(Err), [](std::unique_ptr<ECError> M) -> Error {
+ // Try to handle 'M'. If successful, return a success value from
+ // the handler.
+ if (M->convertToErrorCode() == object_error::invalid_file_type)
+ return Error::success();
+
+ // We failed to handle 'M' - return it from the handler.
+ // This value will be passed back from catchErrors and
+ // wind up in Err2, where it will be returned from this function.
+ return Error(std::move(M));
+ });
+}
diff --git a/contrib/libs/llvm12/lib/Object/IRObjectFile.cpp b/contrib/libs/llvm12/lib/Object/IRObjectFile.cpp
index e183cc6db5..befba5d571 100644
--- a/contrib/libs/llvm12/lib/Object/IRObjectFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/IRObjectFile.cpp
@@ -1,156 +1,156 @@
-//===- IRObjectFile.cpp - IR object file implementation ---------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Part of the IRObjectFile class implementation.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/IRObjectFile.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/BinaryFormat/Magic.h"
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/IR/GVMaterializer.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/IR/Mangler.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/raw_ostream.h"
-using namespace llvm;
-using namespace object;
-
-IRObjectFile::IRObjectFile(MemoryBufferRef Object,
- std::vector<std::unique_ptr<Module>> Mods)
- : SymbolicFile(Binary::ID_IR, Object), Mods(std::move(Mods)) {
- for (auto &M : this->Mods)
- SymTab.addModule(M.get());
-}
-
-IRObjectFile::~IRObjectFile() {}
-
-static ModuleSymbolTable::Symbol getSym(DataRefImpl &Symb) {
- return *reinterpret_cast<ModuleSymbolTable::Symbol *>(Symb.p);
-}
-
-void IRObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
- Symb.p += sizeof(ModuleSymbolTable::Symbol);
-}
-
-Error IRObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {
- SymTab.printSymbolName(OS, getSym(Symb));
- return Error::success();
-}
-
-Expected<uint32_t> IRObjectFile::getSymbolFlags(DataRefImpl Symb) const {
- return SymTab.getSymbolFlags(getSym(Symb));
-}
-
-basic_symbol_iterator IRObjectFile::symbol_begin() const {
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(SymTab.symbols().data());
- return basic_symbol_iterator(BasicSymbolRef(Ret, this));
-}
-
-basic_symbol_iterator IRObjectFile::symbol_end() const {
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(SymTab.symbols().data() +
- SymTab.symbols().size());
- return basic_symbol_iterator(BasicSymbolRef(Ret, this));
-}
-
-StringRef IRObjectFile::getTargetTriple() const {
- // Each module must have the same target triple, so we arbitrarily access the
- // first one.
- return Mods[0]->getTargetTriple();
-}
-
-Expected<MemoryBufferRef>
-IRObjectFile::findBitcodeInObject(const ObjectFile &Obj) {
- for (const SectionRef &Sec : Obj.sections()) {
- if (Sec.isBitcode()) {
- Expected<StringRef> Contents = Sec.getContents();
- if (!Contents)
- return Contents.takeError();
- if (Contents->size() <= 1)
- return errorCodeToError(object_error::bitcode_section_not_found);
- return MemoryBufferRef(*Contents, Obj.getFileName());
- }
- }
-
- return errorCodeToError(object_error::bitcode_section_not_found);
-}
-
-Expected<MemoryBufferRef>
-IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) {
- file_magic Type = identify_magic(Object.getBuffer());
- switch (Type) {
- case file_magic::bitcode:
- return Object;
- case file_magic::elf_relocatable:
- case file_magic::macho_object:
- case file_magic::wasm_object:
- case file_magic::coff_object: {
- Expected<std::unique_ptr<ObjectFile>> ObjFile =
- ObjectFile::createObjectFile(Object, Type);
- if (!ObjFile)
- return ObjFile.takeError();
- return findBitcodeInObject(*ObjFile->get());
- }
- default:
- return errorCodeToError(object_error::invalid_file_type);
- }
-}
-
-Expected<std::unique_ptr<IRObjectFile>>
-IRObjectFile::create(MemoryBufferRef Object, LLVMContext &Context) {
- Expected<MemoryBufferRef> BCOrErr = findBitcodeInMemBuffer(Object);
- if (!BCOrErr)
- return BCOrErr.takeError();
-
- Expected<std::vector<BitcodeModule>> BMsOrErr =
- getBitcodeModuleList(*BCOrErr);
- if (!BMsOrErr)
- return BMsOrErr.takeError();
-
- std::vector<std::unique_ptr<Module>> Mods;
- for (auto BM : *BMsOrErr) {
- Expected<std::unique_ptr<Module>> MOrErr =
- BM.getLazyModule(Context, /*ShouldLazyLoadMetadata*/ true,
- /*IsImporting*/ false);
- if (!MOrErr)
- return MOrErr.takeError();
-
- Mods.push_back(std::move(*MOrErr));
- }
-
- return std::unique_ptr<IRObjectFile>(
- new IRObjectFile(*BCOrErr, std::move(Mods)));
-}
-
-Expected<IRSymtabFile> object::readIRSymtab(MemoryBufferRef MBRef) {
- IRSymtabFile F;
- Expected<MemoryBufferRef> BCOrErr =
- IRObjectFile::findBitcodeInMemBuffer(MBRef);
- if (!BCOrErr)
- return BCOrErr.takeError();
-
- Expected<BitcodeFileContents> BFCOrErr = getBitcodeFileContents(*BCOrErr);
- if (!BFCOrErr)
- return BFCOrErr.takeError();
-
- Expected<irsymtab::FileContents> FCOrErr = irsymtab::readBitcode(*BFCOrErr);
- if (!FCOrErr)
- return FCOrErr.takeError();
-
- F.Mods = std::move(BFCOrErr->Mods);
- F.Symtab = std::move(FCOrErr->Symtab);
- F.Strtab = std::move(FCOrErr->Strtab);
- F.TheReader = std::move(FCOrErr->TheReader);
- return std::move(F);
-}
+//===- IRObjectFile.cpp - IR object file implementation ---------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Part of the IRObjectFile class implementation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/IR/GVMaterializer.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+using namespace object;
+
+IRObjectFile::IRObjectFile(MemoryBufferRef Object,
+ std::vector<std::unique_ptr<Module>> Mods)
+ : SymbolicFile(Binary::ID_IR, Object), Mods(std::move(Mods)) {
+ for (auto &M : this->Mods)
+ SymTab.addModule(M.get());
+}
+
+IRObjectFile::~IRObjectFile() {}
+
+static ModuleSymbolTable::Symbol getSym(DataRefImpl &Symb) {
+ return *reinterpret_cast<ModuleSymbolTable::Symbol *>(Symb.p);
+}
+
+void IRObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
+ Symb.p += sizeof(ModuleSymbolTable::Symbol);
+}
+
+Error IRObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {
+ SymTab.printSymbolName(OS, getSym(Symb));
+ return Error::success();
+}
+
+Expected<uint32_t> IRObjectFile::getSymbolFlags(DataRefImpl Symb) const {
+ return SymTab.getSymbolFlags(getSym(Symb));
+}
+
+basic_symbol_iterator IRObjectFile::symbol_begin() const {
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(SymTab.symbols().data());
+ return basic_symbol_iterator(BasicSymbolRef(Ret, this));
+}
+
+basic_symbol_iterator IRObjectFile::symbol_end() const {
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(SymTab.symbols().data() +
+ SymTab.symbols().size());
+ return basic_symbol_iterator(BasicSymbolRef(Ret, this));
+}
+
+StringRef IRObjectFile::getTargetTriple() const {
+ // Each module must have the same target triple, so we arbitrarily access the
+ // first one.
+ return Mods[0]->getTargetTriple();
+}
+
+Expected<MemoryBufferRef>
+IRObjectFile::findBitcodeInObject(const ObjectFile &Obj) {
+ for (const SectionRef &Sec : Obj.sections()) {
+ if (Sec.isBitcode()) {
+ Expected<StringRef> Contents = Sec.getContents();
+ if (!Contents)
+ return Contents.takeError();
+ if (Contents->size() <= 1)
+ return errorCodeToError(object_error::bitcode_section_not_found);
+ return MemoryBufferRef(*Contents, Obj.getFileName());
+ }
+ }
+
+ return errorCodeToError(object_error::bitcode_section_not_found);
+}
+
+Expected<MemoryBufferRef>
+IRObjectFile::findBitcodeInMemBuffer(MemoryBufferRef Object) {
+ file_magic Type = identify_magic(Object.getBuffer());
+ switch (Type) {
+ case file_magic::bitcode:
+ return Object;
+ case file_magic::elf_relocatable:
+ case file_magic::macho_object:
+ case file_magic::wasm_object:
+ case file_magic::coff_object: {
+ Expected<std::unique_ptr<ObjectFile>> ObjFile =
+ ObjectFile::createObjectFile(Object, Type);
+ if (!ObjFile)
+ return ObjFile.takeError();
+ return findBitcodeInObject(*ObjFile->get());
+ }
+ default:
+ return errorCodeToError(object_error::invalid_file_type);
+ }
+}
+
+Expected<std::unique_ptr<IRObjectFile>>
+IRObjectFile::create(MemoryBufferRef Object, LLVMContext &Context) {
+ Expected<MemoryBufferRef> BCOrErr = findBitcodeInMemBuffer(Object);
+ if (!BCOrErr)
+ return BCOrErr.takeError();
+
+ Expected<std::vector<BitcodeModule>> BMsOrErr =
+ getBitcodeModuleList(*BCOrErr);
+ if (!BMsOrErr)
+ return BMsOrErr.takeError();
+
+ std::vector<std::unique_ptr<Module>> Mods;
+ for (auto BM : *BMsOrErr) {
+ Expected<std::unique_ptr<Module>> MOrErr =
+ BM.getLazyModule(Context, /*ShouldLazyLoadMetadata*/ true,
+ /*IsImporting*/ false);
+ if (!MOrErr)
+ return MOrErr.takeError();
+
+ Mods.push_back(std::move(*MOrErr));
+ }
+
+ return std::unique_ptr<IRObjectFile>(
+ new IRObjectFile(*BCOrErr, std::move(Mods)));
+}
+
+Expected<IRSymtabFile> object::readIRSymtab(MemoryBufferRef MBRef) {
+ IRSymtabFile F;
+ Expected<MemoryBufferRef> BCOrErr =
+ IRObjectFile::findBitcodeInMemBuffer(MBRef);
+ if (!BCOrErr)
+ return BCOrErr.takeError();
+
+ Expected<BitcodeFileContents> BFCOrErr = getBitcodeFileContents(*BCOrErr);
+ if (!BFCOrErr)
+ return BFCOrErr.takeError();
+
+ Expected<irsymtab::FileContents> FCOrErr = irsymtab::readBitcode(*BFCOrErr);
+ if (!FCOrErr)
+ return FCOrErr.takeError();
+
+ F.Mods = std::move(BFCOrErr->Mods);
+ F.Symtab = std::move(FCOrErr->Symtab);
+ F.Strtab = std::move(FCOrErr->Strtab);
+ F.TheReader = std::move(FCOrErr->TheReader);
+ return std::move(F);
+}
diff --git a/contrib/libs/llvm12/lib/Object/IRSymtab.cpp b/contrib/libs/llvm12/lib/Object/IRSymtab.cpp
index 148437c478..e39cb732ad 100644
--- a/contrib/libs/llvm12/lib/Object/IRSymtab.cpp
+++ b/contrib/libs/llvm12/lib/Object/IRSymtab.cpp
@@ -1,413 +1,413 @@
-//===- IRSymtab.cpp - implementation of IR symbol tables ------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/IRSymtab.h"
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/Config/llvm-config.h"
-#include "llvm/IR/Comdat.h"
-#include "llvm/IR/DataLayout.h"
-#include "llvm/IR/GlobalAlias.h"
-#include "llvm/IR/GlobalObject.h"
-#include "llvm/IR/Mangler.h"
-#include "llvm/IR/Metadata.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Bitcode/BitcodeReader.h"
-#include "llvm/MC/StringTableBuilder.h"
-#include "llvm/Object/IRObjectFile.h"
-#include "llvm/Object/ModuleSymbolTable.h"
-#include "llvm/Object/SymbolicFile.h"
-#include "llvm/Support/Allocator.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/StringSaver.h"
-#include "llvm/Support/VCSRevision.h"
-#include "llvm/Support/raw_ostream.h"
-#include <cassert>
-#include <string>
-#include <utility>
-#include <vector>
-
-using namespace llvm;
-using namespace irsymtab;
-
-static const char *LibcallRoutineNames[] = {
-#define HANDLE_LIBCALL(code, name) name,
-#include "llvm/IR/RuntimeLibcalls.def"
-#undef HANDLE_LIBCALL
-};
-
-namespace {
-
-const char *getExpectedProducerName() {
- static char DefaultName[] = LLVM_VERSION_STRING
-#ifdef LLVM_REVISION
- " " LLVM_REVISION
-#endif
- ;
- // Allows for testing of the irsymtab writer and upgrade mechanism. This
- // environment variable should not be set by users.
- if (char *OverrideName = getenv("LLVM_OVERRIDE_PRODUCER"))
- return OverrideName;
- return DefaultName;
-}
-
-const char *kExpectedProducerName = getExpectedProducerName();
-
-/// Stores the temporary state that is required to build an IR symbol table.
-struct Builder {
- SmallVector<char, 0> &Symtab;
- StringTableBuilder &StrtabBuilder;
- StringSaver Saver;
-
- // This ctor initializes a StringSaver using the passed in BumpPtrAllocator.
- // The StringTableBuilder does not create a copy of any strings added to it,
- // so this provides somewhere to store any strings that we create.
- Builder(SmallVector<char, 0> &Symtab, StringTableBuilder &StrtabBuilder,
- BumpPtrAllocator &Alloc)
- : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc) {}
-
- DenseMap<const Comdat *, int> ComdatMap;
- Mangler Mang;
- Triple TT;
-
- std::vector<storage::Comdat> Comdats;
- std::vector<storage::Module> Mods;
- std::vector<storage::Symbol> Syms;
- std::vector<storage::Uncommon> Uncommons;
-
- std::string COFFLinkerOpts;
- raw_string_ostream COFFLinkerOptsOS{COFFLinkerOpts};
-
- std::vector<storage::Str> DependentLibraries;
-
- void setStr(storage::Str &S, StringRef Value) {
- S.Offset = StrtabBuilder.add(Value);
- S.Size = Value.size();
- }
-
- template <typename T>
- void writeRange(storage::Range<T> &R, const std::vector<T> &Objs) {
- R.Offset = Symtab.size();
- R.Size = Objs.size();
- Symtab.insert(Symtab.end(), reinterpret_cast<const char *>(Objs.data()),
- 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,
- ModuleSymbolTable::Symbol Sym);
-
- Error build(ArrayRef<Module *> Mods);
-};
-
-Error Builder::addModule(Module *M) {
- if (M->getDataLayoutStr().empty())
- return make_error<StringError>("input module has no datalayout",
- inconvertibleErrorCode());
-
- SmallPtrSet<GlobalValue *, 8> Used;
- collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false);
-
- ModuleSymbolTable Msymtab;
- Msymtab.addModule(M);
-
- storage::Module Mod;
- Mod.Begin = Syms.size();
- Mod.End = Syms.size() + Msymtab.symbols().size();
- Mod.UncBegin = Uncommons.size();
- Mods.push_back(Mod);
-
- if (TT.isOSBinFormatCOFF()) {
- if (auto E = M->materializeMetadata())
- return E;
- if (NamedMDNode *LinkerOptions =
- M->getNamedMetadata("llvm.linker.options")) {
- for (MDNode *MDOptions : LinkerOptions->operands())
- for (const MDOperand &MDOption : cast<MDNode>(MDOptions)->operands())
- COFFLinkerOptsOS << " " << cast<MDString>(MDOption)->getString();
- }
- }
-
- if (TT.isOSBinFormatELF()) {
- if (auto E = M->materializeMetadata())
- return E;
- if (NamedMDNode *N = M->getNamedMetadata("llvm.dependent-libraries")) {
- for (MDNode *MDOptions : N->operands()) {
- const auto OperandStr =
- cast<MDString>(cast<MDNode>(MDOptions)->getOperand(0))->getString();
- storage::Str Specifier;
- setStr(Specifier, OperandStr);
- DependentLibraries.emplace_back(Specifier);
- }
- }
- }
-
- for (ModuleSymbolTable::Symbol Msym : Msymtab.symbols())
- if (Error Err = addSymbol(Msymtab, Used, Msym))
- return Err;
-
- 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 = std::string(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) {
- Syms.emplace_back();
- storage::Symbol &Sym = Syms.back();
- Sym = {};
-
- storage::Uncommon *Unc = nullptr;
- auto Uncommon = [&]() -> storage::Uncommon & {
- if (Unc)
- return *Unc;
- Sym.Flags |= 1 << storage::Symbol::FB_has_uncommon;
- Uncommons.emplace_back();
- Unc = &Uncommons.back();
- *Unc = {};
- setStr(Unc->COFFWeakExternFallbackName, "");
- setStr(Unc->SectionName, "");
- return *Unc;
- };
-
- SmallString<64> Name;
- {
- raw_svector_ostream OS(Name);
- Msymtab.printSymbolName(OS, Msym);
- }
- setStr(Sym.Name, Saver.save(StringRef(Name)));
-
- auto Flags = Msymtab.getSymbolFlags(Msym);
- if (Flags & object::BasicSymbolRef::SF_Undefined)
- Sym.Flags |= 1 << storage::Symbol::FB_undefined;
- if (Flags & object::BasicSymbolRef::SF_Weak)
- Sym.Flags |= 1 << storage::Symbol::FB_weak;
- if (Flags & object::BasicSymbolRef::SF_Common)
- Sym.Flags |= 1 << storage::Symbol::FB_common;
- if (Flags & object::BasicSymbolRef::SF_Indirect)
- Sym.Flags |= 1 << storage::Symbol::FB_indirect;
- if (Flags & object::BasicSymbolRef::SF_Global)
- Sym.Flags |= 1 << storage::Symbol::FB_global;
- if (Flags & object::BasicSymbolRef::SF_FormatSpecific)
- Sym.Flags |= 1 << storage::Symbol::FB_format_specific;
- if (Flags & object::BasicSymbolRef::SF_Executable)
- Sym.Flags |= 1 << storage::Symbol::FB_executable;
-
- Sym.ComdatIndex = -1;
- auto *GV = Msym.dyn_cast<GlobalValue *>();
- if (!GV) {
- // Undefined module asm symbols act as GC roots and are implicitly used.
- if (Flags & object::BasicSymbolRef::SF_Undefined)
- Sym.Flags |= 1 << storage::Symbol::FB_used;
- setStr(Sym.IRName, "");
- return Error::success();
- }
-
- setStr(Sym.IRName, GV->getName());
-
- bool IsBuiltinFunc = false;
-
- for (const char *LibcallName : LibcallRoutineNames)
- if (GV->getName() == LibcallName)
- IsBuiltinFunc = true;
-
- if (Used.count(GV) || IsBuiltinFunc)
- Sym.Flags |= 1 << storage::Symbol::FB_used;
- if (GV->isThreadLocal())
- Sym.Flags |= 1 << storage::Symbol::FB_tls;
- if (GV->hasGlobalUnnamedAddr())
- Sym.Flags |= 1 << storage::Symbol::FB_unnamed_addr;
- if (GV->canBeOmittedFromSymbolTable())
- Sym.Flags |= 1 << storage::Symbol::FB_may_omit;
- Sym.Flags |= unsigned(GV->getVisibility()) << storage::Symbol::FB_visibility;
-
- if (Flags & object::BasicSymbolRef::SF_Common) {
- auto *GVar = dyn_cast<GlobalVariable>(GV);
- if (!GVar)
- return make_error<StringError>("Only variables can have common linkage!",
- inconvertibleErrorCode());
- Uncommon().CommonSize = GV->getParent()->getDataLayout().getTypeAllocSize(
- GV->getType()->getElementType());
- Uncommon().CommonAlign = GVar->getAlignment();
- }
-
- const GlobalObject *Base = GV->getBaseObject();
- if (!Base)
- return make_error<StringError>("Unable to determine comdat of alias!",
- inconvertibleErrorCode());
- if (const Comdat *C = Base->getComdat()) {
- Expected<int> ComdatIndexOrErr = getComdatIndex(C, GV->getParent());
- if (!ComdatIndexOrErr)
- return ComdatIndexOrErr.takeError();
- Sym.ComdatIndex = *ComdatIndexOrErr;
- }
-
- if (TT.isOSBinFormatCOFF()) {
- emitLinkerFlagsForGlobalCOFF(COFFLinkerOptsOS, GV, TT, Mang);
-
- 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, Fallback);
- OS.flush();
- setStr(Uncommon().COFFWeakExternFallbackName, Saver.save(FallbackName));
- }
- }
-
- if (!Base->getSection().empty())
- setStr(Uncommon().SectionName, Saver.save(Base->getSection()));
-
- return Error::success();
-}
-
-Error Builder::build(ArrayRef<Module *> IRMods) {
- storage::Header Hdr;
-
- assert(!IRMods.empty());
- Hdr.Version = storage::Header::kCurrentVersion;
- setStr(Hdr.Producer, kExpectedProducerName);
- setStr(Hdr.TargetTriple, IRMods[0]->getTargetTriple());
- setStr(Hdr.SourceFileName, IRMods[0]->getSourceFileName());
- TT = Triple(IRMods[0]->getTargetTriple());
-
- for (auto *M : IRMods)
- if (Error Err = addModule(M))
- return Err;
-
- COFFLinkerOptsOS.flush();
- setStr(Hdr.COFFLinkerOpts, Saver.save(COFFLinkerOpts));
-
- // We are about to fill in the header's range fields, so reserve space for it
- // and copy it in afterwards.
- Symtab.resize(sizeof(storage::Header));
- writeRange(Hdr.Modules, Mods);
- writeRange(Hdr.Comdats, Comdats);
- writeRange(Hdr.Symbols, Syms);
- writeRange(Hdr.Uncommons, Uncommons);
- writeRange(Hdr.DependentLibraries, DependentLibraries);
- *reinterpret_cast<storage::Header *>(Symtab.data()) = Hdr;
- return Error::success();
-}
-
-} // end anonymous namespace
-
-Error irsymtab::build(ArrayRef<Module *> Mods, SmallVector<char, 0> &Symtab,
- StringTableBuilder &StrtabBuilder,
- BumpPtrAllocator &Alloc) {
- return Builder(Symtab, StrtabBuilder, Alloc).build(Mods);
-}
-
-// Upgrade a vector of bitcode modules created by an old version of LLVM by
-// creating an irsymtab for them in the current format.
-static Expected<FileContents> upgrade(ArrayRef<BitcodeModule> BMs) {
- FileContents FC;
-
- LLVMContext Ctx;
- std::vector<Module *> Mods;
- std::vector<std::unique_ptr<Module>> OwnedMods;
- for (auto BM : BMs) {
- Expected<std::unique_ptr<Module>> MOrErr =
- BM.getLazyModule(Ctx, /*ShouldLazyLoadMetadata*/ true,
- /*IsImporting*/ false);
- if (!MOrErr)
- return MOrErr.takeError();
-
- Mods.push_back(MOrErr->get());
- OwnedMods.push_back(std::move(*MOrErr));
- }
-
- StringTableBuilder StrtabBuilder(StringTableBuilder::RAW);
- BumpPtrAllocator Alloc;
- if (Error E = build(Mods, FC.Symtab, StrtabBuilder, Alloc))
- return std::move(E);
-
- StrtabBuilder.finalizeInOrder();
- FC.Strtab.resize(StrtabBuilder.getSize());
- StrtabBuilder.write((uint8_t *)FC.Strtab.data());
-
- FC.TheReader = {{FC.Symtab.data(), FC.Symtab.size()},
- {FC.Strtab.data(), FC.Strtab.size()}};
- return std::move(FC);
-}
-
-Expected<FileContents> irsymtab::readBitcode(const BitcodeFileContents &BFC) {
- if (BFC.Mods.empty())
- return make_error<StringError>("Bitcode file does not contain any modules",
- inconvertibleErrorCode());
-
- if (BFC.StrtabForSymtab.empty() ||
- BFC.Symtab.size() < sizeof(storage::Header))
- return upgrade(BFC.Mods);
-
- // We cannot use the regular reader to read the version and producer, because
- // it will expect the header to be in the current format. The only thing we
- // can rely on is that the version and producer will be present as the first
- // struct elements.
- auto *Hdr = reinterpret_cast<const storage::Header *>(BFC.Symtab.data());
- unsigned Version = Hdr->Version;
- StringRef Producer = Hdr->Producer.get(BFC.StrtabForSymtab);
- if (Version != storage::Header::kCurrentVersion ||
- Producer != kExpectedProducerName)
- return upgrade(BFC.Mods);
-
- FileContents FC;
- FC.TheReader = {{BFC.Symtab.data(), BFC.Symtab.size()},
- {BFC.StrtabForSymtab.data(), BFC.StrtabForSymtab.size()}};
-
- // Finally, make sure that the number of modules in the symbol table matches
- // the number of modules in the bitcode file. If they differ, it may mean that
- // the bitcode file was created by binary concatenation, so we need to create
- // a new symbol table from scratch.
- if (FC.TheReader.getNumModules() != BFC.Mods.size())
- return upgrade(std::move(BFC.Mods));
-
- return std::move(FC);
-}
+//===- IRSymtab.cpp - implementation of IR symbol tables ------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/IRSymtab.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/Comdat.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalAlias.h"
+#include "llvm/IR/GlobalObject.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Bitcode/BitcodeReader.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Object/ModuleSymbolTable.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/StringSaver.h"
+#include "llvm/Support/VCSRevision.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace irsymtab;
+
+static const char *LibcallRoutineNames[] = {
+#define HANDLE_LIBCALL(code, name) name,
+#include "llvm/IR/RuntimeLibcalls.def"
+#undef HANDLE_LIBCALL
+};
+
+namespace {
+
+const char *getExpectedProducerName() {
+ static char DefaultName[] = LLVM_VERSION_STRING
+#ifdef LLVM_REVISION
+ " " LLVM_REVISION
+#endif
+ ;
+ // Allows for testing of the irsymtab writer and upgrade mechanism. This
+ // environment variable should not be set by users.
+ if (char *OverrideName = getenv("LLVM_OVERRIDE_PRODUCER"))
+ return OverrideName;
+ return DefaultName;
+}
+
+const char *kExpectedProducerName = getExpectedProducerName();
+
+/// Stores the temporary state that is required to build an IR symbol table.
+struct Builder {
+ SmallVector<char, 0> &Symtab;
+ StringTableBuilder &StrtabBuilder;
+ StringSaver Saver;
+
+ // This ctor initializes a StringSaver using the passed in BumpPtrAllocator.
+ // The StringTableBuilder does not create a copy of any strings added to it,
+ // so this provides somewhere to store any strings that we create.
+ Builder(SmallVector<char, 0> &Symtab, StringTableBuilder &StrtabBuilder,
+ BumpPtrAllocator &Alloc)
+ : Symtab(Symtab), StrtabBuilder(StrtabBuilder), Saver(Alloc) {}
+
+ DenseMap<const Comdat *, int> ComdatMap;
+ Mangler Mang;
+ Triple TT;
+
+ std::vector<storage::Comdat> Comdats;
+ std::vector<storage::Module> Mods;
+ std::vector<storage::Symbol> Syms;
+ std::vector<storage::Uncommon> Uncommons;
+
+ std::string COFFLinkerOpts;
+ raw_string_ostream COFFLinkerOptsOS{COFFLinkerOpts};
+
+ std::vector<storage::Str> DependentLibraries;
+
+ void setStr(storage::Str &S, StringRef Value) {
+ S.Offset = StrtabBuilder.add(Value);
+ S.Size = Value.size();
+ }
+
+ template <typename T>
+ void writeRange(storage::Range<T> &R, const std::vector<T> &Objs) {
+ R.Offset = Symtab.size();
+ R.Size = Objs.size();
+ Symtab.insert(Symtab.end(), reinterpret_cast<const char *>(Objs.data()),
+ 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,
+ ModuleSymbolTable::Symbol Sym);
+
+ Error build(ArrayRef<Module *> Mods);
+};
+
+Error Builder::addModule(Module *M) {
+ if (M->getDataLayoutStr().empty())
+ return make_error<StringError>("input module has no datalayout",
+ inconvertibleErrorCode());
+
+ SmallPtrSet<GlobalValue *, 8> Used;
+ collectUsedGlobalVariables(*M, Used, /*CompilerUsed*/ false);
+
+ ModuleSymbolTable Msymtab;
+ Msymtab.addModule(M);
+
+ storage::Module Mod;
+ Mod.Begin = Syms.size();
+ Mod.End = Syms.size() + Msymtab.symbols().size();
+ Mod.UncBegin = Uncommons.size();
+ Mods.push_back(Mod);
+
+ if (TT.isOSBinFormatCOFF()) {
+ if (auto E = M->materializeMetadata())
+ return E;
+ if (NamedMDNode *LinkerOptions =
+ M->getNamedMetadata("llvm.linker.options")) {
+ for (MDNode *MDOptions : LinkerOptions->operands())
+ for (const MDOperand &MDOption : cast<MDNode>(MDOptions)->operands())
+ COFFLinkerOptsOS << " " << cast<MDString>(MDOption)->getString();
+ }
+ }
+
+ if (TT.isOSBinFormatELF()) {
+ if (auto E = M->materializeMetadata())
+ return E;
+ if (NamedMDNode *N = M->getNamedMetadata("llvm.dependent-libraries")) {
+ for (MDNode *MDOptions : N->operands()) {
+ const auto OperandStr =
+ cast<MDString>(cast<MDNode>(MDOptions)->getOperand(0))->getString();
+ storage::Str Specifier;
+ setStr(Specifier, OperandStr);
+ DependentLibraries.emplace_back(Specifier);
+ }
+ }
+ }
+
+ for (ModuleSymbolTable::Symbol Msym : Msymtab.symbols())
+ if (Error Err = addSymbol(Msymtab, Used, Msym))
+ return Err;
+
+ 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 = std::string(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) {
+ Syms.emplace_back();
+ storage::Symbol &Sym = Syms.back();
+ Sym = {};
+
+ storage::Uncommon *Unc = nullptr;
+ auto Uncommon = [&]() -> storage::Uncommon & {
+ if (Unc)
+ return *Unc;
+ Sym.Flags |= 1 << storage::Symbol::FB_has_uncommon;
+ Uncommons.emplace_back();
+ Unc = &Uncommons.back();
+ *Unc = {};
+ setStr(Unc->COFFWeakExternFallbackName, "");
+ setStr(Unc->SectionName, "");
+ return *Unc;
+ };
+
+ SmallString<64> Name;
+ {
+ raw_svector_ostream OS(Name);
+ Msymtab.printSymbolName(OS, Msym);
+ }
+ setStr(Sym.Name, Saver.save(StringRef(Name)));
+
+ auto Flags = Msymtab.getSymbolFlags(Msym);
+ if (Flags & object::BasicSymbolRef::SF_Undefined)
+ Sym.Flags |= 1 << storage::Symbol::FB_undefined;
+ if (Flags & object::BasicSymbolRef::SF_Weak)
+ Sym.Flags |= 1 << storage::Symbol::FB_weak;
+ if (Flags & object::BasicSymbolRef::SF_Common)
+ Sym.Flags |= 1 << storage::Symbol::FB_common;
+ if (Flags & object::BasicSymbolRef::SF_Indirect)
+ Sym.Flags |= 1 << storage::Symbol::FB_indirect;
+ if (Flags & object::BasicSymbolRef::SF_Global)
+ Sym.Flags |= 1 << storage::Symbol::FB_global;
+ if (Flags & object::BasicSymbolRef::SF_FormatSpecific)
+ Sym.Flags |= 1 << storage::Symbol::FB_format_specific;
+ if (Flags & object::BasicSymbolRef::SF_Executable)
+ Sym.Flags |= 1 << storage::Symbol::FB_executable;
+
+ Sym.ComdatIndex = -1;
+ auto *GV = Msym.dyn_cast<GlobalValue *>();
+ if (!GV) {
+ // Undefined module asm symbols act as GC roots and are implicitly used.
+ if (Flags & object::BasicSymbolRef::SF_Undefined)
+ Sym.Flags |= 1 << storage::Symbol::FB_used;
+ setStr(Sym.IRName, "");
+ return Error::success();
+ }
+
+ setStr(Sym.IRName, GV->getName());
+
+ bool IsBuiltinFunc = false;
+
+ for (const char *LibcallName : LibcallRoutineNames)
+ if (GV->getName() == LibcallName)
+ IsBuiltinFunc = true;
+
+ if (Used.count(GV) || IsBuiltinFunc)
+ Sym.Flags |= 1 << storage::Symbol::FB_used;
+ if (GV->isThreadLocal())
+ Sym.Flags |= 1 << storage::Symbol::FB_tls;
+ if (GV->hasGlobalUnnamedAddr())
+ Sym.Flags |= 1 << storage::Symbol::FB_unnamed_addr;
+ if (GV->canBeOmittedFromSymbolTable())
+ Sym.Flags |= 1 << storage::Symbol::FB_may_omit;
+ Sym.Flags |= unsigned(GV->getVisibility()) << storage::Symbol::FB_visibility;
+
+ if (Flags & object::BasicSymbolRef::SF_Common) {
+ auto *GVar = dyn_cast<GlobalVariable>(GV);
+ if (!GVar)
+ return make_error<StringError>("Only variables can have common linkage!",
+ inconvertibleErrorCode());
+ Uncommon().CommonSize = GV->getParent()->getDataLayout().getTypeAllocSize(
+ GV->getType()->getElementType());
+ Uncommon().CommonAlign = GVar->getAlignment();
+ }
+
+ const GlobalObject *Base = GV->getBaseObject();
+ if (!Base)
+ return make_error<StringError>("Unable to determine comdat of alias!",
+ inconvertibleErrorCode());
+ if (const Comdat *C = Base->getComdat()) {
+ Expected<int> ComdatIndexOrErr = getComdatIndex(C, GV->getParent());
+ if (!ComdatIndexOrErr)
+ return ComdatIndexOrErr.takeError();
+ Sym.ComdatIndex = *ComdatIndexOrErr;
+ }
+
+ if (TT.isOSBinFormatCOFF()) {
+ emitLinkerFlagsForGlobalCOFF(COFFLinkerOptsOS, GV, TT, Mang);
+
+ 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, Fallback);
+ OS.flush();
+ setStr(Uncommon().COFFWeakExternFallbackName, Saver.save(FallbackName));
+ }
+ }
+
+ if (!Base->getSection().empty())
+ setStr(Uncommon().SectionName, Saver.save(Base->getSection()));
+
+ return Error::success();
+}
+
+Error Builder::build(ArrayRef<Module *> IRMods) {
+ storage::Header Hdr;
+
+ assert(!IRMods.empty());
+ Hdr.Version = storage::Header::kCurrentVersion;
+ setStr(Hdr.Producer, kExpectedProducerName);
+ setStr(Hdr.TargetTriple, IRMods[0]->getTargetTriple());
+ setStr(Hdr.SourceFileName, IRMods[0]->getSourceFileName());
+ TT = Triple(IRMods[0]->getTargetTriple());
+
+ for (auto *M : IRMods)
+ if (Error Err = addModule(M))
+ return Err;
+
+ COFFLinkerOptsOS.flush();
+ setStr(Hdr.COFFLinkerOpts, Saver.save(COFFLinkerOpts));
+
+ // We are about to fill in the header's range fields, so reserve space for it
+ // and copy it in afterwards.
+ Symtab.resize(sizeof(storage::Header));
+ writeRange(Hdr.Modules, Mods);
+ writeRange(Hdr.Comdats, Comdats);
+ writeRange(Hdr.Symbols, Syms);
+ writeRange(Hdr.Uncommons, Uncommons);
+ writeRange(Hdr.DependentLibraries, DependentLibraries);
+ *reinterpret_cast<storage::Header *>(Symtab.data()) = Hdr;
+ return Error::success();
+}
+
+} // end anonymous namespace
+
+Error irsymtab::build(ArrayRef<Module *> Mods, SmallVector<char, 0> &Symtab,
+ StringTableBuilder &StrtabBuilder,
+ BumpPtrAllocator &Alloc) {
+ return Builder(Symtab, StrtabBuilder, Alloc).build(Mods);
+}
+
+// Upgrade a vector of bitcode modules created by an old version of LLVM by
+// creating an irsymtab for them in the current format.
+static Expected<FileContents> upgrade(ArrayRef<BitcodeModule> BMs) {
+ FileContents FC;
+
+ LLVMContext Ctx;
+ std::vector<Module *> Mods;
+ std::vector<std::unique_ptr<Module>> OwnedMods;
+ for (auto BM : BMs) {
+ Expected<std::unique_ptr<Module>> MOrErr =
+ BM.getLazyModule(Ctx, /*ShouldLazyLoadMetadata*/ true,
+ /*IsImporting*/ false);
+ if (!MOrErr)
+ return MOrErr.takeError();
+
+ Mods.push_back(MOrErr->get());
+ OwnedMods.push_back(std::move(*MOrErr));
+ }
+
+ StringTableBuilder StrtabBuilder(StringTableBuilder::RAW);
+ BumpPtrAllocator Alloc;
+ if (Error E = build(Mods, FC.Symtab, StrtabBuilder, Alloc))
+ return std::move(E);
+
+ StrtabBuilder.finalizeInOrder();
+ FC.Strtab.resize(StrtabBuilder.getSize());
+ StrtabBuilder.write((uint8_t *)FC.Strtab.data());
+
+ FC.TheReader = {{FC.Symtab.data(), FC.Symtab.size()},
+ {FC.Strtab.data(), FC.Strtab.size()}};
+ return std::move(FC);
+}
+
+Expected<FileContents> irsymtab::readBitcode(const BitcodeFileContents &BFC) {
+ if (BFC.Mods.empty())
+ return make_error<StringError>("Bitcode file does not contain any modules",
+ inconvertibleErrorCode());
+
+ if (BFC.StrtabForSymtab.empty() ||
+ BFC.Symtab.size() < sizeof(storage::Header))
+ return upgrade(BFC.Mods);
+
+ // We cannot use the regular reader to read the version and producer, because
+ // it will expect the header to be in the current format. The only thing we
+ // can rely on is that the version and producer will be present as the first
+ // struct elements.
+ auto *Hdr = reinterpret_cast<const storage::Header *>(BFC.Symtab.data());
+ unsigned Version = Hdr->Version;
+ StringRef Producer = Hdr->Producer.get(BFC.StrtabForSymtab);
+ if (Version != storage::Header::kCurrentVersion ||
+ Producer != kExpectedProducerName)
+ return upgrade(BFC.Mods);
+
+ FileContents FC;
+ FC.TheReader = {{BFC.Symtab.data(), BFC.Symtab.size()},
+ {BFC.StrtabForSymtab.data(), BFC.StrtabForSymtab.size()}};
+
+ // Finally, make sure that the number of modules in the symbol table matches
+ // the number of modules in the bitcode file. If they differ, it may mean that
+ // the bitcode file was created by binary concatenation, so we need to create
+ // a new symbol table from scratch.
+ if (FC.TheReader.getNumModules() != BFC.Mods.size())
+ return upgrade(std::move(BFC.Mods));
+
+ return std::move(FC);
+}
diff --git a/contrib/libs/llvm12/lib/Object/MachOObjectFile.cpp b/contrib/libs/llvm12/lib/Object/MachOObjectFile.cpp
index 982dc0791f..3022559262 100644
--- a/contrib/libs/llvm12/lib/Object/MachOObjectFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/MachOObjectFile.cpp
@@ -1,2752 +1,2752 @@
-//===- MachOObjectFile.cpp - Mach-O object file binding -------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the MachOObjectFile class, which binds the MachOObject
-// class to the generic ObjectFile wrapper.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/None.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/ADT/Twine.h"
-#include "llvm/BinaryFormat/MachO.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Object/SymbolicFile.h"
-#include "llvm/Support/DataExtractor.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/Format.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SwapByteOrder.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cassert>
-#include <cstddef>
-#include <cstdint>
-#include <cstring>
-#include <limits>
-#include <list>
-#include <memory>
-#include <string>
-#include <system_error>
-
-using namespace llvm;
-using namespace object;
-
-namespace {
-
- struct section_base {
- char sectname[16];
- char segname[16];
- };
-
-} // end anonymous namespace
-
-static Error malformedError(const Twine &Msg) {
- return make_error<GenericBinaryError>("truncated or malformed object (" +
- Msg + ")",
- object_error::parse_failed);
-}
-
-// FIXME: Replace all uses of this function with getStructOrErr.
-template <typename T>
-static T getStruct(const MachOObjectFile &O, const char *P) {
- // Don't read before the beginning or past the end of the file
- if (P < O.getData().begin() || P + sizeof(T) > O.getData().end())
- report_fatal_error("Malformed MachO file.");
-
- T Cmd;
- memcpy(&Cmd, P, sizeof(T));
- if (O.isLittleEndian() != sys::IsLittleEndianHost)
- MachO::swapStruct(Cmd);
- return Cmd;
-}
-
-template <typename T>
-static Expected<T> getStructOrErr(const MachOObjectFile &O, const char *P) {
- // Don't read before the beginning or past the end of the file
- if (P < O.getData().begin() || P + sizeof(T) > O.getData().end())
- return malformedError("Structure read out-of-range");
-
- T Cmd;
- memcpy(&Cmd, P, sizeof(T));
- if (O.isLittleEndian() != sys::IsLittleEndianHost)
- MachO::swapStruct(Cmd);
- return Cmd;
-}
-
-static const char *
-getSectionPtr(const MachOObjectFile &O, MachOObjectFile::LoadCommandInfo L,
- unsigned Sec) {
- uintptr_t CommandAddr = reinterpret_cast<uintptr_t>(L.Ptr);
-
- bool Is64 = O.is64Bit();
- unsigned SegmentLoadSize = Is64 ? sizeof(MachO::segment_command_64) :
- sizeof(MachO::segment_command);
- unsigned SectionSize = Is64 ? sizeof(MachO::section_64) :
- sizeof(MachO::section);
-
- uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize;
- return reinterpret_cast<const char*>(SectionAddr);
-}
-
-static const char *getPtr(const MachOObjectFile &O, size_t Offset) {
- assert(Offset <= O.getData().size());
- return O.getData().data() + Offset;
-}
-
-static MachO::nlist_base
-getSymbolTableEntryBase(const MachOObjectFile &O, DataRefImpl DRI) {
- const char *P = reinterpret_cast<const char *>(DRI.p);
- return getStruct<MachO::nlist_base>(O, P);
-}
-
-static StringRef parseSegmentOrSectionName(const char *P) {
- if (P[15] == 0)
- // Null terminated.
- return P;
- // Not null terminated, so this is a 16 char string.
- return StringRef(P, 16);
-}
-
-static unsigned getCPUType(const MachOObjectFile &O) {
- return O.getHeader().cputype;
-}
-
-static unsigned getCPUSubType(const MachOObjectFile &O) {
- return O.getHeader().cpusubtype;
-}
-
-static uint32_t
-getPlainRelocationAddress(const MachO::any_relocation_info &RE) {
- return RE.r_word0;
-}
-
-static unsigned
-getScatteredRelocationAddress(const MachO::any_relocation_info &RE) {
- return RE.r_word0 & 0xffffff;
-}
-
-static bool getPlainRelocationPCRel(const MachOObjectFile &O,
- const MachO::any_relocation_info &RE) {
- if (O.isLittleEndian())
- return (RE.r_word1 >> 24) & 1;
- return (RE.r_word1 >> 7) & 1;
-}
-
-static bool
-getScatteredRelocationPCRel(const MachO::any_relocation_info &RE) {
- return (RE.r_word0 >> 30) & 1;
-}
-
-static unsigned getPlainRelocationLength(const MachOObjectFile &O,
- const MachO::any_relocation_info &RE) {
- if (O.isLittleEndian())
- return (RE.r_word1 >> 25) & 3;
- return (RE.r_word1 >> 5) & 3;
-}
-
-static unsigned
-getScatteredRelocationLength(const MachO::any_relocation_info &RE) {
- return (RE.r_word0 >> 28) & 3;
-}
-
-static unsigned getPlainRelocationType(const MachOObjectFile &O,
- const MachO::any_relocation_info &RE) {
- if (O.isLittleEndian())
- return RE.r_word1 >> 28;
- return RE.r_word1 & 0xf;
-}
-
-static uint32_t getSectionFlags(const MachOObjectFile &O,
- DataRefImpl Sec) {
- if (O.is64Bit()) {
- MachO::section_64 Sect = O.getSection64(Sec);
- return Sect.flags;
- }
- MachO::section Sect = O.getSection(Sec);
- return Sect.flags;
-}
-
-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");
- return MachOObjectFile::LoadCommandInfo({Ptr, *CmdOrErr});
- } else
- return CmdOrErr.takeError();
-}
-
-static Expected<MachOObjectFile::LoadCommandInfo>
-getFirstLoadCommandInfo(const MachOObjectFile &Obj) {
- unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)
- : sizeof(MachO::mach_header);
- if (sizeof(MachO::load_command) > Obj.getHeader().sizeofcmds)
- return malformedError("load command 0 extends past the end all load "
- "commands in the file");
- return getLoadCommandInfo(Obj, getPtr(Obj, HeaderSize), 0);
-}
-
-static Expected<MachOObjectFile::LoadCommandInfo>
-getNextLoadCommandInfo(const MachOObjectFile &Obj, uint32_t LoadCommandIndex,
- const MachOObjectFile::LoadCommandInfo &L) {
- unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)
- : sizeof(MachO::mach_header);
- if (L.Ptr + L.C.cmdsize + sizeof(MachO::load_command) >
- Obj.getData().data() + HeaderSize + Obj.getHeader().sizeofcmds)
- return malformedError("load command " + Twine(LoadCommandIndex + 1) +
- " extends past the end all load commands in the file");
- return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize, LoadCommandIndex + 1);
-}
-
-template <typename T>
-static void parseHeader(const MachOObjectFile &Obj, T &Header,
- Error &Err) {
- if (sizeof(T) > Obj.getData().size()) {
- Err = malformedError("the mach header extends past the end of the "
- "file");
- return;
- }
- if (auto HeaderOrErr = getStructOrErr<T>(Obj, getPtr(Obj, 0)))
- Header = *HeaderOrErr;
- else
- Err = HeaderOrErr.takeError();
-}
-
-// This is used to check for overlapping of Mach-O elements.
-struct MachOElement {
- uint64_t Offset;
- uint64_t Size;
- const char *Name;
-};
-
-static Error checkOverlappingElement(std::list<MachOElement> &Elements,
- uint64_t Offset, uint64_t Size,
- const char *Name) {
- if (Size == 0)
- return Error::success();
-
- for (auto it=Elements.begin() ; it != Elements.end(); ++it) {
- auto E = *it;
- if ((Offset >= E.Offset && Offset < E.Offset + E.Size) ||
- (Offset + Size > E.Offset && Offset + Size < E.Offset + E.Size) ||
- (Offset <= E.Offset && Offset + Size >= E.Offset + E.Size))
- return malformedError(Twine(Name) + " at offset " + Twine(Offset) +
- " with a size of " + Twine(Size) + ", overlaps " +
- E.Name + " at offset " + Twine(E.Offset) + " with "
- "a size of " + Twine(E.Size));
- auto nt = it;
- nt++;
- if (nt != Elements.end()) {
- auto N = *nt;
- if (Offset + Size <= N.Offset) {
- Elements.insert(nt, {Offset, Size, Name});
- return Error::success();
- }
- }
- }
- Elements.push_back({Offset, Size, Name});
- return Error::success();
-}
-
-// Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all
-// sections to \param Sections, and optionally sets
-// \param IsPageZeroSegment to true.
-template <typename Segment, typename Section>
-static Error parseSegmentLoadCommand(
- const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &Load,
- SmallVectorImpl<const char *> &Sections, bool &IsPageZeroSegment,
- uint32_t LoadCommandIndex, const char *CmdName, uint64_t SizeOfHeaders,
- std::list<MachOElement> &Elements) {
- const unsigned SegmentLoadSize = sizeof(Segment);
- if (Load.C.cmdsize < SegmentLoadSize)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " " + CmdName + " cmdsize too small");
- if (auto SegOrErr = getStructOrErr<Segment>(Obj, Load.Ptr)) {
- Segment S = SegOrErr.get();
- const unsigned SectionSize = sizeof(Section);
- uint64_t FileSize = Obj.getData().size();
- if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
- S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " inconsistent cmdsize in " + CmdName +
- " for the number of sections");
- for (unsigned J = 0; J < S.nsects; ++J) {
- const char *Sec = getSectionPtr(Obj, Load, J);
- Sections.push_back(Sec);
- auto SectionOrErr = getStructOrErr<Section>(Obj, Sec);
- if (!SectionOrErr)
- return SectionOrErr.takeError();
- Section s = SectionOrErr.get();
- if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
- Obj.getHeader().filetype != MachO::MH_DSYM &&
- s.flags != MachO::S_ZEROFILL &&
- s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
- s.offset > FileSize)
- return malformedError("offset field of section " + Twine(J) + " in " +
- CmdName + " command " + Twine(LoadCommandIndex) +
- " extends past the end of the file");
- if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
- Obj.getHeader().filetype != MachO::MH_DSYM &&
- s.flags != MachO::S_ZEROFILL &&
- s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && S.fileoff == 0 &&
- s.offset < SizeOfHeaders && s.size != 0)
- return malformedError("offset field of section " + Twine(J) + " in " +
- CmdName + " command " + Twine(LoadCommandIndex) +
- " not past the headers of the file");
- uint64_t BigSize = s.offset;
- BigSize += s.size;
- if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
- Obj.getHeader().filetype != MachO::MH_DSYM &&
- s.flags != MachO::S_ZEROFILL &&
- s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
- BigSize > FileSize)
- return malformedError("offset field plus size field of section " +
- Twine(J) + " in " + CmdName + " command " +
- Twine(LoadCommandIndex) +
- " extends past the end of the file");
- if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
- Obj.getHeader().filetype != MachO::MH_DSYM &&
- s.flags != MachO::S_ZEROFILL &&
- s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
- s.size > S.filesize)
- return malformedError("size field of section " +
- Twine(J) + " in " + CmdName + " command " +
- Twine(LoadCommandIndex) +
- " greater than the segment");
- if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
- Obj.getHeader().filetype != MachO::MH_DSYM && s.size != 0 &&
- s.addr < S.vmaddr)
- return malformedError("addr field of section " + Twine(J) + " in " +
- CmdName + " command " + Twine(LoadCommandIndex) +
- " less than the segment's vmaddr");
- BigSize = s.addr;
- BigSize += s.size;
- uint64_t BigEnd = S.vmaddr;
- BigEnd += S.vmsize;
- if (S.vmsize != 0 && s.size != 0 && BigSize > BigEnd)
- return malformedError("addr field plus size of section " + Twine(J) +
- " in " + CmdName + " command " +
- Twine(LoadCommandIndex) +
- " greater than than "
- "the segment's vmaddr plus vmsize");
- if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
- Obj.getHeader().filetype != MachO::MH_DSYM &&
- s.flags != MachO::S_ZEROFILL &&
- s.flags != MachO::S_THREAD_LOCAL_ZEROFILL)
- if (Error Err = checkOverlappingElement(Elements, s.offset, s.size,
- "section contents"))
- return Err;
- if (s.reloff > FileSize)
- return malformedError("reloff field of section " + Twine(J) + " in " +
- CmdName + " command " + Twine(LoadCommandIndex) +
- " extends past the end of the file");
- BigSize = s.nreloc;
- BigSize *= sizeof(struct MachO::relocation_info);
- BigSize += s.reloff;
- if (BigSize > FileSize)
- return malformedError("reloff field plus nreloc field times sizeof("
- "struct relocation_info) of section " +
- Twine(J) + " in " + CmdName + " command " +
- Twine(LoadCommandIndex) +
- " extends past the end of the file");
- if (Error Err = checkOverlappingElement(Elements, s.reloff, s.nreloc *
- sizeof(struct
- MachO::relocation_info),
- "section relocation entries"))
- return Err;
- }
- if (S.fileoff > FileSize)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " fileoff field in " + CmdName +
- " extends past the end of the file");
- uint64_t BigSize = S.fileoff;
- BigSize += S.filesize;
- if (BigSize > FileSize)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " fileoff field plus filesize field in " +
- CmdName + " extends past the end of the file");
- if (S.vmsize != 0 && S.filesize > S.vmsize)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " filesize field in " + CmdName +
- " greater than vmsize field");
- IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname);
- } else
- return SegOrErr.takeError();
-
- return Error::success();
-}
-
-static Error checkSymtabCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- const char **SymtabLoadCmd,
- std::list<MachOElement> &Elements) {
- if (Load.C.cmdsize < sizeof(MachO::symtab_command))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_SYMTAB cmdsize too small");
- if (*SymtabLoadCmd != nullptr)
- return malformedError("more than one LC_SYMTAB command");
- auto SymtabOrErr = getStructOrErr<MachO::symtab_command>(Obj, Load.Ptr);
- if (!SymtabOrErr)
- return SymtabOrErr.takeError();
- MachO::symtab_command Symtab = SymtabOrErr.get();
- if (Symtab.cmdsize != sizeof(MachO::symtab_command))
- return malformedError("LC_SYMTAB command " + Twine(LoadCommandIndex) +
- " has incorrect cmdsize");
- uint64_t FileSize = Obj.getData().size();
- if (Symtab.symoff > FileSize)
- return malformedError("symoff field of LC_SYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end "
- "of the file");
- uint64_t SymtabSize = Symtab.nsyms;
- const char *struct_nlist_name;
- if (Obj.is64Bit()) {
- SymtabSize *= sizeof(MachO::nlist_64);
- struct_nlist_name = "struct nlist_64";
- } else {
- SymtabSize *= sizeof(MachO::nlist);
- struct_nlist_name = "struct nlist";
- }
- uint64_t BigSize = SymtabSize;
- BigSize += Symtab.symoff;
- if (BigSize > FileSize)
- return malformedError("symoff field plus nsyms field times sizeof(" +
- Twine(struct_nlist_name) + ") of LC_SYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end "
- "of the file");
- if (Error Err = checkOverlappingElement(Elements, Symtab.symoff, SymtabSize,
- "symbol table"))
- return Err;
- if (Symtab.stroff > FileSize)
- return malformedError("stroff field of LC_SYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end "
- "of the file");
- BigSize = Symtab.stroff;
- BigSize += Symtab.strsize;
- if (BigSize > FileSize)
- return malformedError("stroff field plus strsize field of LC_SYMTAB "
- "command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- if (Error Err = checkOverlappingElement(Elements, Symtab.stroff,
- Symtab.strsize, "string table"))
- return Err;
- *SymtabLoadCmd = Load.Ptr;
- return Error::success();
-}
-
-static Error checkDysymtabCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- const char **DysymtabLoadCmd,
- std::list<MachOElement> &Elements) {
- if (Load.C.cmdsize < sizeof(MachO::dysymtab_command))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_DYSYMTAB cmdsize too small");
- if (*DysymtabLoadCmd != nullptr)
- return malformedError("more than one LC_DYSYMTAB command");
- auto DysymtabOrErr =
- getStructOrErr<MachO::dysymtab_command>(Obj, Load.Ptr);
- if (!DysymtabOrErr)
- return DysymtabOrErr.takeError();
- MachO::dysymtab_command Dysymtab = DysymtabOrErr.get();
- if (Dysymtab.cmdsize != sizeof(MachO::dysymtab_command))
- return malformedError("LC_DYSYMTAB command " + Twine(LoadCommandIndex) +
- " has incorrect cmdsize");
- uint64_t FileSize = Obj.getData().size();
- if (Dysymtab.tocoff > FileSize)
- return malformedError("tocoff field of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- uint64_t BigSize = Dysymtab.ntoc;
- BigSize *= sizeof(MachO::dylib_table_of_contents);
- BigSize += Dysymtab.tocoff;
- if (BigSize > FileSize)
- return malformedError("tocoff field plus ntoc field times sizeof(struct "
- "dylib_table_of_contents) of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, Dysymtab.tocoff,
- Dysymtab.ntoc * sizeof(struct
- MachO::dylib_table_of_contents),
- "table of contents"))
- return Err;
- if (Dysymtab.modtaboff > FileSize)
- return malformedError("modtaboff field of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- BigSize = Dysymtab.nmodtab;
- const char *struct_dylib_module_name;
- uint64_t sizeof_modtab;
- if (Obj.is64Bit()) {
- sizeof_modtab = sizeof(MachO::dylib_module_64);
- struct_dylib_module_name = "struct dylib_module_64";
- } else {
- sizeof_modtab = sizeof(MachO::dylib_module);
- struct_dylib_module_name = "struct dylib_module";
- }
- BigSize *= sizeof_modtab;
- BigSize += Dysymtab.modtaboff;
- if (BigSize > FileSize)
- return malformedError("modtaboff field plus nmodtab field times sizeof(" +
- Twine(struct_dylib_module_name) + ") of LC_DYSYMTAB "
- "command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- if (Error Err = checkOverlappingElement(Elements, Dysymtab.modtaboff,
- Dysymtab.nmodtab * sizeof_modtab,
- "module table"))
- return Err;
- if (Dysymtab.extrefsymoff > FileSize)
- return malformedError("extrefsymoff field of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- BigSize = Dysymtab.nextrefsyms;
- BigSize *= sizeof(MachO::dylib_reference);
- BigSize += Dysymtab.extrefsymoff;
- if (BigSize > FileSize)
- return malformedError("extrefsymoff field plus nextrefsyms field times "
- "sizeof(struct dylib_reference) of LC_DYSYMTAB "
- "command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- if (Error Err = checkOverlappingElement(Elements, Dysymtab.extrefsymoff,
- Dysymtab.nextrefsyms *
- sizeof(MachO::dylib_reference),
- "reference table"))
- return Err;
- if (Dysymtab.indirectsymoff > FileSize)
- return malformedError("indirectsymoff field of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- BigSize = Dysymtab.nindirectsyms;
- BigSize *= sizeof(uint32_t);
- BigSize += Dysymtab.indirectsymoff;
- if (BigSize > FileSize)
- return malformedError("indirectsymoff field plus nindirectsyms field times "
- "sizeof(uint32_t) of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, Dysymtab.indirectsymoff,
- Dysymtab.nindirectsyms *
- sizeof(uint32_t),
- "indirect table"))
- return Err;
- if (Dysymtab.extreloff > FileSize)
- return malformedError("extreloff field of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- BigSize = Dysymtab.nextrel;
- BigSize *= sizeof(MachO::relocation_info);
- BigSize += Dysymtab.extreloff;
- if (BigSize > FileSize)
- return malformedError("extreloff field plus nextrel field times sizeof"
- "(struct relocation_info) of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, Dysymtab.extreloff,
- Dysymtab.nextrel *
- sizeof(MachO::relocation_info),
- "external relocation table"))
- return Err;
- if (Dysymtab.locreloff > FileSize)
- return malformedError("locreloff field of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- BigSize = Dysymtab.nlocrel;
- BigSize *= sizeof(MachO::relocation_info);
- BigSize += Dysymtab.locreloff;
- if (BigSize > FileSize)
- return malformedError("locreloff field plus nlocrel field times sizeof"
- "(struct relocation_info) of LC_DYSYMTAB command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, Dysymtab.locreloff,
- Dysymtab.nlocrel *
- sizeof(MachO::relocation_info),
- "local relocation table"))
- return Err;
- *DysymtabLoadCmd = Load.Ptr;
- return Error::success();
-}
-
-static Error checkLinkeditDataCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- const char **LoadCmd, const char *CmdName,
- std::list<MachOElement> &Elements,
- const char *ElementName) {
- if (Load.C.cmdsize < sizeof(MachO::linkedit_data_command))
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " cmdsize too small");
- if (*LoadCmd != nullptr)
- return malformedError("more than one " + Twine(CmdName) + " command");
- auto LinkDataOrError =
- getStructOrErr<MachO::linkedit_data_command>(Obj, Load.Ptr);
- if (!LinkDataOrError)
- return LinkDataOrError.takeError();
- MachO::linkedit_data_command LinkData = LinkDataOrError.get();
- if (LinkData.cmdsize != sizeof(MachO::linkedit_data_command))
- return malformedError(Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " has incorrect cmdsize");
- uint64_t FileSize = Obj.getData().size();
- if (LinkData.dataoff > FileSize)
- return malformedError("dataoff field of " + Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- uint64_t BigSize = LinkData.dataoff;
- BigSize += LinkData.datasize;
- if (BigSize > FileSize)
- return malformedError("dataoff field plus datasize field of " +
- Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, LinkData.dataoff,
- LinkData.datasize, ElementName))
- return Err;
- *LoadCmd = Load.Ptr;
- return Error::success();
-}
-
-static Error checkDyldInfoCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- const char **LoadCmd, const char *CmdName,
- std::list<MachOElement> &Elements) {
- if (Load.C.cmdsize < sizeof(MachO::dyld_info_command))
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " cmdsize too small");
- if (*LoadCmd != nullptr)
- return malformedError("more than one LC_DYLD_INFO and or LC_DYLD_INFO_ONLY "
- "command");
- auto DyldInfoOrErr =
- getStructOrErr<MachO::dyld_info_command>(Obj, Load.Ptr);
- if (!DyldInfoOrErr)
- return DyldInfoOrErr.takeError();
- MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
- if (DyldInfo.cmdsize != sizeof(MachO::dyld_info_command))
- return malformedError(Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " has incorrect cmdsize");
- uint64_t FileSize = Obj.getData().size();
- if (DyldInfo.rebase_off > FileSize)
- return malformedError("rebase_off field of " + Twine(CmdName) +
- " command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- uint64_t BigSize = DyldInfo.rebase_off;
- BigSize += DyldInfo.rebase_size;
- if (BigSize > FileSize)
- return malformedError("rebase_off field plus rebase_size field of " +
- Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, DyldInfo.rebase_off,
- DyldInfo.rebase_size,
- "dyld rebase info"))
- return Err;
- if (DyldInfo.bind_off > FileSize)
- return malformedError("bind_off field of " + Twine(CmdName) +
- " command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- BigSize = DyldInfo.bind_off;
- BigSize += DyldInfo.bind_size;
- if (BigSize > FileSize)
- return malformedError("bind_off field plus bind_size field of " +
- Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, DyldInfo.bind_off,
- DyldInfo.bind_size,
- "dyld bind info"))
- return Err;
- if (DyldInfo.weak_bind_off > FileSize)
- return malformedError("weak_bind_off field of " + Twine(CmdName) +
- " command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- BigSize = DyldInfo.weak_bind_off;
- BigSize += DyldInfo.weak_bind_size;
- if (BigSize > FileSize)
- return malformedError("weak_bind_off field plus weak_bind_size field of " +
- Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, DyldInfo.weak_bind_off,
- DyldInfo.weak_bind_size,
- "dyld weak bind info"))
- return Err;
- if (DyldInfo.lazy_bind_off > FileSize)
- return malformedError("lazy_bind_off field of " + Twine(CmdName) +
- " command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- BigSize = DyldInfo.lazy_bind_off;
- BigSize += DyldInfo.lazy_bind_size;
- if (BigSize > FileSize)
- return malformedError("lazy_bind_off field plus lazy_bind_size field of " +
- Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, DyldInfo.lazy_bind_off,
- DyldInfo.lazy_bind_size,
- "dyld lazy bind info"))
- return Err;
- if (DyldInfo.export_off > FileSize)
- return malformedError("export_off field of " + Twine(CmdName) +
- " command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- BigSize = DyldInfo.export_off;
- BigSize += DyldInfo.export_size;
- if (BigSize > FileSize)
- return malformedError("export_off field plus export_size field of " +
- Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, DyldInfo.export_off,
- DyldInfo.export_size,
- "dyld export info"))
- return Err;
- *LoadCmd = Load.Ptr;
- return Error::success();
-}
-
-static Error checkDylibCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex, const char *CmdName) {
- if (Load.C.cmdsize < sizeof(MachO::dylib_command))
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " cmdsize too small");
- auto CommandOrErr = getStructOrErr<MachO::dylib_command>(Obj, Load.Ptr);
- if (!CommandOrErr)
- return CommandOrErr.takeError();
- MachO::dylib_command D = CommandOrErr.get();
- if (D.dylib.name < sizeof(MachO::dylib_command))
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " name.offset field too small, not past "
- "the end of the dylib_command struct");
- if (D.dylib.name >= D.cmdsize)
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " name.offset field extends past the end "
- "of the load command");
- // Make sure there is a null between the starting offset of the name and
- // the end of the load command.
- uint32_t i;
- const char *P = (const char *)Load.Ptr;
- for (i = D.dylib.name; i < D.cmdsize; i++)
- if (P[i] == '\0')
- break;
- if (i >= D.cmdsize)
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " library name extends past the end of the "
- "load command");
- return Error::success();
-}
-
-static Error checkDylibIdCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- const char **LoadCmd) {
- if (Error Err = checkDylibCommand(Obj, Load, LoadCommandIndex,
- "LC_ID_DYLIB"))
- return Err;
- if (*LoadCmd != nullptr)
- return malformedError("more than one LC_ID_DYLIB command");
- if (Obj.getHeader().filetype != MachO::MH_DYLIB &&
- Obj.getHeader().filetype != MachO::MH_DYLIB_STUB)
- return malformedError("LC_ID_DYLIB load command in non-dynamic library "
- "file type");
- *LoadCmd = Load.Ptr;
- return Error::success();
-}
-
-static Error checkDyldCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex, const char *CmdName) {
- if (Load.C.cmdsize < sizeof(MachO::dylinker_command))
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " cmdsize too small");
- auto CommandOrErr = getStructOrErr<MachO::dylinker_command>(Obj, Load.Ptr);
- if (!CommandOrErr)
- return CommandOrErr.takeError();
- MachO::dylinker_command D = CommandOrErr.get();
- if (D.name < sizeof(MachO::dylinker_command))
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " name.offset field too small, not past "
- "the end of the dylinker_command struct");
- if (D.name >= D.cmdsize)
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " name.offset field extends past the end "
- "of the load command");
- // Make sure there is a null between the starting offset of the name and
- // the end of the load command.
- uint32_t i;
- const char *P = (const char *)Load.Ptr;
- for (i = D.name; i < D.cmdsize; i++)
- if (P[i] == '\0')
- break;
- if (i >= D.cmdsize)
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " dyld name extends past the end of the "
- "load command");
- return Error::success();
-}
-
-static Error checkVersCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- const char **LoadCmd, const char *CmdName) {
- if (Load.C.cmdsize != sizeof(MachO::version_min_command))
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " has incorrect cmdsize");
- if (*LoadCmd != nullptr)
- return malformedError("more than one LC_VERSION_MIN_MACOSX, "
- "LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS or "
- "LC_VERSION_MIN_WATCHOS command");
- *LoadCmd = Load.Ptr;
- return Error::success();
-}
-
-static Error checkNoteCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- std::list<MachOElement> &Elements) {
- if (Load.C.cmdsize != sizeof(MachO::note_command))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_NOTE has incorrect cmdsize");
- auto NoteCmdOrErr = getStructOrErr<MachO::note_command>(Obj, Load.Ptr);
- if (!NoteCmdOrErr)
- return NoteCmdOrErr.takeError();
- MachO::note_command Nt = NoteCmdOrErr.get();
- uint64_t FileSize = Obj.getData().size();
- if (Nt.offset > FileSize)
- return malformedError("offset field of LC_NOTE command " +
- Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- uint64_t BigSize = Nt.offset;
- BigSize += Nt.size;
- if (BigSize > FileSize)
- return malformedError("size field plus offset field of LC_NOTE command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, Nt.offset, Nt.size,
- "LC_NOTE data"))
- return Err;
- return Error::success();
-}
-
-static Error
-parseBuildVersionCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- SmallVectorImpl<const char*> &BuildTools,
- uint32_t LoadCommandIndex) {
- auto BVCOrErr =
- getStructOrErr<MachO::build_version_command>(Obj, Load.Ptr);
- if (!BVCOrErr)
- return BVCOrErr.takeError();
- MachO::build_version_command BVC = BVCOrErr.get();
- if (Load.C.cmdsize !=
- sizeof(MachO::build_version_command) +
- BVC.ntools * sizeof(MachO::build_tool_version))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_BUILD_VERSION_COMMAND has incorrect cmdsize");
-
- auto Start = Load.Ptr + sizeof(MachO::build_version_command);
- BuildTools.resize(BVC.ntools);
- for (unsigned i = 0; i < BVC.ntools; ++i)
- BuildTools[i] = Start + i * sizeof(MachO::build_tool_version);
-
- return Error::success();
-}
-
-static Error checkRpathCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex) {
- if (Load.C.cmdsize < sizeof(MachO::rpath_command))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_RPATH cmdsize too small");
- auto ROrErr = getStructOrErr<MachO::rpath_command>(Obj, Load.Ptr);
- if (!ROrErr)
- return ROrErr.takeError();
- MachO::rpath_command R = ROrErr.get();
- if (R.path < sizeof(MachO::rpath_command))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_RPATH path.offset field too small, not past "
- "the end of the rpath_command struct");
- if (R.path >= R.cmdsize)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_RPATH path.offset field extends past the end "
- "of the load command");
- // Make sure there is a null between the starting offset of the path and
- // the end of the load command.
- uint32_t i;
- const char *P = (const char *)Load.Ptr;
- for (i = R.path; i < R.cmdsize; i++)
- if (P[i] == '\0')
- break;
- if (i >= R.cmdsize)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_RPATH library name extends past the end of the "
- "load command");
- return Error::success();
-}
-
-static Error checkEncryptCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- uint64_t cryptoff, uint64_t cryptsize,
- const char **LoadCmd, const char *CmdName) {
- if (*LoadCmd != nullptr)
- return malformedError("more than one LC_ENCRYPTION_INFO and or "
- "LC_ENCRYPTION_INFO_64 command");
- uint64_t FileSize = Obj.getData().size();
- if (cryptoff > FileSize)
- return malformedError("cryptoff field of " + Twine(CmdName) +
- " command " + Twine(LoadCommandIndex) + " extends "
- "past the end of the file");
- uint64_t BigSize = cryptoff;
- BigSize += cryptsize;
- if (BigSize > FileSize)
- return malformedError("cryptoff field plus cryptsize field of " +
- Twine(CmdName) + " command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- *LoadCmd = Load.Ptr;
- return Error::success();
-}
-
-static Error checkLinkerOptCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex) {
- if (Load.C.cmdsize < sizeof(MachO::linker_option_command))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_LINKER_OPTION cmdsize too small");
- auto LinkOptionOrErr =
- getStructOrErr<MachO::linker_option_command>(Obj, Load.Ptr);
- if (!LinkOptionOrErr)
- return LinkOptionOrErr.takeError();
- MachO::linker_option_command L = LinkOptionOrErr.get();
- // Make sure the count of strings is correct.
- const char *string = (const char *)Load.Ptr +
- sizeof(struct MachO::linker_option_command);
- uint32_t left = L.cmdsize - sizeof(struct MachO::linker_option_command);
- uint32_t i = 0;
- while (left > 0) {
- while (*string == '\0' && left > 0) {
- string++;
- left--;
- }
- if (left > 0) {
- i++;
- uint32_t NullPos = StringRef(string, left).find('\0');
- if (0xffffffff == NullPos)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_LINKER_OPTION string #" + Twine(i) +
- " is not NULL terminated");
- uint32_t len = std::min(NullPos, left) + 1;
- string += len;
- left -= len;
- }
- }
- if (L.count != i)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_LINKER_OPTION string count " + Twine(L.count) +
- " does not match number of strings");
- return Error::success();
-}
-
-static Error checkSubCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex, const char *CmdName,
- size_t SizeOfCmd, const char *CmdStructName,
- uint32_t PathOffset, const char *PathFieldName) {
- if (PathOffset < SizeOfCmd)
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " " + PathFieldName + ".offset field too "
- "small, not past the end of the " + CmdStructName);
- if (PathOffset >= Load.C.cmdsize)
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " " + PathFieldName + ".offset field "
- "extends past the end of the load command");
- // Make sure there is a null between the starting offset of the path and
- // the end of the load command.
- uint32_t i;
- const char *P = (const char *)Load.Ptr;
- for (i = PathOffset; i < Load.C.cmdsize; i++)
- if (P[i] == '\0')
- break;
- if (i >= Load.C.cmdsize)
- return malformedError("load command " + Twine(LoadCommandIndex) + " " +
- CmdName + " " + PathFieldName + " name extends past "
- "the end of the load command");
- return Error::success();
-}
-
-static Error checkThreadCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo &Load,
- uint32_t LoadCommandIndex,
- const char *CmdName) {
- if (Load.C.cmdsize < sizeof(MachO::thread_command))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- CmdName + " cmdsize too small");
- auto ThreadCommandOrErr =
- getStructOrErr<MachO::thread_command>(Obj, Load.Ptr);
- if (!ThreadCommandOrErr)
- return ThreadCommandOrErr.takeError();
- MachO::thread_command T = ThreadCommandOrErr.get();
- const char *state = Load.Ptr + sizeof(MachO::thread_command);
- const char *end = Load.Ptr + T.cmdsize;
- uint32_t nflavor = 0;
- uint32_t cputype = getCPUType(Obj);
- while (state < end) {
- if(state + sizeof(uint32_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- "flavor in " + CmdName + " extends past end of "
- "command");
- uint32_t flavor;
- memcpy(&flavor, state, sizeof(uint32_t));
- if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
- sys::swapByteOrder(flavor);
- state += sizeof(uint32_t);
-
- if(state + sizeof(uint32_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count in " + CmdName + " extends past end of "
- "command");
- uint32_t count;
- memcpy(&count, state, sizeof(uint32_t));
- if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
- sys::swapByteOrder(count);
- state += sizeof(uint32_t);
-
- if (cputype == MachO::CPU_TYPE_I386) {
- if (flavor == MachO::x86_THREAD_STATE32) {
- if (count != MachO::x86_THREAD_STATE32_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not x86_THREAD_STATE32_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a x86_THREAD_STATE32 flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::x86_thread_state32_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " x86_THREAD_STATE32 extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::x86_thread_state32_t);
- } else {
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " unknown flavor (" + Twine(flavor) + ") for "
- "flavor number " + Twine(nflavor) + " in " +
- CmdName + " command");
- }
- } else if (cputype == MachO::CPU_TYPE_X86_64) {
- if (flavor == MachO::x86_THREAD_STATE) {
- if (count != MachO::x86_THREAD_STATE_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not x86_THREAD_STATE_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a x86_THREAD_STATE flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::x86_thread_state_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " x86_THREAD_STATE extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::x86_thread_state_t);
- } else if (flavor == MachO::x86_FLOAT_STATE) {
- if (count != MachO::x86_FLOAT_STATE_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not x86_FLOAT_STATE_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a x86_FLOAT_STATE flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::x86_float_state_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " x86_FLOAT_STATE extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::x86_float_state_t);
- } else if (flavor == MachO::x86_EXCEPTION_STATE) {
- if (count != MachO::x86_EXCEPTION_STATE_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not x86_EXCEPTION_STATE_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a x86_EXCEPTION_STATE flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::x86_exception_state_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " x86_EXCEPTION_STATE extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::x86_exception_state_t);
- } else if (flavor == MachO::x86_THREAD_STATE64) {
- if (count != MachO::x86_THREAD_STATE64_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not x86_THREAD_STATE64_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a x86_THREAD_STATE64 flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::x86_thread_state64_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " x86_THREAD_STATE64 extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::x86_thread_state64_t);
- } else if (flavor == MachO::x86_EXCEPTION_STATE64) {
- if (count != MachO::x86_EXCEPTION_STATE64_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not x86_EXCEPTION_STATE64_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a x86_EXCEPTION_STATE64 flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::x86_exception_state64_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " x86_EXCEPTION_STATE64 extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::x86_exception_state64_t);
- } else {
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " unknown flavor (" + Twine(flavor) + ") for "
- "flavor number " + Twine(nflavor) + " in " +
- CmdName + " command");
- }
- } else if (cputype == MachO::CPU_TYPE_ARM) {
- if (flavor == MachO::ARM_THREAD_STATE) {
- if (count != MachO::ARM_THREAD_STATE_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not ARM_THREAD_STATE_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a ARM_THREAD_STATE flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::arm_thread_state32_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " ARM_THREAD_STATE extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::arm_thread_state32_t);
- } else {
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " unknown flavor (" + Twine(flavor) + ") for "
- "flavor number " + Twine(nflavor) + " in " +
- CmdName + " command");
- }
- } else if (cputype == MachO::CPU_TYPE_ARM64 ||
- cputype == MachO::CPU_TYPE_ARM64_32) {
- if (flavor == MachO::ARM_THREAD_STATE64) {
- if (count != MachO::ARM_THREAD_STATE64_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not ARM_THREAD_STATE64_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a ARM_THREAD_STATE64 flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::arm_thread_state64_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " ARM_THREAD_STATE64 extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::arm_thread_state64_t);
- } else {
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " unknown flavor (" + Twine(flavor) + ") for "
- "flavor number " + Twine(nflavor) + " in " +
- CmdName + " command");
- }
- } else if (cputype == MachO::CPU_TYPE_POWERPC) {
- if (flavor == MachO::PPC_THREAD_STATE) {
- if (count != MachO::PPC_THREAD_STATE_COUNT)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " count not PPC_THREAD_STATE_COUNT for "
- "flavor number " + Twine(nflavor) + " which is "
- "a PPC_THREAD_STATE flavor in " + CmdName +
- " command");
- if (state + sizeof(MachO::ppc_thread_state32_t) > end)
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " PPC_THREAD_STATE extends past end of "
- "command in " + CmdName + " command");
- state += sizeof(MachO::ppc_thread_state32_t);
- } else {
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " unknown flavor (" + Twine(flavor) + ") for "
- "flavor number " + Twine(nflavor) + " in " +
- CmdName + " command");
- }
- } else {
- return malformedError("unknown cputype (" + Twine(cputype) + ") load "
- "command " + Twine(LoadCommandIndex) + " for " +
- CmdName + " command can't be checked");
- }
- nflavor++;
- }
- return Error::success();
-}
-
-static Error checkTwoLevelHintsCommand(const MachOObjectFile &Obj,
- const MachOObjectFile::LoadCommandInfo
- &Load,
- uint32_t LoadCommandIndex,
- const char **LoadCmd,
- std::list<MachOElement> &Elements) {
- if (Load.C.cmdsize != sizeof(MachO::twolevel_hints_command))
- return malformedError("load command " + Twine(LoadCommandIndex) +
- " LC_TWOLEVEL_HINTS has incorrect cmdsize");
- if (*LoadCmd != nullptr)
- return malformedError("more than one LC_TWOLEVEL_HINTS command");
- auto HintsOrErr = getStructOrErr<MachO::twolevel_hints_command>(Obj, Load.Ptr);
- if(!HintsOrErr)
- return HintsOrErr.takeError();
- MachO::twolevel_hints_command Hints = HintsOrErr.get();
- uint64_t FileSize = Obj.getData().size();
- if (Hints.offset > FileSize)
- return malformedError("offset field of LC_TWOLEVEL_HINTS command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- uint64_t BigSize = Hints.nhints;
- BigSize *= sizeof(MachO::twolevel_hint);
- BigSize += Hints.offset;
- if (BigSize > FileSize)
- return malformedError("offset field plus nhints times sizeof(struct "
- "twolevel_hint) field of LC_TWOLEVEL_HINTS command " +
- Twine(LoadCommandIndex) + " extends past the end of "
- "the file");
- if (Error Err = checkOverlappingElement(Elements, Hints.offset, Hints.nhints *
- sizeof(MachO::twolevel_hint),
- "two level hints"))
- return Err;
- *LoadCmd = Load.Ptr;
- return Error::success();
-}
-
-// Returns true if the libObject code does not support the load command and its
-// contents. The cmd value it is treated as an unknown load command but with
-// an error message that says the cmd value is obsolete.
-static bool isLoadCommandObsolete(uint32_t cmd) {
- if (cmd == MachO::LC_SYMSEG ||
- cmd == MachO::LC_LOADFVMLIB ||
- cmd == MachO::LC_IDFVMLIB ||
- cmd == MachO::LC_IDENT ||
- cmd == MachO::LC_FVMFILE ||
- cmd == MachO::LC_PREPAGE ||
- cmd == MachO::LC_PREBOUND_DYLIB ||
- cmd == MachO::LC_TWOLEVEL_HINTS ||
- cmd == MachO::LC_PREBIND_CKSUM)
- return true;
- return false;
-}
-
-Expected<std::unique_ptr<MachOObjectFile>>
-MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
- bool Is64Bits, uint32_t UniversalCputype,
- uint32_t UniversalIndex) {
- Error Err = Error::success();
- std::unique_ptr<MachOObjectFile> Obj(
- new MachOObjectFile(std::move(Object), IsLittleEndian,
- Is64Bits, Err, UniversalCputype,
- UniversalIndex));
- if (Err)
- return std::move(Err);
- return std::move(Obj);
-}
-
-MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
- bool Is64bits, Error &Err,
- uint32_t UniversalCputype,
- uint32_t UniversalIndex)
- : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object) {
- ErrorAsOutParameter ErrAsOutParam(&Err);
- uint64_t SizeOfHeaders;
- uint32_t cputype;
- if (is64Bit()) {
- parseHeader(*this, Header64, Err);
- SizeOfHeaders = sizeof(MachO::mach_header_64);
- cputype = Header64.cputype;
- } else {
- parseHeader(*this, Header, Err);
- SizeOfHeaders = sizeof(MachO::mach_header);
- cputype = Header.cputype;
- }
- if (Err)
- return;
- SizeOfHeaders += getHeader().sizeofcmds;
- if (getData().data() + SizeOfHeaders > getData().end()) {
- Err = malformedError("load commands extend past the end of the file");
- return;
- }
- if (UniversalCputype != 0 && cputype != UniversalCputype) {
- Err = malformedError("universal header architecture: " +
- Twine(UniversalIndex) + "'s cputype does not match "
- "object file's mach header");
- return;
- }
- std::list<MachOElement> Elements;
- Elements.push_back({0, SizeOfHeaders, "Mach-O headers"});
-
- uint32_t LoadCommandCount = getHeader().ncmds;
- LoadCommandInfo Load;
- if (LoadCommandCount != 0) {
- if (auto LoadOrErr = getFirstLoadCommandInfo(*this))
- Load = *LoadOrErr;
- else {
- Err = LoadOrErr.takeError();
- return;
- }
- }
-
- const char *DyldIdLoadCmd = nullptr;
- const char *FuncStartsLoadCmd = nullptr;
- const char *SplitInfoLoadCmd = nullptr;
- const char *CodeSignDrsLoadCmd = nullptr;
- const char *CodeSignLoadCmd = nullptr;
- const char *VersLoadCmd = nullptr;
- const char *SourceLoadCmd = nullptr;
- const char *EntryPointLoadCmd = nullptr;
- const char *EncryptLoadCmd = nullptr;
- const char *RoutinesLoadCmd = nullptr;
- const char *UnixThreadLoadCmd = nullptr;
- const char *TwoLevelHintsLoadCmd = nullptr;
- for (unsigned I = 0; I < LoadCommandCount; ++I) {
- if (is64Bit()) {
- if (Load.C.cmdsize % 8 != 0) {
- // We have a hack here to allow 64-bit Mach-O core files to have
- // LC_THREAD commands that are only a multiple of 4 and not 8 to be
- // allowed since the macOS kernel produces them.
- if (getHeader().filetype != MachO::MH_CORE ||
- Load.C.cmd != MachO::LC_THREAD || Load.C.cmdsize % 4) {
- Err = malformedError("load command " + Twine(I) + " cmdsize not a "
- "multiple of 8");
- return;
- }
- }
- } else {
- if (Load.C.cmdsize % 4 != 0) {
- Err = malformedError("load command " + Twine(I) + " cmdsize not a "
- "multiple of 4");
- return;
- }
- }
- LoadCommands.push_back(Load);
- if (Load.C.cmd == MachO::LC_SYMTAB) {
- if ((Err = checkSymtabCommand(*this, Load, I, &SymtabLoadCmd, Elements)))
- return;
- } else if (Load.C.cmd == MachO::LC_DYSYMTAB) {
- if ((Err = checkDysymtabCommand(*this, Load, I, &DysymtabLoadCmd,
- Elements)))
- return;
- } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) {
- if ((Err = checkLinkeditDataCommand(*this, Load, I, &DataInCodeLoadCmd,
- "LC_DATA_IN_CODE", Elements,
- "data in code info")))
- return;
- } else if (Load.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) {
- if ((Err = checkLinkeditDataCommand(*this, Load, I, &LinkOptHintsLoadCmd,
- "LC_LINKER_OPTIMIZATION_HINT",
- Elements, "linker optimization "
- "hints")))
- return;
- } else if (Load.C.cmd == MachO::LC_FUNCTION_STARTS) {
- if ((Err = checkLinkeditDataCommand(*this, Load, I, &FuncStartsLoadCmd,
- "LC_FUNCTION_STARTS", Elements,
- "function starts data")))
- return;
- } else if (Load.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO) {
- if ((Err = checkLinkeditDataCommand(*this, Load, I, &SplitInfoLoadCmd,
- "LC_SEGMENT_SPLIT_INFO", Elements,
- "split info data")))
- return;
- } else if (Load.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS) {
- if ((Err = checkLinkeditDataCommand(*this, Load, I, &CodeSignDrsLoadCmd,
- "LC_DYLIB_CODE_SIGN_DRS", Elements,
- "code signing RDs data")))
- return;
- } else if (Load.C.cmd == MachO::LC_CODE_SIGNATURE) {
- if ((Err = checkLinkeditDataCommand(*this, Load, I, &CodeSignLoadCmd,
- "LC_CODE_SIGNATURE", Elements,
- "code signature data")))
- return;
- } else if (Load.C.cmd == MachO::LC_DYLD_INFO) {
- if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,
- "LC_DYLD_INFO", Elements)))
- return;
- } else if (Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
- if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,
- "LC_DYLD_INFO_ONLY", Elements)))
- return;
- } else if (Load.C.cmd == MachO::LC_UUID) {
- if (Load.C.cmdsize != sizeof(MachO::uuid_command)) {
- Err = malformedError("LC_UUID command " + Twine(I) + " has incorrect "
- "cmdsize");
- return;
- }
- if (UuidLoadCmd) {
- Err = malformedError("more than one LC_UUID command");
- return;
- }
- UuidLoadCmd = Load.Ptr;
- } else if (Load.C.cmd == MachO::LC_SEGMENT_64) {
- if ((Err = parseSegmentLoadCommand<MachO::segment_command_64,
- MachO::section_64>(
- *this, Load, Sections, HasPageZeroSegment, I,
- "LC_SEGMENT_64", SizeOfHeaders, Elements)))
- return;
- } else if (Load.C.cmd == MachO::LC_SEGMENT) {
- if ((Err = parseSegmentLoadCommand<MachO::segment_command,
- MachO::section>(
- *this, Load, Sections, HasPageZeroSegment, I,
- "LC_SEGMENT", SizeOfHeaders, Elements)))
- return;
- } else if (Load.C.cmd == MachO::LC_ID_DYLIB) {
- if ((Err = checkDylibIdCommand(*this, Load, I, &DyldIdLoadCmd)))
- return;
- } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB) {
- if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_DYLIB")))
- return;
- Libraries.push_back(Load.Ptr);
- } else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB) {
- if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_WEAK_DYLIB")))
- return;
- Libraries.push_back(Load.Ptr);
- } else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB) {
- if ((Err = checkDylibCommand(*this, Load, I, "LC_LAZY_LOAD_DYLIB")))
- return;
- Libraries.push_back(Load.Ptr);
- } else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB) {
- if ((Err = checkDylibCommand(*this, Load, I, "LC_REEXPORT_DYLIB")))
- return;
- Libraries.push_back(Load.Ptr);
- } else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
- if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_UPWARD_DYLIB")))
- return;
- Libraries.push_back(Load.Ptr);
- } else if (Load.C.cmd == MachO::LC_ID_DYLINKER) {
- if ((Err = checkDyldCommand(*this, Load, I, "LC_ID_DYLINKER")))
- return;
- } else if (Load.C.cmd == MachO::LC_LOAD_DYLINKER) {
- if ((Err = checkDyldCommand(*this, Load, I, "LC_LOAD_DYLINKER")))
- return;
- } else if (Load.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
- if ((Err = checkDyldCommand(*this, Load, I, "LC_DYLD_ENVIRONMENT")))
- return;
- } else if (Load.C.cmd == MachO::LC_VERSION_MIN_MACOSX) {
- if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
- "LC_VERSION_MIN_MACOSX")))
- return;
- } else if (Load.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) {
- if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
- "LC_VERSION_MIN_IPHONEOS")))
- return;
- } else if (Load.C.cmd == MachO::LC_VERSION_MIN_TVOS) {
- if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
- "LC_VERSION_MIN_TVOS")))
- return;
- } else if (Load.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
- if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
- "LC_VERSION_MIN_WATCHOS")))
- return;
- } else if (Load.C.cmd == MachO::LC_NOTE) {
- if ((Err = checkNoteCommand(*this, Load, I, Elements)))
- return;
- } else if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
- if ((Err = parseBuildVersionCommand(*this, Load, BuildTools, I)))
- return;
- } else if (Load.C.cmd == MachO::LC_RPATH) {
- if ((Err = checkRpathCommand(*this, Load, I)))
- return;
- } else if (Load.C.cmd == MachO::LC_SOURCE_VERSION) {
- if (Load.C.cmdsize != sizeof(MachO::source_version_command)) {
- Err = malformedError("LC_SOURCE_VERSION command " + Twine(I) +
- " has incorrect cmdsize");
- return;
- }
- if (SourceLoadCmd) {
- Err = malformedError("more than one LC_SOURCE_VERSION command");
- return;
- }
- SourceLoadCmd = Load.Ptr;
- } else if (Load.C.cmd == MachO::LC_MAIN) {
- if (Load.C.cmdsize != sizeof(MachO::entry_point_command)) {
- Err = malformedError("LC_MAIN command " + Twine(I) +
- " has incorrect cmdsize");
- return;
- }
- if (EntryPointLoadCmd) {
- Err = malformedError("more than one LC_MAIN command");
- return;
- }
- EntryPointLoadCmd = Load.Ptr;
- } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO) {
- if (Load.C.cmdsize != sizeof(MachO::encryption_info_command)) {
- Err = malformedError("LC_ENCRYPTION_INFO command " + Twine(I) +
- " has incorrect cmdsize");
- return;
- }
- MachO::encryption_info_command E =
- getStruct<MachO::encryption_info_command>(*this, Load.Ptr);
- if ((Err = checkEncryptCommand(*this, Load, I, E.cryptoff, E.cryptsize,
- &EncryptLoadCmd, "LC_ENCRYPTION_INFO")))
- return;
- } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
- if (Load.C.cmdsize != sizeof(MachO::encryption_info_command_64)) {
- Err = malformedError("LC_ENCRYPTION_INFO_64 command " + Twine(I) +
- " has incorrect cmdsize");
- return;
- }
- MachO::encryption_info_command_64 E =
- getStruct<MachO::encryption_info_command_64>(*this, Load.Ptr);
- if ((Err = checkEncryptCommand(*this, Load, I, E.cryptoff, E.cryptsize,
- &EncryptLoadCmd, "LC_ENCRYPTION_INFO_64")))
- return;
- } else if (Load.C.cmd == MachO::LC_LINKER_OPTION) {
- if ((Err = checkLinkerOptCommand(*this, Load, I)))
- return;
- } else if (Load.C.cmd == MachO::LC_SUB_FRAMEWORK) {
- if (Load.C.cmdsize < sizeof(MachO::sub_framework_command)) {
- Err = malformedError("load command " + Twine(I) +
- " LC_SUB_FRAMEWORK cmdsize too small");
- return;
- }
- MachO::sub_framework_command S =
- getStruct<MachO::sub_framework_command>(*this, Load.Ptr);
- if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_FRAMEWORK",
- sizeof(MachO::sub_framework_command),
- "sub_framework_command", S.umbrella,
- "umbrella")))
- return;
- } else if (Load.C.cmd == MachO::LC_SUB_UMBRELLA) {
- if (Load.C.cmdsize < sizeof(MachO::sub_umbrella_command)) {
- Err = malformedError("load command " + Twine(I) +
- " LC_SUB_UMBRELLA cmdsize too small");
- return;
- }
- MachO::sub_umbrella_command S =
- getStruct<MachO::sub_umbrella_command>(*this, Load.Ptr);
- if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_UMBRELLA",
- sizeof(MachO::sub_umbrella_command),
- "sub_umbrella_command", S.sub_umbrella,
- "sub_umbrella")))
- return;
- } else if (Load.C.cmd == MachO::LC_SUB_LIBRARY) {
- if (Load.C.cmdsize < sizeof(MachO::sub_library_command)) {
- Err = malformedError("load command " + Twine(I) +
- " LC_SUB_LIBRARY cmdsize too small");
- return;
- }
- MachO::sub_library_command S =
- getStruct<MachO::sub_library_command>(*this, Load.Ptr);
- if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_LIBRARY",
- sizeof(MachO::sub_library_command),
- "sub_library_command", S.sub_library,
- "sub_library")))
- return;
- } else if (Load.C.cmd == MachO::LC_SUB_CLIENT) {
- if (Load.C.cmdsize < sizeof(MachO::sub_client_command)) {
- Err = malformedError("load command " + Twine(I) +
- " LC_SUB_CLIENT cmdsize too small");
- return;
- }
- MachO::sub_client_command S =
- getStruct<MachO::sub_client_command>(*this, Load.Ptr);
- if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_CLIENT",
- sizeof(MachO::sub_client_command),
- "sub_client_command", S.client, "client")))
- return;
- } else if (Load.C.cmd == MachO::LC_ROUTINES) {
- if (Load.C.cmdsize != sizeof(MachO::routines_command)) {
- Err = malformedError("LC_ROUTINES command " + Twine(I) +
- " has incorrect cmdsize");
- return;
- }
- if (RoutinesLoadCmd) {
- Err = malformedError("more than one LC_ROUTINES and or LC_ROUTINES_64 "
- "command");
- return;
- }
- RoutinesLoadCmd = Load.Ptr;
- } else if (Load.C.cmd == MachO::LC_ROUTINES_64) {
- if (Load.C.cmdsize != sizeof(MachO::routines_command_64)) {
- Err = malformedError("LC_ROUTINES_64 command " + Twine(I) +
- " has incorrect cmdsize");
- return;
- }
- if (RoutinesLoadCmd) {
- Err = malformedError("more than one LC_ROUTINES_64 and or LC_ROUTINES "
- "command");
- return;
- }
- RoutinesLoadCmd = Load.Ptr;
- } else if (Load.C.cmd == MachO::LC_UNIXTHREAD) {
- if ((Err = checkThreadCommand(*this, Load, I, "LC_UNIXTHREAD")))
- return;
- if (UnixThreadLoadCmd) {
- Err = malformedError("more than one LC_UNIXTHREAD command");
- return;
- }
- UnixThreadLoadCmd = Load.Ptr;
- } else if (Load.C.cmd == MachO::LC_THREAD) {
- if ((Err = checkThreadCommand(*this, Load, I, "LC_THREAD")))
- return;
- // Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported.
- } else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) {
- if ((Err = checkTwoLevelHintsCommand(*this, Load, I,
- &TwoLevelHintsLoadCmd, Elements)))
- return;
+//===- MachOObjectFile.cpp - Mach-O object file binding -------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the MachOObjectFile class, which binds the MachOObject
+// class to the generic ObjectFile wrapper.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/BinaryFormat/MachO.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SwapByteOrder.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <limits>
+#include <list>
+#include <memory>
+#include <string>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+
+namespace {
+
+ struct section_base {
+ char sectname[16];
+ char segname[16];
+ };
+
+} // end anonymous namespace
+
+static Error malformedError(const Twine &Msg) {
+ return make_error<GenericBinaryError>("truncated or malformed object (" +
+ Msg + ")",
+ object_error::parse_failed);
+}
+
+// FIXME: Replace all uses of this function with getStructOrErr.
+template <typename T>
+static T getStruct(const MachOObjectFile &O, const char *P) {
+ // Don't read before the beginning or past the end of the file
+ if (P < O.getData().begin() || P + sizeof(T) > O.getData().end())
+ report_fatal_error("Malformed MachO file.");
+
+ T Cmd;
+ memcpy(&Cmd, P, sizeof(T));
+ if (O.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(Cmd);
+ return Cmd;
+}
+
+template <typename T>
+static Expected<T> getStructOrErr(const MachOObjectFile &O, const char *P) {
+ // Don't read before the beginning or past the end of the file
+ if (P < O.getData().begin() || P + sizeof(T) > O.getData().end())
+ return malformedError("Structure read out-of-range");
+
+ T Cmd;
+ memcpy(&Cmd, P, sizeof(T));
+ if (O.isLittleEndian() != sys::IsLittleEndianHost)
+ MachO::swapStruct(Cmd);
+ return Cmd;
+}
+
+static const char *
+getSectionPtr(const MachOObjectFile &O, MachOObjectFile::LoadCommandInfo L,
+ unsigned Sec) {
+ uintptr_t CommandAddr = reinterpret_cast<uintptr_t>(L.Ptr);
+
+ bool Is64 = O.is64Bit();
+ unsigned SegmentLoadSize = Is64 ? sizeof(MachO::segment_command_64) :
+ sizeof(MachO::segment_command);
+ unsigned SectionSize = Is64 ? sizeof(MachO::section_64) :
+ sizeof(MachO::section);
+
+ uintptr_t SectionAddr = CommandAddr + SegmentLoadSize + Sec * SectionSize;
+ return reinterpret_cast<const char*>(SectionAddr);
+}
+
+static const char *getPtr(const MachOObjectFile &O, size_t Offset) {
+ assert(Offset <= O.getData().size());
+ return O.getData().data() + Offset;
+}
+
+static MachO::nlist_base
+getSymbolTableEntryBase(const MachOObjectFile &O, DataRefImpl DRI) {
+ const char *P = reinterpret_cast<const char *>(DRI.p);
+ return getStruct<MachO::nlist_base>(O, P);
+}
+
+static StringRef parseSegmentOrSectionName(const char *P) {
+ if (P[15] == 0)
+ // Null terminated.
+ return P;
+ // Not null terminated, so this is a 16 char string.
+ return StringRef(P, 16);
+}
+
+static unsigned getCPUType(const MachOObjectFile &O) {
+ return O.getHeader().cputype;
+}
+
+static unsigned getCPUSubType(const MachOObjectFile &O) {
+ return O.getHeader().cpusubtype;
+}
+
+static uint32_t
+getPlainRelocationAddress(const MachO::any_relocation_info &RE) {
+ return RE.r_word0;
+}
+
+static unsigned
+getScatteredRelocationAddress(const MachO::any_relocation_info &RE) {
+ return RE.r_word0 & 0xffffff;
+}
+
+static bool getPlainRelocationPCRel(const MachOObjectFile &O,
+ const MachO::any_relocation_info &RE) {
+ if (O.isLittleEndian())
+ return (RE.r_word1 >> 24) & 1;
+ return (RE.r_word1 >> 7) & 1;
+}
+
+static bool
+getScatteredRelocationPCRel(const MachO::any_relocation_info &RE) {
+ return (RE.r_word0 >> 30) & 1;
+}
+
+static unsigned getPlainRelocationLength(const MachOObjectFile &O,
+ const MachO::any_relocation_info &RE) {
+ if (O.isLittleEndian())
+ return (RE.r_word1 >> 25) & 3;
+ return (RE.r_word1 >> 5) & 3;
+}
+
+static unsigned
+getScatteredRelocationLength(const MachO::any_relocation_info &RE) {
+ return (RE.r_word0 >> 28) & 3;
+}
+
+static unsigned getPlainRelocationType(const MachOObjectFile &O,
+ const MachO::any_relocation_info &RE) {
+ if (O.isLittleEndian())
+ return RE.r_word1 >> 28;
+ return RE.r_word1 & 0xf;
+}
+
+static uint32_t getSectionFlags(const MachOObjectFile &O,
+ DataRefImpl Sec) {
+ if (O.is64Bit()) {
+ MachO::section_64 Sect = O.getSection64(Sec);
+ return Sect.flags;
+ }
+ MachO::section Sect = O.getSection(Sec);
+ return Sect.flags;
+}
+
+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");
+ return MachOObjectFile::LoadCommandInfo({Ptr, *CmdOrErr});
+ } else
+ return CmdOrErr.takeError();
+}
+
+static Expected<MachOObjectFile::LoadCommandInfo>
+getFirstLoadCommandInfo(const MachOObjectFile &Obj) {
+ unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)
+ : sizeof(MachO::mach_header);
+ if (sizeof(MachO::load_command) > Obj.getHeader().sizeofcmds)
+ return malformedError("load command 0 extends past the end all load "
+ "commands in the file");
+ return getLoadCommandInfo(Obj, getPtr(Obj, HeaderSize), 0);
+}
+
+static Expected<MachOObjectFile::LoadCommandInfo>
+getNextLoadCommandInfo(const MachOObjectFile &Obj, uint32_t LoadCommandIndex,
+ const MachOObjectFile::LoadCommandInfo &L) {
+ unsigned HeaderSize = Obj.is64Bit() ? sizeof(MachO::mach_header_64)
+ : sizeof(MachO::mach_header);
+ if (L.Ptr + L.C.cmdsize + sizeof(MachO::load_command) >
+ Obj.getData().data() + HeaderSize + Obj.getHeader().sizeofcmds)
+ return malformedError("load command " + Twine(LoadCommandIndex + 1) +
+ " extends past the end all load commands in the file");
+ return getLoadCommandInfo(Obj, L.Ptr + L.C.cmdsize, LoadCommandIndex + 1);
+}
+
+template <typename T>
+static void parseHeader(const MachOObjectFile &Obj, T &Header,
+ Error &Err) {
+ if (sizeof(T) > Obj.getData().size()) {
+ Err = malformedError("the mach header extends past the end of the "
+ "file");
+ return;
+ }
+ if (auto HeaderOrErr = getStructOrErr<T>(Obj, getPtr(Obj, 0)))
+ Header = *HeaderOrErr;
+ else
+ Err = HeaderOrErr.takeError();
+}
+
+// This is used to check for overlapping of Mach-O elements.
+struct MachOElement {
+ uint64_t Offset;
+ uint64_t Size;
+ const char *Name;
+};
+
+static Error checkOverlappingElement(std::list<MachOElement> &Elements,
+ uint64_t Offset, uint64_t Size,
+ const char *Name) {
+ if (Size == 0)
+ return Error::success();
+
+ for (auto it=Elements.begin() ; it != Elements.end(); ++it) {
+ auto E = *it;
+ if ((Offset >= E.Offset && Offset < E.Offset + E.Size) ||
+ (Offset + Size > E.Offset && Offset + Size < E.Offset + E.Size) ||
+ (Offset <= E.Offset && Offset + Size >= E.Offset + E.Size))
+ return malformedError(Twine(Name) + " at offset " + Twine(Offset) +
+ " with a size of " + Twine(Size) + ", overlaps " +
+ E.Name + " at offset " + Twine(E.Offset) + " with "
+ "a size of " + Twine(E.Size));
+ auto nt = it;
+ nt++;
+ if (nt != Elements.end()) {
+ auto N = *nt;
+ if (Offset + Size <= N.Offset) {
+ Elements.insert(nt, {Offset, Size, Name});
+ return Error::success();
+ }
+ }
+ }
+ Elements.push_back({Offset, Size, Name});
+ return Error::success();
+}
+
+// Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all
+// sections to \param Sections, and optionally sets
+// \param IsPageZeroSegment to true.
+template <typename Segment, typename Section>
+static Error parseSegmentLoadCommand(
+ const MachOObjectFile &Obj, const MachOObjectFile::LoadCommandInfo &Load,
+ SmallVectorImpl<const char *> &Sections, bool &IsPageZeroSegment,
+ uint32_t LoadCommandIndex, const char *CmdName, uint64_t SizeOfHeaders,
+ std::list<MachOElement> &Elements) {
+ const unsigned SegmentLoadSize = sizeof(Segment);
+ if (Load.C.cmdsize < SegmentLoadSize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " " + CmdName + " cmdsize too small");
+ if (auto SegOrErr = getStructOrErr<Segment>(Obj, Load.Ptr)) {
+ Segment S = SegOrErr.get();
+ const unsigned SectionSize = sizeof(Section);
+ uint64_t FileSize = Obj.getData().size();
+ if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
+ S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " inconsistent cmdsize in " + CmdName +
+ " for the number of sections");
+ for (unsigned J = 0; J < S.nsects; ++J) {
+ const char *Sec = getSectionPtr(Obj, Load, J);
+ Sections.push_back(Sec);
+ auto SectionOrErr = getStructOrErr<Section>(Obj, Sec);
+ if (!SectionOrErr)
+ return SectionOrErr.takeError();
+ Section s = SectionOrErr.get();
+ if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj.getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
+ s.offset > FileSize)
+ return malformedError("offset field of section " + Twine(J) + " in " +
+ CmdName + " command " + Twine(LoadCommandIndex) +
+ " extends past the end of the file");
+ if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj.getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && S.fileoff == 0 &&
+ s.offset < SizeOfHeaders && s.size != 0)
+ return malformedError("offset field of section " + Twine(J) + " in " +
+ CmdName + " command " + Twine(LoadCommandIndex) +
+ " not past the headers of the file");
+ uint64_t BigSize = s.offset;
+ BigSize += s.size;
+ if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj.getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
+ BigSize > FileSize)
+ return malformedError("offset field plus size field of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " extends past the end of the file");
+ if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj.getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL &&
+ s.size > S.filesize)
+ return malformedError("size field of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " greater than the segment");
+ if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj.getHeader().filetype != MachO::MH_DSYM && s.size != 0 &&
+ s.addr < S.vmaddr)
+ return malformedError("addr field of section " + Twine(J) + " in " +
+ CmdName + " command " + Twine(LoadCommandIndex) +
+ " less than the segment's vmaddr");
+ BigSize = s.addr;
+ BigSize += s.size;
+ uint64_t BigEnd = S.vmaddr;
+ BigEnd += S.vmsize;
+ if (S.vmsize != 0 && s.size != 0 && BigSize > BigEnd)
+ return malformedError("addr field plus size of section " + Twine(J) +
+ " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " greater than than "
+ "the segment's vmaddr plus vmsize");
+ if (Obj.getHeader().filetype != MachO::MH_DYLIB_STUB &&
+ Obj.getHeader().filetype != MachO::MH_DSYM &&
+ s.flags != MachO::S_ZEROFILL &&
+ s.flags != MachO::S_THREAD_LOCAL_ZEROFILL)
+ if (Error Err = checkOverlappingElement(Elements, s.offset, s.size,
+ "section contents"))
+ return Err;
+ if (s.reloff > FileSize)
+ return malformedError("reloff field of section " + Twine(J) + " in " +
+ CmdName + " command " + Twine(LoadCommandIndex) +
+ " extends past the end of the file");
+ BigSize = s.nreloc;
+ BigSize *= sizeof(struct MachO::relocation_info);
+ BigSize += s.reloff;
+ if (BigSize > FileSize)
+ return malformedError("reloff field plus nreloc field times sizeof("
+ "struct relocation_info) of section " +
+ Twine(J) + " in " + CmdName + " command " +
+ Twine(LoadCommandIndex) +
+ " extends past the end of the file");
+ if (Error Err = checkOverlappingElement(Elements, s.reloff, s.nreloc *
+ sizeof(struct
+ MachO::relocation_info),
+ "section relocation entries"))
+ return Err;
+ }
+ if (S.fileoff > FileSize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " fileoff field in " + CmdName +
+ " extends past the end of the file");
+ uint64_t BigSize = S.fileoff;
+ BigSize += S.filesize;
+ if (BigSize > FileSize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " fileoff field plus filesize field in " +
+ CmdName + " extends past the end of the file");
+ if (S.vmsize != 0 && S.filesize > S.vmsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " filesize field in " + CmdName +
+ " greater than vmsize field");
+ IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname);
+ } else
+ return SegOrErr.takeError();
+
+ return Error::success();
+}
+
+static Error checkSymtabCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ const char **SymtabLoadCmd,
+ std::list<MachOElement> &Elements) {
+ if (Load.C.cmdsize < sizeof(MachO::symtab_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_SYMTAB cmdsize too small");
+ if (*SymtabLoadCmd != nullptr)
+ return malformedError("more than one LC_SYMTAB command");
+ auto SymtabOrErr = getStructOrErr<MachO::symtab_command>(Obj, Load.Ptr);
+ if (!SymtabOrErr)
+ return SymtabOrErr.takeError();
+ MachO::symtab_command Symtab = SymtabOrErr.get();
+ if (Symtab.cmdsize != sizeof(MachO::symtab_command))
+ return malformedError("LC_SYMTAB command " + Twine(LoadCommandIndex) +
+ " has incorrect cmdsize");
+ uint64_t FileSize = Obj.getData().size();
+ if (Symtab.symoff > FileSize)
+ return malformedError("symoff field of LC_SYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end "
+ "of the file");
+ uint64_t SymtabSize = Symtab.nsyms;
+ const char *struct_nlist_name;
+ if (Obj.is64Bit()) {
+ SymtabSize *= sizeof(MachO::nlist_64);
+ struct_nlist_name = "struct nlist_64";
+ } else {
+ SymtabSize *= sizeof(MachO::nlist);
+ struct_nlist_name = "struct nlist";
+ }
+ uint64_t BigSize = SymtabSize;
+ BigSize += Symtab.symoff;
+ if (BigSize > FileSize)
+ return malformedError("symoff field plus nsyms field times sizeof(" +
+ Twine(struct_nlist_name) + ") of LC_SYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end "
+ "of the file");
+ if (Error Err = checkOverlappingElement(Elements, Symtab.symoff, SymtabSize,
+ "symbol table"))
+ return Err;
+ if (Symtab.stroff > FileSize)
+ return malformedError("stroff field of LC_SYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end "
+ "of the file");
+ BigSize = Symtab.stroff;
+ BigSize += Symtab.strsize;
+ if (BigSize > FileSize)
+ return malformedError("stroff field plus strsize field of LC_SYMTAB "
+ "command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ if (Error Err = checkOverlappingElement(Elements, Symtab.stroff,
+ Symtab.strsize, "string table"))
+ return Err;
+ *SymtabLoadCmd = Load.Ptr;
+ return Error::success();
+}
+
+static Error checkDysymtabCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ const char **DysymtabLoadCmd,
+ std::list<MachOElement> &Elements) {
+ if (Load.C.cmdsize < sizeof(MachO::dysymtab_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_DYSYMTAB cmdsize too small");
+ if (*DysymtabLoadCmd != nullptr)
+ return malformedError("more than one LC_DYSYMTAB command");
+ auto DysymtabOrErr =
+ getStructOrErr<MachO::dysymtab_command>(Obj, Load.Ptr);
+ if (!DysymtabOrErr)
+ return DysymtabOrErr.takeError();
+ MachO::dysymtab_command Dysymtab = DysymtabOrErr.get();
+ if (Dysymtab.cmdsize != sizeof(MachO::dysymtab_command))
+ return malformedError("LC_DYSYMTAB command " + Twine(LoadCommandIndex) +
+ " has incorrect cmdsize");
+ uint64_t FileSize = Obj.getData().size();
+ if (Dysymtab.tocoff > FileSize)
+ return malformedError("tocoff field of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ uint64_t BigSize = Dysymtab.ntoc;
+ BigSize *= sizeof(MachO::dylib_table_of_contents);
+ BigSize += Dysymtab.tocoff;
+ if (BigSize > FileSize)
+ return malformedError("tocoff field plus ntoc field times sizeof(struct "
+ "dylib_table_of_contents) of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, Dysymtab.tocoff,
+ Dysymtab.ntoc * sizeof(struct
+ MachO::dylib_table_of_contents),
+ "table of contents"))
+ return Err;
+ if (Dysymtab.modtaboff > FileSize)
+ return malformedError("modtaboff field of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ BigSize = Dysymtab.nmodtab;
+ const char *struct_dylib_module_name;
+ uint64_t sizeof_modtab;
+ if (Obj.is64Bit()) {
+ sizeof_modtab = sizeof(MachO::dylib_module_64);
+ struct_dylib_module_name = "struct dylib_module_64";
+ } else {
+ sizeof_modtab = sizeof(MachO::dylib_module);
+ struct_dylib_module_name = "struct dylib_module";
+ }
+ BigSize *= sizeof_modtab;
+ BigSize += Dysymtab.modtaboff;
+ if (BigSize > FileSize)
+ return malformedError("modtaboff field plus nmodtab field times sizeof(" +
+ Twine(struct_dylib_module_name) + ") of LC_DYSYMTAB "
+ "command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ if (Error Err = checkOverlappingElement(Elements, Dysymtab.modtaboff,
+ Dysymtab.nmodtab * sizeof_modtab,
+ "module table"))
+ return Err;
+ if (Dysymtab.extrefsymoff > FileSize)
+ return malformedError("extrefsymoff field of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ BigSize = Dysymtab.nextrefsyms;
+ BigSize *= sizeof(MachO::dylib_reference);
+ BigSize += Dysymtab.extrefsymoff;
+ if (BigSize > FileSize)
+ return malformedError("extrefsymoff field plus nextrefsyms field times "
+ "sizeof(struct dylib_reference) of LC_DYSYMTAB "
+ "command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ if (Error Err = checkOverlappingElement(Elements, Dysymtab.extrefsymoff,
+ Dysymtab.nextrefsyms *
+ sizeof(MachO::dylib_reference),
+ "reference table"))
+ return Err;
+ if (Dysymtab.indirectsymoff > FileSize)
+ return malformedError("indirectsymoff field of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ BigSize = Dysymtab.nindirectsyms;
+ BigSize *= sizeof(uint32_t);
+ BigSize += Dysymtab.indirectsymoff;
+ if (BigSize > FileSize)
+ return malformedError("indirectsymoff field plus nindirectsyms field times "
+ "sizeof(uint32_t) of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, Dysymtab.indirectsymoff,
+ Dysymtab.nindirectsyms *
+ sizeof(uint32_t),
+ "indirect table"))
+ return Err;
+ if (Dysymtab.extreloff > FileSize)
+ return malformedError("extreloff field of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ BigSize = Dysymtab.nextrel;
+ BigSize *= sizeof(MachO::relocation_info);
+ BigSize += Dysymtab.extreloff;
+ if (BigSize > FileSize)
+ return malformedError("extreloff field plus nextrel field times sizeof"
+ "(struct relocation_info) of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, Dysymtab.extreloff,
+ Dysymtab.nextrel *
+ sizeof(MachO::relocation_info),
+ "external relocation table"))
+ return Err;
+ if (Dysymtab.locreloff > FileSize)
+ return malformedError("locreloff field of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ BigSize = Dysymtab.nlocrel;
+ BigSize *= sizeof(MachO::relocation_info);
+ BigSize += Dysymtab.locreloff;
+ if (BigSize > FileSize)
+ return malformedError("locreloff field plus nlocrel field times sizeof"
+ "(struct relocation_info) of LC_DYSYMTAB command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, Dysymtab.locreloff,
+ Dysymtab.nlocrel *
+ sizeof(MachO::relocation_info),
+ "local relocation table"))
+ return Err;
+ *DysymtabLoadCmd = Load.Ptr;
+ return Error::success();
+}
+
+static Error checkLinkeditDataCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ const char **LoadCmd, const char *CmdName,
+ std::list<MachOElement> &Elements,
+ const char *ElementName) {
+ if (Load.C.cmdsize < sizeof(MachO::linkedit_data_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " cmdsize too small");
+ if (*LoadCmd != nullptr)
+ return malformedError("more than one " + Twine(CmdName) + " command");
+ auto LinkDataOrError =
+ getStructOrErr<MachO::linkedit_data_command>(Obj, Load.Ptr);
+ if (!LinkDataOrError)
+ return LinkDataOrError.takeError();
+ MachO::linkedit_data_command LinkData = LinkDataOrError.get();
+ if (LinkData.cmdsize != sizeof(MachO::linkedit_data_command))
+ return malformedError(Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " has incorrect cmdsize");
+ uint64_t FileSize = Obj.getData().size();
+ if (LinkData.dataoff > FileSize)
+ return malformedError("dataoff field of " + Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ uint64_t BigSize = LinkData.dataoff;
+ BigSize += LinkData.datasize;
+ if (BigSize > FileSize)
+ return malformedError("dataoff field plus datasize field of " +
+ Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, LinkData.dataoff,
+ LinkData.datasize, ElementName))
+ return Err;
+ *LoadCmd = Load.Ptr;
+ return Error::success();
+}
+
+static Error checkDyldInfoCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ const char **LoadCmd, const char *CmdName,
+ std::list<MachOElement> &Elements) {
+ if (Load.C.cmdsize < sizeof(MachO::dyld_info_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " cmdsize too small");
+ if (*LoadCmd != nullptr)
+ return malformedError("more than one LC_DYLD_INFO and or LC_DYLD_INFO_ONLY "
+ "command");
+ auto DyldInfoOrErr =
+ getStructOrErr<MachO::dyld_info_command>(Obj, Load.Ptr);
+ if (!DyldInfoOrErr)
+ return DyldInfoOrErr.takeError();
+ MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
+ if (DyldInfo.cmdsize != sizeof(MachO::dyld_info_command))
+ return malformedError(Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " has incorrect cmdsize");
+ uint64_t FileSize = Obj.getData().size();
+ if (DyldInfo.rebase_off > FileSize)
+ return malformedError("rebase_off field of " + Twine(CmdName) +
+ " command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ uint64_t BigSize = DyldInfo.rebase_off;
+ BigSize += DyldInfo.rebase_size;
+ if (BigSize > FileSize)
+ return malformedError("rebase_off field plus rebase_size field of " +
+ Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, DyldInfo.rebase_off,
+ DyldInfo.rebase_size,
+ "dyld rebase info"))
+ return Err;
+ if (DyldInfo.bind_off > FileSize)
+ return malformedError("bind_off field of " + Twine(CmdName) +
+ " command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ BigSize = DyldInfo.bind_off;
+ BigSize += DyldInfo.bind_size;
+ if (BigSize > FileSize)
+ return malformedError("bind_off field plus bind_size field of " +
+ Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, DyldInfo.bind_off,
+ DyldInfo.bind_size,
+ "dyld bind info"))
+ return Err;
+ if (DyldInfo.weak_bind_off > FileSize)
+ return malformedError("weak_bind_off field of " + Twine(CmdName) +
+ " command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ BigSize = DyldInfo.weak_bind_off;
+ BigSize += DyldInfo.weak_bind_size;
+ if (BigSize > FileSize)
+ return malformedError("weak_bind_off field plus weak_bind_size field of " +
+ Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, DyldInfo.weak_bind_off,
+ DyldInfo.weak_bind_size,
+ "dyld weak bind info"))
+ return Err;
+ if (DyldInfo.lazy_bind_off > FileSize)
+ return malformedError("lazy_bind_off field of " + Twine(CmdName) +
+ " command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ BigSize = DyldInfo.lazy_bind_off;
+ BigSize += DyldInfo.lazy_bind_size;
+ if (BigSize > FileSize)
+ return malformedError("lazy_bind_off field plus lazy_bind_size field of " +
+ Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, DyldInfo.lazy_bind_off,
+ DyldInfo.lazy_bind_size,
+ "dyld lazy bind info"))
+ return Err;
+ if (DyldInfo.export_off > FileSize)
+ return malformedError("export_off field of " + Twine(CmdName) +
+ " command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ BigSize = DyldInfo.export_off;
+ BigSize += DyldInfo.export_size;
+ if (BigSize > FileSize)
+ return malformedError("export_off field plus export_size field of " +
+ Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, DyldInfo.export_off,
+ DyldInfo.export_size,
+ "dyld export info"))
+ return Err;
+ *LoadCmd = Load.Ptr;
+ return Error::success();
+}
+
+static Error checkDylibCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex, const char *CmdName) {
+ if (Load.C.cmdsize < sizeof(MachO::dylib_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " cmdsize too small");
+ auto CommandOrErr = getStructOrErr<MachO::dylib_command>(Obj, Load.Ptr);
+ if (!CommandOrErr)
+ return CommandOrErr.takeError();
+ MachO::dylib_command D = CommandOrErr.get();
+ if (D.dylib.name < sizeof(MachO::dylib_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " name.offset field too small, not past "
+ "the end of the dylib_command struct");
+ if (D.dylib.name >= D.cmdsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " name.offset field extends past the end "
+ "of the load command");
+ // Make sure there is a null between the starting offset of the name and
+ // the end of the load command.
+ uint32_t i;
+ const char *P = (const char *)Load.Ptr;
+ for (i = D.dylib.name; i < D.cmdsize; i++)
+ if (P[i] == '\0')
+ break;
+ if (i >= D.cmdsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " library name extends past the end of the "
+ "load command");
+ return Error::success();
+}
+
+static Error checkDylibIdCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ const char **LoadCmd) {
+ if (Error Err = checkDylibCommand(Obj, Load, LoadCommandIndex,
+ "LC_ID_DYLIB"))
+ return Err;
+ if (*LoadCmd != nullptr)
+ return malformedError("more than one LC_ID_DYLIB command");
+ if (Obj.getHeader().filetype != MachO::MH_DYLIB &&
+ Obj.getHeader().filetype != MachO::MH_DYLIB_STUB)
+ return malformedError("LC_ID_DYLIB load command in non-dynamic library "
+ "file type");
+ *LoadCmd = Load.Ptr;
+ return Error::success();
+}
+
+static Error checkDyldCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex, const char *CmdName) {
+ if (Load.C.cmdsize < sizeof(MachO::dylinker_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " cmdsize too small");
+ auto CommandOrErr = getStructOrErr<MachO::dylinker_command>(Obj, Load.Ptr);
+ if (!CommandOrErr)
+ return CommandOrErr.takeError();
+ MachO::dylinker_command D = CommandOrErr.get();
+ if (D.name < sizeof(MachO::dylinker_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " name.offset field too small, not past "
+ "the end of the dylinker_command struct");
+ if (D.name >= D.cmdsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " name.offset field extends past the end "
+ "of the load command");
+ // Make sure there is a null between the starting offset of the name and
+ // the end of the load command.
+ uint32_t i;
+ const char *P = (const char *)Load.Ptr;
+ for (i = D.name; i < D.cmdsize; i++)
+ if (P[i] == '\0')
+ break;
+ if (i >= D.cmdsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " dyld name extends past the end of the "
+ "load command");
+ return Error::success();
+}
+
+static Error checkVersCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ const char **LoadCmd, const char *CmdName) {
+ if (Load.C.cmdsize != sizeof(MachO::version_min_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " has incorrect cmdsize");
+ if (*LoadCmd != nullptr)
+ return malformedError("more than one LC_VERSION_MIN_MACOSX, "
+ "LC_VERSION_MIN_IPHONEOS, LC_VERSION_MIN_TVOS or "
+ "LC_VERSION_MIN_WATCHOS command");
+ *LoadCmd = Load.Ptr;
+ return Error::success();
+}
+
+static Error checkNoteCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ std::list<MachOElement> &Elements) {
+ if (Load.C.cmdsize != sizeof(MachO::note_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_NOTE has incorrect cmdsize");
+ auto NoteCmdOrErr = getStructOrErr<MachO::note_command>(Obj, Load.Ptr);
+ if (!NoteCmdOrErr)
+ return NoteCmdOrErr.takeError();
+ MachO::note_command Nt = NoteCmdOrErr.get();
+ uint64_t FileSize = Obj.getData().size();
+ if (Nt.offset > FileSize)
+ return malformedError("offset field of LC_NOTE command " +
+ Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ uint64_t BigSize = Nt.offset;
+ BigSize += Nt.size;
+ if (BigSize > FileSize)
+ return malformedError("size field plus offset field of LC_NOTE command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, Nt.offset, Nt.size,
+ "LC_NOTE data"))
+ return Err;
+ return Error::success();
+}
+
+static Error
+parseBuildVersionCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ SmallVectorImpl<const char*> &BuildTools,
+ uint32_t LoadCommandIndex) {
+ auto BVCOrErr =
+ getStructOrErr<MachO::build_version_command>(Obj, Load.Ptr);
+ if (!BVCOrErr)
+ return BVCOrErr.takeError();
+ MachO::build_version_command BVC = BVCOrErr.get();
+ if (Load.C.cmdsize !=
+ sizeof(MachO::build_version_command) +
+ BVC.ntools * sizeof(MachO::build_tool_version))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_BUILD_VERSION_COMMAND has incorrect cmdsize");
+
+ auto Start = Load.Ptr + sizeof(MachO::build_version_command);
+ BuildTools.resize(BVC.ntools);
+ for (unsigned i = 0; i < BVC.ntools; ++i)
+ BuildTools[i] = Start + i * sizeof(MachO::build_tool_version);
+
+ return Error::success();
+}
+
+static Error checkRpathCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex) {
+ if (Load.C.cmdsize < sizeof(MachO::rpath_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_RPATH cmdsize too small");
+ auto ROrErr = getStructOrErr<MachO::rpath_command>(Obj, Load.Ptr);
+ if (!ROrErr)
+ return ROrErr.takeError();
+ MachO::rpath_command R = ROrErr.get();
+ if (R.path < sizeof(MachO::rpath_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_RPATH path.offset field too small, not past "
+ "the end of the rpath_command struct");
+ if (R.path >= R.cmdsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_RPATH path.offset field extends past the end "
+ "of the load command");
+ // Make sure there is a null between the starting offset of the path and
+ // the end of the load command.
+ uint32_t i;
+ const char *P = (const char *)Load.Ptr;
+ for (i = R.path; i < R.cmdsize; i++)
+ if (P[i] == '\0')
+ break;
+ if (i >= R.cmdsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_RPATH library name extends past the end of the "
+ "load command");
+ return Error::success();
+}
+
+static Error checkEncryptCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ uint64_t cryptoff, uint64_t cryptsize,
+ const char **LoadCmd, const char *CmdName) {
+ if (*LoadCmd != nullptr)
+ return malformedError("more than one LC_ENCRYPTION_INFO and or "
+ "LC_ENCRYPTION_INFO_64 command");
+ uint64_t FileSize = Obj.getData().size();
+ if (cryptoff > FileSize)
+ return malformedError("cryptoff field of " + Twine(CmdName) +
+ " command " + Twine(LoadCommandIndex) + " extends "
+ "past the end of the file");
+ uint64_t BigSize = cryptoff;
+ BigSize += cryptsize;
+ if (BigSize > FileSize)
+ return malformedError("cryptoff field plus cryptsize field of " +
+ Twine(CmdName) + " command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ *LoadCmd = Load.Ptr;
+ return Error::success();
+}
+
+static Error checkLinkerOptCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex) {
+ if (Load.C.cmdsize < sizeof(MachO::linker_option_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_LINKER_OPTION cmdsize too small");
+ auto LinkOptionOrErr =
+ getStructOrErr<MachO::linker_option_command>(Obj, Load.Ptr);
+ if (!LinkOptionOrErr)
+ return LinkOptionOrErr.takeError();
+ MachO::linker_option_command L = LinkOptionOrErr.get();
+ // Make sure the count of strings is correct.
+ const char *string = (const char *)Load.Ptr +
+ sizeof(struct MachO::linker_option_command);
+ uint32_t left = L.cmdsize - sizeof(struct MachO::linker_option_command);
+ uint32_t i = 0;
+ while (left > 0) {
+ while (*string == '\0' && left > 0) {
+ string++;
+ left--;
+ }
+ if (left > 0) {
+ i++;
+ uint32_t NullPos = StringRef(string, left).find('\0');
+ if (0xffffffff == NullPos)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_LINKER_OPTION string #" + Twine(i) +
+ " is not NULL terminated");
+ uint32_t len = std::min(NullPos, left) + 1;
+ string += len;
+ left -= len;
+ }
+ }
+ if (L.count != i)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_LINKER_OPTION string count " + Twine(L.count) +
+ " does not match number of strings");
+ return Error::success();
+}
+
+static Error checkSubCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex, const char *CmdName,
+ size_t SizeOfCmd, const char *CmdStructName,
+ uint32_t PathOffset, const char *PathFieldName) {
+ if (PathOffset < SizeOfCmd)
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " " + PathFieldName + ".offset field too "
+ "small, not past the end of the " + CmdStructName);
+ if (PathOffset >= Load.C.cmdsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " " + PathFieldName + ".offset field "
+ "extends past the end of the load command");
+ // Make sure there is a null between the starting offset of the path and
+ // the end of the load command.
+ uint32_t i;
+ const char *P = (const char *)Load.Ptr;
+ for (i = PathOffset; i < Load.C.cmdsize; i++)
+ if (P[i] == '\0')
+ break;
+ if (i >= Load.C.cmdsize)
+ return malformedError("load command " + Twine(LoadCommandIndex) + " " +
+ CmdName + " " + PathFieldName + " name extends past "
+ "the end of the load command");
+ return Error::success();
+}
+
+static Error checkThreadCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo &Load,
+ uint32_t LoadCommandIndex,
+ const char *CmdName) {
+ if (Load.C.cmdsize < sizeof(MachO::thread_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ CmdName + " cmdsize too small");
+ auto ThreadCommandOrErr =
+ getStructOrErr<MachO::thread_command>(Obj, Load.Ptr);
+ if (!ThreadCommandOrErr)
+ return ThreadCommandOrErr.takeError();
+ MachO::thread_command T = ThreadCommandOrErr.get();
+ const char *state = Load.Ptr + sizeof(MachO::thread_command);
+ const char *end = Load.Ptr + T.cmdsize;
+ uint32_t nflavor = 0;
+ uint32_t cputype = getCPUType(Obj);
+ while (state < end) {
+ if(state + sizeof(uint32_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ "flavor in " + CmdName + " extends past end of "
+ "command");
+ uint32_t flavor;
+ memcpy(&flavor, state, sizeof(uint32_t));
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(flavor);
+ state += sizeof(uint32_t);
+
+ if(state + sizeof(uint32_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count in " + CmdName + " extends past end of "
+ "command");
+ uint32_t count;
+ memcpy(&count, state, sizeof(uint32_t));
+ if (Obj.isLittleEndian() != sys::IsLittleEndianHost)
+ sys::swapByteOrder(count);
+ state += sizeof(uint32_t);
+
+ if (cputype == MachO::CPU_TYPE_I386) {
+ if (flavor == MachO::x86_THREAD_STATE32) {
+ if (count != MachO::x86_THREAD_STATE32_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not x86_THREAD_STATE32_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a x86_THREAD_STATE32 flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::x86_thread_state32_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " x86_THREAD_STATE32 extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::x86_thread_state32_t);
+ } else {
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " unknown flavor (" + Twine(flavor) + ") for "
+ "flavor number " + Twine(nflavor) + " in " +
+ CmdName + " command");
+ }
+ } else if (cputype == MachO::CPU_TYPE_X86_64) {
+ if (flavor == MachO::x86_THREAD_STATE) {
+ if (count != MachO::x86_THREAD_STATE_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not x86_THREAD_STATE_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a x86_THREAD_STATE flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::x86_thread_state_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " x86_THREAD_STATE extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::x86_thread_state_t);
+ } else if (flavor == MachO::x86_FLOAT_STATE) {
+ if (count != MachO::x86_FLOAT_STATE_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not x86_FLOAT_STATE_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a x86_FLOAT_STATE flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::x86_float_state_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " x86_FLOAT_STATE extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::x86_float_state_t);
+ } else if (flavor == MachO::x86_EXCEPTION_STATE) {
+ if (count != MachO::x86_EXCEPTION_STATE_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not x86_EXCEPTION_STATE_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a x86_EXCEPTION_STATE flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::x86_exception_state_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " x86_EXCEPTION_STATE extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::x86_exception_state_t);
+ } else if (flavor == MachO::x86_THREAD_STATE64) {
+ if (count != MachO::x86_THREAD_STATE64_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not x86_THREAD_STATE64_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a x86_THREAD_STATE64 flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::x86_thread_state64_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " x86_THREAD_STATE64 extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::x86_thread_state64_t);
+ } else if (flavor == MachO::x86_EXCEPTION_STATE64) {
+ if (count != MachO::x86_EXCEPTION_STATE64_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not x86_EXCEPTION_STATE64_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a x86_EXCEPTION_STATE64 flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::x86_exception_state64_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " x86_EXCEPTION_STATE64 extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::x86_exception_state64_t);
+ } else {
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " unknown flavor (" + Twine(flavor) + ") for "
+ "flavor number " + Twine(nflavor) + " in " +
+ CmdName + " command");
+ }
+ } else if (cputype == MachO::CPU_TYPE_ARM) {
+ if (flavor == MachO::ARM_THREAD_STATE) {
+ if (count != MachO::ARM_THREAD_STATE_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not ARM_THREAD_STATE_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a ARM_THREAD_STATE flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::arm_thread_state32_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " ARM_THREAD_STATE extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::arm_thread_state32_t);
+ } else {
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " unknown flavor (" + Twine(flavor) + ") for "
+ "flavor number " + Twine(nflavor) + " in " +
+ CmdName + " command");
+ }
+ } else if (cputype == MachO::CPU_TYPE_ARM64 ||
+ cputype == MachO::CPU_TYPE_ARM64_32) {
+ if (flavor == MachO::ARM_THREAD_STATE64) {
+ if (count != MachO::ARM_THREAD_STATE64_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not ARM_THREAD_STATE64_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a ARM_THREAD_STATE64 flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::arm_thread_state64_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " ARM_THREAD_STATE64 extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::arm_thread_state64_t);
+ } else {
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " unknown flavor (" + Twine(flavor) + ") for "
+ "flavor number " + Twine(nflavor) + " in " +
+ CmdName + " command");
+ }
+ } else if (cputype == MachO::CPU_TYPE_POWERPC) {
+ if (flavor == MachO::PPC_THREAD_STATE) {
+ if (count != MachO::PPC_THREAD_STATE_COUNT)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " count not PPC_THREAD_STATE_COUNT for "
+ "flavor number " + Twine(nflavor) + " which is "
+ "a PPC_THREAD_STATE flavor in " + CmdName +
+ " command");
+ if (state + sizeof(MachO::ppc_thread_state32_t) > end)
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " PPC_THREAD_STATE extends past end of "
+ "command in " + CmdName + " command");
+ state += sizeof(MachO::ppc_thread_state32_t);
+ } else {
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " unknown flavor (" + Twine(flavor) + ") for "
+ "flavor number " + Twine(nflavor) + " in " +
+ CmdName + " command");
+ }
+ } else {
+ return malformedError("unknown cputype (" + Twine(cputype) + ") load "
+ "command " + Twine(LoadCommandIndex) + " for " +
+ CmdName + " command can't be checked");
+ }
+ nflavor++;
+ }
+ return Error::success();
+}
+
+static Error checkTwoLevelHintsCommand(const MachOObjectFile &Obj,
+ const MachOObjectFile::LoadCommandInfo
+ &Load,
+ uint32_t LoadCommandIndex,
+ const char **LoadCmd,
+ std::list<MachOElement> &Elements) {
+ if (Load.C.cmdsize != sizeof(MachO::twolevel_hints_command))
+ return malformedError("load command " + Twine(LoadCommandIndex) +
+ " LC_TWOLEVEL_HINTS has incorrect cmdsize");
+ if (*LoadCmd != nullptr)
+ return malformedError("more than one LC_TWOLEVEL_HINTS command");
+ auto HintsOrErr = getStructOrErr<MachO::twolevel_hints_command>(Obj, Load.Ptr);
+ if(!HintsOrErr)
+ return HintsOrErr.takeError();
+ MachO::twolevel_hints_command Hints = HintsOrErr.get();
+ uint64_t FileSize = Obj.getData().size();
+ if (Hints.offset > FileSize)
+ return malformedError("offset field of LC_TWOLEVEL_HINTS command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ uint64_t BigSize = Hints.nhints;
+ BigSize *= sizeof(MachO::twolevel_hint);
+ BigSize += Hints.offset;
+ if (BigSize > FileSize)
+ return malformedError("offset field plus nhints times sizeof(struct "
+ "twolevel_hint) field of LC_TWOLEVEL_HINTS command " +
+ Twine(LoadCommandIndex) + " extends past the end of "
+ "the file");
+ if (Error Err = checkOverlappingElement(Elements, Hints.offset, Hints.nhints *
+ sizeof(MachO::twolevel_hint),
+ "two level hints"))
+ return Err;
+ *LoadCmd = Load.Ptr;
+ return Error::success();
+}
+
+// Returns true if the libObject code does not support the load command and its
+// contents. The cmd value it is treated as an unknown load command but with
+// an error message that says the cmd value is obsolete.
+static bool isLoadCommandObsolete(uint32_t cmd) {
+ if (cmd == MachO::LC_SYMSEG ||
+ cmd == MachO::LC_LOADFVMLIB ||
+ cmd == MachO::LC_IDFVMLIB ||
+ cmd == MachO::LC_IDENT ||
+ cmd == MachO::LC_FVMFILE ||
+ cmd == MachO::LC_PREPAGE ||
+ cmd == MachO::LC_PREBOUND_DYLIB ||
+ cmd == MachO::LC_TWOLEVEL_HINTS ||
+ cmd == MachO::LC_PREBIND_CKSUM)
+ return true;
+ return false;
+}
+
+Expected<std::unique_ptr<MachOObjectFile>>
+MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
+ bool Is64Bits, uint32_t UniversalCputype,
+ uint32_t UniversalIndex) {
+ Error Err = Error::success();
+ std::unique_ptr<MachOObjectFile> Obj(
+ new MachOObjectFile(std::move(Object), IsLittleEndian,
+ Is64Bits, Err, UniversalCputype,
+ UniversalIndex));
+ if (Err)
+ return std::move(Err);
+ return std::move(Obj);
+}
+
+MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
+ bool Is64bits, Error &Err,
+ uint32_t UniversalCputype,
+ uint32_t UniversalIndex)
+ : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object) {
+ ErrorAsOutParameter ErrAsOutParam(&Err);
+ uint64_t SizeOfHeaders;
+ uint32_t cputype;
+ if (is64Bit()) {
+ parseHeader(*this, Header64, Err);
+ SizeOfHeaders = sizeof(MachO::mach_header_64);
+ cputype = Header64.cputype;
+ } else {
+ parseHeader(*this, Header, Err);
+ SizeOfHeaders = sizeof(MachO::mach_header);
+ cputype = Header.cputype;
+ }
+ if (Err)
+ return;
+ SizeOfHeaders += getHeader().sizeofcmds;
+ if (getData().data() + SizeOfHeaders > getData().end()) {
+ Err = malformedError("load commands extend past the end of the file");
+ return;
+ }
+ if (UniversalCputype != 0 && cputype != UniversalCputype) {
+ Err = malformedError("universal header architecture: " +
+ Twine(UniversalIndex) + "'s cputype does not match "
+ "object file's mach header");
+ return;
+ }
+ std::list<MachOElement> Elements;
+ Elements.push_back({0, SizeOfHeaders, "Mach-O headers"});
+
+ uint32_t LoadCommandCount = getHeader().ncmds;
+ LoadCommandInfo Load;
+ if (LoadCommandCount != 0) {
+ if (auto LoadOrErr = getFirstLoadCommandInfo(*this))
+ Load = *LoadOrErr;
+ else {
+ Err = LoadOrErr.takeError();
+ return;
+ }
+ }
+
+ const char *DyldIdLoadCmd = nullptr;
+ const char *FuncStartsLoadCmd = nullptr;
+ const char *SplitInfoLoadCmd = nullptr;
+ const char *CodeSignDrsLoadCmd = nullptr;
+ const char *CodeSignLoadCmd = nullptr;
+ const char *VersLoadCmd = nullptr;
+ const char *SourceLoadCmd = nullptr;
+ const char *EntryPointLoadCmd = nullptr;
+ const char *EncryptLoadCmd = nullptr;
+ const char *RoutinesLoadCmd = nullptr;
+ const char *UnixThreadLoadCmd = nullptr;
+ const char *TwoLevelHintsLoadCmd = nullptr;
+ for (unsigned I = 0; I < LoadCommandCount; ++I) {
+ if (is64Bit()) {
+ if (Load.C.cmdsize % 8 != 0) {
+ // We have a hack here to allow 64-bit Mach-O core files to have
+ // LC_THREAD commands that are only a multiple of 4 and not 8 to be
+ // allowed since the macOS kernel produces them.
+ if (getHeader().filetype != MachO::MH_CORE ||
+ Load.C.cmd != MachO::LC_THREAD || Load.C.cmdsize % 4) {
+ Err = malformedError("load command " + Twine(I) + " cmdsize not a "
+ "multiple of 8");
+ return;
+ }
+ }
+ } else {
+ if (Load.C.cmdsize % 4 != 0) {
+ Err = malformedError("load command " + Twine(I) + " cmdsize not a "
+ "multiple of 4");
+ return;
+ }
+ }
+ LoadCommands.push_back(Load);
+ if (Load.C.cmd == MachO::LC_SYMTAB) {
+ if ((Err = checkSymtabCommand(*this, Load, I, &SymtabLoadCmd, Elements)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_DYSYMTAB) {
+ if ((Err = checkDysymtabCommand(*this, Load, I, &DysymtabLoadCmd,
+ Elements)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_DATA_IN_CODE) {
+ if ((Err = checkLinkeditDataCommand(*this, Load, I, &DataInCodeLoadCmd,
+ "LC_DATA_IN_CODE", Elements,
+ "data in code info")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_LINKER_OPTIMIZATION_HINT) {
+ if ((Err = checkLinkeditDataCommand(*this, Load, I, &LinkOptHintsLoadCmd,
+ "LC_LINKER_OPTIMIZATION_HINT",
+ Elements, "linker optimization "
+ "hints")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_FUNCTION_STARTS) {
+ if ((Err = checkLinkeditDataCommand(*this, Load, I, &FuncStartsLoadCmd,
+ "LC_FUNCTION_STARTS", Elements,
+ "function starts data")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_SEGMENT_SPLIT_INFO) {
+ if ((Err = checkLinkeditDataCommand(*this, Load, I, &SplitInfoLoadCmd,
+ "LC_SEGMENT_SPLIT_INFO", Elements,
+ "split info data")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_DYLIB_CODE_SIGN_DRS) {
+ if ((Err = checkLinkeditDataCommand(*this, Load, I, &CodeSignDrsLoadCmd,
+ "LC_DYLIB_CODE_SIGN_DRS", Elements,
+ "code signing RDs data")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_CODE_SIGNATURE) {
+ if ((Err = checkLinkeditDataCommand(*this, Load, I, &CodeSignLoadCmd,
+ "LC_CODE_SIGNATURE", Elements,
+ "code signature data")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_DYLD_INFO) {
+ if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,
+ "LC_DYLD_INFO", Elements)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_DYLD_INFO_ONLY) {
+ if ((Err = checkDyldInfoCommand(*this, Load, I, &DyldInfoLoadCmd,
+ "LC_DYLD_INFO_ONLY", Elements)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_UUID) {
+ if (Load.C.cmdsize != sizeof(MachO::uuid_command)) {
+ Err = malformedError("LC_UUID command " + Twine(I) + " has incorrect "
+ "cmdsize");
+ return;
+ }
+ if (UuidLoadCmd) {
+ Err = malformedError("more than one LC_UUID command");
+ return;
+ }
+ UuidLoadCmd = Load.Ptr;
+ } else if (Load.C.cmd == MachO::LC_SEGMENT_64) {
+ if ((Err = parseSegmentLoadCommand<MachO::segment_command_64,
+ MachO::section_64>(
+ *this, Load, Sections, HasPageZeroSegment, I,
+ "LC_SEGMENT_64", SizeOfHeaders, Elements)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_SEGMENT) {
+ if ((Err = parseSegmentLoadCommand<MachO::segment_command,
+ MachO::section>(
+ *this, Load, Sections, HasPageZeroSegment, I,
+ "LC_SEGMENT", SizeOfHeaders, Elements)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_ID_DYLIB) {
+ if ((Err = checkDylibIdCommand(*this, Load, I, &DyldIdLoadCmd)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB) {
+ if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_DYLIB")))
+ return;
+ Libraries.push_back(Load.Ptr);
+ } else if (Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB) {
+ if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_WEAK_DYLIB")))
+ return;
+ Libraries.push_back(Load.Ptr);
+ } else if (Load.C.cmd == MachO::LC_LAZY_LOAD_DYLIB) {
+ if ((Err = checkDylibCommand(*this, Load, I, "LC_LAZY_LOAD_DYLIB")))
+ return;
+ Libraries.push_back(Load.Ptr);
+ } else if (Load.C.cmd == MachO::LC_REEXPORT_DYLIB) {
+ if ((Err = checkDylibCommand(*this, Load, I, "LC_REEXPORT_DYLIB")))
+ return;
+ Libraries.push_back(Load.Ptr);
+ } else if (Load.C.cmd == MachO::LC_LOAD_UPWARD_DYLIB) {
+ if ((Err = checkDylibCommand(*this, Load, I, "LC_LOAD_UPWARD_DYLIB")))
+ return;
+ Libraries.push_back(Load.Ptr);
+ } else if (Load.C.cmd == MachO::LC_ID_DYLINKER) {
+ if ((Err = checkDyldCommand(*this, Load, I, "LC_ID_DYLINKER")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_LOAD_DYLINKER) {
+ if ((Err = checkDyldCommand(*this, Load, I, "LC_LOAD_DYLINKER")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_DYLD_ENVIRONMENT) {
+ if ((Err = checkDyldCommand(*this, Load, I, "LC_DYLD_ENVIRONMENT")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_VERSION_MIN_MACOSX) {
+ if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
+ "LC_VERSION_MIN_MACOSX")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_VERSION_MIN_IPHONEOS) {
+ if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
+ "LC_VERSION_MIN_IPHONEOS")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_VERSION_MIN_TVOS) {
+ if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
+ "LC_VERSION_MIN_TVOS")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) {
+ if ((Err = checkVersCommand(*this, Load, I, &VersLoadCmd,
+ "LC_VERSION_MIN_WATCHOS")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_NOTE) {
+ if ((Err = checkNoteCommand(*this, Load, I, Elements)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_BUILD_VERSION) {
+ if ((Err = parseBuildVersionCommand(*this, Load, BuildTools, I)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_RPATH) {
+ if ((Err = checkRpathCommand(*this, Load, I)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_SOURCE_VERSION) {
+ if (Load.C.cmdsize != sizeof(MachO::source_version_command)) {
+ Err = malformedError("LC_SOURCE_VERSION command " + Twine(I) +
+ " has incorrect cmdsize");
+ return;
+ }
+ if (SourceLoadCmd) {
+ Err = malformedError("more than one LC_SOURCE_VERSION command");
+ return;
+ }
+ SourceLoadCmd = Load.Ptr;
+ } else if (Load.C.cmd == MachO::LC_MAIN) {
+ if (Load.C.cmdsize != sizeof(MachO::entry_point_command)) {
+ Err = malformedError("LC_MAIN command " + Twine(I) +
+ " has incorrect cmdsize");
+ return;
+ }
+ if (EntryPointLoadCmd) {
+ Err = malformedError("more than one LC_MAIN command");
+ return;
+ }
+ EntryPointLoadCmd = Load.Ptr;
+ } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO) {
+ if (Load.C.cmdsize != sizeof(MachO::encryption_info_command)) {
+ Err = malformedError("LC_ENCRYPTION_INFO command " + Twine(I) +
+ " has incorrect cmdsize");
+ return;
+ }
+ MachO::encryption_info_command E =
+ getStruct<MachO::encryption_info_command>(*this, Load.Ptr);
+ if ((Err = checkEncryptCommand(*this, Load, I, E.cryptoff, E.cryptsize,
+ &EncryptLoadCmd, "LC_ENCRYPTION_INFO")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_ENCRYPTION_INFO_64) {
+ if (Load.C.cmdsize != sizeof(MachO::encryption_info_command_64)) {
+ Err = malformedError("LC_ENCRYPTION_INFO_64 command " + Twine(I) +
+ " has incorrect cmdsize");
+ return;
+ }
+ MachO::encryption_info_command_64 E =
+ getStruct<MachO::encryption_info_command_64>(*this, Load.Ptr);
+ if ((Err = checkEncryptCommand(*this, Load, I, E.cryptoff, E.cryptsize,
+ &EncryptLoadCmd, "LC_ENCRYPTION_INFO_64")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_LINKER_OPTION) {
+ if ((Err = checkLinkerOptCommand(*this, Load, I)))
+ return;
+ } else if (Load.C.cmd == MachO::LC_SUB_FRAMEWORK) {
+ if (Load.C.cmdsize < sizeof(MachO::sub_framework_command)) {
+ Err = malformedError("load command " + Twine(I) +
+ " LC_SUB_FRAMEWORK cmdsize too small");
+ return;
+ }
+ MachO::sub_framework_command S =
+ getStruct<MachO::sub_framework_command>(*this, Load.Ptr);
+ if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_FRAMEWORK",
+ sizeof(MachO::sub_framework_command),
+ "sub_framework_command", S.umbrella,
+ "umbrella")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_SUB_UMBRELLA) {
+ if (Load.C.cmdsize < sizeof(MachO::sub_umbrella_command)) {
+ Err = malformedError("load command " + Twine(I) +
+ " LC_SUB_UMBRELLA cmdsize too small");
+ return;
+ }
+ MachO::sub_umbrella_command S =
+ getStruct<MachO::sub_umbrella_command>(*this, Load.Ptr);
+ if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_UMBRELLA",
+ sizeof(MachO::sub_umbrella_command),
+ "sub_umbrella_command", S.sub_umbrella,
+ "sub_umbrella")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_SUB_LIBRARY) {
+ if (Load.C.cmdsize < sizeof(MachO::sub_library_command)) {
+ Err = malformedError("load command " + Twine(I) +
+ " LC_SUB_LIBRARY cmdsize too small");
+ return;
+ }
+ MachO::sub_library_command S =
+ getStruct<MachO::sub_library_command>(*this, Load.Ptr);
+ if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_LIBRARY",
+ sizeof(MachO::sub_library_command),
+ "sub_library_command", S.sub_library,
+ "sub_library")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_SUB_CLIENT) {
+ if (Load.C.cmdsize < sizeof(MachO::sub_client_command)) {
+ Err = malformedError("load command " + Twine(I) +
+ " LC_SUB_CLIENT cmdsize too small");
+ return;
+ }
+ MachO::sub_client_command S =
+ getStruct<MachO::sub_client_command>(*this, Load.Ptr);
+ if ((Err = checkSubCommand(*this, Load, I, "LC_SUB_CLIENT",
+ sizeof(MachO::sub_client_command),
+ "sub_client_command", S.client, "client")))
+ return;
+ } else if (Load.C.cmd == MachO::LC_ROUTINES) {
+ if (Load.C.cmdsize != sizeof(MachO::routines_command)) {
+ Err = malformedError("LC_ROUTINES command " + Twine(I) +
+ " has incorrect cmdsize");
+ return;
+ }
+ if (RoutinesLoadCmd) {
+ Err = malformedError("more than one LC_ROUTINES and or LC_ROUTINES_64 "
+ "command");
+ return;
+ }
+ RoutinesLoadCmd = Load.Ptr;
+ } else if (Load.C.cmd == MachO::LC_ROUTINES_64) {
+ if (Load.C.cmdsize != sizeof(MachO::routines_command_64)) {
+ Err = malformedError("LC_ROUTINES_64 command " + Twine(I) +
+ " has incorrect cmdsize");
+ return;
+ }
+ if (RoutinesLoadCmd) {
+ Err = malformedError("more than one LC_ROUTINES_64 and or LC_ROUTINES "
+ "command");
+ return;
+ }
+ RoutinesLoadCmd = Load.Ptr;
+ } else if (Load.C.cmd == MachO::LC_UNIXTHREAD) {
+ if ((Err = checkThreadCommand(*this, Load, I, "LC_UNIXTHREAD")))
+ return;
+ if (UnixThreadLoadCmd) {
+ Err = malformedError("more than one LC_UNIXTHREAD command");
+ return;
+ }
+ UnixThreadLoadCmd = Load.Ptr;
+ } else if (Load.C.cmd == MachO::LC_THREAD) {
+ if ((Err = checkThreadCommand(*this, Load, I, "LC_THREAD")))
+ return;
+ // Note: LC_TWOLEVEL_HINTS is really obsolete and is not supported.
+ } else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) {
+ if ((Err = checkTwoLevelHintsCommand(*this, Load, I,
+ &TwoLevelHintsLoadCmd, Elements)))
+ return;
} else if (Load.C.cmd == MachO::LC_IDENT) {
// Note: LC_IDENT is ignored.
continue;
- } else if (isLoadCommandObsolete(Load.C.cmd)) {
- Err = malformedError("load command " + Twine(I) + " for cmd value of: " +
- Twine(Load.C.cmd) + " is obsolete and not "
- "supported");
- return;
- }
- // TODO: generate a error for unknown load commands by default. But still
- // need work out an approach to allow or not allow unknown values like this
- // as an option for some uses like lldb.
- if (I < LoadCommandCount - 1) {
- if (auto LoadOrErr = getNextLoadCommandInfo(*this, I, Load))
- Load = *LoadOrErr;
- else {
- Err = LoadOrErr.takeError();
- return;
- }
- }
- }
- if (!SymtabLoadCmd) {
- if (DysymtabLoadCmd) {
- Err = malformedError("contains LC_DYSYMTAB load command without a "
- "LC_SYMTAB load command");
- return;
- }
- } else if (DysymtabLoadCmd) {
- MachO::symtab_command Symtab =
- getStruct<MachO::symtab_command>(*this, SymtabLoadCmd);
- MachO::dysymtab_command Dysymtab =
- getStruct<MachO::dysymtab_command>(*this, DysymtabLoadCmd);
- if (Dysymtab.nlocalsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) {
- Err = malformedError("ilocalsym in LC_DYSYMTAB load command "
- "extends past the end of the symbol table");
- return;
- }
- uint64_t BigSize = Dysymtab.ilocalsym;
- BigSize += Dysymtab.nlocalsym;
- if (Dysymtab.nlocalsym != 0 && BigSize > Symtab.nsyms) {
- Err = malformedError("ilocalsym plus nlocalsym in LC_DYSYMTAB load "
- "command extends past the end of the symbol table");
- return;
- }
- if (Dysymtab.nextdefsym != 0 && Dysymtab.iextdefsym > Symtab.nsyms) {
- Err = malformedError("iextdefsym in LC_DYSYMTAB load command "
- "extends past the end of the symbol table");
- return;
- }
- BigSize = Dysymtab.iextdefsym;
- BigSize += Dysymtab.nextdefsym;
- if (Dysymtab.nextdefsym != 0 && BigSize > Symtab.nsyms) {
- Err = malformedError("iextdefsym plus nextdefsym in LC_DYSYMTAB "
- "load command extends past the end of the symbol "
- "table");
- return;
- }
- if (Dysymtab.nundefsym != 0 && Dysymtab.iundefsym > Symtab.nsyms) {
- Err = malformedError("iundefsym in LC_DYSYMTAB load command "
- "extends past the end of the symbol table");
- return;
- }
- BigSize = Dysymtab.iundefsym;
- BigSize += Dysymtab.nundefsym;
- if (Dysymtab.nundefsym != 0 && BigSize > Symtab.nsyms) {
- Err = malformedError("iundefsym plus nundefsym in LC_DYSYMTAB load "
- " command extends past the end of the symbol table");
- return;
- }
- }
- if ((getHeader().filetype == MachO::MH_DYLIB ||
- getHeader().filetype == MachO::MH_DYLIB_STUB) &&
- DyldIdLoadCmd == nullptr) {
- Err = malformedError("no LC_ID_DYLIB load command in dynamic library "
- "filetype");
- return;
- }
- assert(LoadCommands.size() == LoadCommandCount);
-
- Err = Error::success();
-}
-
-Error MachOObjectFile::checkSymbolTable() const {
- uint32_t Flags = 0;
- if (is64Bit()) {
- MachO::mach_header_64 H_64 = MachOObjectFile::getHeader64();
- Flags = H_64.flags;
- } else {
- MachO::mach_header H = MachOObjectFile::getHeader();
- Flags = H.flags;
- }
- uint8_t NType = 0;
- uint8_t NSect = 0;
- uint16_t NDesc = 0;
- uint32_t NStrx = 0;
- uint64_t NValue = 0;
- uint32_t SymbolIndex = 0;
- MachO::symtab_command S = getSymtabLoadCommand();
- for (const SymbolRef &Symbol : symbols()) {
- DataRefImpl SymDRI = Symbol.getRawDataRefImpl();
- if (is64Bit()) {
- MachO::nlist_64 STE_64 = getSymbol64TableEntry(SymDRI);
- NType = STE_64.n_type;
- NSect = STE_64.n_sect;
- NDesc = STE_64.n_desc;
- NStrx = STE_64.n_strx;
- NValue = STE_64.n_value;
- } else {
- MachO::nlist STE = getSymbolTableEntry(SymDRI);
- NType = STE.n_type;
- NSect = STE.n_sect;
- NDesc = STE.n_desc;
- NStrx = STE.n_strx;
- NValue = STE.n_value;
- }
- if ((NType & MachO::N_STAB) == 0) {
- if ((NType & MachO::N_TYPE) == MachO::N_SECT) {
- if (NSect == 0 || NSect > Sections.size())
- return malformedError("bad section index: " + Twine((int)NSect) +
- " for symbol at index " + Twine(SymbolIndex));
- }
- if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
- if (NValue >= S.strsize)
- return malformedError("bad n_value: " + Twine((int)NValue) + " past "
- "the end of string table, for N_INDR symbol at "
- "index " + Twine(SymbolIndex));
- }
- if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
- (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
- (NType & MachO::N_TYPE) == MachO::N_PBUD)) {
- uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);
- if (LibraryOrdinal != 0 &&
- LibraryOrdinal != MachO::EXECUTABLE_ORDINAL &&
- LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL &&
- LibraryOrdinal - 1 >= Libraries.size() ) {
- return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) +
- " for symbol at index " + Twine(SymbolIndex));
- }
- }
- }
- if (NStrx >= S.strsize)
- return malformedError("bad string table index: " + Twine((int)NStrx) +
- " past the end of string table, for symbol at "
- "index " + Twine(SymbolIndex));
- SymbolIndex++;
- }
- return Error::success();
-}
-
-void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
- unsigned SymbolTableEntrySize = is64Bit() ?
- sizeof(MachO::nlist_64) :
- sizeof(MachO::nlist);
- Symb.p += SymbolTableEntrySize;
-}
-
-Expected<StringRef> MachOObjectFile::getSymbolName(DataRefImpl Symb) const {
- StringRef StringTable = getStringTableData();
- MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
- if (Entry.n_strx == 0)
- // A n_strx value of 0 indicates that no name is associated with a
- // particular symbol table entry.
- return StringRef();
- const char *Start = &StringTable.data()[Entry.n_strx];
- if (Start < getData().begin() || Start >= getData().end()) {
- return malformedError("bad string index: " + Twine(Entry.n_strx) +
- " for symbol at index " + Twine(getSymbolIndex(Symb)));
- }
- return StringRef(Start);
-}
-
-unsigned MachOObjectFile::getSectionType(SectionRef Sec) const {
- DataRefImpl DRI = Sec.getRawDataRefImpl();
- uint32_t Flags = getSectionFlags(*this, DRI);
- return Flags & MachO::SECTION_TYPE;
-}
-
-uint64_t MachOObjectFile::getNValue(DataRefImpl Sym) const {
- if (is64Bit()) {
- MachO::nlist_64 Entry = getSymbol64TableEntry(Sym);
- return Entry.n_value;
- }
- MachO::nlist Entry = getSymbolTableEntry(Sym);
- return Entry.n_value;
-}
-
-// getIndirectName() returns the name of the alias'ed symbol who's string table
-// index is in the n_value field.
-std::error_code MachOObjectFile::getIndirectName(DataRefImpl Symb,
- StringRef &Res) const {
- StringRef StringTable = getStringTableData();
- MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
- if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR)
- return object_error::parse_failed;
- uint64_t NValue = getNValue(Symb);
- if (NValue >= StringTable.size())
- return object_error::parse_failed;
- const char *Start = &StringTable.data()[NValue];
- Res = StringRef(Start);
- return std::error_code();
-}
-
-uint64_t MachOObjectFile::getSymbolValueImpl(DataRefImpl Sym) const {
- return getNValue(Sym);
-}
-
-Expected<uint64_t> MachOObjectFile::getSymbolAddress(DataRefImpl Sym) const {
- return getSymbolValue(Sym);
-}
-
-uint32_t MachOObjectFile::getSymbolAlignment(DataRefImpl DRI) const {
- uint32_t Flags = cantFail(getSymbolFlags(DRI));
- if (Flags & SymbolRef::SF_Common) {
- MachO::nlist_base Entry = getSymbolTableEntryBase(*this, DRI);
- return 1 << MachO::GET_COMM_ALIGN(Entry.n_desc);
- }
- return 0;
-}
-
-uint64_t MachOObjectFile::getCommonSymbolSizeImpl(DataRefImpl DRI) const {
- return getNValue(DRI);
-}
-
-Expected<SymbolRef::Type>
-MachOObjectFile::getSymbolType(DataRefImpl Symb) const {
- MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
- uint8_t n_type = Entry.n_type;
-
- // If this is a STAB debugging symbol, we can do nothing more.
- if (n_type & MachO::N_STAB)
- return SymbolRef::ST_Debug;
-
- switch (n_type & MachO::N_TYPE) {
- case MachO::N_UNDF :
- return SymbolRef::ST_Unknown;
- case MachO::N_SECT :
- Expected<section_iterator> SecOrError = getSymbolSection(Symb);
- if (!SecOrError)
- return SecOrError.takeError();
- section_iterator Sec = *SecOrError;
- if (Sec->isData() || Sec->isBSS())
- return SymbolRef::ST_Data;
- return SymbolRef::ST_Function;
- }
- return SymbolRef::ST_Other;
-}
-
-Expected<uint32_t> MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const {
- MachO::nlist_base Entry = getSymbolTableEntryBase(*this, DRI);
-
- uint8_t MachOType = Entry.n_type;
- uint16_t MachOFlags = Entry.n_desc;
-
- uint32_t Result = SymbolRef::SF_None;
-
- if ((MachOType & MachO::N_TYPE) == MachO::N_INDR)
- Result |= SymbolRef::SF_Indirect;
-
- if (MachOType & MachO::N_STAB)
- Result |= SymbolRef::SF_FormatSpecific;
-
- if (MachOType & MachO::N_EXT) {
- Result |= SymbolRef::SF_Global;
- if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) {
- if (getNValue(DRI))
- Result |= SymbolRef::SF_Common;
- else
- Result |= SymbolRef::SF_Undefined;
- }
-
- if (!(MachOType & MachO::N_PEXT))
- Result |= SymbolRef::SF_Exported;
- }
-
- if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
- Result |= SymbolRef::SF_Weak;
-
- if (MachOFlags & (MachO::N_ARM_THUMB_DEF))
- Result |= SymbolRef::SF_Thumb;
-
- if ((MachOType & MachO::N_TYPE) == MachO::N_ABS)
- Result |= SymbolRef::SF_Absolute;
-
- return Result;
-}
-
-Expected<section_iterator>
-MachOObjectFile::getSymbolSection(DataRefImpl Symb) const {
- MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
- uint8_t index = Entry.n_sect;
-
- if (index == 0)
- return section_end();
- DataRefImpl DRI;
- DRI.d.a = index - 1;
- if (DRI.d.a >= Sections.size()){
- return malformedError("bad section index: " + Twine((int)index) +
- " for symbol at index " + Twine(getSymbolIndex(Symb)));
- }
- return section_iterator(SectionRef(DRI, this));
-}
-
-unsigned MachOObjectFile::getSymbolSectionID(SymbolRef Sym) const {
- MachO::nlist_base Entry =
- getSymbolTableEntryBase(*this, Sym.getRawDataRefImpl());
- return Entry.n_sect - 1;
-}
-
-void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const {
- Sec.d.a++;
-}
-
-Expected<StringRef> MachOObjectFile::getSectionName(DataRefImpl Sec) const {
- ArrayRef<char> Raw = getSectionRawName(Sec);
- return parseSegmentOrSectionName(Raw.data());
-}
-
-uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const {
- if (is64Bit())
- return getSection64(Sec).addr;
- return getSection(Sec).addr;
-}
-
-uint64_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const {
- return Sec.d.a;
-}
-
-uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const {
- // In the case if a malformed Mach-O file where the section offset is past
- // the end of the file or some part of the section size is past the end of
- // the file return a size of zero or a size that covers the rest of the file
- // but does not extend past the end of the file.
- uint32_t SectOffset, SectType;
- uint64_t SectSize;
-
- if (is64Bit()) {
- MachO::section_64 Sect = getSection64(Sec);
- SectOffset = Sect.offset;
- SectSize = Sect.size;
- SectType = Sect.flags & MachO::SECTION_TYPE;
- } else {
- MachO::section Sect = getSection(Sec);
- SectOffset = Sect.offset;
- SectSize = Sect.size;
- SectType = Sect.flags & MachO::SECTION_TYPE;
- }
- if (SectType == MachO::S_ZEROFILL || SectType == MachO::S_GB_ZEROFILL)
- return SectSize;
- uint64_t FileSize = getData().size();
- if (SectOffset > FileSize)
- return 0;
- if (FileSize - SectOffset < SectSize)
- return FileSize - SectOffset;
- return SectSize;
-}
-
-ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint32_t Offset,
- uint64_t Size) const {
- return arrayRefFromStringRef(getData().substr(Offset, Size));
-}
-
-Expected<ArrayRef<uint8_t>>
-MachOObjectFile::getSectionContents(DataRefImpl Sec) const {
- uint32_t Offset;
- uint64_t Size;
-
- if (is64Bit()) {
- MachO::section_64 Sect = getSection64(Sec);
- Offset = Sect.offset;
- Size = Sect.size;
- } else {
- MachO::section Sect = getSection(Sec);
- Offset = Sect.offset;
- Size = Sect.size;
- }
-
- return getSectionContents(Offset, Size);
-}
-
-uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const {
- uint32_t Align;
- if (is64Bit()) {
- MachO::section_64 Sect = getSection64(Sec);
- Align = Sect.align;
- } else {
- MachO::section Sect = getSection(Sec);
- Align = Sect.align;
- }
-
- return uint64_t(1) << Align;
-}
-
-Expected<SectionRef> MachOObjectFile::getSection(unsigned SectionIndex) const {
- if (SectionIndex < 1 || SectionIndex > Sections.size())
- return malformedError("bad section index: " + Twine((int)SectionIndex));
-
- DataRefImpl DRI;
- DRI.d.a = SectionIndex - 1;
- return SectionRef(DRI, this);
-}
-
-Expected<SectionRef> MachOObjectFile::getSection(StringRef SectionName) const {
- for (const SectionRef &Section : sections()) {
- auto NameOrErr = Section.getName();
- if (!NameOrErr)
- return NameOrErr.takeError();
- if (*NameOrErr == SectionName)
- return Section;
- }
- return errorCodeToError(object_error::parse_failed);
-}
-
-bool MachOObjectFile::isSectionCompressed(DataRefImpl Sec) const {
- return false;
-}
-
-bool MachOObjectFile::isSectionText(DataRefImpl Sec) const {
- uint32_t Flags = getSectionFlags(*this, Sec);
- return Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;
-}
-
-bool MachOObjectFile::isSectionData(DataRefImpl Sec) const {
- uint32_t Flags = getSectionFlags(*this, Sec);
- unsigned SectionType = Flags & MachO::SECTION_TYPE;
- return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) &&
- !(SectionType == MachO::S_ZEROFILL ||
- SectionType == MachO::S_GB_ZEROFILL);
-}
-
-bool MachOObjectFile::isSectionBSS(DataRefImpl Sec) const {
- uint32_t Flags = getSectionFlags(*this, Sec);
- unsigned SectionType = Flags & MachO::SECTION_TYPE;
- return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) &&
- (SectionType == MachO::S_ZEROFILL ||
- SectionType == MachO::S_GB_ZEROFILL);
-}
-
-bool MachOObjectFile::isDebugSection(StringRef SectionName) const {
- return SectionName.startswith("__debug") ||
+ } else if (isLoadCommandObsolete(Load.C.cmd)) {
+ Err = malformedError("load command " + Twine(I) + " for cmd value of: " +
+ Twine(Load.C.cmd) + " is obsolete and not "
+ "supported");
+ return;
+ }
+ // TODO: generate a error for unknown load commands by default. But still
+ // need work out an approach to allow or not allow unknown values like this
+ // as an option for some uses like lldb.
+ if (I < LoadCommandCount - 1) {
+ if (auto LoadOrErr = getNextLoadCommandInfo(*this, I, Load))
+ Load = *LoadOrErr;
+ else {
+ Err = LoadOrErr.takeError();
+ return;
+ }
+ }
+ }
+ if (!SymtabLoadCmd) {
+ if (DysymtabLoadCmd) {
+ Err = malformedError("contains LC_DYSYMTAB load command without a "
+ "LC_SYMTAB load command");
+ return;
+ }
+ } else if (DysymtabLoadCmd) {
+ MachO::symtab_command Symtab =
+ getStruct<MachO::symtab_command>(*this, SymtabLoadCmd);
+ MachO::dysymtab_command Dysymtab =
+ getStruct<MachO::dysymtab_command>(*this, DysymtabLoadCmd);
+ if (Dysymtab.nlocalsym != 0 && Dysymtab.ilocalsym > Symtab.nsyms) {
+ Err = malformedError("ilocalsym in LC_DYSYMTAB load command "
+ "extends past the end of the symbol table");
+ return;
+ }
+ uint64_t BigSize = Dysymtab.ilocalsym;
+ BigSize += Dysymtab.nlocalsym;
+ if (Dysymtab.nlocalsym != 0 && BigSize > Symtab.nsyms) {
+ Err = malformedError("ilocalsym plus nlocalsym in LC_DYSYMTAB load "
+ "command extends past the end of the symbol table");
+ return;
+ }
+ if (Dysymtab.nextdefsym != 0 && Dysymtab.iextdefsym > Symtab.nsyms) {
+ Err = malformedError("iextdefsym in LC_DYSYMTAB load command "
+ "extends past the end of the symbol table");
+ return;
+ }
+ BigSize = Dysymtab.iextdefsym;
+ BigSize += Dysymtab.nextdefsym;
+ if (Dysymtab.nextdefsym != 0 && BigSize > Symtab.nsyms) {
+ Err = malformedError("iextdefsym plus nextdefsym in LC_DYSYMTAB "
+ "load command extends past the end of the symbol "
+ "table");
+ return;
+ }
+ if (Dysymtab.nundefsym != 0 && Dysymtab.iundefsym > Symtab.nsyms) {
+ Err = malformedError("iundefsym in LC_DYSYMTAB load command "
+ "extends past the end of the symbol table");
+ return;
+ }
+ BigSize = Dysymtab.iundefsym;
+ BigSize += Dysymtab.nundefsym;
+ if (Dysymtab.nundefsym != 0 && BigSize > Symtab.nsyms) {
+ Err = malformedError("iundefsym plus nundefsym in LC_DYSYMTAB load "
+ " command extends past the end of the symbol table");
+ return;
+ }
+ }
+ if ((getHeader().filetype == MachO::MH_DYLIB ||
+ getHeader().filetype == MachO::MH_DYLIB_STUB) &&
+ DyldIdLoadCmd == nullptr) {
+ Err = malformedError("no LC_ID_DYLIB load command in dynamic library "
+ "filetype");
+ return;
+ }
+ assert(LoadCommands.size() == LoadCommandCount);
+
+ Err = Error::success();
+}
+
+Error MachOObjectFile::checkSymbolTable() const {
+ uint32_t Flags = 0;
+ if (is64Bit()) {
+ MachO::mach_header_64 H_64 = MachOObjectFile::getHeader64();
+ Flags = H_64.flags;
+ } else {
+ MachO::mach_header H = MachOObjectFile::getHeader();
+ Flags = H.flags;
+ }
+ uint8_t NType = 0;
+ uint8_t NSect = 0;
+ uint16_t NDesc = 0;
+ uint32_t NStrx = 0;
+ uint64_t NValue = 0;
+ uint32_t SymbolIndex = 0;
+ MachO::symtab_command S = getSymtabLoadCommand();
+ for (const SymbolRef &Symbol : symbols()) {
+ DataRefImpl SymDRI = Symbol.getRawDataRefImpl();
+ if (is64Bit()) {
+ MachO::nlist_64 STE_64 = getSymbol64TableEntry(SymDRI);
+ NType = STE_64.n_type;
+ NSect = STE_64.n_sect;
+ NDesc = STE_64.n_desc;
+ NStrx = STE_64.n_strx;
+ NValue = STE_64.n_value;
+ } else {
+ MachO::nlist STE = getSymbolTableEntry(SymDRI);
+ NType = STE.n_type;
+ NSect = STE.n_sect;
+ NDesc = STE.n_desc;
+ NStrx = STE.n_strx;
+ NValue = STE.n_value;
+ }
+ if ((NType & MachO::N_STAB) == 0) {
+ if ((NType & MachO::N_TYPE) == MachO::N_SECT) {
+ if (NSect == 0 || NSect > Sections.size())
+ return malformedError("bad section index: " + Twine((int)NSect) +
+ " for symbol at index " + Twine(SymbolIndex));
+ }
+ if ((NType & MachO::N_TYPE) == MachO::N_INDR) {
+ if (NValue >= S.strsize)
+ return malformedError("bad n_value: " + Twine((int)NValue) + " past "
+ "the end of string table, for N_INDR symbol at "
+ "index " + Twine(SymbolIndex));
+ }
+ if ((Flags & MachO::MH_TWOLEVEL) == MachO::MH_TWOLEVEL &&
+ (((NType & MachO::N_TYPE) == MachO::N_UNDF && NValue == 0) ||
+ (NType & MachO::N_TYPE) == MachO::N_PBUD)) {
+ uint32_t LibraryOrdinal = MachO::GET_LIBRARY_ORDINAL(NDesc);
+ if (LibraryOrdinal != 0 &&
+ LibraryOrdinal != MachO::EXECUTABLE_ORDINAL &&
+ LibraryOrdinal != MachO::DYNAMIC_LOOKUP_ORDINAL &&
+ LibraryOrdinal - 1 >= Libraries.size() ) {
+ return malformedError("bad library ordinal: " + Twine(LibraryOrdinal) +
+ " for symbol at index " + Twine(SymbolIndex));
+ }
+ }
+ }
+ if (NStrx >= S.strsize)
+ return malformedError("bad string table index: " + Twine((int)NStrx) +
+ " past the end of string table, for symbol at "
+ "index " + Twine(SymbolIndex));
+ SymbolIndex++;
+ }
+ return Error::success();
+}
+
+void MachOObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
+ unsigned SymbolTableEntrySize = is64Bit() ?
+ sizeof(MachO::nlist_64) :
+ sizeof(MachO::nlist);
+ Symb.p += SymbolTableEntrySize;
+}
+
+Expected<StringRef> MachOObjectFile::getSymbolName(DataRefImpl Symb) const {
+ StringRef StringTable = getStringTableData();
+ MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
+ if (Entry.n_strx == 0)
+ // A n_strx value of 0 indicates that no name is associated with a
+ // particular symbol table entry.
+ return StringRef();
+ const char *Start = &StringTable.data()[Entry.n_strx];
+ if (Start < getData().begin() || Start >= getData().end()) {
+ return malformedError("bad string index: " + Twine(Entry.n_strx) +
+ " for symbol at index " + Twine(getSymbolIndex(Symb)));
+ }
+ return StringRef(Start);
+}
+
+unsigned MachOObjectFile::getSectionType(SectionRef Sec) const {
+ DataRefImpl DRI = Sec.getRawDataRefImpl();
+ uint32_t Flags = getSectionFlags(*this, DRI);
+ return Flags & MachO::SECTION_TYPE;
+}
+
+uint64_t MachOObjectFile::getNValue(DataRefImpl Sym) const {
+ if (is64Bit()) {
+ MachO::nlist_64 Entry = getSymbol64TableEntry(Sym);
+ return Entry.n_value;
+ }
+ MachO::nlist Entry = getSymbolTableEntry(Sym);
+ return Entry.n_value;
+}
+
+// getIndirectName() returns the name of the alias'ed symbol who's string table
+// index is in the n_value field.
+std::error_code MachOObjectFile::getIndirectName(DataRefImpl Symb,
+ StringRef &Res) const {
+ StringRef StringTable = getStringTableData();
+ MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
+ if ((Entry.n_type & MachO::N_TYPE) != MachO::N_INDR)
+ return object_error::parse_failed;
+ uint64_t NValue = getNValue(Symb);
+ if (NValue >= StringTable.size())
+ return object_error::parse_failed;
+ const char *Start = &StringTable.data()[NValue];
+ Res = StringRef(Start);
+ return std::error_code();
+}
+
+uint64_t MachOObjectFile::getSymbolValueImpl(DataRefImpl Sym) const {
+ return getNValue(Sym);
+}
+
+Expected<uint64_t> MachOObjectFile::getSymbolAddress(DataRefImpl Sym) const {
+ return getSymbolValue(Sym);
+}
+
+uint32_t MachOObjectFile::getSymbolAlignment(DataRefImpl DRI) const {
+ uint32_t Flags = cantFail(getSymbolFlags(DRI));
+ if (Flags & SymbolRef::SF_Common) {
+ MachO::nlist_base Entry = getSymbolTableEntryBase(*this, DRI);
+ return 1 << MachO::GET_COMM_ALIGN(Entry.n_desc);
+ }
+ return 0;
+}
+
+uint64_t MachOObjectFile::getCommonSymbolSizeImpl(DataRefImpl DRI) const {
+ return getNValue(DRI);
+}
+
+Expected<SymbolRef::Type>
+MachOObjectFile::getSymbolType(DataRefImpl Symb) const {
+ MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
+ uint8_t n_type = Entry.n_type;
+
+ // If this is a STAB debugging symbol, we can do nothing more.
+ if (n_type & MachO::N_STAB)
+ return SymbolRef::ST_Debug;
+
+ switch (n_type & MachO::N_TYPE) {
+ case MachO::N_UNDF :
+ return SymbolRef::ST_Unknown;
+ case MachO::N_SECT :
+ Expected<section_iterator> SecOrError = getSymbolSection(Symb);
+ if (!SecOrError)
+ return SecOrError.takeError();
+ section_iterator Sec = *SecOrError;
+ if (Sec->isData() || Sec->isBSS())
+ return SymbolRef::ST_Data;
+ return SymbolRef::ST_Function;
+ }
+ return SymbolRef::ST_Other;
+}
+
+Expected<uint32_t> MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const {
+ MachO::nlist_base Entry = getSymbolTableEntryBase(*this, DRI);
+
+ uint8_t MachOType = Entry.n_type;
+ uint16_t MachOFlags = Entry.n_desc;
+
+ uint32_t Result = SymbolRef::SF_None;
+
+ if ((MachOType & MachO::N_TYPE) == MachO::N_INDR)
+ Result |= SymbolRef::SF_Indirect;
+
+ if (MachOType & MachO::N_STAB)
+ Result |= SymbolRef::SF_FormatSpecific;
+
+ if (MachOType & MachO::N_EXT) {
+ Result |= SymbolRef::SF_Global;
+ if ((MachOType & MachO::N_TYPE) == MachO::N_UNDF) {
+ if (getNValue(DRI))
+ Result |= SymbolRef::SF_Common;
+ else
+ Result |= SymbolRef::SF_Undefined;
+ }
+
+ if (!(MachOType & MachO::N_PEXT))
+ Result |= SymbolRef::SF_Exported;
+ }
+
+ if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF))
+ Result |= SymbolRef::SF_Weak;
+
+ if (MachOFlags & (MachO::N_ARM_THUMB_DEF))
+ Result |= SymbolRef::SF_Thumb;
+
+ if ((MachOType & MachO::N_TYPE) == MachO::N_ABS)
+ Result |= SymbolRef::SF_Absolute;
+
+ return Result;
+}
+
+Expected<section_iterator>
+MachOObjectFile::getSymbolSection(DataRefImpl Symb) const {
+ MachO::nlist_base Entry = getSymbolTableEntryBase(*this, Symb);
+ uint8_t index = Entry.n_sect;
+
+ if (index == 0)
+ return section_end();
+ DataRefImpl DRI;
+ DRI.d.a = index - 1;
+ if (DRI.d.a >= Sections.size()){
+ return malformedError("bad section index: " + Twine((int)index) +
+ " for symbol at index " + Twine(getSymbolIndex(Symb)));
+ }
+ return section_iterator(SectionRef(DRI, this));
+}
+
+unsigned MachOObjectFile::getSymbolSectionID(SymbolRef Sym) const {
+ MachO::nlist_base Entry =
+ getSymbolTableEntryBase(*this, Sym.getRawDataRefImpl());
+ return Entry.n_sect - 1;
+}
+
+void MachOObjectFile::moveSectionNext(DataRefImpl &Sec) const {
+ Sec.d.a++;
+}
+
+Expected<StringRef> MachOObjectFile::getSectionName(DataRefImpl Sec) const {
+ ArrayRef<char> Raw = getSectionRawName(Sec);
+ return parseSegmentOrSectionName(Raw.data());
+}
+
+uint64_t MachOObjectFile::getSectionAddress(DataRefImpl Sec) const {
+ if (is64Bit())
+ return getSection64(Sec).addr;
+ return getSection(Sec).addr;
+}
+
+uint64_t MachOObjectFile::getSectionIndex(DataRefImpl Sec) const {
+ return Sec.d.a;
+}
+
+uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const {
+ // In the case if a malformed Mach-O file where the section offset is past
+ // the end of the file or some part of the section size is past the end of
+ // the file return a size of zero or a size that covers the rest of the file
+ // but does not extend past the end of the file.
+ uint32_t SectOffset, SectType;
+ uint64_t SectSize;
+
+ if (is64Bit()) {
+ MachO::section_64 Sect = getSection64(Sec);
+ SectOffset = Sect.offset;
+ SectSize = Sect.size;
+ SectType = Sect.flags & MachO::SECTION_TYPE;
+ } else {
+ MachO::section Sect = getSection(Sec);
+ SectOffset = Sect.offset;
+ SectSize = Sect.size;
+ SectType = Sect.flags & MachO::SECTION_TYPE;
+ }
+ if (SectType == MachO::S_ZEROFILL || SectType == MachO::S_GB_ZEROFILL)
+ return SectSize;
+ uint64_t FileSize = getData().size();
+ if (SectOffset > FileSize)
+ return 0;
+ if (FileSize - SectOffset < SectSize)
+ return FileSize - SectOffset;
+ return SectSize;
+}
+
+ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint32_t Offset,
+ uint64_t Size) const {
+ return arrayRefFromStringRef(getData().substr(Offset, Size));
+}
+
+Expected<ArrayRef<uint8_t>>
+MachOObjectFile::getSectionContents(DataRefImpl Sec) const {
+ uint32_t Offset;
+ uint64_t Size;
+
+ if (is64Bit()) {
+ MachO::section_64 Sect = getSection64(Sec);
+ Offset = Sect.offset;
+ Size = Sect.size;
+ } else {
+ MachO::section Sect = getSection(Sec);
+ Offset = Sect.offset;
+ Size = Sect.size;
+ }
+
+ return getSectionContents(Offset, Size);
+}
+
+uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const {
+ uint32_t Align;
+ if (is64Bit()) {
+ MachO::section_64 Sect = getSection64(Sec);
+ Align = Sect.align;
+ } else {
+ MachO::section Sect = getSection(Sec);
+ Align = Sect.align;
+ }
+
+ return uint64_t(1) << Align;
+}
+
+Expected<SectionRef> MachOObjectFile::getSection(unsigned SectionIndex) const {
+ if (SectionIndex < 1 || SectionIndex > Sections.size())
+ return malformedError("bad section index: " + Twine((int)SectionIndex));
+
+ DataRefImpl DRI;
+ DRI.d.a = SectionIndex - 1;
+ return SectionRef(DRI, this);
+}
+
+Expected<SectionRef> MachOObjectFile::getSection(StringRef SectionName) const {
+ for (const SectionRef &Section : sections()) {
+ auto NameOrErr = Section.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ if (*NameOrErr == SectionName)
+ return Section;
+ }
+ return errorCodeToError(object_error::parse_failed);
+}
+
+bool MachOObjectFile::isSectionCompressed(DataRefImpl Sec) const {
+ return false;
+}
+
+bool MachOObjectFile::isSectionText(DataRefImpl Sec) const {
+ uint32_t Flags = getSectionFlags(*this, Sec);
+ return Flags & MachO::S_ATTR_PURE_INSTRUCTIONS;
+}
+
+bool MachOObjectFile::isSectionData(DataRefImpl Sec) const {
+ uint32_t Flags = getSectionFlags(*this, Sec);
+ unsigned SectionType = Flags & MachO::SECTION_TYPE;
+ return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) &&
+ !(SectionType == MachO::S_ZEROFILL ||
+ SectionType == MachO::S_GB_ZEROFILL);
+}
+
+bool MachOObjectFile::isSectionBSS(DataRefImpl Sec) const {
+ uint32_t Flags = getSectionFlags(*this, Sec);
+ unsigned SectionType = Flags & MachO::SECTION_TYPE;
+ return !(Flags & MachO::S_ATTR_PURE_INSTRUCTIONS) &&
+ (SectionType == MachO::S_ZEROFILL ||
+ SectionType == MachO::S_GB_ZEROFILL);
+}
+
+bool MachOObjectFile::isDebugSection(StringRef SectionName) const {
+ return SectionName.startswith("__debug") ||
SectionName.startswith("__zdebug") ||
SectionName.startswith("__apple") || SectionName == "__gdb_index" ||
SectionName == "__swift_ast";
-}
-
-unsigned MachOObjectFile::getSectionID(SectionRef Sec) const {
- return Sec.getRawDataRefImpl().d.a;
-}
-
-bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const {
- uint32_t Flags = getSectionFlags(*this, Sec);
- unsigned SectionType = Flags & MachO::SECTION_TYPE;
- return SectionType == MachO::S_ZEROFILL ||
- SectionType == MachO::S_GB_ZEROFILL;
-}
-
-bool MachOObjectFile::isSectionBitcode(DataRefImpl Sec) const {
- StringRef SegmentName = getSectionFinalSegmentName(Sec);
- if (Expected<StringRef> NameOrErr = getSectionName(Sec))
- return (SegmentName == "__LLVM" && *NameOrErr == "__bitcode");
- 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;
- Ret.d.b = 0;
- return relocation_iterator(RelocationRef(Ret, this));
-}
-
-relocation_iterator
-MachOObjectFile::section_rel_end(DataRefImpl Sec) const {
- uint32_t Num;
- if (is64Bit()) {
- MachO::section_64 Sect = getSection64(Sec);
- Num = Sect.nreloc;
- } else {
- MachO::section Sect = getSection(Sec);
- Num = Sect.nreloc;
- }
-
- DataRefImpl Ret;
- Ret.d.a = Sec.d.a;
- Ret.d.b = Num;
- return relocation_iterator(RelocationRef(Ret, this));
-}
-
-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));
-}
-
-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;
-}
-
-uint64_t MachOObjectFile::getRelocationOffset(DataRefImpl Rel) const {
- assert((getHeader().filetype == MachO::MH_OBJECT ||
- getHeader().filetype == MachO::MH_KEXT_BUNDLE) &&
- "Only implemented for MH_OBJECT && MH_KEXT_BUNDLE");
- MachO::any_relocation_info RE = getRelocation(Rel);
- return getAnyRelocationAddress(RE);
-}
-
-symbol_iterator
-MachOObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
- MachO::any_relocation_info RE = getRelocation(Rel);
- if (isRelocationScattered(RE))
- return symbol_end();
-
- uint32_t SymbolIdx = getPlainRelocationSymbolNum(RE);
- bool isExtern = getPlainRelocationExternal(RE);
- if (!isExtern)
- return symbol_end();
-
- MachO::symtab_command S = getSymtabLoadCommand();
- unsigned SymbolTableEntrySize = is64Bit() ?
- sizeof(MachO::nlist_64) :
- sizeof(MachO::nlist);
- uint64_t Offset = S.symoff + SymbolIdx * SymbolTableEntrySize;
- DataRefImpl Sym;
- Sym.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
- return symbol_iterator(SymbolRef(Sym, this));
-}
-
-section_iterator
-MachOObjectFile::getRelocationSection(DataRefImpl Rel) const {
- return section_iterator(getAnyRelocationSection(getRelocation(Rel)));
-}
-
-uint64_t MachOObjectFile::getRelocationType(DataRefImpl Rel) const {
- MachO::any_relocation_info RE = getRelocation(Rel);
- return getAnyRelocationType(RE);
-}
-
-void MachOObjectFile::getRelocationTypeName(
- DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
- StringRef res;
- uint64_t RType = getRelocationType(Rel);
-
- unsigned Arch = this->getArch();
-
- switch (Arch) {
- case Triple::x86: {
- static const char *const Table[] = {
- "GENERIC_RELOC_VANILLA",
- "GENERIC_RELOC_PAIR",
- "GENERIC_RELOC_SECTDIFF",
- "GENERIC_RELOC_PB_LA_PTR",
- "GENERIC_RELOC_LOCAL_SECTDIFF",
- "GENERIC_RELOC_TLV" };
-
- if (RType > 5)
- res = "Unknown";
- else
- res = Table[RType];
- break;
- }
- case Triple::x86_64: {
- static const char *const Table[] = {
- "X86_64_RELOC_UNSIGNED",
- "X86_64_RELOC_SIGNED",
- "X86_64_RELOC_BRANCH",
- "X86_64_RELOC_GOT_LOAD",
- "X86_64_RELOC_GOT",
- "X86_64_RELOC_SUBTRACTOR",
- "X86_64_RELOC_SIGNED_1",
- "X86_64_RELOC_SIGNED_2",
- "X86_64_RELOC_SIGNED_4",
- "X86_64_RELOC_TLV" };
-
- if (RType > 9)
- res = "Unknown";
- else
- res = Table[RType];
- break;
- }
- case Triple::arm: {
- static const char *const Table[] = {
- "ARM_RELOC_VANILLA",
- "ARM_RELOC_PAIR",
- "ARM_RELOC_SECTDIFF",
- "ARM_RELOC_LOCAL_SECTDIFF",
- "ARM_RELOC_PB_LA_PTR",
- "ARM_RELOC_BR24",
- "ARM_THUMB_RELOC_BR22",
- "ARM_THUMB_32BIT_BRANCH",
- "ARM_RELOC_HALF",
- "ARM_RELOC_HALF_SECTDIFF" };
-
- if (RType > 9)
- res = "Unknown";
- else
- res = Table[RType];
- break;
- }
- case Triple::aarch64:
- case Triple::aarch64_32: {
- static const char *const Table[] = {
- "ARM64_RELOC_UNSIGNED", "ARM64_RELOC_SUBTRACTOR",
- "ARM64_RELOC_BRANCH26", "ARM64_RELOC_PAGE21",
- "ARM64_RELOC_PAGEOFF12", "ARM64_RELOC_GOT_LOAD_PAGE21",
- "ARM64_RELOC_GOT_LOAD_PAGEOFF12", "ARM64_RELOC_POINTER_TO_GOT",
- "ARM64_RELOC_TLVP_LOAD_PAGE21", "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
- "ARM64_RELOC_ADDEND"
- };
-
- if (RType >= array_lengthof(Table))
- res = "Unknown";
- else
- res = Table[RType];
- break;
- }
- case Triple::ppc: {
- static const char *const Table[] = {
- "PPC_RELOC_VANILLA",
- "PPC_RELOC_PAIR",
- "PPC_RELOC_BR14",
- "PPC_RELOC_BR24",
- "PPC_RELOC_HI16",
- "PPC_RELOC_LO16",
- "PPC_RELOC_HA16",
- "PPC_RELOC_LO14",
- "PPC_RELOC_SECTDIFF",
- "PPC_RELOC_PB_LA_PTR",
- "PPC_RELOC_HI16_SECTDIFF",
- "PPC_RELOC_LO16_SECTDIFF",
- "PPC_RELOC_HA16_SECTDIFF",
- "PPC_RELOC_JBSR",
- "PPC_RELOC_LO14_SECTDIFF",
- "PPC_RELOC_LOCAL_SECTDIFF" };
-
- if (RType > 15)
- res = "Unknown";
- else
- res = Table[RType];
- break;
- }
- case Triple::UnknownArch:
- res = "Unknown";
- break;
- }
- Result.append(res.begin(), res.end());
-}
-
-uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const {
- MachO::any_relocation_info RE = getRelocation(Rel);
- return getAnyRelocationLength(RE);
-}
-
-//
-// guessLibraryShortName() is passed a name of a dynamic library and returns a
-// guess on what the short name is. Then name is returned as a substring of the
-// StringRef Name passed in. The name of the dynamic library is recognized as
-// a framework if it has one of the two following forms:
-// Foo.framework/Versions/A/Foo
-// Foo.framework/Foo
-// Where A and Foo can be any string. And may contain a trailing suffix
-// starting with an underbar. If the Name is recognized as a framework then
-// isFramework is set to true else it is set to false. If the Name has a
-// suffix then Suffix is set to the substring in Name that contains the suffix
-// else it is set to a NULL StringRef.
-//
-// The Name of the dynamic library is recognized as a library name if it has
-// one of the two following forms:
-// libFoo.A.dylib
-// libFoo.dylib
-//
-// The library may have a suffix trailing the name Foo of the form:
-// libFoo_profile.A.dylib
-// libFoo_profile.dylib
-// These dyld image suffixes are separated from the short name by a '_'
-// character. Because the '_' character is commonly used to separate words in
-// filenames guessLibraryShortName() cannot reliably separate a dylib's short
-// name from an arbitrary image suffix; imagine if both the short name and the
-// suffix contains an '_' character! To better deal with this ambiguity,
-// guessLibraryShortName() will recognize only "_debug" and "_profile" as valid
-// Suffix values. Calling code needs to be tolerant of guessLibraryShortName()
-// guessing incorrectly.
-//
-// The Name of the dynamic library is also recognized as a library name if it
-// has the following form:
-// Foo.qtx
-//
-// If the Name of the dynamic library is none of the forms above then a NULL
-// StringRef is returned.
-StringRef MachOObjectFile::guessLibraryShortName(StringRef Name,
- bool &isFramework,
- StringRef &Suffix) {
- StringRef Foo, F, DotFramework, V, Dylib, Lib, Dot, Qtx;
- size_t a, b, c, d, Idx;
-
- isFramework = false;
- Suffix = StringRef();
-
- // Pull off the last component and make Foo point to it
- a = Name.rfind('/');
- if (a == Name.npos || a == 0)
- goto guess_library;
- Foo = Name.slice(a+1, Name.npos);
-
- // Look for a suffix starting with a '_'
- Idx = Foo.rfind('_');
- if (Idx != Foo.npos && Foo.size() >= 2) {
- Suffix = Foo.slice(Idx, Foo.npos);
- if (Suffix != "_debug" && Suffix != "_profile")
- Suffix = StringRef();
- else
- Foo = Foo.slice(0, Idx);
- }
-
- // First look for the form Foo.framework/Foo
- b = Name.rfind('/', a);
- if (b == Name.npos)
- Idx = 0;
- else
- Idx = b+1;
- F = Name.slice(Idx, Idx + Foo.size());
- DotFramework = Name.slice(Idx + Foo.size(),
- Idx + Foo.size() + sizeof(".framework/")-1);
- if (F == Foo && DotFramework == ".framework/") {
- isFramework = true;
- return Foo;
- }
-
- // Next look for the form Foo.framework/Versions/A/Foo
- if (b == Name.npos)
- goto guess_library;
- c = Name.rfind('/', b);
- if (c == Name.npos || c == 0)
- goto guess_library;
- V = Name.slice(c+1, Name.npos);
- if (!V.startswith("Versions/"))
- goto guess_library;
- d = Name.rfind('/', c);
- if (d == Name.npos)
- Idx = 0;
- else
- Idx = d+1;
- F = Name.slice(Idx, Idx + Foo.size());
- DotFramework = Name.slice(Idx + Foo.size(),
- Idx + Foo.size() + sizeof(".framework/")-1);
- if (F == Foo && DotFramework == ".framework/") {
- isFramework = true;
- return Foo;
- }
-
-guess_library:
- // pull off the suffix after the "." and make a point to it
- a = Name.rfind('.');
- if (a == Name.npos || a == 0)
- return StringRef();
- Dylib = Name.slice(a, Name.npos);
- if (Dylib != ".dylib")
- goto guess_qtx;
-
- // First pull off the version letter for the form Foo.A.dylib if any.
- if (a >= 3) {
- Dot = Name.slice(a-2, a-1);
- if (Dot == ".")
- a = a - 2;
- }
-
- b = Name.rfind('/', a);
- if (b == Name.npos)
- b = 0;
- else
- b = b+1;
- // ignore any suffix after an underbar like Foo_profile.A.dylib
- Idx = Name.rfind('_');
- if (Idx != Name.npos && Idx != b) {
- Lib = Name.slice(b, Idx);
- Suffix = Name.slice(Idx, a);
- if (Suffix != "_debug" && Suffix != "_profile") {
- Suffix = StringRef();
- Lib = Name.slice(b, a);
- }
- }
- else
- Lib = Name.slice(b, a);
- // There are incorrect library names of the form:
- // libATS.A_profile.dylib so check for these.
- if (Lib.size() >= 3) {
- Dot = Lib.slice(Lib.size()-2, Lib.size()-1);
- if (Dot == ".")
- Lib = Lib.slice(0, Lib.size()-2);
- }
- return Lib;
-
-guess_qtx:
- Qtx = Name.slice(a, Name.npos);
- if (Qtx != ".qtx")
- return StringRef();
- b = Name.rfind('/', a);
- if (b == Name.npos)
- Lib = Name.slice(0, a);
- else
- Lib = Name.slice(b+1, a);
- // There are library names of the form: QT.A.qtx so check for these.
- if (Lib.size() >= 3) {
- Dot = Lib.slice(Lib.size()-2, Lib.size()-1);
- if (Dot == ".")
- Lib = Lib.slice(0, Lib.size()-2);
- }
- return Lib;
-}
-
-// getLibraryShortNameByIndex() is used to get the short name of the library
-// for an undefined symbol in a linked Mach-O binary that was linked with the
-// normal two-level namespace default (that is MH_TWOLEVEL in the header).
-// It is passed the index (0 - based) of the library as translated from
-// GET_LIBRARY_ORDINAL (1 - based).
-std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index,
- StringRef &Res) const {
- if (Index >= Libraries.size())
- return object_error::parse_failed;
-
- // If the cache of LibrariesShortNames is not built up do that first for
- // all the Libraries.
- if (LibrariesShortNames.size() == 0) {
- for (unsigned i = 0; i < Libraries.size(); i++) {
- auto CommandOrErr =
- getStructOrErr<MachO::dylib_command>(*this, Libraries[i]);
- if (!CommandOrErr)
- return object_error::parse_failed;
- MachO::dylib_command D = CommandOrErr.get();
- if (D.dylib.name >= D.cmdsize)
- return object_error::parse_failed;
- const char *P = (const char *)(Libraries[i]) + D.dylib.name;
- StringRef Name = StringRef(P);
- if (D.dylib.name+Name.size() >= D.cmdsize)
- return object_error::parse_failed;
- StringRef Suffix;
- bool isFramework;
- StringRef shortName = guessLibraryShortName(Name, isFramework, Suffix);
- if (shortName.empty())
- LibrariesShortNames.push_back(Name);
- else
- LibrariesShortNames.push_back(shortName);
- }
- }
-
- Res = LibrariesShortNames[Index];
- return std::error_code();
-}
-
-uint32_t MachOObjectFile::getLibraryCount() const {
- return Libraries.size();
-}
-
-section_iterator
-MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const {
- DataRefImpl Sec;
- Sec.d.a = Rel->getRawDataRefImpl().d.a;
- return section_iterator(SectionRef(Sec, this));
-}
-
-basic_symbol_iterator MachOObjectFile::symbol_begin() const {
- DataRefImpl DRI;
- MachO::symtab_command Symtab = getSymtabLoadCommand();
- if (!SymtabLoadCmd || Symtab.nsyms == 0)
- return basic_symbol_iterator(SymbolRef(DRI, this));
-
- return getSymbolByIndex(0);
-}
-
-basic_symbol_iterator MachOObjectFile::symbol_end() const {
- DataRefImpl DRI;
- MachO::symtab_command Symtab = getSymtabLoadCommand();
- if (!SymtabLoadCmd || Symtab.nsyms == 0)
- return basic_symbol_iterator(SymbolRef(DRI, this));
-
- unsigned SymbolTableEntrySize = is64Bit() ?
- sizeof(MachO::nlist_64) :
- sizeof(MachO::nlist);
- unsigned Offset = Symtab.symoff +
- Symtab.nsyms * SymbolTableEntrySize;
- DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
- return basic_symbol_iterator(SymbolRef(DRI, this));
-}
-
-symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const {
- MachO::symtab_command Symtab = getSymtabLoadCommand();
- if (!SymtabLoadCmd || Index >= Symtab.nsyms)
- report_fatal_error("Requested symbol index is out of range.");
- unsigned SymbolTableEntrySize =
- is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
- DataRefImpl DRI;
- DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Symtab.symoff));
- DRI.p += Index * SymbolTableEntrySize;
- return basic_symbol_iterator(SymbolRef(DRI, this));
-}
-
-uint64_t MachOObjectFile::getSymbolIndex(DataRefImpl Symb) const {
- MachO::symtab_command Symtab = getSymtabLoadCommand();
- if (!SymtabLoadCmd)
- report_fatal_error("getSymbolIndex() called with no symbol table symbol");
- unsigned SymbolTableEntrySize =
- is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
- DataRefImpl DRIstart;
- DRIstart.p = reinterpret_cast<uintptr_t>(getPtr(*this, Symtab.symoff));
- uint64_t Index = (Symb.p - DRIstart.p) / SymbolTableEntrySize;
- return Index;
-}
-
-section_iterator MachOObjectFile::section_begin() const {
- DataRefImpl DRI;
- return section_iterator(SectionRef(DRI, this));
-}
-
-section_iterator MachOObjectFile::section_end() const {
- DataRefImpl DRI;
- DRI.d.a = Sections.size();
- return section_iterator(SectionRef(DRI, this));
-}
-
-uint8_t MachOObjectFile::getBytesInAddress() const {
- return is64Bit() ? 8 : 4;
-}
-
-StringRef MachOObjectFile::getFileFormatName() const {
- unsigned CPUType = getCPUType(*this);
- if (!is64Bit()) {
- switch (CPUType) {
- case MachO::CPU_TYPE_I386:
- return "Mach-O 32-bit i386";
- case MachO::CPU_TYPE_ARM:
- return "Mach-O arm";
- case MachO::CPU_TYPE_ARM64_32:
- return "Mach-O arm64 (ILP32)";
- case MachO::CPU_TYPE_POWERPC:
- return "Mach-O 32-bit ppc";
- default:
- return "Mach-O 32-bit unknown";
- }
- }
-
- switch (CPUType) {
- case MachO::CPU_TYPE_X86_64:
- return "Mach-O 64-bit x86-64";
- case MachO::CPU_TYPE_ARM64:
- return "Mach-O arm64";
- case MachO::CPU_TYPE_POWERPC64:
- return "Mach-O 64-bit ppc64";
- default:
- return "Mach-O 64-bit unknown";
- }
-}
-
-Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) {
- switch (CPUType) {
- case MachO::CPU_TYPE_I386:
- return Triple::x86;
- case MachO::CPU_TYPE_X86_64:
- return Triple::x86_64;
- case MachO::CPU_TYPE_ARM:
- return Triple::arm;
- case MachO::CPU_TYPE_ARM64:
- return Triple::aarch64;
- case MachO::CPU_TYPE_ARM64_32:
- return Triple::aarch64_32;
- case MachO::CPU_TYPE_POWERPC:
- return Triple::ppc;
- case MachO::CPU_TYPE_POWERPC64:
- return Triple::ppc64;
- default:
- return Triple::UnknownArch;
- }
-}
-
-Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType,
- const char **McpuDefault,
- const char **ArchFlag) {
- if (McpuDefault)
- *McpuDefault = nullptr;
- if (ArchFlag)
- *ArchFlag = nullptr;
-
- switch (CPUType) {
- case MachO::CPU_TYPE_I386:
- switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
- case MachO::CPU_SUBTYPE_I386_ALL:
- if (ArchFlag)
- *ArchFlag = "i386";
- return Triple("i386-apple-darwin");
- default:
- return Triple();
- }
- case MachO::CPU_TYPE_X86_64:
- switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
- case MachO::CPU_SUBTYPE_X86_64_ALL:
- if (ArchFlag)
- *ArchFlag = "x86_64";
- return Triple("x86_64-apple-darwin");
- case MachO::CPU_SUBTYPE_X86_64_H:
- if (ArchFlag)
- *ArchFlag = "x86_64h";
- return Triple("x86_64h-apple-darwin");
- default:
- return Triple();
- }
- case MachO::CPU_TYPE_ARM:
- switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
- case MachO::CPU_SUBTYPE_ARM_V4T:
- if (ArchFlag)
- *ArchFlag = "armv4t";
- return Triple("armv4t-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_V5TEJ:
- if (ArchFlag)
- *ArchFlag = "armv5e";
- return Triple("armv5e-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_XSCALE:
- if (ArchFlag)
- *ArchFlag = "xscale";
- return Triple("xscale-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_V6:
- if (ArchFlag)
- *ArchFlag = "armv6";
- return Triple("armv6-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_V6M:
- if (McpuDefault)
- *McpuDefault = "cortex-m0";
- if (ArchFlag)
- *ArchFlag = "armv6m";
- return Triple("armv6m-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_V7:
- if (ArchFlag)
- *ArchFlag = "armv7";
- return Triple("armv7-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_V7EM:
- if (McpuDefault)
- *McpuDefault = "cortex-m4";
- if (ArchFlag)
- *ArchFlag = "armv7em";
- return Triple("thumbv7em-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_V7K:
- if (McpuDefault)
- *McpuDefault = "cortex-a7";
- if (ArchFlag)
- *ArchFlag = "armv7k";
- return Triple("armv7k-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_V7M:
- if (McpuDefault)
- *McpuDefault = "cortex-m3";
- if (ArchFlag)
- *ArchFlag = "armv7m";
- return Triple("thumbv7m-apple-darwin");
- case MachO::CPU_SUBTYPE_ARM_V7S:
- if (McpuDefault)
- *McpuDefault = "cortex-a7";
- if (ArchFlag)
- *ArchFlag = "armv7s";
- return Triple("armv7s-apple-darwin");
- default:
- return Triple();
- }
- case MachO::CPU_TYPE_ARM64:
- switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
- case MachO::CPU_SUBTYPE_ARM64_ALL:
- if (McpuDefault)
- *McpuDefault = "cyclone";
- if (ArchFlag)
- *ArchFlag = "arm64";
- return Triple("arm64-apple-darwin");
+}
+
+unsigned MachOObjectFile::getSectionID(SectionRef Sec) const {
+ return Sec.getRawDataRefImpl().d.a;
+}
+
+bool MachOObjectFile::isSectionVirtual(DataRefImpl Sec) const {
+ uint32_t Flags = getSectionFlags(*this, Sec);
+ unsigned SectionType = Flags & MachO::SECTION_TYPE;
+ return SectionType == MachO::S_ZEROFILL ||
+ SectionType == MachO::S_GB_ZEROFILL;
+}
+
+bool MachOObjectFile::isSectionBitcode(DataRefImpl Sec) const {
+ StringRef SegmentName = getSectionFinalSegmentName(Sec);
+ if (Expected<StringRef> NameOrErr = getSectionName(Sec))
+ return (SegmentName == "__LLVM" && *NameOrErr == "__bitcode");
+ 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;
+ Ret.d.b = 0;
+ return relocation_iterator(RelocationRef(Ret, this));
+}
+
+relocation_iterator
+MachOObjectFile::section_rel_end(DataRefImpl Sec) const {
+ uint32_t Num;
+ if (is64Bit()) {
+ MachO::section_64 Sect = getSection64(Sec);
+ Num = Sect.nreloc;
+ } else {
+ MachO::section Sect = getSection(Sec);
+ Num = Sect.nreloc;
+ }
+
+ DataRefImpl Ret;
+ Ret.d.a = Sec.d.a;
+ Ret.d.b = Num;
+ return relocation_iterator(RelocationRef(Ret, this));
+}
+
+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));
+}
+
+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;
+}
+
+uint64_t MachOObjectFile::getRelocationOffset(DataRefImpl Rel) const {
+ assert((getHeader().filetype == MachO::MH_OBJECT ||
+ getHeader().filetype == MachO::MH_KEXT_BUNDLE) &&
+ "Only implemented for MH_OBJECT && MH_KEXT_BUNDLE");
+ MachO::any_relocation_info RE = getRelocation(Rel);
+ return getAnyRelocationAddress(RE);
+}
+
+symbol_iterator
+MachOObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
+ MachO::any_relocation_info RE = getRelocation(Rel);
+ if (isRelocationScattered(RE))
+ return symbol_end();
+
+ uint32_t SymbolIdx = getPlainRelocationSymbolNum(RE);
+ bool isExtern = getPlainRelocationExternal(RE);
+ if (!isExtern)
+ return symbol_end();
+
+ MachO::symtab_command S = getSymtabLoadCommand();
+ unsigned SymbolTableEntrySize = is64Bit() ?
+ sizeof(MachO::nlist_64) :
+ sizeof(MachO::nlist);
+ uint64_t Offset = S.symoff + SymbolIdx * SymbolTableEntrySize;
+ DataRefImpl Sym;
+ Sym.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
+ return symbol_iterator(SymbolRef(Sym, this));
+}
+
+section_iterator
+MachOObjectFile::getRelocationSection(DataRefImpl Rel) const {
+ return section_iterator(getAnyRelocationSection(getRelocation(Rel)));
+}
+
+uint64_t MachOObjectFile::getRelocationType(DataRefImpl Rel) const {
+ MachO::any_relocation_info RE = getRelocation(Rel);
+ return getAnyRelocationType(RE);
+}
+
+void MachOObjectFile::getRelocationTypeName(
+ DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
+ StringRef res;
+ uint64_t RType = getRelocationType(Rel);
+
+ unsigned Arch = this->getArch();
+
+ switch (Arch) {
+ case Triple::x86: {
+ static const char *const Table[] = {
+ "GENERIC_RELOC_VANILLA",
+ "GENERIC_RELOC_PAIR",
+ "GENERIC_RELOC_SECTDIFF",
+ "GENERIC_RELOC_PB_LA_PTR",
+ "GENERIC_RELOC_LOCAL_SECTDIFF",
+ "GENERIC_RELOC_TLV" };
+
+ if (RType > 5)
+ res = "Unknown";
+ else
+ res = Table[RType];
+ break;
+ }
+ case Triple::x86_64: {
+ static const char *const Table[] = {
+ "X86_64_RELOC_UNSIGNED",
+ "X86_64_RELOC_SIGNED",
+ "X86_64_RELOC_BRANCH",
+ "X86_64_RELOC_GOT_LOAD",
+ "X86_64_RELOC_GOT",
+ "X86_64_RELOC_SUBTRACTOR",
+ "X86_64_RELOC_SIGNED_1",
+ "X86_64_RELOC_SIGNED_2",
+ "X86_64_RELOC_SIGNED_4",
+ "X86_64_RELOC_TLV" };
+
+ if (RType > 9)
+ res = "Unknown";
+ else
+ res = Table[RType];
+ break;
+ }
+ case Triple::arm: {
+ static const char *const Table[] = {
+ "ARM_RELOC_VANILLA",
+ "ARM_RELOC_PAIR",
+ "ARM_RELOC_SECTDIFF",
+ "ARM_RELOC_LOCAL_SECTDIFF",
+ "ARM_RELOC_PB_LA_PTR",
+ "ARM_RELOC_BR24",
+ "ARM_THUMB_RELOC_BR22",
+ "ARM_THUMB_32BIT_BRANCH",
+ "ARM_RELOC_HALF",
+ "ARM_RELOC_HALF_SECTDIFF" };
+
+ if (RType > 9)
+ res = "Unknown";
+ else
+ res = Table[RType];
+ break;
+ }
+ case Triple::aarch64:
+ case Triple::aarch64_32: {
+ static const char *const Table[] = {
+ "ARM64_RELOC_UNSIGNED", "ARM64_RELOC_SUBTRACTOR",
+ "ARM64_RELOC_BRANCH26", "ARM64_RELOC_PAGE21",
+ "ARM64_RELOC_PAGEOFF12", "ARM64_RELOC_GOT_LOAD_PAGE21",
+ "ARM64_RELOC_GOT_LOAD_PAGEOFF12", "ARM64_RELOC_POINTER_TO_GOT",
+ "ARM64_RELOC_TLVP_LOAD_PAGE21", "ARM64_RELOC_TLVP_LOAD_PAGEOFF12",
+ "ARM64_RELOC_ADDEND"
+ };
+
+ if (RType >= array_lengthof(Table))
+ res = "Unknown";
+ else
+ res = Table[RType];
+ break;
+ }
+ case Triple::ppc: {
+ static const char *const Table[] = {
+ "PPC_RELOC_VANILLA",
+ "PPC_RELOC_PAIR",
+ "PPC_RELOC_BR14",
+ "PPC_RELOC_BR24",
+ "PPC_RELOC_HI16",
+ "PPC_RELOC_LO16",
+ "PPC_RELOC_HA16",
+ "PPC_RELOC_LO14",
+ "PPC_RELOC_SECTDIFF",
+ "PPC_RELOC_PB_LA_PTR",
+ "PPC_RELOC_HI16_SECTDIFF",
+ "PPC_RELOC_LO16_SECTDIFF",
+ "PPC_RELOC_HA16_SECTDIFF",
+ "PPC_RELOC_JBSR",
+ "PPC_RELOC_LO14_SECTDIFF",
+ "PPC_RELOC_LOCAL_SECTDIFF" };
+
+ if (RType > 15)
+ res = "Unknown";
+ else
+ res = Table[RType];
+ break;
+ }
+ case Triple::UnknownArch:
+ res = "Unknown";
+ break;
+ }
+ Result.append(res.begin(), res.end());
+}
+
+uint8_t MachOObjectFile::getRelocationLength(DataRefImpl Rel) const {
+ MachO::any_relocation_info RE = getRelocation(Rel);
+ return getAnyRelocationLength(RE);
+}
+
+//
+// guessLibraryShortName() is passed a name of a dynamic library and returns a
+// guess on what the short name is. Then name is returned as a substring of the
+// StringRef Name passed in. The name of the dynamic library is recognized as
+// a framework if it has one of the two following forms:
+// Foo.framework/Versions/A/Foo
+// Foo.framework/Foo
+// Where A and Foo can be any string. And may contain a trailing suffix
+// starting with an underbar. If the Name is recognized as a framework then
+// isFramework is set to true else it is set to false. If the Name has a
+// suffix then Suffix is set to the substring in Name that contains the suffix
+// else it is set to a NULL StringRef.
+//
+// The Name of the dynamic library is recognized as a library name if it has
+// one of the two following forms:
+// libFoo.A.dylib
+// libFoo.dylib
+//
+// The library may have a suffix trailing the name Foo of the form:
+// libFoo_profile.A.dylib
+// libFoo_profile.dylib
+// These dyld image suffixes are separated from the short name by a '_'
+// character. Because the '_' character is commonly used to separate words in
+// filenames guessLibraryShortName() cannot reliably separate a dylib's short
+// name from an arbitrary image suffix; imagine if both the short name and the
+// suffix contains an '_' character! To better deal with this ambiguity,
+// guessLibraryShortName() will recognize only "_debug" and "_profile" as valid
+// Suffix values. Calling code needs to be tolerant of guessLibraryShortName()
+// guessing incorrectly.
+//
+// The Name of the dynamic library is also recognized as a library name if it
+// has the following form:
+// Foo.qtx
+//
+// If the Name of the dynamic library is none of the forms above then a NULL
+// StringRef is returned.
+StringRef MachOObjectFile::guessLibraryShortName(StringRef Name,
+ bool &isFramework,
+ StringRef &Suffix) {
+ StringRef Foo, F, DotFramework, V, Dylib, Lib, Dot, Qtx;
+ size_t a, b, c, d, Idx;
+
+ isFramework = false;
+ Suffix = StringRef();
+
+ // Pull off the last component and make Foo point to it
+ a = Name.rfind('/');
+ if (a == Name.npos || a == 0)
+ goto guess_library;
+ Foo = Name.slice(a+1, Name.npos);
+
+ // Look for a suffix starting with a '_'
+ Idx = Foo.rfind('_');
+ if (Idx != Foo.npos && Foo.size() >= 2) {
+ Suffix = Foo.slice(Idx, Foo.npos);
+ if (Suffix != "_debug" && Suffix != "_profile")
+ Suffix = StringRef();
+ else
+ Foo = Foo.slice(0, Idx);
+ }
+
+ // First look for the form Foo.framework/Foo
+ b = Name.rfind('/', a);
+ if (b == Name.npos)
+ Idx = 0;
+ else
+ Idx = b+1;
+ F = Name.slice(Idx, Idx + Foo.size());
+ DotFramework = Name.slice(Idx + Foo.size(),
+ Idx + Foo.size() + sizeof(".framework/")-1);
+ if (F == Foo && DotFramework == ".framework/") {
+ isFramework = true;
+ return Foo;
+ }
+
+ // Next look for the form Foo.framework/Versions/A/Foo
+ if (b == Name.npos)
+ goto guess_library;
+ c = Name.rfind('/', b);
+ if (c == Name.npos || c == 0)
+ goto guess_library;
+ V = Name.slice(c+1, Name.npos);
+ if (!V.startswith("Versions/"))
+ goto guess_library;
+ d = Name.rfind('/', c);
+ if (d == Name.npos)
+ Idx = 0;
+ else
+ Idx = d+1;
+ F = Name.slice(Idx, Idx + Foo.size());
+ DotFramework = Name.slice(Idx + Foo.size(),
+ Idx + Foo.size() + sizeof(".framework/")-1);
+ if (F == Foo && DotFramework == ".framework/") {
+ isFramework = true;
+ return Foo;
+ }
+
+guess_library:
+ // pull off the suffix after the "." and make a point to it
+ a = Name.rfind('.');
+ if (a == Name.npos || a == 0)
+ return StringRef();
+ Dylib = Name.slice(a, Name.npos);
+ if (Dylib != ".dylib")
+ goto guess_qtx;
+
+ // First pull off the version letter for the form Foo.A.dylib if any.
+ if (a >= 3) {
+ Dot = Name.slice(a-2, a-1);
+ if (Dot == ".")
+ a = a - 2;
+ }
+
+ b = Name.rfind('/', a);
+ if (b == Name.npos)
+ b = 0;
+ else
+ b = b+1;
+ // ignore any suffix after an underbar like Foo_profile.A.dylib
+ Idx = Name.rfind('_');
+ if (Idx != Name.npos && Idx != b) {
+ Lib = Name.slice(b, Idx);
+ Suffix = Name.slice(Idx, a);
+ if (Suffix != "_debug" && Suffix != "_profile") {
+ Suffix = StringRef();
+ Lib = Name.slice(b, a);
+ }
+ }
+ else
+ Lib = Name.slice(b, a);
+ // There are incorrect library names of the form:
+ // libATS.A_profile.dylib so check for these.
+ if (Lib.size() >= 3) {
+ Dot = Lib.slice(Lib.size()-2, Lib.size()-1);
+ if (Dot == ".")
+ Lib = Lib.slice(0, Lib.size()-2);
+ }
+ return Lib;
+
+guess_qtx:
+ Qtx = Name.slice(a, Name.npos);
+ if (Qtx != ".qtx")
+ return StringRef();
+ b = Name.rfind('/', a);
+ if (b == Name.npos)
+ Lib = Name.slice(0, a);
+ else
+ Lib = Name.slice(b+1, a);
+ // There are library names of the form: QT.A.qtx so check for these.
+ if (Lib.size() >= 3) {
+ Dot = Lib.slice(Lib.size()-2, Lib.size()-1);
+ if (Dot == ".")
+ Lib = Lib.slice(0, Lib.size()-2);
+ }
+ return Lib;
+}
+
+// getLibraryShortNameByIndex() is used to get the short name of the library
+// for an undefined symbol in a linked Mach-O binary that was linked with the
+// normal two-level namespace default (that is MH_TWOLEVEL in the header).
+// It is passed the index (0 - based) of the library as translated from
+// GET_LIBRARY_ORDINAL (1 - based).
+std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index,
+ StringRef &Res) const {
+ if (Index >= Libraries.size())
+ return object_error::parse_failed;
+
+ // If the cache of LibrariesShortNames is not built up do that first for
+ // all the Libraries.
+ if (LibrariesShortNames.size() == 0) {
+ for (unsigned i = 0; i < Libraries.size(); i++) {
+ auto CommandOrErr =
+ getStructOrErr<MachO::dylib_command>(*this, Libraries[i]);
+ if (!CommandOrErr)
+ return object_error::parse_failed;
+ MachO::dylib_command D = CommandOrErr.get();
+ if (D.dylib.name >= D.cmdsize)
+ return object_error::parse_failed;
+ const char *P = (const char *)(Libraries[i]) + D.dylib.name;
+ StringRef Name = StringRef(P);
+ if (D.dylib.name+Name.size() >= D.cmdsize)
+ return object_error::parse_failed;
+ StringRef Suffix;
+ bool isFramework;
+ StringRef shortName = guessLibraryShortName(Name, isFramework, Suffix);
+ if (shortName.empty())
+ LibrariesShortNames.push_back(Name);
+ else
+ LibrariesShortNames.push_back(shortName);
+ }
+ }
+
+ Res = LibrariesShortNames[Index];
+ return std::error_code();
+}
+
+uint32_t MachOObjectFile::getLibraryCount() const {
+ return Libraries.size();
+}
+
+section_iterator
+MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const {
+ DataRefImpl Sec;
+ Sec.d.a = Rel->getRawDataRefImpl().d.a;
+ return section_iterator(SectionRef(Sec, this));
+}
+
+basic_symbol_iterator MachOObjectFile::symbol_begin() const {
+ DataRefImpl DRI;
+ MachO::symtab_command Symtab = getSymtabLoadCommand();
+ if (!SymtabLoadCmd || Symtab.nsyms == 0)
+ return basic_symbol_iterator(SymbolRef(DRI, this));
+
+ return getSymbolByIndex(0);
+}
+
+basic_symbol_iterator MachOObjectFile::symbol_end() const {
+ DataRefImpl DRI;
+ MachO::symtab_command Symtab = getSymtabLoadCommand();
+ if (!SymtabLoadCmd || Symtab.nsyms == 0)
+ return basic_symbol_iterator(SymbolRef(DRI, this));
+
+ unsigned SymbolTableEntrySize = is64Bit() ?
+ sizeof(MachO::nlist_64) :
+ sizeof(MachO::nlist);
+ unsigned Offset = Symtab.symoff +
+ Symtab.nsyms * SymbolTableEntrySize;
+ DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
+ return basic_symbol_iterator(SymbolRef(DRI, this));
+}
+
+symbol_iterator MachOObjectFile::getSymbolByIndex(unsigned Index) const {
+ MachO::symtab_command Symtab = getSymtabLoadCommand();
+ if (!SymtabLoadCmd || Index >= Symtab.nsyms)
+ report_fatal_error("Requested symbol index is out of range.");
+ unsigned SymbolTableEntrySize =
+ is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
+ DataRefImpl DRI;
+ DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Symtab.symoff));
+ DRI.p += Index * SymbolTableEntrySize;
+ return basic_symbol_iterator(SymbolRef(DRI, this));
+}
+
+uint64_t MachOObjectFile::getSymbolIndex(DataRefImpl Symb) const {
+ MachO::symtab_command Symtab = getSymtabLoadCommand();
+ if (!SymtabLoadCmd)
+ report_fatal_error("getSymbolIndex() called with no symbol table symbol");
+ unsigned SymbolTableEntrySize =
+ is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
+ DataRefImpl DRIstart;
+ DRIstart.p = reinterpret_cast<uintptr_t>(getPtr(*this, Symtab.symoff));
+ uint64_t Index = (Symb.p - DRIstart.p) / SymbolTableEntrySize;
+ return Index;
+}
+
+section_iterator MachOObjectFile::section_begin() const {
+ DataRefImpl DRI;
+ return section_iterator(SectionRef(DRI, this));
+}
+
+section_iterator MachOObjectFile::section_end() const {
+ DataRefImpl DRI;
+ DRI.d.a = Sections.size();
+ return section_iterator(SectionRef(DRI, this));
+}
+
+uint8_t MachOObjectFile::getBytesInAddress() const {
+ return is64Bit() ? 8 : 4;
+}
+
+StringRef MachOObjectFile::getFileFormatName() const {
+ unsigned CPUType = getCPUType(*this);
+ if (!is64Bit()) {
+ switch (CPUType) {
+ case MachO::CPU_TYPE_I386:
+ return "Mach-O 32-bit i386";
+ case MachO::CPU_TYPE_ARM:
+ return "Mach-O arm";
+ case MachO::CPU_TYPE_ARM64_32:
+ return "Mach-O arm64 (ILP32)";
+ case MachO::CPU_TYPE_POWERPC:
+ return "Mach-O 32-bit ppc";
+ default:
+ return "Mach-O 32-bit unknown";
+ }
+ }
+
+ switch (CPUType) {
+ case MachO::CPU_TYPE_X86_64:
+ return "Mach-O 64-bit x86-64";
+ case MachO::CPU_TYPE_ARM64:
+ return "Mach-O arm64";
+ case MachO::CPU_TYPE_POWERPC64:
+ return "Mach-O 64-bit ppc64";
+ default:
+ return "Mach-O 64-bit unknown";
+ }
+}
+
+Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) {
+ switch (CPUType) {
+ case MachO::CPU_TYPE_I386:
+ return Triple::x86;
+ case MachO::CPU_TYPE_X86_64:
+ return Triple::x86_64;
+ case MachO::CPU_TYPE_ARM:
+ return Triple::arm;
+ case MachO::CPU_TYPE_ARM64:
+ return Triple::aarch64;
+ case MachO::CPU_TYPE_ARM64_32:
+ return Triple::aarch64_32;
+ case MachO::CPU_TYPE_POWERPC:
+ return Triple::ppc;
+ case MachO::CPU_TYPE_POWERPC64:
+ return Triple::ppc64;
+ default:
+ return Triple::UnknownArch;
+ }
+}
+
+Triple MachOObjectFile::getArchTriple(uint32_t CPUType, uint32_t CPUSubType,
+ const char **McpuDefault,
+ const char **ArchFlag) {
+ if (McpuDefault)
+ *McpuDefault = nullptr;
+ if (ArchFlag)
+ *ArchFlag = nullptr;
+
+ switch (CPUType) {
+ case MachO::CPU_TYPE_I386:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_I386_ALL:
+ if (ArchFlag)
+ *ArchFlag = "i386";
+ return Triple("i386-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_X86_64:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_X86_64_ALL:
+ if (ArchFlag)
+ *ArchFlag = "x86_64";
+ return Triple("x86_64-apple-darwin");
+ case MachO::CPU_SUBTYPE_X86_64_H:
+ if (ArchFlag)
+ *ArchFlag = "x86_64h";
+ return Triple("x86_64h-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_ARM:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM_V4T:
+ if (ArchFlag)
+ *ArchFlag = "armv4t";
+ return Triple("armv4t-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V5TEJ:
+ if (ArchFlag)
+ *ArchFlag = "armv5e";
+ return Triple("armv5e-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_XSCALE:
+ if (ArchFlag)
+ *ArchFlag = "xscale";
+ return Triple("xscale-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V6:
+ if (ArchFlag)
+ *ArchFlag = "armv6";
+ return Triple("armv6-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V6M:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m0";
+ if (ArchFlag)
+ *ArchFlag = "armv6m";
+ return Triple("armv6m-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7:
+ if (ArchFlag)
+ *ArchFlag = "armv7";
+ return Triple("armv7-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7EM:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m4";
+ if (ArchFlag)
+ *ArchFlag = "armv7em";
+ return Triple("thumbv7em-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7K:
+ if (McpuDefault)
+ *McpuDefault = "cortex-a7";
+ if (ArchFlag)
+ *ArchFlag = "armv7k";
+ return Triple("armv7k-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7M:
+ if (McpuDefault)
+ *McpuDefault = "cortex-m3";
+ if (ArchFlag)
+ *ArchFlag = "armv7m";
+ return Triple("thumbv7m-apple-darwin");
+ case MachO::CPU_SUBTYPE_ARM_V7S:
+ if (McpuDefault)
+ *McpuDefault = "cortex-a7";
+ if (ArchFlag)
+ *ArchFlag = "armv7s";
+ return Triple("armv7s-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_ARM64:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM64_ALL:
+ if (McpuDefault)
+ *McpuDefault = "cyclone";
+ if (ArchFlag)
+ *ArchFlag = "arm64";
+ return Triple("arm64-apple-darwin");
case MachO::CPU_SUBTYPE_ARM64E:
if (McpuDefault)
*McpuDefault = "apple-a12";
if (ArchFlag)
*ArchFlag = "arm64e";
return Triple("arm64e-apple-darwin");
- default:
- return Triple();
- }
- case MachO::CPU_TYPE_ARM64_32:
- switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
- case MachO::CPU_SUBTYPE_ARM64_32_V8:
- if (McpuDefault)
- *McpuDefault = "cyclone";
- if (ArchFlag)
- *ArchFlag = "arm64_32";
- return Triple("arm64_32-apple-darwin");
- default:
- return Triple();
- }
- case MachO::CPU_TYPE_POWERPC:
- switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
- case MachO::CPU_SUBTYPE_POWERPC_ALL:
- if (ArchFlag)
- *ArchFlag = "ppc";
- return Triple("ppc-apple-darwin");
- default:
- return Triple();
- }
- case MachO::CPU_TYPE_POWERPC64:
- switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
- case MachO::CPU_SUBTYPE_POWERPC_ALL:
- if (ArchFlag)
- *ArchFlag = "ppc64";
- return Triple("ppc64-apple-darwin");
- default:
- return Triple();
- }
- default:
- return Triple();
- }
-}
-
-Triple MachOObjectFile::getHostArch() {
- return Triple(sys::getDefaultTargetTriple());
-}
-
-bool MachOObjectFile::isValidArch(StringRef ArchFlag) {
- auto validArchs = getValidArchs();
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_ARM64_32:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_ARM64_32_V8:
+ if (McpuDefault)
+ *McpuDefault = "cyclone";
+ if (ArchFlag)
+ *ArchFlag = "arm64_32";
+ return Triple("arm64_32-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_POWERPC:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_POWERPC_ALL:
+ if (ArchFlag)
+ *ArchFlag = "ppc";
+ return Triple("ppc-apple-darwin");
+ default:
+ return Triple();
+ }
+ case MachO::CPU_TYPE_POWERPC64:
+ switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) {
+ case MachO::CPU_SUBTYPE_POWERPC_ALL:
+ if (ArchFlag)
+ *ArchFlag = "ppc64";
+ return Triple("ppc64-apple-darwin");
+ default:
+ return Triple();
+ }
+ default:
+ return Triple();
+ }
+}
+
+Triple MachOObjectFile::getHostArch() {
+ return Triple(sys::getDefaultTargetTriple());
+}
+
+bool MachOObjectFile::isValidArch(StringRef ArchFlag) {
+ auto validArchs = getValidArchs();
return llvm::is_contained(validArchs, ArchFlag);
-}
-
-ArrayRef<StringRef> MachOObjectFile::getValidArchs() {
+}
+
+ArrayRef<StringRef> MachOObjectFile::getValidArchs() {
static const std::array<StringRef, 18> ValidArchs = {{
"i386",
"x86_64",
@@ -2766,1908 +2766,1908 @@ ArrayRef<StringRef> MachOObjectFile::getValidArchs() {
"arm64_32",
"ppc",
"ppc64",
- }};
-
+ }};
+
return ValidArchs;
-}
-
-Triple::ArchType MachOObjectFile::getArch() const {
- return getArch(getCPUType(*this), getCPUSubType(*this));
-}
-
-Triple MachOObjectFile::getArchTriple(const char **McpuDefault) const {
- return getArchTriple(Header.cputype, Header.cpusubtype, McpuDefault);
-}
-
-relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const {
- DataRefImpl DRI;
- DRI.d.a = Index;
- return section_rel_begin(DRI);
-}
-
-relocation_iterator MachOObjectFile::section_rel_end(unsigned Index) const {
- DataRefImpl DRI;
- DRI.d.a = Index;
- return section_rel_end(DRI);
-}
-
-dice_iterator MachOObjectFile::begin_dices() const {
- DataRefImpl DRI;
- if (!DataInCodeLoadCmd)
- return dice_iterator(DiceRef(DRI, this));
-
- MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();
- DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, DicLC.dataoff));
- return dice_iterator(DiceRef(DRI, this));
-}
-
-dice_iterator MachOObjectFile::end_dices() const {
- DataRefImpl DRI;
- if (!DataInCodeLoadCmd)
- return dice_iterator(DiceRef(DRI, this));
-
- MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();
- unsigned Offset = DicLC.dataoff + DicLC.datasize;
- DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
- return dice_iterator(DiceRef(DRI, this));
-}
-
-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();
-}
-
-void ExportEntry::moveToEnd() {
- Stack.clear();
- Done = true;
-}
-
-bool ExportEntry::operator==(const ExportEntry &Other) const {
- // Common case, one at end, other iterating from begin.
- if (Done || Other.Done)
- return (Done == Other.Done);
- // Not equal if different stack sizes.
- if (Stack.size() != Other.Stack.size())
- return false;
- // Not equal if different cumulative strings.
- if (!CumulativeString.equals(Other.CumulativeString))
- return false;
- // Equal if all nodes in both stacks match.
- for (unsigned i=0; i < Stack.size(); ++i) {
- if (Stack[i].Start != Other.Stack[i].Start)
- return false;
- }
- return true;
-}
-
-uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr, const char **error) {
- unsigned Count;
- uint64_t Result = decodeULEB128(Ptr, &Count, Trie.end(), error);
- Ptr += Count;
- if (Ptr > Trie.end())
- Ptr = Trie.end();
- return Result;
-}
-
-StringRef ExportEntry::name() const {
- return CumulativeString;
-}
-
-uint64_t ExportEntry::flags() const {
- return Stack.back().Flags;
-}
-
-uint64_t ExportEntry::address() const {
- return Stack.back().Address;
-}
-
-uint64_t ExportEntry::other() const {
- return Stack.back().Other;
-}
-
-StringRef ExportEntry::otherName() const {
- const char* ImportName = Stack.back().ImportName;
- if (ImportName)
- return StringRef(ImportName);
- return StringRef();
-}
-
-uint32_t ExportEntry::nodeOffset() const {
- return Stack.back().Start - Trie.begin();
-}
-
-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);
- 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) {
- 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, &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, &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();
- Stack.push_back(State);
-}
-
-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 < 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, &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) {
- *E = malformedError("node is not an export node in export trie data at "
- "node: 0x" +
- Twine::utohexstr(Stack.back().Start - Trie.begin()));
- moveToEnd();
- return;
- }
-}
-
-// We have a trie data structure and need a way to walk it that is compatible
-// with the C++ iterator model. The solution is a non-recursive depth first
-// traversal where the iterator contains a stack of parent nodes along with a
-// string that is the accumulation of all edge strings along the parent chain
-// to this point.
-//
-// There is one "export" node for each exported symbol. But because some
-// symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export
-// node may have child nodes too.
-//
-// The algorithm for moveNext() is to keep moving down the leftmost unvisited
-// child until hitting a node with no children (which is an export node or
-// else the trie is malformed). On the way down, each node is pushed on the
-// 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() {
- 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;
- }
-
- Stack.pop_back();
- while (!Stack.empty()) {
- NodeState &Top = Stack.back();
- if (Top.NextChildIndex < Top.ChildCount) {
- pushDownUntilBottom();
- // Now at the next export node.
- return;
- } else {
- if (Top.IsExportNode) {
- // This node has no children but is itself an export node.
- CumulativeString.resize(Top.ParentStringLength);
- return;
- }
- Stack.pop_back();
- }
- }
- Done = true;
-}
-
-iterator_range<export_iterator>
-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(&E, O, Trie);
- Finish.moveToEnd();
-
- return make_range(export_iterator(Start), export_iterator(Finish));
-}
-
-iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const {
- return exports(Err, getDyldInfoExportsTrie(), this);
-}
-
-MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O,
- ArrayRef<uint8_t> Bytes, bool is64Bit)
- : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),
- PointerSize(is64Bit ? 8 : 4) {}
-
-void MachORebaseEntry::moveToFirst() {
- Ptr = Opcodes.begin();
- moveNext();
-}
-
-void MachORebaseEntry::moveToEnd() {
- Ptr = Opcodes.end();
- RemainingLoopCount = 0;
- Done = true;
-}
-
-void MachORebaseEntry::moveNext() {
- ErrorAsOutParameter ErrAsOutParam(E);
- // If in the middle of some loop, move to next rebasing in loop.
- SegmentOffset += AdvanceAmount;
- if (RemainingLoopCount) {
- --RemainingLoopCount;
- return;
- }
- // REBASE_OPCODE_DONE is only used for padding if we are not aligned to
- // pointer size. Therefore it is possible to reach the end without ever having
- // seen REBASE_OPCODE_DONE.
- if (Ptr == Opcodes.end()) {
- Done = true;
- return;
- }
- bool More = true;
- while (More) {
- // Parse next opcode and set up next loop.
- const uint8_t *OpcodeStart = Ptr;
- uint8_t Byte = *Ptr++;
- uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK;
- uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK;
- uint32_t Count, Skip;
- const char *error = nullptr;
- switch (Opcode) {
- case MachO::REBASE_OPCODE_DONE:
- More = false;
- Done = true;
- moveToEnd();
- DEBUG_WITH_TYPE("mach-o-rebase", dbgs() << "REBASE_OPCODE_DONE\n");
- break;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-rebase",
- dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: "
- << "RebaseType=" << (int) RebaseType << "\n");
- break;
- case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
- SegmentIndex = ImmValue;
- SegmentOffset = readULEB128(&error);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-rebase",
- dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "
- << "SegmentIndex=" << SegmentIndex << ", "
- << format("SegmentOffset=0x%06X", SegmentOffset)
- << "\n");
- break;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) +
- " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE("mach-o-rebase",
- dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: "
- << format("SegmentOffset=0x%06X",
- SegmentOffset) << "\n");
- break;
- case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
- SegmentOffset += ImmValue * PointerSize;
- error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE("mach-o-rebase",
- dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: "
- << format("SegmentOffset=0x%06X",
- SegmentOffset) << "\n");
- break;
- case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES:
- AdvanceAmount = PointerSize;
- Skip = 0;
- Count = ImmValue;
- if (ImmValue != 0)
- RemainingLoopCount = ImmValue - 1;
- else
- RemainingLoopCount = 0;
- error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize, Count, Skip);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-rebase",
- dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: "
- << format("SegmentOffset=0x%06X", SegmentOffset)
- << ", AdvanceAmount=" << AdvanceAmount
- << ", RemainingLoopCount=" << RemainingLoopCount
- << "\n");
- return;
- case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
- AdvanceAmount = PointerSize;
- Skip = 0;
- Count = readULEB128(&error);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- if (Count != 0)
- RemainingLoopCount = Count - 1;
- else
- RemainingLoopCount = 0;
- error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize, Count, Skip);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-rebase",
- dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: "
- << format("SegmentOffset=0x%06X", SegmentOffset)
- << ", AdvanceAmount=" << AdvanceAmount
- << ", RemainingLoopCount=" << RemainingLoopCount
- << "\n");
- return;
- case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
- Skip = readULEB128(&error);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- AdvanceAmount = Skip + PointerSize;
- Count = 1;
- RemainingLoopCount = 0;
- error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize, Count, Skip);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-rebase",
- dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: "
- << format("SegmentOffset=0x%06X", SegmentOffset)
- << ", AdvanceAmount=" << AdvanceAmount
- << ", RemainingLoopCount=" << RemainingLoopCount
- << "\n");
- return;
- case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
- Count = readULEB128(&error);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
- "ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- if (Count != 0)
- RemainingLoopCount = Count - 1;
- else
- RemainingLoopCount = 0;
- Skip = readULEB128(&error);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
- "ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- AdvanceAmount = Skip + PointerSize;
-
- error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize, Count, Skip);
- if (error) {
- *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
- "ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-rebase",
- dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: "
- << format("SegmentOffset=0x%06X", SegmentOffset)
- << ", AdvanceAmount=" << AdvanceAmount
- << ", RemainingLoopCount=" << RemainingLoopCount
- << "\n");
- return;
- default:
- *E = malformedError("bad rebase info (bad opcode value 0x" +
- Twine::utohexstr(Opcode) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- }
-}
-
-uint64_t MachORebaseEntry::readULEB128(const char **error) {
- unsigned Count;
- uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);
- Ptr += Count;
- if (Ptr > Opcodes.end())
- Ptr = Opcodes.end();
- return Result;
-}
-
-int32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; }
-
-uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; }
-
-StringRef MachORebaseEntry::typeName() const {
- switch (RebaseType) {
- case MachO::REBASE_TYPE_POINTER:
- return "pointer";
- case MachO::REBASE_TYPE_TEXT_ABSOLUTE32:
- return "text abs32";
- case MachO::REBASE_TYPE_TEXT_PCREL32:
- return "text rel32";
- }
- return "unknown";
-}
-
-// For use with the SegIndex of a checked Mach-O Rebase entry
-// to get the segment name.
-StringRef MachORebaseEntry::segmentName() const {
- return O->BindRebaseSegmentName(SegmentIndex);
-}
-
-// For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry
-// to get the section name.
-StringRef MachORebaseEntry::sectionName() const {
- return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);
-}
-
-// For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry
-// to get the address.
-uint64_t MachORebaseEntry::address() const {
- return O->BindRebaseAddress(SegmentIndex, SegmentOffset);
-}
-
-bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const {
-#ifdef EXPENSIVE_CHECKS
- assert(Opcodes == Other.Opcodes && "compare iterators of different files");
-#else
- assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files");
-#endif
- return (Ptr == Other.Ptr) &&
- (RemainingLoopCount == Other.RemainingLoopCount) &&
- (Done == Other.Done);
-}
-
-iterator_range<rebase_iterator>
-MachOObjectFile::rebaseTable(Error &Err, MachOObjectFile *O,
- ArrayRef<uint8_t> Opcodes, bool is64) {
- if (O->BindRebaseSectionTable == nullptr)
- O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);
- MachORebaseEntry Start(&Err, O, Opcodes, is64);
- Start.moveToFirst();
-
- MachORebaseEntry Finish(&Err, O, Opcodes, is64);
- Finish.moveToEnd();
-
- return make_range(rebase_iterator(Start), rebase_iterator(Finish));
-}
-
-iterator_range<rebase_iterator> MachOObjectFile::rebaseTable(Error &Err) {
- return rebaseTable(Err, this, getDyldInfoRebaseOpcodes(), is64Bit());
-}
-
-MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O,
- ArrayRef<uint8_t> Bytes, bool is64Bit, Kind BK)
- : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),
- PointerSize(is64Bit ? 8 : 4), TableKind(BK) {}
-
-void MachOBindEntry::moveToFirst() {
- Ptr = Opcodes.begin();
- moveNext();
-}
-
-void MachOBindEntry::moveToEnd() {
- Ptr = Opcodes.end();
- RemainingLoopCount = 0;
- Done = true;
-}
-
-void MachOBindEntry::moveNext() {
- ErrorAsOutParameter ErrAsOutParam(E);
- // If in the middle of some loop, move to next binding in loop.
- SegmentOffset += AdvanceAmount;
- if (RemainingLoopCount) {
- --RemainingLoopCount;
- return;
- }
- // BIND_OPCODE_DONE is only used for padding if we are not aligned to
- // pointer size. Therefore it is possible to reach the end without ever having
- // seen BIND_OPCODE_DONE.
- if (Ptr == Opcodes.end()) {
- Done = true;
- return;
- }
- bool More = true;
- while (More) {
- // Parse next opcode and set up next loop.
- const uint8_t *OpcodeStart = Ptr;
- uint8_t Byte = *Ptr++;
- uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK;
- uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK;
- int8_t SignExtended;
- const uint8_t *SymStart;
- uint32_t Count, Skip;
- const char *error = nullptr;
- switch (Opcode) {
- case MachO::BIND_OPCODE_DONE:
- if (TableKind == Kind::Lazy) {
- // Lazying bindings have a DONE opcode between entries. Need to ignore
- // it to advance to next entry. But need not if this is last entry.
- bool NotLastEntry = false;
- for (const uint8_t *P = Ptr; P < Opcodes.end(); ++P) {
- if (*P) {
- NotLastEntry = true;
- }
- }
- if (NotLastEntry)
- break;
- }
- More = false;
- moveToEnd();
- DEBUG_WITH_TYPE("mach-o-bind", dbgs() << "BIND_OPCODE_DONE\n");
- break;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- Ordinal = ImmValue;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: "
- << "Ordinal=" << Ordinal << "\n");
- break;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- Ordinal = readULEB128(&error);
- LibraryOrdinalSet = true;
- if (error) {
- *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB " +
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: "
- << "Ordinal=" << Ordinal << "\n");
- break;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- if (ImmValue) {
- SignExtended = MachO::BIND_OPCODE_MASK | ImmValue;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- } else
- Ordinal = 0;
- LibraryOrdinalSet = true;
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: "
- << "Ordinal=" << Ordinal << "\n");
- break;
- case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
- Flags = ImmValue;
- SymStart = Ptr;
- while (*Ptr && (Ptr < Opcodes.end())) {
- ++Ptr;
- }
- if (Ptr == Opcodes.end()) {
- *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);
- ++Ptr;
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: "
- << "SymbolName=" << SymbolName << "\n");
- if (TableKind == Kind::Weak) {
- if (ImmValue & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION)
- return;
- }
- break;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_SET_TYPE_IMM: "
- << "BindType=" << (int)BindType << "\n");
- break;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: "
- << "Addend=" << Addend << "\n");
- break;
- case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
- SegmentIndex = ImmValue;
- SegmentOffset = readULEB128(&error);
- if (error) {
- *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize);
- if (error) {
- *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "
- << "SegmentIndex=" << SegmentIndex << ", "
- << format("SegmentOffset=0x%06X", SegmentOffset)
- << "\n");
- break;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize);
- if (error) {
- *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) +
- " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE("mach-o-bind",
- dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: "
- << format("SegmentOffset=0x%06X",
- SegmentOffset) << "\n");
- break;
- case MachO::BIND_OPCODE_DO_BIND:
- AdvanceAmount = PointerSize;
- RemainingLoopCount = 0;
- error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize);
- if (error) {
- *E = malformedError("for BIND_OPCODE_DO_BIND " + Twine(error) +
- " 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" +
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE("mach-o-bind",
- dbgs() << "BIND_OPCODE_DO_BIND: "
- << format("SegmentOffset=0x%06X",
- SegmentOffset) << "\n");
- return;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize);
- if (error) {
- *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " +
- 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" +
- 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" +
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- // Note, this is not really an error until the next bind but make no sense
- // for a BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB to not be followed by another
- // bind operation.
- error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset +
- AdvanceAmount, PointerSize);
- if (error) {
- *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB (after adding "
- "ULEB) " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- RemainingLoopCount = 0;
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: "
- << format("SegmentOffset=0x%06X", SegmentOffset)
- << ", AdvanceAmount=" << AdvanceAmount
- << ", RemainingLoopCount=" << RemainingLoopCount
- << "\n");
- return;
- 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" +
- 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" +
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- AdvanceAmount = ImmValue * PointerSize + PointerSize;
- RemainingLoopCount = 0;
- error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset +
- AdvanceAmount, PointerSize);
- if (error) {
- *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE("mach-o-bind",
- dbgs()
- << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: "
- << format("SegmentOffset=0x%06X", SegmentOffset) << "\n");
- return;
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- Count = readULEB128(&error);
- if (Count != 0)
- RemainingLoopCount = Count - 1;
- else
- RemainingLoopCount = 0;
- if (error) {
- *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "
- " (count value) " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- Skip = readULEB128(&error);
- AdvanceAmount = Skip + PointerSize;
- if (error) {
- *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "
- " (skip value) " +
- 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" +
- 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" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
- PointerSize, Count, Skip);
- if (error) {
- *E =
- malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +
- Twine(error) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- DEBUG_WITH_TYPE(
- "mach-o-bind",
- dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: "
- << format("SegmentOffset=0x%06X", SegmentOffset)
- << ", AdvanceAmount=" << AdvanceAmount
- << ", RemainingLoopCount=" << RemainingLoopCount
- << "\n");
- return;
- default:
- *E = malformedError("bad bind info (bad opcode value 0x" +
- Twine::utohexstr(Opcode) + " for opcode at: 0x" +
- Twine::utohexstr(OpcodeStart - Opcodes.begin()));
- moveToEnd();
- return;
- }
- }
-}
-
-uint64_t MachOBindEntry::readULEB128(const char **error) {
- unsigned Count;
- uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);
- Ptr += Count;
- if (Ptr > Opcodes.end())
- Ptr = Opcodes.end();
- return Result;
-}
-
-int64_t MachOBindEntry::readSLEB128(const char **error) {
- unsigned Count;
- int64_t Result = decodeSLEB128(Ptr, &Count, Opcodes.end(), error);
- Ptr += Count;
- if (Ptr > Opcodes.end())
- Ptr = Opcodes.end();
- return Result;
-}
-
-int32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; }
-
-uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; }
-
-StringRef MachOBindEntry::typeName() const {
- switch (BindType) {
- case MachO::BIND_TYPE_POINTER:
- return "pointer";
- case MachO::BIND_TYPE_TEXT_ABSOLUTE32:
- return "text abs32";
- case MachO::BIND_TYPE_TEXT_PCREL32:
- return "text rel32";
- }
- return "unknown";
-}
-
-StringRef MachOBindEntry::symbolName() const { return SymbolName; }
-
-int64_t MachOBindEntry::addend() const { return Addend; }
-
-uint32_t MachOBindEntry::flags() const { return Flags; }
-
-int MachOBindEntry::ordinal() const { return Ordinal; }
-
-// For use with the SegIndex of a checked Mach-O Bind entry
-// to get the segment name.
-StringRef MachOBindEntry::segmentName() const {
- return O->BindRebaseSegmentName(SegmentIndex);
-}
-
-// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry
-// to get the section name.
-StringRef MachOBindEntry::sectionName() const {
- return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);
-}
-
-// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry
-// to get the address.
-uint64_t MachOBindEntry::address() const {
- return O->BindRebaseAddress(SegmentIndex, SegmentOffset);
-}
-
-bool MachOBindEntry::operator==(const MachOBindEntry &Other) const {
-#ifdef EXPENSIVE_CHECKS
- assert(Opcodes == Other.Opcodes && "compare iterators of different files");
-#else
- assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files");
-#endif
- return (Ptr == Other.Ptr) &&
- (RemainingLoopCount == Other.RemainingLoopCount) &&
- (Done == Other.Done);
-}
-
-// Build table of sections so SegIndex/SegOffset pairs can be translated.
-BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) {
- uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;
- StringRef CurSegName;
- uint64_t CurSegAddress;
- for (const SectionRef &Section : Obj->sections()) {
- SectionInfo Info;
- Expected<StringRef> NameOrErr = Section.getName();
- if (!NameOrErr)
- consumeError(NameOrErr.takeError());
- else
- Info.SectionName = *NameOrErr;
- Info.Address = Section.getAddress();
- Info.Size = Section.getSize();
- Info.SegmentName =
- Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl());
- if (!Info.SegmentName.equals(CurSegName)) {
- ++CurSegIndex;
- CurSegName = Info.SegmentName;
- CurSegAddress = Info.Address;
- }
- Info.SegmentIndex = CurSegIndex - 1;
- Info.OffsetInSegment = Info.Address - CurSegAddress;
- Info.SegmentStartAddress = CurSegAddress;
- Sections.push_back(Info);
- }
- MaxSegIndex = CurSegIndex;
-}
-
-// For use with a SegIndex, SegOffset, and PointerSize triple in
-// MachOBindEntry::moveNext() to validate a MachOBindEntry or MachORebaseEntry.
-//
-// Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists
-// that fully contains a pointer at that location. Multiple fixups in a bind
-// (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can
-// be tested via the Count and Skip parameters.
-const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex,
- uint64_t SegOffset,
- uint8_t PointerSize,
- uint32_t Count,
- uint32_t Skip) {
- if (SegIndex == -1)
- return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB";
- if (SegIndex >= MaxSegIndex)
- return "bad segIndex (too large)";
- for (uint32_t i = 0; i < Count; ++i) {
- uint32_t Start = SegOffset + i * (PointerSize + Skip);
- uint32_t End = Start + PointerSize;
- bool Found = false;
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex != SegIndex)
- continue;
- if ((SI.OffsetInSegment<=Start) && (Start<(SI.OffsetInSegment+SI.Size))) {
- if (End <= SI.OffsetInSegment + SI.Size) {
- Found = true;
- break;
- }
- else
- return "bad offset, extends beyond section boundary";
- }
- }
- if (!Found)
- return "bad offset, not in section";
- }
- return nullptr;
-}
-
-// For use with the SegIndex of a checked Mach-O Bind or Rebase entry
-// to get the segment name.
-StringRef BindRebaseSegInfo::segmentName(int32_t SegIndex) {
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex == SegIndex)
- return SI.SegmentName;
- }
- llvm_unreachable("invalid SegIndex");
-}
-
-// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
-// to get the SectionInfo.
-const BindRebaseSegInfo::SectionInfo &BindRebaseSegInfo::findSection(
- int32_t SegIndex, uint64_t SegOffset) {
- for (const SectionInfo &SI : Sections) {
- if (SI.SegmentIndex != SegIndex)
- continue;
- if (SI.OffsetInSegment > SegOffset)
- continue;
- if (SegOffset >= (SI.OffsetInSegment + SI.Size))
- continue;
- return SI;
- }
- llvm_unreachable("SegIndex and SegOffset not in any section");
-}
-
-// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
-// entry to get the section name.
-StringRef BindRebaseSegInfo::sectionName(int32_t SegIndex,
- uint64_t SegOffset) {
- return findSection(SegIndex, SegOffset).SectionName;
-}
-
-// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
-// entry to get the address.
-uint64_t BindRebaseSegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) {
- const SectionInfo &SI = findSection(SegIndex, OffsetInSeg);
- return SI.SegmentStartAddress + OffsetInSeg;
-}
-
-iterator_range<bind_iterator>
-MachOObjectFile::bindTable(Error &Err, MachOObjectFile *O,
- ArrayRef<uint8_t> Opcodes, bool is64,
- MachOBindEntry::Kind BKind) {
- if (O->BindRebaseSectionTable == nullptr)
- O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);
- MachOBindEntry Start(&Err, O, Opcodes, is64, BKind);
- Start.moveToFirst();
-
- MachOBindEntry Finish(&Err, O, Opcodes, is64, BKind);
- Finish.moveToEnd();
-
- return make_range(bind_iterator(Start), bind_iterator(Finish));
-}
-
-iterator_range<bind_iterator> MachOObjectFile::bindTable(Error &Err) {
- return bindTable(Err, this, getDyldInfoBindOpcodes(), is64Bit(),
- MachOBindEntry::Kind::Regular);
-}
-
-iterator_range<bind_iterator> MachOObjectFile::lazyBindTable(Error &Err) {
- return bindTable(Err, this, getDyldInfoLazyBindOpcodes(), is64Bit(),
- MachOBindEntry::Kind::Lazy);
-}
-
-iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) {
- return bindTable(Err, this, getDyldInfoWeakBindOpcodes(), is64Bit(),
- MachOBindEntry::Kind::Weak);
-}
-
-MachOObjectFile::load_command_iterator
-MachOObjectFile::begin_load_commands() const {
- return LoadCommands.begin();
-}
-
-MachOObjectFile::load_command_iterator
-MachOObjectFile::end_load_commands() const {
- return LoadCommands.end();
-}
-
-iterator_range<MachOObjectFile::load_command_iterator>
-MachOObjectFile::load_commands() const {
- return make_range(begin_load_commands(), end_load_commands());
-}
-
-StringRef
-MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {
- ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec);
- return parseSegmentOrSectionName(Raw.data());
-}
-
-ArrayRef<char>
-MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {
- assert(Sec.d.a < Sections.size() && "Should have detected this earlier");
- const section_base *Base =
- reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
- return makeArrayRef(Base->sectname);
-}
-
-ArrayRef<char>
-MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const {
- assert(Sec.d.a < Sections.size() && "Should have detected this earlier");
- const section_base *Base =
- reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
- return makeArrayRef(Base->segname);
-}
-
-bool
-MachOObjectFile::isRelocationScattered(const MachO::any_relocation_info &RE)
- const {
- if (getCPUType(*this) == MachO::CPU_TYPE_X86_64)
- return false;
- return getPlainRelocationAddress(RE) & MachO::R_SCATTERED;
-}
-
-unsigned MachOObjectFile::getPlainRelocationSymbolNum(
- const MachO::any_relocation_info &RE) const {
- if (isLittleEndian())
- return RE.r_word1 & 0xffffff;
- return RE.r_word1 >> 8;
-}
-
-bool MachOObjectFile::getPlainRelocationExternal(
- const MachO::any_relocation_info &RE) const {
- if (isLittleEndian())
- return (RE.r_word1 >> 27) & 1;
- return (RE.r_word1 >> 4) & 1;
-}
-
-bool MachOObjectFile::getScatteredRelocationScattered(
- const MachO::any_relocation_info &RE) const {
- return RE.r_word0 >> 31;
-}
-
-uint32_t MachOObjectFile::getScatteredRelocationValue(
- const MachO::any_relocation_info &RE) const {
- return RE.r_word1;
-}
-
-uint32_t MachOObjectFile::getScatteredRelocationType(
- const MachO::any_relocation_info &RE) const {
- return (RE.r_word0 >> 24) & 0xf;
-}
-
-unsigned MachOObjectFile::getAnyRelocationAddress(
- const MachO::any_relocation_info &RE) const {
- if (isRelocationScattered(RE))
- return getScatteredRelocationAddress(RE);
- return getPlainRelocationAddress(RE);
-}
-
-unsigned MachOObjectFile::getAnyRelocationPCRel(
- const MachO::any_relocation_info &RE) const {
- if (isRelocationScattered(RE))
- return getScatteredRelocationPCRel(RE);
- return getPlainRelocationPCRel(*this, RE);
-}
-
-unsigned MachOObjectFile::getAnyRelocationLength(
- const MachO::any_relocation_info &RE) const {
- if (isRelocationScattered(RE))
- return getScatteredRelocationLength(RE);
- return getPlainRelocationLength(*this, RE);
-}
-
-unsigned
-MachOObjectFile::getAnyRelocationType(
- const MachO::any_relocation_info &RE) const {
- if (isRelocationScattered(RE))
- return getScatteredRelocationType(RE);
- return getPlainRelocationType(*this, RE);
-}
-
-SectionRef
-MachOObjectFile::getAnyRelocationSection(
- const MachO::any_relocation_info &RE) const {
- if (isRelocationScattered(RE) || getPlainRelocationExternal(RE))
- return *section_end();
- unsigned SecNum = getPlainRelocationSymbolNum(RE);
- if (SecNum == MachO::R_ABS || SecNum > Sections.size())
- return *section_end();
- DataRefImpl DRI;
- DRI.d.a = SecNum - 1;
- return SectionRef(DRI, this);
-}
-
-MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const {
- assert(DRI.d.a < Sections.size() && "Should have detected this earlier");
- return getStruct<MachO::section>(*this, Sections[DRI.d.a]);
-}
-
-MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const {
- assert(DRI.d.a < Sections.size() && "Should have detected this earlier");
- return getStruct<MachO::section_64>(*this, Sections[DRI.d.a]);
-}
-
-MachO::section MachOObjectFile::getSection(const LoadCommandInfo &L,
- unsigned Index) const {
- const char *Sec = getSectionPtr(*this, L, Index);
- return getStruct<MachO::section>(*this, Sec);
-}
-
-MachO::section_64 MachOObjectFile::getSection64(const LoadCommandInfo &L,
- unsigned Index) const {
- const char *Sec = getSectionPtr(*this, L, Index);
- return getStruct<MachO::section_64>(*this, Sec);
-}
-
-MachO::nlist
-MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const {
- const char *P = reinterpret_cast<const char *>(DRI.p);
- return getStruct<MachO::nlist>(*this, P);
-}
-
-MachO::nlist_64
-MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI) const {
- const char *P = reinterpret_cast<const char *>(DRI.p);
- return getStruct<MachO::nlist_64>(*this, P);
-}
-
-MachO::linkedit_data_command
-MachOObjectFile::getLinkeditDataLoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::linkedit_data_command>(*this, L.Ptr);
-}
-
-MachO::segment_command
-MachOObjectFile::getSegmentLoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::segment_command>(*this, L.Ptr);
-}
-
-MachO::segment_command_64
-MachOObjectFile::getSegment64LoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::segment_command_64>(*this, L.Ptr);
-}
-
-MachO::linker_option_command
-MachOObjectFile::getLinkerOptionLoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::linker_option_command>(*this, L.Ptr);
-}
-
-MachO::version_min_command
-MachOObjectFile::getVersionMinLoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::version_min_command>(*this, L.Ptr);
-}
-
-MachO::note_command
-MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::note_command>(*this, L.Ptr);
-}
-
-MachO::build_version_command
-MachOObjectFile::getBuildVersionLoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::build_version_command>(*this, L.Ptr);
-}
-
-MachO::build_tool_version
-MachOObjectFile::getBuildToolVersion(unsigned index) const {
- return getStruct<MachO::build_tool_version>(*this, BuildTools[index]);
-}
-
-MachO::dylib_command
-MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::dylib_command>(*this, L.Ptr);
-}
-
-MachO::dyld_info_command
-MachOObjectFile::getDyldInfoLoadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::dyld_info_command>(*this, L.Ptr);
-}
-
-MachO::dylinker_command
-MachOObjectFile::getDylinkerCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::dylinker_command>(*this, L.Ptr);
-}
-
-MachO::uuid_command
-MachOObjectFile::getUuidCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::uuid_command>(*this, L.Ptr);
-}
-
-MachO::rpath_command
-MachOObjectFile::getRpathCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::rpath_command>(*this, L.Ptr);
-}
-
-MachO::source_version_command
-MachOObjectFile::getSourceVersionCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::source_version_command>(*this, L.Ptr);
-}
-
-MachO::entry_point_command
-MachOObjectFile::getEntryPointCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::entry_point_command>(*this, L.Ptr);
-}
-
-MachO::encryption_info_command
-MachOObjectFile::getEncryptionInfoCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::encryption_info_command>(*this, L.Ptr);
-}
-
-MachO::encryption_info_command_64
-MachOObjectFile::getEncryptionInfoCommand64(const LoadCommandInfo &L) const {
- return getStruct<MachO::encryption_info_command_64>(*this, L.Ptr);
-}
-
-MachO::sub_framework_command
-MachOObjectFile::getSubFrameworkCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::sub_framework_command>(*this, L.Ptr);
-}
-
-MachO::sub_umbrella_command
-MachOObjectFile::getSubUmbrellaCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::sub_umbrella_command>(*this, L.Ptr);
-}
-
-MachO::sub_library_command
-MachOObjectFile::getSubLibraryCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::sub_library_command>(*this, L.Ptr);
-}
-
-MachO::sub_client_command
-MachOObjectFile::getSubClientCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::sub_client_command>(*this, L.Ptr);
-}
-
-MachO::routines_command
-MachOObjectFile::getRoutinesCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::routines_command>(*this, L.Ptr);
-}
-
-MachO::routines_command_64
-MachOObjectFile::getRoutinesCommand64(const LoadCommandInfo &L) const {
- return getStruct<MachO::routines_command_64>(*this, L.Ptr);
-}
-
-MachO::thread_command
-MachOObjectFile::getThreadCommand(const LoadCommandInfo &L) const {
- return getStruct<MachO::thread_command>(*this, L.Ptr);
-}
-
-MachO::any_relocation_info
-MachOObjectFile::getRelocation(DataRefImpl Rel) const {
- uint32_t Offset;
- if (getHeader().filetype == MachO::MH_OBJECT) {
- DataRefImpl Sec;
- Sec.d.a = Rel.d.a;
- if (is64Bit()) {
- MachO::section_64 Sect = getSection64(Sec);
- Offset = Sect.reloff;
- } else {
- MachO::section Sect = getSection(Sec);
- Offset = Sect.reloff;
- }
- } else {
- MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();
- 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 *>(
- getPtr(*this, Offset)) + Rel.d.b;
- return getStruct<MachO::any_relocation_info>(
- *this, reinterpret_cast<const char *>(P));
-}
-
-MachO::data_in_code_entry
-MachOObjectFile::getDice(DataRefImpl Rel) const {
- const char *P = reinterpret_cast<const char *>(Rel.p);
- return getStruct<MachO::data_in_code_entry>(*this, P);
-}
-
-const MachO::mach_header &MachOObjectFile::getHeader() const {
- return Header;
-}
-
-const MachO::mach_header_64 &MachOObjectFile::getHeader64() const {
- assert(is64Bit());
- return Header64;
-}
-
-uint32_t MachOObjectFile::getIndirectSymbolTableEntry(
- const MachO::dysymtab_command &DLC,
- unsigned Index) const {
- uint64_t Offset = DLC.indirectsymoff + Index * sizeof(uint32_t);
- return getStruct<uint32_t>(*this, getPtr(*this, Offset));
-}
-
-MachO::data_in_code_entry
-MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset,
- unsigned Index) const {
- uint64_t Offset = DataOffset + Index * sizeof(MachO::data_in_code_entry);
- return getStruct<MachO::data_in_code_entry>(*this, getPtr(*this, Offset));
-}
-
-MachO::symtab_command MachOObjectFile::getSymtabLoadCommand() const {
- if (SymtabLoadCmd)
- return getStruct<MachO::symtab_command>(*this, SymtabLoadCmd);
-
- // If there is no SymtabLoadCmd return a load command with zero'ed fields.
- MachO::symtab_command Cmd;
- Cmd.cmd = MachO::LC_SYMTAB;
- Cmd.cmdsize = sizeof(MachO::symtab_command);
- Cmd.symoff = 0;
- Cmd.nsyms = 0;
- Cmd.stroff = 0;
- Cmd.strsize = 0;
- return Cmd;
-}
-
-MachO::dysymtab_command MachOObjectFile::getDysymtabLoadCommand() const {
- if (DysymtabLoadCmd)
- return getStruct<MachO::dysymtab_command>(*this, DysymtabLoadCmd);
-
- // If there is no DysymtabLoadCmd return a load command with zero'ed fields.
- MachO::dysymtab_command Cmd;
- Cmd.cmd = MachO::LC_DYSYMTAB;
- Cmd.cmdsize = sizeof(MachO::dysymtab_command);
- Cmd.ilocalsym = 0;
- Cmd.nlocalsym = 0;
- Cmd.iextdefsym = 0;
- Cmd.nextdefsym = 0;
- Cmd.iundefsym = 0;
- Cmd.nundefsym = 0;
- Cmd.tocoff = 0;
- Cmd.ntoc = 0;
- Cmd.modtaboff = 0;
- Cmd.nmodtab = 0;
- Cmd.extrefsymoff = 0;
- Cmd.nextrefsyms = 0;
- Cmd.indirectsymoff = 0;
- Cmd.nindirectsyms = 0;
- Cmd.extreloff = 0;
- Cmd.nextrel = 0;
- Cmd.locreloff = 0;
- Cmd.nlocrel = 0;
- return Cmd;
-}
-
-MachO::linkedit_data_command
-MachOObjectFile::getDataInCodeLoadCommand() const {
- if (DataInCodeLoadCmd)
- return getStruct<MachO::linkedit_data_command>(*this, DataInCodeLoadCmd);
-
- // If there is no DataInCodeLoadCmd return a load command with zero'ed fields.
- MachO::linkedit_data_command Cmd;
- Cmd.cmd = MachO::LC_DATA_IN_CODE;
- Cmd.cmdsize = sizeof(MachO::linkedit_data_command);
- Cmd.dataoff = 0;
- Cmd.datasize = 0;
- return Cmd;
-}
-
-MachO::linkedit_data_command
-MachOObjectFile::getLinkOptHintsLoadCommand() const {
- if (LinkOptHintsLoadCmd)
- return getStruct<MachO::linkedit_data_command>(*this, LinkOptHintsLoadCmd);
-
- // If there is no LinkOptHintsLoadCmd return a load command with zero'ed
- // fields.
- MachO::linkedit_data_command Cmd;
- Cmd.cmd = MachO::LC_LINKER_OPTIMIZATION_HINT;
- Cmd.cmdsize = sizeof(MachO::linkedit_data_command);
- Cmd.dataoff = 0;
- Cmd.datasize = 0;
- return Cmd;
-}
-
-ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const {
- if (!DyldInfoLoadCmd)
- return None;
-
- auto DyldInfoOrErr =
- getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
- if (!DyldInfoOrErr)
- return None;
- MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
- const uint8_t *Ptr =
- reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.rebase_off));
- return makeArrayRef(Ptr, DyldInfo.rebase_size);
-}
-
-ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const {
- if (!DyldInfoLoadCmd)
- return None;
-
- auto DyldInfoOrErr =
- getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
- if (!DyldInfoOrErr)
- return None;
- MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
- const uint8_t *Ptr =
- reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.bind_off));
- return makeArrayRef(Ptr, DyldInfo.bind_size);
-}
-
-ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const {
- if (!DyldInfoLoadCmd)
- return None;
-
- auto DyldInfoOrErr =
- getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
- if (!DyldInfoOrErr)
- return None;
- MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
- const uint8_t *Ptr =
- reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.weak_bind_off));
- return makeArrayRef(Ptr, DyldInfo.weak_bind_size);
-}
-
-ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
- if (!DyldInfoLoadCmd)
- return None;
-
- auto DyldInfoOrErr =
- getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
- if (!DyldInfoOrErr)
- return None;
- MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
- const uint8_t *Ptr =
- reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.lazy_bind_off));
- return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
-}
-
-ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {
- if (!DyldInfoLoadCmd)
- return None;
-
- auto DyldInfoOrErr =
- getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
- if (!DyldInfoOrErr)
- return None;
- MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
- const uint8_t *Ptr =
- reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.export_off));
- return makeArrayRef(Ptr, DyldInfo.export_size);
-}
-
-ArrayRef<uint8_t> MachOObjectFile::getUuid() const {
- if (!UuidLoadCmd)
- return None;
- // Returning a pointer is fine as uuid doesn't need endian swapping.
- const char *Ptr = UuidLoadCmd + offsetof(MachO::uuid_command, uuid);
- return makeArrayRef(reinterpret_cast<const uint8_t *>(Ptr), 16);
-}
-
-StringRef MachOObjectFile::getStringTableData() const {
- MachO::symtab_command S = getSymtabLoadCommand();
- return getData().substr(S.stroff, S.strsize);
-}
-
-bool MachOObjectFile::is64Bit() const {
- return getType() == getMachOType(false, true) ||
- getType() == getMachOType(true, true);
-}
-
-void MachOObjectFile::ReadULEB128s(uint64_t Index,
- SmallVectorImpl<uint64_t> &Out) const {
- DataExtractor extractor(ObjectFile::getData(), true, 0);
-
- uint64_t offset = Index;
- uint64_t data = 0;
- while (uint64_t delta = extractor.getULEB128(&offset)) {
- data += delta;
- Out.push_back(data);
- }
-}
-
-bool MachOObjectFile::isRelocatableObject() const {
- return getHeader().filetype == MachO::MH_OBJECT;
-}
-
-Expected<std::unique_ptr<MachOObjectFile>>
-ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer,
- uint32_t UniversalCputype,
- uint32_t UniversalIndex) {
- StringRef Magic = Buffer.getBuffer().slice(0, 4);
- if (Magic == "\xFE\xED\xFA\xCE")
- return MachOObjectFile::create(Buffer, false, false,
- UniversalCputype, UniversalIndex);
- if (Magic == "\xCE\xFA\xED\xFE")
- return MachOObjectFile::create(Buffer, true, false,
- UniversalCputype, UniversalIndex);
- if (Magic == "\xFE\xED\xFA\xCF")
- return MachOObjectFile::create(Buffer, false, true,
- UniversalCputype, UniversalIndex);
- if (Magic == "\xCF\xFA\xED\xFE")
- return MachOObjectFile::create(Buffer, true, true,
- UniversalCputype, UniversalIndex);
- return make_error<GenericBinaryError>("Unrecognized MachO magic number",
- object_error::invalid_file_type);
-}
-
-StringRef MachOObjectFile::mapDebugSectionName(StringRef Name) const {
- return StringSwitch<StringRef>(Name)
- .Case("debug_str_offs", "debug_str_offsets")
- .Default(Name);
-}
+}
+
+Triple::ArchType MachOObjectFile::getArch() const {
+ return getArch(getCPUType(*this), getCPUSubType(*this));
+}
+
+Triple MachOObjectFile::getArchTriple(const char **McpuDefault) const {
+ return getArchTriple(Header.cputype, Header.cpusubtype, McpuDefault);
+}
+
+relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const {
+ DataRefImpl DRI;
+ DRI.d.a = Index;
+ return section_rel_begin(DRI);
+}
+
+relocation_iterator MachOObjectFile::section_rel_end(unsigned Index) const {
+ DataRefImpl DRI;
+ DRI.d.a = Index;
+ return section_rel_end(DRI);
+}
+
+dice_iterator MachOObjectFile::begin_dices() const {
+ DataRefImpl DRI;
+ if (!DataInCodeLoadCmd)
+ return dice_iterator(DiceRef(DRI, this));
+
+ MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();
+ DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, DicLC.dataoff));
+ return dice_iterator(DiceRef(DRI, this));
+}
+
+dice_iterator MachOObjectFile::end_dices() const {
+ DataRefImpl DRI;
+ if (!DataInCodeLoadCmd)
+ return dice_iterator(DiceRef(DRI, this));
+
+ MachO::linkedit_data_command DicLC = getDataInCodeLoadCommand();
+ unsigned Offset = DicLC.dataoff + DicLC.datasize;
+ DRI.p = reinterpret_cast<uintptr_t>(getPtr(*this, Offset));
+ return dice_iterator(DiceRef(DRI, this));
+}
+
+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();
+}
+
+void ExportEntry::moveToEnd() {
+ Stack.clear();
+ Done = true;
+}
+
+bool ExportEntry::operator==(const ExportEntry &Other) const {
+ // Common case, one at end, other iterating from begin.
+ if (Done || Other.Done)
+ return (Done == Other.Done);
+ // Not equal if different stack sizes.
+ if (Stack.size() != Other.Stack.size())
+ return false;
+ // Not equal if different cumulative strings.
+ if (!CumulativeString.equals(Other.CumulativeString))
+ return false;
+ // Equal if all nodes in both stacks match.
+ for (unsigned i=0; i < Stack.size(); ++i) {
+ if (Stack[i].Start != Other.Stack[i].Start)
+ return false;
+ }
+ return true;
+}
+
+uint64_t ExportEntry::readULEB128(const uint8_t *&Ptr, const char **error) {
+ unsigned Count;
+ uint64_t Result = decodeULEB128(Ptr, &Count, Trie.end(), error);
+ Ptr += Count;
+ if (Ptr > Trie.end())
+ Ptr = Trie.end();
+ return Result;
+}
+
+StringRef ExportEntry::name() const {
+ return CumulativeString;
+}
+
+uint64_t ExportEntry::flags() const {
+ return Stack.back().Flags;
+}
+
+uint64_t ExportEntry::address() const {
+ return Stack.back().Address;
+}
+
+uint64_t ExportEntry::other() const {
+ return Stack.back().Other;
+}
+
+StringRef ExportEntry::otherName() const {
+ const char* ImportName = Stack.back().ImportName;
+ if (ImportName)
+ return StringRef(ImportName);
+ return StringRef();
+}
+
+uint32_t ExportEntry::nodeOffset() const {
+ return Stack.back().Start - Trie.begin();
+}
+
+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);
+ 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) {
+ 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, &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, &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();
+ Stack.push_back(State);
+}
+
+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 < 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, &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) {
+ *E = malformedError("node is not an export node in export trie data at "
+ "node: 0x" +
+ Twine::utohexstr(Stack.back().Start - Trie.begin()));
+ moveToEnd();
+ return;
+ }
+}
+
+// We have a trie data structure and need a way to walk it that is compatible
+// with the C++ iterator model. The solution is a non-recursive depth first
+// traversal where the iterator contains a stack of parent nodes along with a
+// string that is the accumulation of all edge strings along the parent chain
+// to this point.
+//
+// There is one "export" node for each exported symbol. But because some
+// symbols may be a prefix of another symbol (e.g. _dup and _dup2), an export
+// node may have child nodes too.
+//
+// The algorithm for moveNext() is to keep moving down the leftmost unvisited
+// child until hitting a node with no children (which is an export node or
+// else the trie is malformed). On the way down, each node is pushed on the
+// 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() {
+ 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;
+ }
+
+ Stack.pop_back();
+ while (!Stack.empty()) {
+ NodeState &Top = Stack.back();
+ if (Top.NextChildIndex < Top.ChildCount) {
+ pushDownUntilBottom();
+ // Now at the next export node.
+ return;
+ } else {
+ if (Top.IsExportNode) {
+ // This node has no children but is itself an export node.
+ CumulativeString.resize(Top.ParentStringLength);
+ return;
+ }
+ Stack.pop_back();
+ }
+ }
+ Done = true;
+}
+
+iterator_range<export_iterator>
+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(&E, O, Trie);
+ Finish.moveToEnd();
+
+ return make_range(export_iterator(Start), export_iterator(Finish));
+}
+
+iterator_range<export_iterator> MachOObjectFile::exports(Error &Err) const {
+ return exports(Err, getDyldInfoExportsTrie(), this);
+}
+
+MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O,
+ ArrayRef<uint8_t> Bytes, bool is64Bit)
+ : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),
+ PointerSize(is64Bit ? 8 : 4) {}
+
+void MachORebaseEntry::moveToFirst() {
+ Ptr = Opcodes.begin();
+ moveNext();
+}
+
+void MachORebaseEntry::moveToEnd() {
+ Ptr = Opcodes.end();
+ RemainingLoopCount = 0;
+ Done = true;
+}
+
+void MachORebaseEntry::moveNext() {
+ ErrorAsOutParameter ErrAsOutParam(E);
+ // If in the middle of some loop, move to next rebasing in loop.
+ SegmentOffset += AdvanceAmount;
+ if (RemainingLoopCount) {
+ --RemainingLoopCount;
+ return;
+ }
+ // REBASE_OPCODE_DONE is only used for padding if we are not aligned to
+ // pointer size. Therefore it is possible to reach the end without ever having
+ // seen REBASE_OPCODE_DONE.
+ if (Ptr == Opcodes.end()) {
+ Done = true;
+ return;
+ }
+ bool More = true;
+ while (More) {
+ // Parse next opcode and set up next loop.
+ const uint8_t *OpcodeStart = Ptr;
+ uint8_t Byte = *Ptr++;
+ uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK;
+ uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK;
+ uint32_t Count, Skip;
+ const char *error = nullptr;
+ switch (Opcode) {
+ case MachO::REBASE_OPCODE_DONE:
+ More = false;
+ Done = true;
+ moveToEnd();
+ DEBUG_WITH_TYPE("mach-o-rebase", dbgs() << "REBASE_OPCODE_DONE\n");
+ break;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-rebase",
+ dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: "
+ << "RebaseType=" << (int) RebaseType << "\n");
+ break;
+ case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ SegmentIndex = ImmValue;
+ SegmentOffset = readULEB128(&error);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-rebase",
+ dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "
+ << "SegmentIndex=" << SegmentIndex << ", "
+ << format("SegmentOffset=0x%06X", SegmentOffset)
+ << "\n");
+ break;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + Twine(error) +
+ " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE("mach-o-rebase",
+ dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: "
+ << format("SegmentOffset=0x%06X",
+ SegmentOffset) << "\n");
+ break;
+ case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED:
+ SegmentOffset += ImmValue * PointerSize;
+ error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE("mach-o-rebase",
+ dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: "
+ << format("SegmentOffset=0x%06X",
+ SegmentOffset) << "\n");
+ break;
+ case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES:
+ AdvanceAmount = PointerSize;
+ Skip = 0;
+ Count = ImmValue;
+ if (ImmValue != 0)
+ RemainingLoopCount = ImmValue - 1;
+ else
+ RemainingLoopCount = 0;
+ error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize, Count, Skip);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-rebase",
+ dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: "
+ << format("SegmentOffset=0x%06X", SegmentOffset)
+ << ", AdvanceAmount=" << AdvanceAmount
+ << ", RemainingLoopCount=" << RemainingLoopCount
+ << "\n");
+ return;
+ case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES:
+ AdvanceAmount = PointerSize;
+ Skip = 0;
+ Count = readULEB128(&error);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ if (Count != 0)
+ RemainingLoopCount = Count - 1;
+ else
+ RemainingLoopCount = 0;
+ error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize, Count, Skip);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-rebase",
+ dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: "
+ << format("SegmentOffset=0x%06X", SegmentOffset)
+ << ", AdvanceAmount=" << AdvanceAmount
+ << ", RemainingLoopCount=" << RemainingLoopCount
+ << "\n");
+ return;
+ case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB:
+ Skip = readULEB128(&error);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ AdvanceAmount = Skip + PointerSize;
+ Count = 1;
+ RemainingLoopCount = 0;
+ error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize, Count, Skip);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-rebase",
+ dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: "
+ << format("SegmentOffset=0x%06X", SegmentOffset)
+ << ", AdvanceAmount=" << AdvanceAmount
+ << ", RemainingLoopCount=" << RemainingLoopCount
+ << "\n");
+ return;
+ case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB:
+ Count = readULEB128(&error);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
+ "ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ if (Count != 0)
+ RemainingLoopCount = Count - 1;
+ else
+ RemainingLoopCount = 0;
+ Skip = readULEB128(&error);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
+ "ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ AdvanceAmount = Skip + PointerSize;
+
+ error = O->RebaseEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize, Count, Skip);
+ if (error) {
+ *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_"
+ "ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-rebase",
+ dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: "
+ << format("SegmentOffset=0x%06X", SegmentOffset)
+ << ", AdvanceAmount=" << AdvanceAmount
+ << ", RemainingLoopCount=" << RemainingLoopCount
+ << "\n");
+ return;
+ default:
+ *E = malformedError("bad rebase info (bad opcode value 0x" +
+ Twine::utohexstr(Opcode) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ }
+}
+
+uint64_t MachORebaseEntry::readULEB128(const char **error) {
+ unsigned Count;
+ uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);
+ Ptr += Count;
+ if (Ptr > Opcodes.end())
+ Ptr = Opcodes.end();
+ return Result;
+}
+
+int32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; }
+
+uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; }
+
+StringRef MachORebaseEntry::typeName() const {
+ switch (RebaseType) {
+ case MachO::REBASE_TYPE_POINTER:
+ return "pointer";
+ case MachO::REBASE_TYPE_TEXT_ABSOLUTE32:
+ return "text abs32";
+ case MachO::REBASE_TYPE_TEXT_PCREL32:
+ return "text rel32";
+ }
+ return "unknown";
+}
+
+// For use with the SegIndex of a checked Mach-O Rebase entry
+// to get the segment name.
+StringRef MachORebaseEntry::segmentName() const {
+ return O->BindRebaseSegmentName(SegmentIndex);
+}
+
+// For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry
+// to get the section name.
+StringRef MachORebaseEntry::sectionName() const {
+ return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);
+}
+
+// For use with a SegIndex,SegOffset pair from a checked Mach-O Rebase entry
+// to get the address.
+uint64_t MachORebaseEntry::address() const {
+ return O->BindRebaseAddress(SegmentIndex, SegmentOffset);
+}
+
+bool MachORebaseEntry::operator==(const MachORebaseEntry &Other) const {
+#ifdef EXPENSIVE_CHECKS
+ assert(Opcodes == Other.Opcodes && "compare iterators of different files");
+#else
+ assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files");
+#endif
+ return (Ptr == Other.Ptr) &&
+ (RemainingLoopCount == Other.RemainingLoopCount) &&
+ (Done == Other.Done);
+}
+
+iterator_range<rebase_iterator>
+MachOObjectFile::rebaseTable(Error &Err, MachOObjectFile *O,
+ ArrayRef<uint8_t> Opcodes, bool is64) {
+ if (O->BindRebaseSectionTable == nullptr)
+ O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);
+ MachORebaseEntry Start(&Err, O, Opcodes, is64);
+ Start.moveToFirst();
+
+ MachORebaseEntry Finish(&Err, O, Opcodes, is64);
+ Finish.moveToEnd();
+
+ return make_range(rebase_iterator(Start), rebase_iterator(Finish));
+}
+
+iterator_range<rebase_iterator> MachOObjectFile::rebaseTable(Error &Err) {
+ return rebaseTable(Err, this, getDyldInfoRebaseOpcodes(), is64Bit());
+}
+
+MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O,
+ ArrayRef<uint8_t> Bytes, bool is64Bit, Kind BK)
+ : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()),
+ PointerSize(is64Bit ? 8 : 4), TableKind(BK) {}
+
+void MachOBindEntry::moveToFirst() {
+ Ptr = Opcodes.begin();
+ moveNext();
+}
+
+void MachOBindEntry::moveToEnd() {
+ Ptr = Opcodes.end();
+ RemainingLoopCount = 0;
+ Done = true;
+}
+
+void MachOBindEntry::moveNext() {
+ ErrorAsOutParameter ErrAsOutParam(E);
+ // If in the middle of some loop, move to next binding in loop.
+ SegmentOffset += AdvanceAmount;
+ if (RemainingLoopCount) {
+ --RemainingLoopCount;
+ return;
+ }
+ // BIND_OPCODE_DONE is only used for padding if we are not aligned to
+ // pointer size. Therefore it is possible to reach the end without ever having
+ // seen BIND_OPCODE_DONE.
+ if (Ptr == Opcodes.end()) {
+ Done = true;
+ return;
+ }
+ bool More = true;
+ while (More) {
+ // Parse next opcode and set up next loop.
+ const uint8_t *OpcodeStart = Ptr;
+ uint8_t Byte = *Ptr++;
+ uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK;
+ uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK;
+ int8_t SignExtended;
+ const uint8_t *SymStart;
+ uint32_t Count, Skip;
+ const char *error = nullptr;
+ switch (Opcode) {
+ case MachO::BIND_OPCODE_DONE:
+ if (TableKind == Kind::Lazy) {
+ // Lazying bindings have a DONE opcode between entries. Need to ignore
+ // it to advance to next entry. But need not if this is last entry.
+ bool NotLastEntry = false;
+ for (const uint8_t *P = Ptr; P < Opcodes.end(); ++P) {
+ if (*P) {
+ NotLastEntry = true;
+ }
+ }
+ if (NotLastEntry)
+ break;
+ }
+ More = false;
+ moveToEnd();
+ DEBUG_WITH_TYPE("mach-o-bind", dbgs() << "BIND_OPCODE_DONE\n");
+ break;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ Ordinal = ImmValue;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: "
+ << "Ordinal=" << Ordinal << "\n");
+ break;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ Ordinal = readULEB128(&error);
+ LibraryOrdinalSet = true;
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB " +
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: "
+ << "Ordinal=" << Ordinal << "\n");
+ break;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ if (ImmValue) {
+ SignExtended = MachO::BIND_OPCODE_MASK | ImmValue;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ } else
+ Ordinal = 0;
+ LibraryOrdinalSet = true;
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: "
+ << "Ordinal=" << Ordinal << "\n");
+ break;
+ case MachO::BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM:
+ Flags = ImmValue;
+ SymStart = Ptr;
+ while (*Ptr && (Ptr < Opcodes.end())) {
+ ++Ptr;
+ }
+ if (Ptr == Opcodes.end()) {
+ *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);
+ ++Ptr;
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_SET_SYMBOL_TRAILING_FLAGS_IMM: "
+ << "SymbolName=" << SymbolName << "\n");
+ if (TableKind == Kind::Weak) {
+ if (ImmValue & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION)
+ return;
+ }
+ break;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_SET_TYPE_IMM: "
+ << "BindType=" << (int)BindType << "\n");
+ break;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: "
+ << "Addend=" << Addend << "\n");
+ break;
+ case MachO::BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
+ SegmentIndex = ImmValue;
+ SegmentOffset = readULEB128(&error);
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize);
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: "
+ << "SegmentIndex=" << SegmentIndex << ", "
+ << format("SegmentOffset=0x%06X", SegmentOffset)
+ << "\n");
+ break;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize);
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB " + Twine(error) +
+ " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE("mach-o-bind",
+ dbgs() << "BIND_OPCODE_ADD_ADDR_ULEB: "
+ << format("SegmentOffset=0x%06X",
+ SegmentOffset) << "\n");
+ break;
+ case MachO::BIND_OPCODE_DO_BIND:
+ AdvanceAmount = PointerSize;
+ RemainingLoopCount = 0;
+ error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize);
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_DO_BIND " + Twine(error) +
+ " 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" +
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE("mach-o-bind",
+ dbgs() << "BIND_OPCODE_DO_BIND: "
+ << format("SegmentOffset=0x%06X",
+ SegmentOffset) << "\n");
+ return;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize);
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " +
+ 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" +
+ 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" +
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ // Note, this is not really an error until the next bind but make no sense
+ // for a BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB to not be followed by another
+ // bind operation.
+ error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset +
+ AdvanceAmount, PointerSize);
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_ADD_ADDR_ULEB (after adding "
+ "ULEB) " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ RemainingLoopCount = 0;
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: "
+ << format("SegmentOffset=0x%06X", SegmentOffset)
+ << ", AdvanceAmount=" << AdvanceAmount
+ << ", RemainingLoopCount=" << RemainingLoopCount
+ << "\n");
+ return;
+ 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" +
+ 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" +
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ AdvanceAmount = ImmValue * PointerSize + PointerSize;
+ RemainingLoopCount = 0;
+ error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset +
+ AdvanceAmount, PointerSize);
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE("mach-o-bind",
+ dbgs()
+ << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: "
+ << format("SegmentOffset=0x%06X", SegmentOffset) << "\n");
+ return;
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ Count = readULEB128(&error);
+ if (Count != 0)
+ RemainingLoopCount = Count - 1;
+ else
+ RemainingLoopCount = 0;
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "
+ " (count value) " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ Skip = readULEB128(&error);
+ AdvanceAmount = Skip + PointerSize;
+ if (error) {
+ *E = malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB "
+ " (skip value) " +
+ 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" +
+ 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" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ error = O->BindEntryCheckSegAndOffsets(SegmentIndex, SegmentOffset,
+ PointerSize, Count, Skip);
+ if (error) {
+ *E =
+ malformedError("for BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB " +
+ Twine(error) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ DEBUG_WITH_TYPE(
+ "mach-o-bind",
+ dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: "
+ << format("SegmentOffset=0x%06X", SegmentOffset)
+ << ", AdvanceAmount=" << AdvanceAmount
+ << ", RemainingLoopCount=" << RemainingLoopCount
+ << "\n");
+ return;
+ default:
+ *E = malformedError("bad bind info (bad opcode value 0x" +
+ Twine::utohexstr(Opcode) + " for opcode at: 0x" +
+ Twine::utohexstr(OpcodeStart - Opcodes.begin()));
+ moveToEnd();
+ return;
+ }
+ }
+}
+
+uint64_t MachOBindEntry::readULEB128(const char **error) {
+ unsigned Count;
+ uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error);
+ Ptr += Count;
+ if (Ptr > Opcodes.end())
+ Ptr = Opcodes.end();
+ return Result;
+}
+
+int64_t MachOBindEntry::readSLEB128(const char **error) {
+ unsigned Count;
+ int64_t Result = decodeSLEB128(Ptr, &Count, Opcodes.end(), error);
+ Ptr += Count;
+ if (Ptr > Opcodes.end())
+ Ptr = Opcodes.end();
+ return Result;
+}
+
+int32_t MachOBindEntry::segmentIndex() const { return SegmentIndex; }
+
+uint64_t MachOBindEntry::segmentOffset() const { return SegmentOffset; }
+
+StringRef MachOBindEntry::typeName() const {
+ switch (BindType) {
+ case MachO::BIND_TYPE_POINTER:
+ return "pointer";
+ case MachO::BIND_TYPE_TEXT_ABSOLUTE32:
+ return "text abs32";
+ case MachO::BIND_TYPE_TEXT_PCREL32:
+ return "text rel32";
+ }
+ return "unknown";
+}
+
+StringRef MachOBindEntry::symbolName() const { return SymbolName; }
+
+int64_t MachOBindEntry::addend() const { return Addend; }
+
+uint32_t MachOBindEntry::flags() const { return Flags; }
+
+int MachOBindEntry::ordinal() const { return Ordinal; }
+
+// For use with the SegIndex of a checked Mach-O Bind entry
+// to get the segment name.
+StringRef MachOBindEntry::segmentName() const {
+ return O->BindRebaseSegmentName(SegmentIndex);
+}
+
+// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry
+// to get the section name.
+StringRef MachOBindEntry::sectionName() const {
+ return O->BindRebaseSectionName(SegmentIndex, SegmentOffset);
+}
+
+// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind entry
+// to get the address.
+uint64_t MachOBindEntry::address() const {
+ return O->BindRebaseAddress(SegmentIndex, SegmentOffset);
+}
+
+bool MachOBindEntry::operator==(const MachOBindEntry &Other) const {
+#ifdef EXPENSIVE_CHECKS
+ assert(Opcodes == Other.Opcodes && "compare iterators of different files");
+#else
+ assert(Opcodes.data() == Other.Opcodes.data() && "compare iterators of different files");
+#endif
+ return (Ptr == Other.Ptr) &&
+ (RemainingLoopCount == Other.RemainingLoopCount) &&
+ (Done == Other.Done);
+}
+
+// Build table of sections so SegIndex/SegOffset pairs can be translated.
+BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) {
+ uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0;
+ StringRef CurSegName;
+ uint64_t CurSegAddress;
+ for (const SectionRef &Section : Obj->sections()) {
+ SectionInfo Info;
+ Expected<StringRef> NameOrErr = Section.getName();
+ if (!NameOrErr)
+ consumeError(NameOrErr.takeError());
+ else
+ Info.SectionName = *NameOrErr;
+ Info.Address = Section.getAddress();
+ Info.Size = Section.getSize();
+ Info.SegmentName =
+ Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl());
+ if (!Info.SegmentName.equals(CurSegName)) {
+ ++CurSegIndex;
+ CurSegName = Info.SegmentName;
+ CurSegAddress = Info.Address;
+ }
+ Info.SegmentIndex = CurSegIndex - 1;
+ Info.OffsetInSegment = Info.Address - CurSegAddress;
+ Info.SegmentStartAddress = CurSegAddress;
+ Sections.push_back(Info);
+ }
+ MaxSegIndex = CurSegIndex;
+}
+
+// For use with a SegIndex, SegOffset, and PointerSize triple in
+// MachOBindEntry::moveNext() to validate a MachOBindEntry or MachORebaseEntry.
+//
+// Given a SegIndex, SegOffset, and PointerSize, verify a valid section exists
+// that fully contains a pointer at that location. Multiple fixups in a bind
+// (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can
+// be tested via the Count and Skip parameters.
+const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex,
+ uint64_t SegOffset,
+ uint8_t PointerSize,
+ uint32_t Count,
+ uint32_t Skip) {
+ if (SegIndex == -1)
+ return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB";
+ if (SegIndex >= MaxSegIndex)
+ return "bad segIndex (too large)";
+ for (uint32_t i = 0; i < Count; ++i) {
+ uint32_t Start = SegOffset + i * (PointerSize + Skip);
+ uint32_t End = Start + PointerSize;
+ bool Found = false;
+ for (const SectionInfo &SI : Sections) {
+ if (SI.SegmentIndex != SegIndex)
+ continue;
+ if ((SI.OffsetInSegment<=Start) && (Start<(SI.OffsetInSegment+SI.Size))) {
+ if (End <= SI.OffsetInSegment + SI.Size) {
+ Found = true;
+ break;
+ }
+ else
+ return "bad offset, extends beyond section boundary";
+ }
+ }
+ if (!Found)
+ return "bad offset, not in section";
+ }
+ return nullptr;
+}
+
+// For use with the SegIndex of a checked Mach-O Bind or Rebase entry
+// to get the segment name.
+StringRef BindRebaseSegInfo::segmentName(int32_t SegIndex) {
+ for (const SectionInfo &SI : Sections) {
+ if (SI.SegmentIndex == SegIndex)
+ return SI.SegmentName;
+ }
+ llvm_unreachable("invalid SegIndex");
+}
+
+// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
+// to get the SectionInfo.
+const BindRebaseSegInfo::SectionInfo &BindRebaseSegInfo::findSection(
+ int32_t SegIndex, uint64_t SegOffset) {
+ for (const SectionInfo &SI : Sections) {
+ if (SI.SegmentIndex != SegIndex)
+ continue;
+ if (SI.OffsetInSegment > SegOffset)
+ continue;
+ if (SegOffset >= (SI.OffsetInSegment + SI.Size))
+ continue;
+ return SI;
+ }
+ llvm_unreachable("SegIndex and SegOffset not in any section");
+}
+
+// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
+// entry to get the section name.
+StringRef BindRebaseSegInfo::sectionName(int32_t SegIndex,
+ uint64_t SegOffset) {
+ return findSection(SegIndex, SegOffset).SectionName;
+}
+
+// For use with a SegIndex,SegOffset pair from a checked Mach-O Bind or Rebase
+// entry to get the address.
+uint64_t BindRebaseSegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) {
+ const SectionInfo &SI = findSection(SegIndex, OffsetInSeg);
+ return SI.SegmentStartAddress + OffsetInSeg;
+}
+
+iterator_range<bind_iterator>
+MachOObjectFile::bindTable(Error &Err, MachOObjectFile *O,
+ ArrayRef<uint8_t> Opcodes, bool is64,
+ MachOBindEntry::Kind BKind) {
+ if (O->BindRebaseSectionTable == nullptr)
+ O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);
+ MachOBindEntry Start(&Err, O, Opcodes, is64, BKind);
+ Start.moveToFirst();
+
+ MachOBindEntry Finish(&Err, O, Opcodes, is64, BKind);
+ Finish.moveToEnd();
+
+ return make_range(bind_iterator(Start), bind_iterator(Finish));
+}
+
+iterator_range<bind_iterator> MachOObjectFile::bindTable(Error &Err) {
+ return bindTable(Err, this, getDyldInfoBindOpcodes(), is64Bit(),
+ MachOBindEntry::Kind::Regular);
+}
+
+iterator_range<bind_iterator> MachOObjectFile::lazyBindTable(Error &Err) {
+ return bindTable(Err, this, getDyldInfoLazyBindOpcodes(), is64Bit(),
+ MachOBindEntry::Kind::Lazy);
+}
+
+iterator_range<bind_iterator> MachOObjectFile::weakBindTable(Error &Err) {
+ return bindTable(Err, this, getDyldInfoWeakBindOpcodes(), is64Bit(),
+ MachOBindEntry::Kind::Weak);
+}
+
+MachOObjectFile::load_command_iterator
+MachOObjectFile::begin_load_commands() const {
+ return LoadCommands.begin();
+}
+
+MachOObjectFile::load_command_iterator
+MachOObjectFile::end_load_commands() const {
+ return LoadCommands.end();
+}
+
+iterator_range<MachOObjectFile::load_command_iterator>
+MachOObjectFile::load_commands() const {
+ return make_range(begin_load_commands(), end_load_commands());
+}
+
+StringRef
+MachOObjectFile::getSectionFinalSegmentName(DataRefImpl Sec) const {
+ ArrayRef<char> Raw = getSectionRawFinalSegmentName(Sec);
+ return parseSegmentOrSectionName(Raw.data());
+}
+
+ArrayRef<char>
+MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {
+ assert(Sec.d.a < Sections.size() && "Should have detected this earlier");
+ const section_base *Base =
+ reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
+ return makeArrayRef(Base->sectname);
+}
+
+ArrayRef<char>
+MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const {
+ assert(Sec.d.a < Sections.size() && "Should have detected this earlier");
+ const section_base *Base =
+ reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
+ return makeArrayRef(Base->segname);
+}
+
+bool
+MachOObjectFile::isRelocationScattered(const MachO::any_relocation_info &RE)
+ const {
+ if (getCPUType(*this) == MachO::CPU_TYPE_X86_64)
+ return false;
+ return getPlainRelocationAddress(RE) & MachO::R_SCATTERED;
+}
+
+unsigned MachOObjectFile::getPlainRelocationSymbolNum(
+ const MachO::any_relocation_info &RE) const {
+ if (isLittleEndian())
+ return RE.r_word1 & 0xffffff;
+ return RE.r_word1 >> 8;
+}
+
+bool MachOObjectFile::getPlainRelocationExternal(
+ const MachO::any_relocation_info &RE) const {
+ if (isLittleEndian())
+ return (RE.r_word1 >> 27) & 1;
+ return (RE.r_word1 >> 4) & 1;
+}
+
+bool MachOObjectFile::getScatteredRelocationScattered(
+ const MachO::any_relocation_info &RE) const {
+ return RE.r_word0 >> 31;
+}
+
+uint32_t MachOObjectFile::getScatteredRelocationValue(
+ const MachO::any_relocation_info &RE) const {
+ return RE.r_word1;
+}
+
+uint32_t MachOObjectFile::getScatteredRelocationType(
+ const MachO::any_relocation_info &RE) const {
+ return (RE.r_word0 >> 24) & 0xf;
+}
+
+unsigned MachOObjectFile::getAnyRelocationAddress(
+ const MachO::any_relocation_info &RE) const {
+ if (isRelocationScattered(RE))
+ return getScatteredRelocationAddress(RE);
+ return getPlainRelocationAddress(RE);
+}
+
+unsigned MachOObjectFile::getAnyRelocationPCRel(
+ const MachO::any_relocation_info &RE) const {
+ if (isRelocationScattered(RE))
+ return getScatteredRelocationPCRel(RE);
+ return getPlainRelocationPCRel(*this, RE);
+}
+
+unsigned MachOObjectFile::getAnyRelocationLength(
+ const MachO::any_relocation_info &RE) const {
+ if (isRelocationScattered(RE))
+ return getScatteredRelocationLength(RE);
+ return getPlainRelocationLength(*this, RE);
+}
+
+unsigned
+MachOObjectFile::getAnyRelocationType(
+ const MachO::any_relocation_info &RE) const {
+ if (isRelocationScattered(RE))
+ return getScatteredRelocationType(RE);
+ return getPlainRelocationType(*this, RE);
+}
+
+SectionRef
+MachOObjectFile::getAnyRelocationSection(
+ const MachO::any_relocation_info &RE) const {
+ if (isRelocationScattered(RE) || getPlainRelocationExternal(RE))
+ return *section_end();
+ unsigned SecNum = getPlainRelocationSymbolNum(RE);
+ if (SecNum == MachO::R_ABS || SecNum > Sections.size())
+ return *section_end();
+ DataRefImpl DRI;
+ DRI.d.a = SecNum - 1;
+ return SectionRef(DRI, this);
+}
+
+MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const {
+ assert(DRI.d.a < Sections.size() && "Should have detected this earlier");
+ return getStruct<MachO::section>(*this, Sections[DRI.d.a]);
+}
+
+MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const {
+ assert(DRI.d.a < Sections.size() && "Should have detected this earlier");
+ return getStruct<MachO::section_64>(*this, Sections[DRI.d.a]);
+}
+
+MachO::section MachOObjectFile::getSection(const LoadCommandInfo &L,
+ unsigned Index) const {
+ const char *Sec = getSectionPtr(*this, L, Index);
+ return getStruct<MachO::section>(*this, Sec);
+}
+
+MachO::section_64 MachOObjectFile::getSection64(const LoadCommandInfo &L,
+ unsigned Index) const {
+ const char *Sec = getSectionPtr(*this, L, Index);
+ return getStruct<MachO::section_64>(*this, Sec);
+}
+
+MachO::nlist
+MachOObjectFile::getSymbolTableEntry(DataRefImpl DRI) const {
+ const char *P = reinterpret_cast<const char *>(DRI.p);
+ return getStruct<MachO::nlist>(*this, P);
+}
+
+MachO::nlist_64
+MachOObjectFile::getSymbol64TableEntry(DataRefImpl DRI) const {
+ const char *P = reinterpret_cast<const char *>(DRI.p);
+ return getStruct<MachO::nlist_64>(*this, P);
+}
+
+MachO::linkedit_data_command
+MachOObjectFile::getLinkeditDataLoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::linkedit_data_command>(*this, L.Ptr);
+}
+
+MachO::segment_command
+MachOObjectFile::getSegmentLoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::segment_command>(*this, L.Ptr);
+}
+
+MachO::segment_command_64
+MachOObjectFile::getSegment64LoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::segment_command_64>(*this, L.Ptr);
+}
+
+MachO::linker_option_command
+MachOObjectFile::getLinkerOptionLoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::linker_option_command>(*this, L.Ptr);
+}
+
+MachO::version_min_command
+MachOObjectFile::getVersionMinLoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::version_min_command>(*this, L.Ptr);
+}
+
+MachO::note_command
+MachOObjectFile::getNoteLoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::note_command>(*this, L.Ptr);
+}
+
+MachO::build_version_command
+MachOObjectFile::getBuildVersionLoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::build_version_command>(*this, L.Ptr);
+}
+
+MachO::build_tool_version
+MachOObjectFile::getBuildToolVersion(unsigned index) const {
+ return getStruct<MachO::build_tool_version>(*this, BuildTools[index]);
+}
+
+MachO::dylib_command
+MachOObjectFile::getDylibIDLoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::dylib_command>(*this, L.Ptr);
+}
+
+MachO::dyld_info_command
+MachOObjectFile::getDyldInfoLoadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::dyld_info_command>(*this, L.Ptr);
+}
+
+MachO::dylinker_command
+MachOObjectFile::getDylinkerCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::dylinker_command>(*this, L.Ptr);
+}
+
+MachO::uuid_command
+MachOObjectFile::getUuidCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::uuid_command>(*this, L.Ptr);
+}
+
+MachO::rpath_command
+MachOObjectFile::getRpathCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::rpath_command>(*this, L.Ptr);
+}
+
+MachO::source_version_command
+MachOObjectFile::getSourceVersionCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::source_version_command>(*this, L.Ptr);
+}
+
+MachO::entry_point_command
+MachOObjectFile::getEntryPointCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::entry_point_command>(*this, L.Ptr);
+}
+
+MachO::encryption_info_command
+MachOObjectFile::getEncryptionInfoCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::encryption_info_command>(*this, L.Ptr);
+}
+
+MachO::encryption_info_command_64
+MachOObjectFile::getEncryptionInfoCommand64(const LoadCommandInfo &L) const {
+ return getStruct<MachO::encryption_info_command_64>(*this, L.Ptr);
+}
+
+MachO::sub_framework_command
+MachOObjectFile::getSubFrameworkCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::sub_framework_command>(*this, L.Ptr);
+}
+
+MachO::sub_umbrella_command
+MachOObjectFile::getSubUmbrellaCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::sub_umbrella_command>(*this, L.Ptr);
+}
+
+MachO::sub_library_command
+MachOObjectFile::getSubLibraryCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::sub_library_command>(*this, L.Ptr);
+}
+
+MachO::sub_client_command
+MachOObjectFile::getSubClientCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::sub_client_command>(*this, L.Ptr);
+}
+
+MachO::routines_command
+MachOObjectFile::getRoutinesCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::routines_command>(*this, L.Ptr);
+}
+
+MachO::routines_command_64
+MachOObjectFile::getRoutinesCommand64(const LoadCommandInfo &L) const {
+ return getStruct<MachO::routines_command_64>(*this, L.Ptr);
+}
+
+MachO::thread_command
+MachOObjectFile::getThreadCommand(const LoadCommandInfo &L) const {
+ return getStruct<MachO::thread_command>(*this, L.Ptr);
+}
+
+MachO::any_relocation_info
+MachOObjectFile::getRelocation(DataRefImpl Rel) const {
+ uint32_t Offset;
+ if (getHeader().filetype == MachO::MH_OBJECT) {
+ DataRefImpl Sec;
+ Sec.d.a = Rel.d.a;
+ if (is64Bit()) {
+ MachO::section_64 Sect = getSection64(Sec);
+ Offset = Sect.reloff;
+ } else {
+ MachO::section Sect = getSection(Sec);
+ Offset = Sect.reloff;
+ }
+ } else {
+ MachO::dysymtab_command DysymtabLoadCmd = getDysymtabLoadCommand();
+ 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 *>(
+ getPtr(*this, Offset)) + Rel.d.b;
+ return getStruct<MachO::any_relocation_info>(
+ *this, reinterpret_cast<const char *>(P));
+}
+
+MachO::data_in_code_entry
+MachOObjectFile::getDice(DataRefImpl Rel) const {
+ const char *P = reinterpret_cast<const char *>(Rel.p);
+ return getStruct<MachO::data_in_code_entry>(*this, P);
+}
+
+const MachO::mach_header &MachOObjectFile::getHeader() const {
+ return Header;
+}
+
+const MachO::mach_header_64 &MachOObjectFile::getHeader64() const {
+ assert(is64Bit());
+ return Header64;
+}
+
+uint32_t MachOObjectFile::getIndirectSymbolTableEntry(
+ const MachO::dysymtab_command &DLC,
+ unsigned Index) const {
+ uint64_t Offset = DLC.indirectsymoff + Index * sizeof(uint32_t);
+ return getStruct<uint32_t>(*this, getPtr(*this, Offset));
+}
+
+MachO::data_in_code_entry
+MachOObjectFile::getDataInCodeTableEntry(uint32_t DataOffset,
+ unsigned Index) const {
+ uint64_t Offset = DataOffset + Index * sizeof(MachO::data_in_code_entry);
+ return getStruct<MachO::data_in_code_entry>(*this, getPtr(*this, Offset));
+}
+
+MachO::symtab_command MachOObjectFile::getSymtabLoadCommand() const {
+ if (SymtabLoadCmd)
+ return getStruct<MachO::symtab_command>(*this, SymtabLoadCmd);
+
+ // If there is no SymtabLoadCmd return a load command with zero'ed fields.
+ MachO::symtab_command Cmd;
+ Cmd.cmd = MachO::LC_SYMTAB;
+ Cmd.cmdsize = sizeof(MachO::symtab_command);
+ Cmd.symoff = 0;
+ Cmd.nsyms = 0;
+ Cmd.stroff = 0;
+ Cmd.strsize = 0;
+ return Cmd;
+}
+
+MachO::dysymtab_command MachOObjectFile::getDysymtabLoadCommand() const {
+ if (DysymtabLoadCmd)
+ return getStruct<MachO::dysymtab_command>(*this, DysymtabLoadCmd);
+
+ // If there is no DysymtabLoadCmd return a load command with zero'ed fields.
+ MachO::dysymtab_command Cmd;
+ Cmd.cmd = MachO::LC_DYSYMTAB;
+ Cmd.cmdsize = sizeof(MachO::dysymtab_command);
+ Cmd.ilocalsym = 0;
+ Cmd.nlocalsym = 0;
+ Cmd.iextdefsym = 0;
+ Cmd.nextdefsym = 0;
+ Cmd.iundefsym = 0;
+ Cmd.nundefsym = 0;
+ Cmd.tocoff = 0;
+ Cmd.ntoc = 0;
+ Cmd.modtaboff = 0;
+ Cmd.nmodtab = 0;
+ Cmd.extrefsymoff = 0;
+ Cmd.nextrefsyms = 0;
+ Cmd.indirectsymoff = 0;
+ Cmd.nindirectsyms = 0;
+ Cmd.extreloff = 0;
+ Cmd.nextrel = 0;
+ Cmd.locreloff = 0;
+ Cmd.nlocrel = 0;
+ return Cmd;
+}
+
+MachO::linkedit_data_command
+MachOObjectFile::getDataInCodeLoadCommand() const {
+ if (DataInCodeLoadCmd)
+ return getStruct<MachO::linkedit_data_command>(*this, DataInCodeLoadCmd);
+
+ // If there is no DataInCodeLoadCmd return a load command with zero'ed fields.
+ MachO::linkedit_data_command Cmd;
+ Cmd.cmd = MachO::LC_DATA_IN_CODE;
+ Cmd.cmdsize = sizeof(MachO::linkedit_data_command);
+ Cmd.dataoff = 0;
+ Cmd.datasize = 0;
+ return Cmd;
+}
+
+MachO::linkedit_data_command
+MachOObjectFile::getLinkOptHintsLoadCommand() const {
+ if (LinkOptHintsLoadCmd)
+ return getStruct<MachO::linkedit_data_command>(*this, LinkOptHintsLoadCmd);
+
+ // If there is no LinkOptHintsLoadCmd return a load command with zero'ed
+ // fields.
+ MachO::linkedit_data_command Cmd;
+ Cmd.cmd = MachO::LC_LINKER_OPTIMIZATION_HINT;
+ Cmd.cmdsize = sizeof(MachO::linkedit_data_command);
+ Cmd.dataoff = 0;
+ Cmd.datasize = 0;
+ return Cmd;
+}
+
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoRebaseOpcodes() const {
+ if (!DyldInfoLoadCmd)
+ return None;
+
+ auto DyldInfoOrErr =
+ getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
+ if (!DyldInfoOrErr)
+ return None;
+ MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
+ const uint8_t *Ptr =
+ reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.rebase_off));
+ return makeArrayRef(Ptr, DyldInfo.rebase_size);
+}
+
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoBindOpcodes() const {
+ if (!DyldInfoLoadCmd)
+ return None;
+
+ auto DyldInfoOrErr =
+ getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
+ if (!DyldInfoOrErr)
+ return None;
+ MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
+ const uint8_t *Ptr =
+ reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.bind_off));
+ return makeArrayRef(Ptr, DyldInfo.bind_size);
+}
+
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoWeakBindOpcodes() const {
+ if (!DyldInfoLoadCmd)
+ return None;
+
+ auto DyldInfoOrErr =
+ getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
+ if (!DyldInfoOrErr)
+ return None;
+ MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
+ const uint8_t *Ptr =
+ reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.weak_bind_off));
+ return makeArrayRef(Ptr, DyldInfo.weak_bind_size);
+}
+
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
+ if (!DyldInfoLoadCmd)
+ return None;
+
+ auto DyldInfoOrErr =
+ getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
+ if (!DyldInfoOrErr)
+ return None;
+ MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
+ const uint8_t *Ptr =
+ reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.lazy_bind_off));
+ return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
+}
+
+ArrayRef<uint8_t> MachOObjectFile::getDyldInfoExportsTrie() const {
+ if (!DyldInfoLoadCmd)
+ return None;
+
+ auto DyldInfoOrErr =
+ getStructOrErr<MachO::dyld_info_command>(*this, DyldInfoLoadCmd);
+ if (!DyldInfoOrErr)
+ return None;
+ MachO::dyld_info_command DyldInfo = DyldInfoOrErr.get();
+ const uint8_t *Ptr =
+ reinterpret_cast<const uint8_t *>(getPtr(*this, DyldInfo.export_off));
+ return makeArrayRef(Ptr, DyldInfo.export_size);
+}
+
+ArrayRef<uint8_t> MachOObjectFile::getUuid() const {
+ if (!UuidLoadCmd)
+ return None;
+ // Returning a pointer is fine as uuid doesn't need endian swapping.
+ const char *Ptr = UuidLoadCmd + offsetof(MachO::uuid_command, uuid);
+ return makeArrayRef(reinterpret_cast<const uint8_t *>(Ptr), 16);
+}
+
+StringRef MachOObjectFile::getStringTableData() const {
+ MachO::symtab_command S = getSymtabLoadCommand();
+ return getData().substr(S.stroff, S.strsize);
+}
+
+bool MachOObjectFile::is64Bit() const {
+ return getType() == getMachOType(false, true) ||
+ getType() == getMachOType(true, true);
+}
+
+void MachOObjectFile::ReadULEB128s(uint64_t Index,
+ SmallVectorImpl<uint64_t> &Out) const {
+ DataExtractor extractor(ObjectFile::getData(), true, 0);
+
+ uint64_t offset = Index;
+ uint64_t data = 0;
+ while (uint64_t delta = extractor.getULEB128(&offset)) {
+ data += delta;
+ Out.push_back(data);
+ }
+}
+
+bool MachOObjectFile::isRelocatableObject() const {
+ return getHeader().filetype == MachO::MH_OBJECT;
+}
+
+Expected<std::unique_ptr<MachOObjectFile>>
+ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer,
+ uint32_t UniversalCputype,
+ uint32_t UniversalIndex) {
+ StringRef Magic = Buffer.getBuffer().slice(0, 4);
+ if (Magic == "\xFE\xED\xFA\xCE")
+ return MachOObjectFile::create(Buffer, false, false,
+ UniversalCputype, UniversalIndex);
+ if (Magic == "\xCE\xFA\xED\xFE")
+ return MachOObjectFile::create(Buffer, true, false,
+ UniversalCputype, UniversalIndex);
+ if (Magic == "\xFE\xED\xFA\xCF")
+ return MachOObjectFile::create(Buffer, false, true,
+ UniversalCputype, UniversalIndex);
+ if (Magic == "\xCF\xFA\xED\xFE")
+ return MachOObjectFile::create(Buffer, true, true,
+ UniversalCputype, UniversalIndex);
+ return make_error<GenericBinaryError>("Unrecognized MachO magic number",
+ object_error::invalid_file_type);
+}
+
+StringRef MachOObjectFile::mapDebugSectionName(StringRef Name) const {
+ return StringSwitch<StringRef>(Name)
+ .Case("debug_str_offs", "debug_str_offsets")
+ .Default(Name);
+}
diff --git a/contrib/libs/llvm12/lib/Object/MachOUniversal.cpp b/contrib/libs/llvm12/lib/Object/MachOUniversal.cpp
index ff9c8570c9..f3ce005e6e 100644
--- a/contrib/libs/llvm12/lib/Object/MachOUniversal.cpp
+++ b/contrib/libs/llvm12/lib/Object/MachOUniversal.cpp
@@ -1,86 +1,86 @@
-//===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the MachOUniversalBinary class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/MachOUniversal.h"
-#include "llvm/Object/Archive.h"
+//===- MachOUniversal.cpp - Mach-O universal binary -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the MachOUniversalBinary class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/Archive.h"
#include "llvm/Object/IRObjectFile.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/Host.h"
-#include "llvm/Support/MemoryBuffer.h"
-
-using namespace llvm;
-using namespace object;
-
-static Error
-malformedError(Twine Msg) {
- std::string StringMsg = "truncated or malformed fat file (" + Msg.str() + ")";
- return make_error<GenericBinaryError>(std::move(StringMsg),
- object_error::parse_failed);
-}
-
-template<typename T>
-static T getUniversalBinaryStruct(const char *Ptr) {
- T Res;
- memcpy(&Res, Ptr, sizeof(T));
- // Universal binary headers have big-endian byte order.
- if (sys::IsLittleEndianHost)
- swapStruct(Res);
- return Res;
-}
-
-MachOUniversalBinary::ObjectForArch::ObjectForArch(
- const MachOUniversalBinary *Parent, uint32_t Index)
- : Parent(Parent), Index(Index) {
- // The iterators use Parent as a nullptr and an Index+1 == NumberOfObjects.
- if (!Parent || Index >= Parent->getNumberOfObjects()) {
- clear();
- } else {
- // Parse object header.
- StringRef ParentData = Parent->getData();
- if (Parent->getMagic() == MachO::FAT_MAGIC) {
- const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
- Index * sizeof(MachO::fat_arch);
- Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
- } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
- const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
- Index * sizeof(MachO::fat_arch_64);
- Header64 = getUniversalBinaryStruct<MachO::fat_arch_64>(HeaderPos);
- }
- }
-}
-
-Expected<std::unique_ptr<MachOObjectFile>>
-MachOUniversalBinary::ObjectForArch::getAsObjectFile() const {
- if (!Parent)
- report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsObjectFile() "
- "called when Parent is a nullptr");
-
- StringRef ParentData = Parent->getData();
- StringRef ObjectData;
- uint32_t cputype;
- if (Parent->getMagic() == MachO::FAT_MAGIC) {
- ObjectData = ParentData.substr(Header.offset, Header.size);
- cputype = Header.cputype;
- } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
- ObjectData = ParentData.substr(Header64.offset, Header64.size);
- cputype = Header64.cputype;
- }
- StringRef ObjectName = Parent->getFileName();
- MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
- return ObjectFile::createMachOObjectFile(ObjBuffer, cputype, Index);
-}
-
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Host.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace object;
+
+static Error
+malformedError(Twine Msg) {
+ std::string StringMsg = "truncated or malformed fat file (" + Msg.str() + ")";
+ return make_error<GenericBinaryError>(std::move(StringMsg),
+ object_error::parse_failed);
+}
+
+template<typename T>
+static T getUniversalBinaryStruct(const char *Ptr) {
+ T Res;
+ memcpy(&Res, Ptr, sizeof(T));
+ // Universal binary headers have big-endian byte order.
+ if (sys::IsLittleEndianHost)
+ swapStruct(Res);
+ return Res;
+}
+
+MachOUniversalBinary::ObjectForArch::ObjectForArch(
+ const MachOUniversalBinary *Parent, uint32_t Index)
+ : Parent(Parent), Index(Index) {
+ // The iterators use Parent as a nullptr and an Index+1 == NumberOfObjects.
+ if (!Parent || Index >= Parent->getNumberOfObjects()) {
+ clear();
+ } else {
+ // Parse object header.
+ StringRef ParentData = Parent->getData();
+ if (Parent->getMagic() == MachO::FAT_MAGIC) {
+ const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
+ Index * sizeof(MachO::fat_arch);
+ Header = getUniversalBinaryStruct<MachO::fat_arch>(HeaderPos);
+ } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
+ const char *HeaderPos = ParentData.begin() + sizeof(MachO::fat_header) +
+ Index * sizeof(MachO::fat_arch_64);
+ Header64 = getUniversalBinaryStruct<MachO::fat_arch_64>(HeaderPos);
+ }
+ }
+}
+
+Expected<std::unique_ptr<MachOObjectFile>>
+MachOUniversalBinary::ObjectForArch::getAsObjectFile() const {
+ if (!Parent)
+ report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsObjectFile() "
+ "called when Parent is a nullptr");
+
+ StringRef ParentData = Parent->getData();
+ StringRef ObjectData;
+ uint32_t cputype;
+ if (Parent->getMagic() == MachO::FAT_MAGIC) {
+ ObjectData = ParentData.substr(Header.offset, Header.size);
+ cputype = Header.cputype;
+ } else { // Parent->getMagic() == MachO::FAT_MAGIC_64
+ ObjectData = ParentData.substr(Header64.offset, Header64.size);
+ cputype = Header64.cputype;
+ }
+ StringRef ObjectName = Parent->getFileName();
+ MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
+ return ObjectFile::createMachOObjectFile(ObjBuffer, cputype, Index);
+}
+
Expected<std::unique_ptr<IRObjectFile>>
MachOUniversalBinary::ObjectForArch::getAsIRObject(LLVMContext &Ctx) const {
if (!Parent)
@@ -100,160 +100,160 @@ MachOUniversalBinary::ObjectForArch::getAsIRObject(LLVMContext &Ctx) const {
return IRObjectFile::create(ObjBuffer, Ctx);
}
-Expected<std::unique_ptr<Archive>>
-MachOUniversalBinary::ObjectForArch::getAsArchive() const {
- if (!Parent)
- report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsArchive() "
- "called when Parent is a nullptr");
-
- StringRef ParentData = Parent->getData();
- StringRef ObjectData;
- if (Parent->getMagic() == MachO::FAT_MAGIC)
- ObjectData = ParentData.substr(Header.offset, Header.size);
- else // Parent->getMagic() == MachO::FAT_MAGIC_64
- ObjectData = ParentData.substr(Header64.offset, Header64.size);
- StringRef ObjectName = Parent->getFileName();
- MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
- return Archive::create(ObjBuffer);
-}
-
-void MachOUniversalBinary::anchor() { }
-
-Expected<std::unique_ptr<MachOUniversalBinary>>
-MachOUniversalBinary::create(MemoryBufferRef Source) {
- Error Err = Error::success();
- std::unique_ptr<MachOUniversalBinary> Ret(
- new MachOUniversalBinary(Source, Err));
- if (Err)
- return std::move(Err);
- return std::move(Ret);
-}
-
-MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, Error &Err)
- : Binary(Binary::ID_MachOUniversalBinary, Source), Magic(0),
- NumberOfObjects(0) {
- ErrorAsOutParameter ErrAsOutParam(&Err);
- if (Data.getBufferSize() < sizeof(MachO::fat_header)) {
- Err = make_error<GenericBinaryError>("File too small to be a Mach-O "
- "universal file",
- object_error::invalid_file_type);
- return;
- }
- // Check for magic value and sufficient header size.
- StringRef Buf = getData();
- MachO::fat_header H =
- getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
- Magic = H.magic;
- NumberOfObjects = H.nfat_arch;
- if (NumberOfObjects == 0) {
- Err = malformedError("contains zero architecture types");
- return;
- }
- uint32_t MinSize = sizeof(MachO::fat_header);
- if (Magic == MachO::FAT_MAGIC)
- MinSize += sizeof(MachO::fat_arch) * NumberOfObjects;
- else if (Magic == MachO::FAT_MAGIC_64)
- MinSize += sizeof(MachO::fat_arch_64) * NumberOfObjects;
- else {
- Err = malformedError("bad magic number");
- return;
- }
- if (Buf.size() < MinSize) {
- Err = malformedError("fat_arch" +
- Twine(Magic == MachO::FAT_MAGIC ? "" : "_64") +
- " structs would extend past the end of the file");
- return;
- }
- for (uint32_t i = 0; i < NumberOfObjects; i++) {
- ObjectForArch A(this, i);
- uint64_t bigSize = A.getOffset();
- bigSize += A.getSize();
- if (bigSize > Buf.size()) {
- Err = malformedError("offset plus size of cputype (" +
- Twine(A.getCPUType()) + ") cpusubtype (" +
- Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
- ") extends past the end of the file");
- return;
- }
-
- if (A.getAlign() > MaxSectionAlignment) {
- Err = malformedError("align (2^" + Twine(A.getAlign()) +
- ") too large for cputype (" + Twine(A.getCPUType()) +
- ") cpusubtype (" +
- Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
- ") (maximum 2^" + Twine(MaxSectionAlignment) + ")");
- return;
- }
- if(A.getOffset() % (1ull << A.getAlign()) != 0){
- Err = malformedError("offset: " + Twine(A.getOffset()) +
- " for cputype (" + Twine(A.getCPUType()) + ") cpusubtype (" +
- Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
- ") not aligned on it's alignment (2^" + Twine(A.getAlign()) + ")");
- return;
- }
- if (A.getOffset() < MinSize) {
- Err = malformedError("cputype (" + Twine(A.getCPUType()) + ") "
- "cpusubtype (" + Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
- ") offset " + Twine(A.getOffset()) + " overlaps universal headers");
- return;
- }
- }
- for (uint32_t i = 0; i < NumberOfObjects; i++) {
- ObjectForArch A(this, i);
- for (uint32_t j = i + 1; j < NumberOfObjects; j++) {
- ObjectForArch B(this, j);
- if (A.getCPUType() == B.getCPUType() &&
- (A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) ==
- (B.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK)) {
- Err = malformedError("contains two of the same architecture (cputype "
- "(" + Twine(A.getCPUType()) + ") cpusubtype (" +
- Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) + "))");
- return;
- }
- if ((A.getOffset() >= B.getOffset() &&
- A.getOffset() < B.getOffset() + B.getSize()) ||
- (A.getOffset() + A.getSize() > B.getOffset() &&
- A.getOffset() + A.getSize() < B.getOffset() + B.getSize()) ||
- (A.getOffset() <= B.getOffset() &&
- A.getOffset() + A.getSize() >= B.getOffset() + B.getSize())) {
- Err = malformedError("cputype (" + Twine(A.getCPUType()) + ") "
- "cpusubtype (" + Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
- ") at offset " + Twine(A.getOffset()) + " with a size of " +
- Twine(A.getSize()) + ", overlaps cputype (" + Twine(B.getCPUType()) +
- ") cpusubtype (" + Twine(B.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK)
- + ") at offset " + Twine(B.getOffset()) + " with a size of "
- + Twine(B.getSize()));
- return;
- }
- }
- }
- Err = Error::success();
-}
-
-Expected<MachOUniversalBinary::ObjectForArch>
-MachOUniversalBinary::getObjectForArch(StringRef ArchName) const {
- if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch)
- return make_error<GenericBinaryError>("Unknown architecture "
- "named: " +
- ArchName,
- object_error::arch_not_found);
- for (const auto &Obj : objects())
- if (Obj.getArchFlagName() == ArchName)
- return Obj;
- return make_error<GenericBinaryError>("fat file does not "
- "contain " +
- ArchName,
- object_error::arch_not_found);
-}
-
-Expected<std::unique_ptr<MachOObjectFile>>
-MachOUniversalBinary::getMachOObjectForArch(StringRef ArchName) const {
- Expected<ObjectForArch> O = getObjectForArch(ArchName);
- if (!O)
- return O.takeError();
- return O->getAsObjectFile();
-}
-
+Expected<std::unique_ptr<Archive>>
+MachOUniversalBinary::ObjectForArch::getAsArchive() const {
+ if (!Parent)
+ report_fatal_error("MachOUniversalBinary::ObjectForArch::getAsArchive() "
+ "called when Parent is a nullptr");
+
+ StringRef ParentData = Parent->getData();
+ StringRef ObjectData;
+ if (Parent->getMagic() == MachO::FAT_MAGIC)
+ ObjectData = ParentData.substr(Header.offset, Header.size);
+ else // Parent->getMagic() == MachO::FAT_MAGIC_64
+ ObjectData = ParentData.substr(Header64.offset, Header64.size);
+ StringRef ObjectName = Parent->getFileName();
+ MemoryBufferRef ObjBuffer(ObjectData, ObjectName);
+ return Archive::create(ObjBuffer);
+}
+
+void MachOUniversalBinary::anchor() { }
+
+Expected<std::unique_ptr<MachOUniversalBinary>>
+MachOUniversalBinary::create(MemoryBufferRef Source) {
+ Error Err = Error::success();
+ std::unique_ptr<MachOUniversalBinary> Ret(
+ new MachOUniversalBinary(Source, Err));
+ if (Err)
+ return std::move(Err);
+ return std::move(Ret);
+}
+
+MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, Error &Err)
+ : Binary(Binary::ID_MachOUniversalBinary, Source), Magic(0),
+ NumberOfObjects(0) {
+ ErrorAsOutParameter ErrAsOutParam(&Err);
+ if (Data.getBufferSize() < sizeof(MachO::fat_header)) {
+ Err = make_error<GenericBinaryError>("File too small to be a Mach-O "
+ "universal file",
+ object_error::invalid_file_type);
+ return;
+ }
+ // Check for magic value and sufficient header size.
+ StringRef Buf = getData();
+ MachO::fat_header H =
+ getUniversalBinaryStruct<MachO::fat_header>(Buf.begin());
+ Magic = H.magic;
+ NumberOfObjects = H.nfat_arch;
+ if (NumberOfObjects == 0) {
+ Err = malformedError("contains zero architecture types");
+ return;
+ }
+ uint32_t MinSize = sizeof(MachO::fat_header);
+ if (Magic == MachO::FAT_MAGIC)
+ MinSize += sizeof(MachO::fat_arch) * NumberOfObjects;
+ else if (Magic == MachO::FAT_MAGIC_64)
+ MinSize += sizeof(MachO::fat_arch_64) * NumberOfObjects;
+ else {
+ Err = malformedError("bad magic number");
+ return;
+ }
+ if (Buf.size() < MinSize) {
+ Err = malformedError("fat_arch" +
+ Twine(Magic == MachO::FAT_MAGIC ? "" : "_64") +
+ " structs would extend past the end of the file");
+ return;
+ }
+ for (uint32_t i = 0; i < NumberOfObjects; i++) {
+ ObjectForArch A(this, i);
+ uint64_t bigSize = A.getOffset();
+ bigSize += A.getSize();
+ if (bigSize > Buf.size()) {
+ Err = malformedError("offset plus size of cputype (" +
+ Twine(A.getCPUType()) + ") cpusubtype (" +
+ Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
+ ") extends past the end of the file");
+ return;
+ }
+
+ if (A.getAlign() > MaxSectionAlignment) {
+ Err = malformedError("align (2^" + Twine(A.getAlign()) +
+ ") too large for cputype (" + Twine(A.getCPUType()) +
+ ") cpusubtype (" +
+ Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
+ ") (maximum 2^" + Twine(MaxSectionAlignment) + ")");
+ return;
+ }
+ if(A.getOffset() % (1ull << A.getAlign()) != 0){
+ Err = malformedError("offset: " + Twine(A.getOffset()) +
+ " for cputype (" + Twine(A.getCPUType()) + ") cpusubtype (" +
+ Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
+ ") not aligned on it's alignment (2^" + Twine(A.getAlign()) + ")");
+ return;
+ }
+ if (A.getOffset() < MinSize) {
+ Err = malformedError("cputype (" + Twine(A.getCPUType()) + ") "
+ "cpusubtype (" + Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
+ ") offset " + Twine(A.getOffset()) + " overlaps universal headers");
+ return;
+ }
+ }
+ for (uint32_t i = 0; i < NumberOfObjects; i++) {
+ ObjectForArch A(this, i);
+ for (uint32_t j = i + 1; j < NumberOfObjects; j++) {
+ ObjectForArch B(this, j);
+ if (A.getCPUType() == B.getCPUType() &&
+ (A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) ==
+ (B.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK)) {
+ Err = malformedError("contains two of the same architecture (cputype "
+ "(" + Twine(A.getCPUType()) + ") cpusubtype (" +
+ Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) + "))");
+ return;
+ }
+ if ((A.getOffset() >= B.getOffset() &&
+ A.getOffset() < B.getOffset() + B.getSize()) ||
+ (A.getOffset() + A.getSize() > B.getOffset() &&
+ A.getOffset() + A.getSize() < B.getOffset() + B.getSize()) ||
+ (A.getOffset() <= B.getOffset() &&
+ A.getOffset() + A.getSize() >= B.getOffset() + B.getSize())) {
+ Err = malformedError("cputype (" + Twine(A.getCPUType()) + ") "
+ "cpusubtype (" + Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
+ ") at offset " + Twine(A.getOffset()) + " with a size of " +
+ Twine(A.getSize()) + ", overlaps cputype (" + Twine(B.getCPUType()) +
+ ") cpusubtype (" + Twine(B.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK)
+ + ") at offset " + Twine(B.getOffset()) + " with a size of "
+ + Twine(B.getSize()));
+ return;
+ }
+ }
+ }
+ Err = Error::success();
+}
+
+Expected<MachOUniversalBinary::ObjectForArch>
+MachOUniversalBinary::getObjectForArch(StringRef ArchName) const {
+ if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch)
+ return make_error<GenericBinaryError>("Unknown architecture "
+ "named: " +
+ ArchName,
+ object_error::arch_not_found);
+ for (const auto &Obj : objects())
+ if (Obj.getArchFlagName() == ArchName)
+ return Obj;
+ return make_error<GenericBinaryError>("fat file does not "
+ "contain " +
+ ArchName,
+ object_error::arch_not_found);
+}
+
+Expected<std::unique_ptr<MachOObjectFile>>
+MachOUniversalBinary::getMachOObjectForArch(StringRef ArchName) const {
+ Expected<ObjectForArch> O = getObjectForArch(ArchName);
+ if (!O)
+ return O.takeError();
+ return O->getAsObjectFile();
+}
+
Expected<std::unique_ptr<IRObjectFile>>
MachOUniversalBinary::getIRObjectForArch(StringRef ArchName,
LLVMContext &Ctx) const {
@@ -263,10 +263,10 @@ MachOUniversalBinary::getIRObjectForArch(StringRef ArchName,
return O->getAsIRObject(Ctx);
}
-Expected<std::unique_ptr<Archive>>
-MachOUniversalBinary::getArchiveForArch(StringRef ArchName) const {
- Expected<ObjectForArch> O = getObjectForArch(ArchName);
- if (!O)
- return O.takeError();
- return O->getAsArchive();
-}
+Expected<std::unique_ptr<Archive>>
+MachOUniversalBinary::getArchiveForArch(StringRef ArchName) const {
+ Expected<ObjectForArch> O = getObjectForArch(ArchName);
+ if (!O)
+ return O.takeError();
+ return O->getAsArchive();
+}
diff --git a/contrib/libs/llvm12/lib/Object/Minidump.cpp b/contrib/libs/llvm12/lib/Object/Minidump.cpp
index 2c3559cb02..3e932fe7be 100644
--- a/contrib/libs/llvm12/lib/Object/Minidump.cpp
+++ b/contrib/libs/llvm12/lib/Object/Minidump.cpp
@@ -1,155 +1,155 @@
-//===- Minidump.cpp - Minidump object file implementation -----------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/Minidump.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Support/ConvertUTF.h"
-
-using namespace llvm;
-using namespace llvm::object;
-using namespace llvm::minidump;
-
-Optional<ArrayRef<uint8_t>>
-MinidumpFile::getRawStream(minidump::StreamType Type) const {
- auto It = StreamMap.find(Type);
- if (It != StreamMap.end())
- return getRawStream(Streams[It->second]);
- return None;
-}
-
-Expected<std::string> MinidumpFile::getString(size_t Offset) const {
- // Minidump strings consist of a 32-bit length field, which gives the size of
- // the string in *bytes*. This is followed by the actual string encoded in
- // UTF16.
- auto ExpectedSize =
- getDataSliceAs<support::ulittle32_t>(getData(), Offset, 1);
- if (!ExpectedSize)
- return ExpectedSize.takeError();
- size_t Size = (*ExpectedSize)[0];
- if (Size % 2 != 0)
- return createError("String size not even");
- Size /= 2;
- if (Size == 0)
- return "";
-
- Offset += sizeof(support::ulittle32_t);
- auto ExpectedData =
- getDataSliceAs<support::ulittle16_t>(getData(), Offset, Size);
- if (!ExpectedData)
- return ExpectedData.takeError();
-
- SmallVector<UTF16, 32> WStr(Size);
- copy(*ExpectedData, WStr.begin());
-
- std::string Result;
- if (!convertUTF16ToUTF8String(WStr, Result))
- return createError("String decoding failed");
-
- return Result;
-}
-
-Expected<iterator_range<MinidumpFile::MemoryInfoIterator>>
-MinidumpFile::getMemoryInfoList() const {
- Optional<ArrayRef<uint8_t>> Stream = getRawStream(StreamType::MemoryInfoList);
- if (!Stream)
- return createError("No such stream");
- auto ExpectedHeader =
- getDataSliceAs<minidump::MemoryInfoListHeader>(*Stream, 0, 1);
- if (!ExpectedHeader)
- return ExpectedHeader.takeError();
- const minidump::MemoryInfoListHeader &H = ExpectedHeader.get()[0];
- Expected<ArrayRef<uint8_t>> Data =
- getDataSlice(*Stream, H.SizeOfHeader, H.SizeOfEntry * H.NumberOfEntries);
- if (!Data)
- return Data.takeError();
- return make_range(MemoryInfoIterator(*Data, H.SizeOfEntry),
- MemoryInfoIterator({}, H.SizeOfEntry));
-}
-
-template <typename T>
-Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Type) const {
- Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type);
- if (!Stream)
- return createError("No such stream");
- auto ExpectedSize = getDataSliceAs<support::ulittle32_t>(*Stream, 0, 1);
- if (!ExpectedSize)
- return ExpectedSize.takeError();
-
- size_t ListSize = ExpectedSize.get()[0];
-
- size_t ListOffset = 4;
- // Some producers insert additional padding bytes to align the list to an
- // 8-byte boundary. Check for that by comparing the list size with the overall
- // stream size.
- if (ListOffset + sizeof(T) * ListSize < Stream->size())
- ListOffset = 8;
-
- return getDataSliceAs<T>(*Stream, ListOffset, ListSize);
-}
-template Expected<ArrayRef<Module>>
- MinidumpFile::getListStream(StreamType) const;
-template Expected<ArrayRef<Thread>>
- MinidumpFile::getListStream(StreamType) const;
-template Expected<ArrayRef<MemoryDescriptor>>
- MinidumpFile::getListStream(StreamType) const;
-
-Expected<ArrayRef<uint8_t>>
-MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
- // Check for overflow.
- if (Offset + Size < Offset || Offset + Size < Size ||
- Offset + Size > Data.size())
- return createEOFError();
- return Data.slice(Offset, Size);
-}
-
-Expected<std::unique_ptr<MinidumpFile>>
-MinidumpFile::create(MemoryBufferRef Source) {
- ArrayRef<uint8_t> Data = arrayRefFromStringRef(Source.getBuffer());
- auto ExpectedHeader = getDataSliceAs<minidump::Header>(Data, 0, 1);
- if (!ExpectedHeader)
- return ExpectedHeader.takeError();
-
- const minidump::Header &Hdr = (*ExpectedHeader)[0];
- if (Hdr.Signature != Header::MagicSignature)
- return createError("Invalid signature");
- if ((Hdr.Version & 0xffff) != Header::MagicVersion)
- return createError("Invalid version");
-
- auto ExpectedStreams = getDataSliceAs<Directory>(Data, Hdr.StreamDirectoryRVA,
- Hdr.NumberOfStreams);
- if (!ExpectedStreams)
- return ExpectedStreams.takeError();
-
- DenseMap<StreamType, std::size_t> StreamMap;
- for (const auto &StreamDescriptor : llvm::enumerate(*ExpectedStreams)) {
- StreamType Type = StreamDescriptor.value().Type;
- const LocationDescriptor &Loc = StreamDescriptor.value().Location;
-
- Expected<ArrayRef<uint8_t>> Stream =
- getDataSlice(Data, Loc.RVA, Loc.DataSize);
- if (!Stream)
- return Stream.takeError();
-
- if (Type == StreamType::Unused && Loc.DataSize == 0) {
- // Ignore dummy streams. This is technically ill-formed, but a number of
- // existing minidumps seem to contain such streams.
- continue;
- }
-
- if (Type == DenseMapInfo<StreamType>::getEmptyKey() ||
- Type == DenseMapInfo<StreamType>::getTombstoneKey())
- return createError("Cannot handle one of the minidump streams");
-
- // Update the directory map, checking for duplicate stream types.
- if (!StreamMap.try_emplace(Type, StreamDescriptor.index()).second)
- return createError("Duplicate stream type");
- }
-
- return std::unique_ptr<MinidumpFile>(
- new MinidumpFile(Source, Hdr, *ExpectedStreams, std::move(StreamMap)));
-}
+//===- Minidump.cpp - Minidump object file implementation -----------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/Minidump.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::minidump;
+
+Optional<ArrayRef<uint8_t>>
+MinidumpFile::getRawStream(minidump::StreamType Type) const {
+ auto It = StreamMap.find(Type);
+ if (It != StreamMap.end())
+ return getRawStream(Streams[It->second]);
+ return None;
+}
+
+Expected<std::string> MinidumpFile::getString(size_t Offset) const {
+ // Minidump strings consist of a 32-bit length field, which gives the size of
+ // the string in *bytes*. This is followed by the actual string encoded in
+ // UTF16.
+ auto ExpectedSize =
+ getDataSliceAs<support::ulittle32_t>(getData(), Offset, 1);
+ if (!ExpectedSize)
+ return ExpectedSize.takeError();
+ size_t Size = (*ExpectedSize)[0];
+ if (Size % 2 != 0)
+ return createError("String size not even");
+ Size /= 2;
+ if (Size == 0)
+ return "";
+
+ Offset += sizeof(support::ulittle32_t);
+ auto ExpectedData =
+ getDataSliceAs<support::ulittle16_t>(getData(), Offset, Size);
+ if (!ExpectedData)
+ return ExpectedData.takeError();
+
+ SmallVector<UTF16, 32> WStr(Size);
+ copy(*ExpectedData, WStr.begin());
+
+ std::string Result;
+ if (!convertUTF16ToUTF8String(WStr, Result))
+ return createError("String decoding failed");
+
+ return Result;
+}
+
+Expected<iterator_range<MinidumpFile::MemoryInfoIterator>>
+MinidumpFile::getMemoryInfoList() const {
+ Optional<ArrayRef<uint8_t>> Stream = getRawStream(StreamType::MemoryInfoList);
+ if (!Stream)
+ return createError("No such stream");
+ auto ExpectedHeader =
+ getDataSliceAs<minidump::MemoryInfoListHeader>(*Stream, 0, 1);
+ if (!ExpectedHeader)
+ return ExpectedHeader.takeError();
+ const minidump::MemoryInfoListHeader &H = ExpectedHeader.get()[0];
+ Expected<ArrayRef<uint8_t>> Data =
+ getDataSlice(*Stream, H.SizeOfHeader, H.SizeOfEntry * H.NumberOfEntries);
+ if (!Data)
+ return Data.takeError();
+ return make_range(MemoryInfoIterator(*Data, H.SizeOfEntry),
+ MemoryInfoIterator({}, H.SizeOfEntry));
+}
+
+template <typename T>
+Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Type) const {
+ Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type);
+ if (!Stream)
+ return createError("No such stream");
+ auto ExpectedSize = getDataSliceAs<support::ulittle32_t>(*Stream, 0, 1);
+ if (!ExpectedSize)
+ return ExpectedSize.takeError();
+
+ size_t ListSize = ExpectedSize.get()[0];
+
+ size_t ListOffset = 4;
+ // Some producers insert additional padding bytes to align the list to an
+ // 8-byte boundary. Check for that by comparing the list size with the overall
+ // stream size.
+ if (ListOffset + sizeof(T) * ListSize < Stream->size())
+ ListOffset = 8;
+
+ return getDataSliceAs<T>(*Stream, ListOffset, ListSize);
+}
+template Expected<ArrayRef<Module>>
+ MinidumpFile::getListStream(StreamType) const;
+template Expected<ArrayRef<Thread>>
+ MinidumpFile::getListStream(StreamType) const;
+template Expected<ArrayRef<MemoryDescriptor>>
+ MinidumpFile::getListStream(StreamType) const;
+
+Expected<ArrayRef<uint8_t>>
+MinidumpFile::getDataSlice(ArrayRef<uint8_t> Data, size_t Offset, size_t Size) {
+ // Check for overflow.
+ if (Offset + Size < Offset || Offset + Size < Size ||
+ Offset + Size > Data.size())
+ return createEOFError();
+ return Data.slice(Offset, Size);
+}
+
+Expected<std::unique_ptr<MinidumpFile>>
+MinidumpFile::create(MemoryBufferRef Source) {
+ ArrayRef<uint8_t> Data = arrayRefFromStringRef(Source.getBuffer());
+ auto ExpectedHeader = getDataSliceAs<minidump::Header>(Data, 0, 1);
+ if (!ExpectedHeader)
+ return ExpectedHeader.takeError();
+
+ const minidump::Header &Hdr = (*ExpectedHeader)[0];
+ if (Hdr.Signature != Header::MagicSignature)
+ return createError("Invalid signature");
+ if ((Hdr.Version & 0xffff) != Header::MagicVersion)
+ return createError("Invalid version");
+
+ auto ExpectedStreams = getDataSliceAs<Directory>(Data, Hdr.StreamDirectoryRVA,
+ Hdr.NumberOfStreams);
+ if (!ExpectedStreams)
+ return ExpectedStreams.takeError();
+
+ DenseMap<StreamType, std::size_t> StreamMap;
+ for (const auto &StreamDescriptor : llvm::enumerate(*ExpectedStreams)) {
+ StreamType Type = StreamDescriptor.value().Type;
+ const LocationDescriptor &Loc = StreamDescriptor.value().Location;
+
+ Expected<ArrayRef<uint8_t>> Stream =
+ getDataSlice(Data, Loc.RVA, Loc.DataSize);
+ if (!Stream)
+ return Stream.takeError();
+
+ if (Type == StreamType::Unused && Loc.DataSize == 0) {
+ // Ignore dummy streams. This is technically ill-formed, but a number of
+ // existing minidumps seem to contain such streams.
+ continue;
+ }
+
+ if (Type == DenseMapInfo<StreamType>::getEmptyKey() ||
+ Type == DenseMapInfo<StreamType>::getTombstoneKey())
+ return createError("Cannot handle one of the minidump streams");
+
+ // Update the directory map, checking for duplicate stream types.
+ if (!StreamMap.try_emplace(Type, StreamDescriptor.index()).second)
+ return createError("Duplicate stream type");
+ }
+
+ return std::unique_ptr<MinidumpFile>(
+ new MinidumpFile(Source, Hdr, *ExpectedStreams, std::move(StreamMap)));
+}
diff --git a/contrib/libs/llvm12/lib/Object/ModuleSymbolTable.cpp b/contrib/libs/llvm12/lib/Object/ModuleSymbolTable.cpp
index 12f35cfeaf..7f3055b5dc 100644
--- a/contrib/libs/llvm12/lib/Object/ModuleSymbolTable.cpp
+++ b/contrib/libs/llvm12/lib/Object/ModuleSymbolTable.cpp
@@ -1,227 +1,227 @@
-//===- ModuleSymbolTable.cpp - symbol table for in-memory IR --------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This class represents a symbol table built from in-memory IR. It provides
-// access to GlobalValues and should only be used if such access is required
-// (e.g. in the LTO implementation).
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/ModuleSymbolTable.h"
-#include "RecordStreamer.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/IR/Function.h"
-#include "llvm/IR/GlobalAlias.h"
-#include "llvm/IR/GlobalValue.h"
-#include "llvm/IR/GlobalVariable.h"
-#include "llvm/IR/InlineAsm.h"
-#include "llvm/IR/Module.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCDirectives.h"
-#include "llvm/MC/MCInstrInfo.h"
-#include "llvm/MC/MCObjectFileInfo.h"
-#include "llvm/MC/MCParser/MCAsmParser.h"
-#include "llvm/MC/MCParser/MCTargetAsmParser.h"
-#include "llvm/MC/MCRegisterInfo.h"
-#include "llvm/MC/MCSubtargetInfo.h"
-#include "llvm/MC/MCSymbol.h"
-#include "llvm/MC/MCTargetOptions.h"
-#include "llvm/Object/SymbolicFile.h"
-#include "llvm/Support/Casting.h"
-#include "llvm/Support/CodeGen.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/SMLoc.h"
-#include "llvm/Support/SourceMgr.h"
-#include "llvm/Support/TargetRegistry.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cassert>
-#include <cstdint>
-#include <memory>
-#include <string>
-
-using namespace llvm;
-using namespace object;
-
-void ModuleSymbolTable::addModule(Module *M) {
- if (FirstMod)
- assert(FirstMod->getTargetTriple() == M->getTargetTriple());
- else
- FirstMod = M;
-
- for (GlobalValue &GV : M->global_values())
- SymTab.push_back(&GV);
-
- CollectAsmSymbols(*M, [this](StringRef Name, BasicSymbolRef::Flags Flags) {
- SymTab.push_back(new (AsmSymbols.Allocate())
- AsmSymbol(std::string(Name), Flags));
- });
-}
-
-static void
-initializeRecordStreamer(const Module &M,
- function_ref<void(RecordStreamer &)> Init) {
- StringRef InlineAsm = M.getModuleInlineAsm();
- if (InlineAsm.empty())
- return;
-
- std::string Err;
- const Triple TT(M.getTargetTriple());
- const Target *T = TargetRegistry::lookupTarget(TT.str(), Err);
- assert(T && T->hasMCAsmParser());
-
- std::unique_ptr<MCRegisterInfo> MRI(T->createMCRegInfo(TT.str()));
- if (!MRI)
- return;
-
- MCTargetOptions MCOptions;
- std::unique_ptr<MCAsmInfo> MAI(T->createMCAsmInfo(*MRI, TT.str(), MCOptions));
- if (!MAI)
- return;
-
- std::unique_ptr<MCSubtargetInfo> STI(
- T->createMCSubtargetInfo(TT.str(), "", ""));
- if (!STI)
- return;
-
- std::unique_ptr<MCInstrInfo> MCII(T->createMCInstrInfo());
- if (!MCII)
- return;
-
- MCObjectFileInfo MOFI;
- MCContext MCCtx(MAI.get(), MRI.get(), &MOFI);
- MOFI.InitMCObjectFileInfo(TT, /*PIC*/ false, MCCtx);
- MOFI.setSDKVersion(M.getSDKVersion());
- RecordStreamer Streamer(MCCtx, M);
- T->createNullTargetStreamer(Streamer);
-
- std::unique_ptr<MemoryBuffer> Buffer(MemoryBuffer::getMemBuffer(InlineAsm));
- SourceMgr SrcMgr;
- SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
- std::unique_ptr<MCAsmParser> Parser(
- createMCAsmParser(SrcMgr, MCCtx, Streamer, *MAI));
-
- std::unique_ptr<MCTargetAsmParser> TAP(
- T->createMCAsmParser(*STI, *Parser, *MCII, MCOptions));
- if (!TAP)
- return;
-
- // Module-level inline asm is assumed to use At&t syntax (see
- // AsmPrinter::doInitialization()).
- Parser->setAssemblerDialect(InlineAsm::AD_ATT);
-
- Parser->setTargetParser(*TAP);
- if (Parser->Run(false))
- return;
-
- Init(Streamer);
-}
-
-void ModuleSymbolTable::CollectAsmSymbols(
- const Module &M,
- function_ref<void(StringRef, BasicSymbolRef::Flags)> AsmSymbol) {
- initializeRecordStreamer(M, [&](RecordStreamer &Streamer) {
- Streamer.flushSymverDirectives();
-
- for (auto &KV : Streamer) {
- StringRef Key = KV.first();
- RecordStreamer::State Value = KV.second;
- // FIXME: For now we just assume that all asm symbols are executable.
- uint32_t Res = BasicSymbolRef::SF_Executable;
- switch (Value) {
- case RecordStreamer::NeverSeen:
- llvm_unreachable("NeverSeen should have been replaced earlier");
- case RecordStreamer::DefinedGlobal:
- Res |= BasicSymbolRef::SF_Global;
- break;
- case RecordStreamer::Defined:
- break;
- case RecordStreamer::Global:
- case RecordStreamer::Used:
- Res |= BasicSymbolRef::SF_Undefined;
- Res |= BasicSymbolRef::SF_Global;
- break;
- case RecordStreamer::DefinedWeak:
- Res |= BasicSymbolRef::SF_Weak;
- Res |= BasicSymbolRef::SF_Global;
- break;
- case RecordStreamer::UndefinedWeak:
- Res |= BasicSymbolRef::SF_Weak;
- Res |= BasicSymbolRef::SF_Undefined;
- }
- AsmSymbol(Key, BasicSymbolRef::Flags(Res));
- }
- });
-}
-
-void ModuleSymbolTable::CollectAsmSymvers(
- const Module &M, function_ref<void(StringRef, StringRef)> AsmSymver) {
- initializeRecordStreamer(M, [&](RecordStreamer &Streamer) {
- for (auto &KV : Streamer.symverAliases())
- for (auto &Alias : KV.second)
- AsmSymver(KV.first->getName(), Alias);
- });
-}
-
-void ModuleSymbolTable::printSymbolName(raw_ostream &OS, Symbol S) const {
- if (S.is<AsmSymbol *>()) {
- OS << S.get<AsmSymbol *>()->first;
- return;
- }
-
- auto *GV = S.get<GlobalValue *>();
- if (GV->hasDLLImportStorageClass())
- OS << "__imp_";
-
- Mang.getNameWithPrefix(OS, GV, false);
-}
-
-uint32_t ModuleSymbolTable::getSymbolFlags(Symbol S) const {
- if (S.is<AsmSymbol *>())
- return S.get<AsmSymbol *>()->second;
-
- auto *GV = S.get<GlobalValue *>();
-
- uint32_t Res = BasicSymbolRef::SF_None;
- if (GV->isDeclarationForLinker())
- Res |= BasicSymbolRef::SF_Undefined;
- else if (GV->hasHiddenVisibility() && !GV->hasLocalLinkage())
- Res |= BasicSymbolRef::SF_Hidden;
- if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV)) {
- if (GVar->isConstant())
- Res |= BasicSymbolRef::SF_Const;
- }
- if (dyn_cast_or_null<Function>(GV->getBaseObject()))
- Res |= BasicSymbolRef::SF_Executable;
- if (isa<GlobalAlias>(GV))
- Res |= BasicSymbolRef::SF_Indirect;
- if (GV->hasPrivateLinkage())
- Res |= BasicSymbolRef::SF_FormatSpecific;
- if (!GV->hasLocalLinkage())
- Res |= BasicSymbolRef::SF_Global;
- if (GV->hasCommonLinkage())
- Res |= BasicSymbolRef::SF_Common;
- if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage() ||
- GV->hasExternalWeakLinkage())
- Res |= BasicSymbolRef::SF_Weak;
-
- if (GV->getName().startswith("llvm."))
- Res |= BasicSymbolRef::SF_FormatSpecific;
- else if (auto *Var = dyn_cast<GlobalVariable>(GV)) {
- if (Var->getSection() == "llvm.metadata")
- Res |= BasicSymbolRef::SF_FormatSpecific;
- }
-
- return Res;
-}
+//===- ModuleSymbolTable.cpp - symbol table for in-memory IR --------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This class represents a symbol table built from in-memory IR. It provides
+// access to GlobalValues and should only be used if such access is required
+// (e.g. in the LTO implementation).
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ModuleSymbolTable.h"
+#include "RecordStreamer.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/GlobalAlias.h"
+#include "llvm/IR/GlobalValue.h"
+#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/InlineAsm.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCObjectFileInfo.h"
+#include "llvm/MC/MCParser/MCAsmParser.h"
+#include "llvm/MC/MCParser/MCTargetAsmParser.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCTargetOptions.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CodeGen.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/SMLoc.h"
+#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <memory>
+#include <string>
+
+using namespace llvm;
+using namespace object;
+
+void ModuleSymbolTable::addModule(Module *M) {
+ if (FirstMod)
+ assert(FirstMod->getTargetTriple() == M->getTargetTriple());
+ else
+ FirstMod = M;
+
+ for (GlobalValue &GV : M->global_values())
+ SymTab.push_back(&GV);
+
+ CollectAsmSymbols(*M, [this](StringRef Name, BasicSymbolRef::Flags Flags) {
+ SymTab.push_back(new (AsmSymbols.Allocate())
+ AsmSymbol(std::string(Name), Flags));
+ });
+}
+
+static void
+initializeRecordStreamer(const Module &M,
+ function_ref<void(RecordStreamer &)> Init) {
+ StringRef InlineAsm = M.getModuleInlineAsm();
+ if (InlineAsm.empty())
+ return;
+
+ std::string Err;
+ const Triple TT(M.getTargetTriple());
+ const Target *T = TargetRegistry::lookupTarget(TT.str(), Err);
+ assert(T && T->hasMCAsmParser());
+
+ std::unique_ptr<MCRegisterInfo> MRI(T->createMCRegInfo(TT.str()));
+ if (!MRI)
+ return;
+
+ MCTargetOptions MCOptions;
+ std::unique_ptr<MCAsmInfo> MAI(T->createMCAsmInfo(*MRI, TT.str(), MCOptions));
+ if (!MAI)
+ return;
+
+ std::unique_ptr<MCSubtargetInfo> STI(
+ T->createMCSubtargetInfo(TT.str(), "", ""));
+ if (!STI)
+ return;
+
+ std::unique_ptr<MCInstrInfo> MCII(T->createMCInstrInfo());
+ if (!MCII)
+ return;
+
+ MCObjectFileInfo MOFI;
+ MCContext MCCtx(MAI.get(), MRI.get(), &MOFI);
+ MOFI.InitMCObjectFileInfo(TT, /*PIC*/ false, MCCtx);
+ MOFI.setSDKVersion(M.getSDKVersion());
+ RecordStreamer Streamer(MCCtx, M);
+ T->createNullTargetStreamer(Streamer);
+
+ std::unique_ptr<MemoryBuffer> Buffer(MemoryBuffer::getMemBuffer(InlineAsm));
+ SourceMgr SrcMgr;
+ SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
+ std::unique_ptr<MCAsmParser> Parser(
+ createMCAsmParser(SrcMgr, MCCtx, Streamer, *MAI));
+
+ std::unique_ptr<MCTargetAsmParser> TAP(
+ T->createMCAsmParser(*STI, *Parser, *MCII, MCOptions));
+ if (!TAP)
+ return;
+
+ // Module-level inline asm is assumed to use At&t syntax (see
+ // AsmPrinter::doInitialization()).
+ Parser->setAssemblerDialect(InlineAsm::AD_ATT);
+
+ Parser->setTargetParser(*TAP);
+ if (Parser->Run(false))
+ return;
+
+ Init(Streamer);
+}
+
+void ModuleSymbolTable::CollectAsmSymbols(
+ const Module &M,
+ function_ref<void(StringRef, BasicSymbolRef::Flags)> AsmSymbol) {
+ initializeRecordStreamer(M, [&](RecordStreamer &Streamer) {
+ Streamer.flushSymverDirectives();
+
+ for (auto &KV : Streamer) {
+ StringRef Key = KV.first();
+ RecordStreamer::State Value = KV.second;
+ // FIXME: For now we just assume that all asm symbols are executable.
+ uint32_t Res = BasicSymbolRef::SF_Executable;
+ switch (Value) {
+ case RecordStreamer::NeverSeen:
+ llvm_unreachable("NeverSeen should have been replaced earlier");
+ case RecordStreamer::DefinedGlobal:
+ Res |= BasicSymbolRef::SF_Global;
+ break;
+ case RecordStreamer::Defined:
+ break;
+ case RecordStreamer::Global:
+ case RecordStreamer::Used:
+ Res |= BasicSymbolRef::SF_Undefined;
+ Res |= BasicSymbolRef::SF_Global;
+ break;
+ case RecordStreamer::DefinedWeak:
+ Res |= BasicSymbolRef::SF_Weak;
+ Res |= BasicSymbolRef::SF_Global;
+ break;
+ case RecordStreamer::UndefinedWeak:
+ Res |= BasicSymbolRef::SF_Weak;
+ Res |= BasicSymbolRef::SF_Undefined;
+ }
+ AsmSymbol(Key, BasicSymbolRef::Flags(Res));
+ }
+ });
+}
+
+void ModuleSymbolTable::CollectAsmSymvers(
+ const Module &M, function_ref<void(StringRef, StringRef)> AsmSymver) {
+ initializeRecordStreamer(M, [&](RecordStreamer &Streamer) {
+ for (auto &KV : Streamer.symverAliases())
+ for (auto &Alias : KV.second)
+ AsmSymver(KV.first->getName(), Alias);
+ });
+}
+
+void ModuleSymbolTable::printSymbolName(raw_ostream &OS, Symbol S) const {
+ if (S.is<AsmSymbol *>()) {
+ OS << S.get<AsmSymbol *>()->first;
+ return;
+ }
+
+ auto *GV = S.get<GlobalValue *>();
+ if (GV->hasDLLImportStorageClass())
+ OS << "__imp_";
+
+ Mang.getNameWithPrefix(OS, GV, false);
+}
+
+uint32_t ModuleSymbolTable::getSymbolFlags(Symbol S) const {
+ if (S.is<AsmSymbol *>())
+ return S.get<AsmSymbol *>()->second;
+
+ auto *GV = S.get<GlobalValue *>();
+
+ uint32_t Res = BasicSymbolRef::SF_None;
+ if (GV->isDeclarationForLinker())
+ Res |= BasicSymbolRef::SF_Undefined;
+ else if (GV->hasHiddenVisibility() && !GV->hasLocalLinkage())
+ Res |= BasicSymbolRef::SF_Hidden;
+ if (const GlobalVariable *GVar = dyn_cast<GlobalVariable>(GV)) {
+ if (GVar->isConstant())
+ Res |= BasicSymbolRef::SF_Const;
+ }
+ if (dyn_cast_or_null<Function>(GV->getBaseObject()))
+ Res |= BasicSymbolRef::SF_Executable;
+ if (isa<GlobalAlias>(GV))
+ Res |= BasicSymbolRef::SF_Indirect;
+ if (GV->hasPrivateLinkage())
+ Res |= BasicSymbolRef::SF_FormatSpecific;
+ if (!GV->hasLocalLinkage())
+ Res |= BasicSymbolRef::SF_Global;
+ if (GV->hasCommonLinkage())
+ Res |= BasicSymbolRef::SF_Common;
+ if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage() ||
+ GV->hasExternalWeakLinkage())
+ Res |= BasicSymbolRef::SF_Weak;
+
+ if (GV->getName().startswith("llvm."))
+ Res |= BasicSymbolRef::SF_FormatSpecific;
+ else if (auto *Var = dyn_cast<GlobalVariable>(GV)) {
+ if (Var->getSection() == "llvm.metadata")
+ Res |= BasicSymbolRef::SF_FormatSpecific;
+ }
+
+ return Res;
+}
diff --git a/contrib/libs/llvm12/lib/Object/Object.cpp b/contrib/libs/llvm12/lib/Object/Object.cpp
index a75733d90e..b486e9f5c9 100644
--- a/contrib/libs/llvm12/lib/Object/Object.cpp
+++ b/contrib/libs/llvm12/lib/Object/Object.cpp
@@ -1,356 +1,356 @@
-//===- Object.cpp - C bindings to the object file library--------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the C bindings to the file-format-independent object
-// library.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm-c/Object.h"
-#include "llvm/ADT/SmallVector.h"
-#include "llvm/IR/LLVMContext.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Object/MachOUniversal.h"
-
-using namespace llvm;
-using namespace object;
-
-inline OwningBinary<ObjectFile> *unwrap(LLVMObjectFileRef OF) {
- return reinterpret_cast<OwningBinary<ObjectFile> *>(OF);
-}
-
-inline LLVMObjectFileRef wrap(const OwningBinary<ObjectFile> *OF) {
- return reinterpret_cast<LLVMObjectFileRef>(
- const_cast<OwningBinary<ObjectFile> *>(OF));
-}
-
-inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
- return reinterpret_cast<section_iterator*>(SI);
-}
-
-inline LLVMSectionIteratorRef
-wrap(const section_iterator *SI) {
- return reinterpret_cast<LLVMSectionIteratorRef>
- (const_cast<section_iterator*>(SI));
-}
-
-inline symbol_iterator *unwrap(LLVMSymbolIteratorRef SI) {
- return reinterpret_cast<symbol_iterator*>(SI);
-}
-
-inline LLVMSymbolIteratorRef
-wrap(const symbol_iterator *SI) {
- return reinterpret_cast<LLVMSymbolIteratorRef>
- (const_cast<symbol_iterator*>(SI));
-}
-
-inline relocation_iterator *unwrap(LLVMRelocationIteratorRef SI) {
- return reinterpret_cast<relocation_iterator*>(SI);
-}
-
-inline LLVMRelocationIteratorRef
-wrap(const relocation_iterator *SI) {
- return reinterpret_cast<LLVMRelocationIteratorRef>
- (const_cast<relocation_iterator*>(SI));
-}
-
-/*--.. Operations on binary files ..........................................--*/
-
-LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf,
- LLVMContextRef Context,
- char **ErrorMessage) {
- auto maybeContext = Context ? unwrap(Context) : nullptr;
- Expected<std::unique_ptr<Binary>> ObjOrErr(
- createBinary(unwrap(MemBuf)->getMemBufferRef(), maybeContext));
- if (!ObjOrErr) {
- *ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str());
- return nullptr;
- }
-
- return wrap(ObjOrErr.get().release());
-}
-
-LLVMMemoryBufferRef LLVMBinaryCopyMemoryBuffer(LLVMBinaryRef BR) {
- auto Buf = unwrap(BR)->getMemoryBufferRef();
- return wrap(llvm::MemoryBuffer::getMemBuffer(
- Buf.getBuffer(), Buf.getBufferIdentifier(),
- /*RequiresNullTerminator*/false).release());
-}
-
-void LLVMDisposeBinary(LLVMBinaryRef BR) {
- delete unwrap(BR);
-}
-
-LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) {
- class BinaryTypeMapper final : public Binary {
- public:
- static LLVMBinaryType mapBinaryTypeToLLVMBinaryType(unsigned Kind) {
- switch (Kind) {
- case ID_Archive:
- return LLVMBinaryTypeArchive;
- case ID_MachOUniversalBinary:
- return LLVMBinaryTypeMachOUniversalBinary;
- case ID_COFFImportFile:
- return LLVMBinaryTypeCOFFImportFile;
- case ID_IR:
- return LLVMBinaryTypeIR;
- case ID_WinRes:
- return LLVMBinaryTypeWinRes;
- case ID_COFF:
- return LLVMBinaryTypeCOFF;
- case ID_ELF32L:
- return LLVMBinaryTypeELF32L;
- case ID_ELF32B:
- return LLVMBinaryTypeELF32B;
- case ID_ELF64L:
- return LLVMBinaryTypeELF64L;
- case ID_ELF64B:
- return LLVMBinaryTypeELF64B;
- case ID_MachO32L:
- return LLVMBinaryTypeMachO32L;
- case ID_MachO32B:
- return LLVMBinaryTypeMachO32B;
- case ID_MachO64L:
- return LLVMBinaryTypeMachO64L;
- case ID_MachO64B:
- return LLVMBinaryTypeMachO64B;
- case ID_Wasm:
- return LLVMBinaryTypeWasm;
- case ID_StartObjects:
- case ID_EndObjects:
- llvm_unreachable("Marker types are not valid binary kinds!");
- default:
- llvm_unreachable("Unknown binary kind!");
- }
- }
- };
- return BinaryTypeMapper::mapBinaryTypeToLLVMBinaryType(unwrap(BR)->getType());
-}
-
-LLVMBinaryRef LLVMMachOUniversalBinaryCopyObjectForArch(LLVMBinaryRef BR,
- const char *Arch,
- size_t ArchLen,
- char **ErrorMessage) {
- auto universal = cast<MachOUniversalBinary>(unwrap(BR));
- Expected<std::unique_ptr<ObjectFile>> ObjOrErr(
- universal->getMachOObjectForArch({Arch, ArchLen}));
- if (!ObjOrErr) {
- *ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str());
- return nullptr;
- }
- return wrap(ObjOrErr.get().release());
-}
-
-LLVMSectionIteratorRef LLVMObjectFileCopySectionIterator(LLVMBinaryRef BR) {
- auto OF = cast<ObjectFile>(unwrap(BR));
- auto sections = OF->sections();
- if (sections.begin() == sections.end())
- return nullptr;
- return wrap(new section_iterator(sections.begin()));
-}
-
-LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
- LLVMSectionIteratorRef SI) {
- auto OF = cast<ObjectFile>(unwrap(BR));
- return (*unwrap(SI) == OF->section_end()) ? 1 : 0;
-}
-
-LLVMSymbolIteratorRef LLVMObjectFileCopySymbolIterator(LLVMBinaryRef BR) {
- auto OF = cast<ObjectFile>(unwrap(BR));
- auto symbols = OF->symbols();
- if (symbols.begin() == symbols.end())
- return nullptr;
- return wrap(new symbol_iterator(symbols.begin()));
-}
-
-LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR,
- LLVMSymbolIteratorRef SI) {
- auto OF = cast<ObjectFile>(unwrap(BR));
- return (*unwrap(SI) == OF->symbol_end()) ? 1 : 0;
-}
-
-// ObjectFile creation
-LLVMObjectFileRef LLVMCreateObjectFile(LLVMMemoryBufferRef MemBuf) {
- std::unique_ptr<MemoryBuffer> Buf(unwrap(MemBuf));
- Expected<std::unique_ptr<ObjectFile>> ObjOrErr(
- ObjectFile::createObjectFile(Buf->getMemBufferRef()));
- std::unique_ptr<ObjectFile> Obj;
- if (!ObjOrErr) {
- // TODO: Actually report errors helpfully.
- consumeError(ObjOrErr.takeError());
- return nullptr;
- }
-
- auto *Ret = new OwningBinary<ObjectFile>(std::move(ObjOrErr.get()), std::move(Buf));
- return wrap(Ret);
-}
-
-void LLVMDisposeObjectFile(LLVMObjectFileRef ObjectFile) {
- delete unwrap(ObjectFile);
-}
-
-// ObjectFile Section iterators
-LLVMSectionIteratorRef LLVMGetSections(LLVMObjectFileRef OF) {
- OwningBinary<ObjectFile> *OB = unwrap(OF);
- section_iterator SI = OB->getBinary()->section_begin();
- return wrap(new section_iterator(SI));
-}
-
-void LLVMDisposeSectionIterator(LLVMSectionIteratorRef SI) {
- delete unwrap(SI);
-}
-
-LLVMBool LLVMIsSectionIteratorAtEnd(LLVMObjectFileRef OF,
- LLVMSectionIteratorRef SI) {
- OwningBinary<ObjectFile> *OB = unwrap(OF);
- return (*unwrap(SI) == OB->getBinary()->section_end()) ? 1 : 0;
-}
-
-void LLVMMoveToNextSection(LLVMSectionIteratorRef SI) {
- ++(*unwrap(SI));
-}
-
-void LLVMMoveToContainingSection(LLVMSectionIteratorRef Sect,
- LLVMSymbolIteratorRef Sym) {
- Expected<section_iterator> SecOrErr = (*unwrap(Sym))->getSection();
- if (!SecOrErr) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- logAllUnhandledErrors(SecOrErr.takeError(), OS);
- OS.flush();
- report_fatal_error(Buf);
- }
- *unwrap(Sect) = *SecOrErr;
-}
-
-// ObjectFile Symbol iterators
-LLVMSymbolIteratorRef LLVMGetSymbols(LLVMObjectFileRef OF) {
- OwningBinary<ObjectFile> *OB = unwrap(OF);
- symbol_iterator SI = OB->getBinary()->symbol_begin();
- return wrap(new symbol_iterator(SI));
-}
-
-void LLVMDisposeSymbolIterator(LLVMSymbolIteratorRef SI) {
- delete unwrap(SI);
-}
-
-LLVMBool LLVMIsSymbolIteratorAtEnd(LLVMObjectFileRef OF,
- LLVMSymbolIteratorRef SI) {
- OwningBinary<ObjectFile> *OB = unwrap(OF);
- return (*unwrap(SI) == OB->getBinary()->symbol_end()) ? 1 : 0;
-}
-
-void LLVMMoveToNextSymbol(LLVMSymbolIteratorRef SI) {
- ++(*unwrap(SI));
-}
-
-// SectionRef accessors
-const char *LLVMGetSectionName(LLVMSectionIteratorRef SI) {
- auto NameOrErr = (*unwrap(SI))->getName();
- if (!NameOrErr)
- report_fatal_error(NameOrErr.takeError());
- return NameOrErr->data();
-}
-
-uint64_t LLVMGetSectionSize(LLVMSectionIteratorRef SI) {
- return (*unwrap(SI))->getSize();
-}
-
-const char *LLVMGetSectionContents(LLVMSectionIteratorRef SI) {
- if (Expected<StringRef> E = (*unwrap(SI))->getContents())
- return E->data();
- else
- report_fatal_error(E.takeError());
-}
-
-uint64_t LLVMGetSectionAddress(LLVMSectionIteratorRef SI) {
- return (*unwrap(SI))->getAddress();
-}
-
-LLVMBool LLVMGetSectionContainsSymbol(LLVMSectionIteratorRef SI,
- LLVMSymbolIteratorRef Sym) {
- return (*unwrap(SI))->containsSymbol(**unwrap(Sym));
-}
-
-// Section Relocation iterators
-LLVMRelocationIteratorRef LLVMGetRelocations(LLVMSectionIteratorRef Section) {
- relocation_iterator SI = (*unwrap(Section))->relocation_begin();
- return wrap(new relocation_iterator(SI));
-}
-
-void LLVMDisposeRelocationIterator(LLVMRelocationIteratorRef SI) {
- delete unwrap(SI);
-}
-
-LLVMBool LLVMIsRelocationIteratorAtEnd(LLVMSectionIteratorRef Section,
- LLVMRelocationIteratorRef SI) {
- return (*unwrap(SI) == (*unwrap(Section))->relocation_end()) ? 1 : 0;
-}
-
-void LLVMMoveToNextRelocation(LLVMRelocationIteratorRef SI) {
- ++(*unwrap(SI));
-}
-
-
-// SymbolRef accessors
-const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI) {
- Expected<StringRef> Ret = (*unwrap(SI))->getName();
- if (!Ret) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- logAllUnhandledErrors(Ret.takeError(), OS);
- OS.flush();
- report_fatal_error(Buf);
- }
- return Ret->data();
-}
-
-uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI) {
- Expected<uint64_t> Ret = (*unwrap(SI))->getAddress();
- if (!Ret) {
- std::string Buf;
- raw_string_ostream OS(Buf);
- logAllUnhandledErrors(Ret.takeError(), OS);
- OS.flush();
- report_fatal_error(Buf);
- }
- return *Ret;
-}
-
-uint64_t LLVMGetSymbolSize(LLVMSymbolIteratorRef SI) {
- return (*unwrap(SI))->getCommonSize();
-}
-
-// RelocationRef accessors
-uint64_t LLVMGetRelocationOffset(LLVMRelocationIteratorRef RI) {
- return (*unwrap(RI))->getOffset();
-}
-
-LLVMSymbolIteratorRef LLVMGetRelocationSymbol(LLVMRelocationIteratorRef RI) {
- symbol_iterator ret = (*unwrap(RI))->getSymbol();
- return wrap(new symbol_iterator(ret));
-}
-
-uint64_t LLVMGetRelocationType(LLVMRelocationIteratorRef RI) {
- return (*unwrap(RI))->getType();
-}
-
-// NOTE: Caller takes ownership of returned string.
-const char *LLVMGetRelocationTypeName(LLVMRelocationIteratorRef RI) {
- SmallVector<char, 0> ret;
- (*unwrap(RI))->getTypeName(ret);
- char *str = static_cast<char*>(safe_malloc(ret.size()));
- llvm::copy(ret, str);
- return str;
-}
-
-// NOTE: Caller takes ownership of returned string.
-const char *LLVMGetRelocationValueString(LLVMRelocationIteratorRef RI) {
- return strdup("");
-}
-
+//===- Object.cpp - C bindings to the object file library--------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the C bindings to the file-format-independent object
+// library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c/Object.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/LLVMContext.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/MachOUniversal.h"
+
+using namespace llvm;
+using namespace object;
+
+inline OwningBinary<ObjectFile> *unwrap(LLVMObjectFileRef OF) {
+ return reinterpret_cast<OwningBinary<ObjectFile> *>(OF);
+}
+
+inline LLVMObjectFileRef wrap(const OwningBinary<ObjectFile> *OF) {
+ return reinterpret_cast<LLVMObjectFileRef>(
+ const_cast<OwningBinary<ObjectFile> *>(OF));
+}
+
+inline section_iterator *unwrap(LLVMSectionIteratorRef SI) {
+ return reinterpret_cast<section_iterator*>(SI);
+}
+
+inline LLVMSectionIteratorRef
+wrap(const section_iterator *SI) {
+ return reinterpret_cast<LLVMSectionIteratorRef>
+ (const_cast<section_iterator*>(SI));
+}
+
+inline symbol_iterator *unwrap(LLVMSymbolIteratorRef SI) {
+ return reinterpret_cast<symbol_iterator*>(SI);
+}
+
+inline LLVMSymbolIteratorRef
+wrap(const symbol_iterator *SI) {
+ return reinterpret_cast<LLVMSymbolIteratorRef>
+ (const_cast<symbol_iterator*>(SI));
+}
+
+inline relocation_iterator *unwrap(LLVMRelocationIteratorRef SI) {
+ return reinterpret_cast<relocation_iterator*>(SI);
+}
+
+inline LLVMRelocationIteratorRef
+wrap(const relocation_iterator *SI) {
+ return reinterpret_cast<LLVMRelocationIteratorRef>
+ (const_cast<relocation_iterator*>(SI));
+}
+
+/*--.. Operations on binary files ..........................................--*/
+
+LLVMBinaryRef LLVMCreateBinary(LLVMMemoryBufferRef MemBuf,
+ LLVMContextRef Context,
+ char **ErrorMessage) {
+ auto maybeContext = Context ? unwrap(Context) : nullptr;
+ Expected<std::unique_ptr<Binary>> ObjOrErr(
+ createBinary(unwrap(MemBuf)->getMemBufferRef(), maybeContext));
+ if (!ObjOrErr) {
+ *ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str());
+ return nullptr;
+ }
+
+ return wrap(ObjOrErr.get().release());
+}
+
+LLVMMemoryBufferRef LLVMBinaryCopyMemoryBuffer(LLVMBinaryRef BR) {
+ auto Buf = unwrap(BR)->getMemoryBufferRef();
+ return wrap(llvm::MemoryBuffer::getMemBuffer(
+ Buf.getBuffer(), Buf.getBufferIdentifier(),
+ /*RequiresNullTerminator*/false).release());
+}
+
+void LLVMDisposeBinary(LLVMBinaryRef BR) {
+ delete unwrap(BR);
+}
+
+LLVMBinaryType LLVMBinaryGetType(LLVMBinaryRef BR) {
+ class BinaryTypeMapper final : public Binary {
+ public:
+ static LLVMBinaryType mapBinaryTypeToLLVMBinaryType(unsigned Kind) {
+ switch (Kind) {
+ case ID_Archive:
+ return LLVMBinaryTypeArchive;
+ case ID_MachOUniversalBinary:
+ return LLVMBinaryTypeMachOUniversalBinary;
+ case ID_COFFImportFile:
+ return LLVMBinaryTypeCOFFImportFile;
+ case ID_IR:
+ return LLVMBinaryTypeIR;
+ case ID_WinRes:
+ return LLVMBinaryTypeWinRes;
+ case ID_COFF:
+ return LLVMBinaryTypeCOFF;
+ case ID_ELF32L:
+ return LLVMBinaryTypeELF32L;
+ case ID_ELF32B:
+ return LLVMBinaryTypeELF32B;
+ case ID_ELF64L:
+ return LLVMBinaryTypeELF64L;
+ case ID_ELF64B:
+ return LLVMBinaryTypeELF64B;
+ case ID_MachO32L:
+ return LLVMBinaryTypeMachO32L;
+ case ID_MachO32B:
+ return LLVMBinaryTypeMachO32B;
+ case ID_MachO64L:
+ return LLVMBinaryTypeMachO64L;
+ case ID_MachO64B:
+ return LLVMBinaryTypeMachO64B;
+ case ID_Wasm:
+ return LLVMBinaryTypeWasm;
+ case ID_StartObjects:
+ case ID_EndObjects:
+ llvm_unreachable("Marker types are not valid binary kinds!");
+ default:
+ llvm_unreachable("Unknown binary kind!");
+ }
+ }
+ };
+ return BinaryTypeMapper::mapBinaryTypeToLLVMBinaryType(unwrap(BR)->getType());
+}
+
+LLVMBinaryRef LLVMMachOUniversalBinaryCopyObjectForArch(LLVMBinaryRef BR,
+ const char *Arch,
+ size_t ArchLen,
+ char **ErrorMessage) {
+ auto universal = cast<MachOUniversalBinary>(unwrap(BR));
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr(
+ universal->getMachOObjectForArch({Arch, ArchLen}));
+ if (!ObjOrErr) {
+ *ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str());
+ return nullptr;
+ }
+ return wrap(ObjOrErr.get().release());
+}
+
+LLVMSectionIteratorRef LLVMObjectFileCopySectionIterator(LLVMBinaryRef BR) {
+ auto OF = cast<ObjectFile>(unwrap(BR));
+ auto sections = OF->sections();
+ if (sections.begin() == sections.end())
+ return nullptr;
+ return wrap(new section_iterator(sections.begin()));
+}
+
+LLVMBool LLVMObjectFileIsSectionIteratorAtEnd(LLVMBinaryRef BR,
+ LLVMSectionIteratorRef SI) {
+ auto OF = cast<ObjectFile>(unwrap(BR));
+ return (*unwrap(SI) == OF->section_end()) ? 1 : 0;
+}
+
+LLVMSymbolIteratorRef LLVMObjectFileCopySymbolIterator(LLVMBinaryRef BR) {
+ auto OF = cast<ObjectFile>(unwrap(BR));
+ auto symbols = OF->symbols();
+ if (symbols.begin() == symbols.end())
+ return nullptr;
+ return wrap(new symbol_iterator(symbols.begin()));
+}
+
+LLVMBool LLVMObjectFileIsSymbolIteratorAtEnd(LLVMBinaryRef BR,
+ LLVMSymbolIteratorRef SI) {
+ auto OF = cast<ObjectFile>(unwrap(BR));
+ return (*unwrap(SI) == OF->symbol_end()) ? 1 : 0;
+}
+
+// ObjectFile creation
+LLVMObjectFileRef LLVMCreateObjectFile(LLVMMemoryBufferRef MemBuf) {
+ std::unique_ptr<MemoryBuffer> Buf(unwrap(MemBuf));
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr(
+ ObjectFile::createObjectFile(Buf->getMemBufferRef()));
+ std::unique_ptr<ObjectFile> Obj;
+ if (!ObjOrErr) {
+ // TODO: Actually report errors helpfully.
+ consumeError(ObjOrErr.takeError());
+ return nullptr;
+ }
+
+ auto *Ret = new OwningBinary<ObjectFile>(std::move(ObjOrErr.get()), std::move(Buf));
+ return wrap(Ret);
+}
+
+void LLVMDisposeObjectFile(LLVMObjectFileRef ObjectFile) {
+ delete unwrap(ObjectFile);
+}
+
+// ObjectFile Section iterators
+LLVMSectionIteratorRef LLVMGetSections(LLVMObjectFileRef OF) {
+ OwningBinary<ObjectFile> *OB = unwrap(OF);
+ section_iterator SI = OB->getBinary()->section_begin();
+ return wrap(new section_iterator(SI));
+}
+
+void LLVMDisposeSectionIterator(LLVMSectionIteratorRef SI) {
+ delete unwrap(SI);
+}
+
+LLVMBool LLVMIsSectionIteratorAtEnd(LLVMObjectFileRef OF,
+ LLVMSectionIteratorRef SI) {
+ OwningBinary<ObjectFile> *OB = unwrap(OF);
+ return (*unwrap(SI) == OB->getBinary()->section_end()) ? 1 : 0;
+}
+
+void LLVMMoveToNextSection(LLVMSectionIteratorRef SI) {
+ ++(*unwrap(SI));
+}
+
+void LLVMMoveToContainingSection(LLVMSectionIteratorRef Sect,
+ LLVMSymbolIteratorRef Sym) {
+ Expected<section_iterator> SecOrErr = (*unwrap(Sym))->getSection();
+ if (!SecOrErr) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(SecOrErr.takeError(), OS);
+ OS.flush();
+ report_fatal_error(Buf);
+ }
+ *unwrap(Sect) = *SecOrErr;
+}
+
+// ObjectFile Symbol iterators
+LLVMSymbolIteratorRef LLVMGetSymbols(LLVMObjectFileRef OF) {
+ OwningBinary<ObjectFile> *OB = unwrap(OF);
+ symbol_iterator SI = OB->getBinary()->symbol_begin();
+ return wrap(new symbol_iterator(SI));
+}
+
+void LLVMDisposeSymbolIterator(LLVMSymbolIteratorRef SI) {
+ delete unwrap(SI);
+}
+
+LLVMBool LLVMIsSymbolIteratorAtEnd(LLVMObjectFileRef OF,
+ LLVMSymbolIteratorRef SI) {
+ OwningBinary<ObjectFile> *OB = unwrap(OF);
+ return (*unwrap(SI) == OB->getBinary()->symbol_end()) ? 1 : 0;
+}
+
+void LLVMMoveToNextSymbol(LLVMSymbolIteratorRef SI) {
+ ++(*unwrap(SI));
+}
+
+// SectionRef accessors
+const char *LLVMGetSectionName(LLVMSectionIteratorRef SI) {
+ auto NameOrErr = (*unwrap(SI))->getName();
+ if (!NameOrErr)
+ report_fatal_error(NameOrErr.takeError());
+ return NameOrErr->data();
+}
+
+uint64_t LLVMGetSectionSize(LLVMSectionIteratorRef SI) {
+ return (*unwrap(SI))->getSize();
+}
+
+const char *LLVMGetSectionContents(LLVMSectionIteratorRef SI) {
+ if (Expected<StringRef> E = (*unwrap(SI))->getContents())
+ return E->data();
+ else
+ report_fatal_error(E.takeError());
+}
+
+uint64_t LLVMGetSectionAddress(LLVMSectionIteratorRef SI) {
+ return (*unwrap(SI))->getAddress();
+}
+
+LLVMBool LLVMGetSectionContainsSymbol(LLVMSectionIteratorRef SI,
+ LLVMSymbolIteratorRef Sym) {
+ return (*unwrap(SI))->containsSymbol(**unwrap(Sym));
+}
+
+// Section Relocation iterators
+LLVMRelocationIteratorRef LLVMGetRelocations(LLVMSectionIteratorRef Section) {
+ relocation_iterator SI = (*unwrap(Section))->relocation_begin();
+ return wrap(new relocation_iterator(SI));
+}
+
+void LLVMDisposeRelocationIterator(LLVMRelocationIteratorRef SI) {
+ delete unwrap(SI);
+}
+
+LLVMBool LLVMIsRelocationIteratorAtEnd(LLVMSectionIteratorRef Section,
+ LLVMRelocationIteratorRef SI) {
+ return (*unwrap(SI) == (*unwrap(Section))->relocation_end()) ? 1 : 0;
+}
+
+void LLVMMoveToNextRelocation(LLVMRelocationIteratorRef SI) {
+ ++(*unwrap(SI));
+}
+
+
+// SymbolRef accessors
+const char *LLVMGetSymbolName(LLVMSymbolIteratorRef SI) {
+ Expected<StringRef> Ret = (*unwrap(SI))->getName();
+ if (!Ret) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(Ret.takeError(), OS);
+ OS.flush();
+ report_fatal_error(Buf);
+ }
+ return Ret->data();
+}
+
+uint64_t LLVMGetSymbolAddress(LLVMSymbolIteratorRef SI) {
+ Expected<uint64_t> Ret = (*unwrap(SI))->getAddress();
+ if (!Ret) {
+ std::string Buf;
+ raw_string_ostream OS(Buf);
+ logAllUnhandledErrors(Ret.takeError(), OS);
+ OS.flush();
+ report_fatal_error(Buf);
+ }
+ return *Ret;
+}
+
+uint64_t LLVMGetSymbolSize(LLVMSymbolIteratorRef SI) {
+ return (*unwrap(SI))->getCommonSize();
+}
+
+// RelocationRef accessors
+uint64_t LLVMGetRelocationOffset(LLVMRelocationIteratorRef RI) {
+ return (*unwrap(RI))->getOffset();
+}
+
+LLVMSymbolIteratorRef LLVMGetRelocationSymbol(LLVMRelocationIteratorRef RI) {
+ symbol_iterator ret = (*unwrap(RI))->getSymbol();
+ return wrap(new symbol_iterator(ret));
+}
+
+uint64_t LLVMGetRelocationType(LLVMRelocationIteratorRef RI) {
+ return (*unwrap(RI))->getType();
+}
+
+// NOTE: Caller takes ownership of returned string.
+const char *LLVMGetRelocationTypeName(LLVMRelocationIteratorRef RI) {
+ SmallVector<char, 0> ret;
+ (*unwrap(RI))->getTypeName(ret);
+ char *str = static_cast<char*>(safe_malloc(ret.size()));
+ llvm::copy(ret, str);
+ return str;
+}
+
+// NOTE: Caller takes ownership of returned string.
+const char *LLVMGetRelocationValueString(LLVMRelocationIteratorRef RI) {
+ return strdup("");
+}
+
diff --git a/contrib/libs/llvm12/lib/Object/ObjectFile.cpp b/contrib/libs/llvm12/lib/Object/ObjectFile.cpp
index 5b7b4f0ff3..cf09a66d9c 100644
--- a/contrib/libs/llvm12/lib/Object/ObjectFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/ObjectFile.cpp
@@ -1,200 +1,200 @@
-//===- ObjectFile.cpp - File format independent object file ---------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a file format independent ObjectFile class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/BinaryFormat/Magic.h"
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Object/Wasm.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
-#include <cstdint>
-#include <memory>
-#include <system_error>
-
-using namespace llvm;
-using namespace object;
-
-raw_ostream &object::operator<<(raw_ostream &OS, const SectionedAddress &Addr) {
- OS << "SectionedAddress{" << format_hex(Addr.Address, 10);
- if (Addr.SectionIndex != SectionedAddress::UndefSection)
- OS << ", " << Addr.SectionIndex;
- return OS << "}";
-}
-
-void ObjectFile::anchor() {}
-
-ObjectFile::ObjectFile(unsigned int Type, MemoryBufferRef Source)
- : SymbolicFile(Type, Source) {}
-
-bool SectionRef::containsSymbol(SymbolRef S) const {
- Expected<section_iterator> SymSec = S.getSection();
- if (!SymSec) {
- // TODO: Actually report errors helpfully.
- consumeError(SymSec.takeError());
- return false;
- }
- return *this == **SymSec;
-}
-
-Expected<uint64_t> ObjectFile::getSymbolValue(DataRefImpl Ref) const {
- if (Expected<uint32_t> FlagsOrErr = getSymbolFlags(Ref)) {
- if (*FlagsOrErr & SymbolRef::SF_Undefined)
- return 0;
- if (*FlagsOrErr & SymbolRef::SF_Common)
- return getCommonSymbolSize(Ref);
- } else
- // TODO: Test this error.
- return FlagsOrErr.takeError();
- return getSymbolValueImpl(Ref);
-}
-
-Error ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {
- Expected<StringRef> Name = getSymbolName(Symb);
- if (!Name)
- return Name.takeError();
- OS << *Name;
- return Error::success();
-}
-
-uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; }
-
-bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const {
- Expected<StringRef> NameOrErr = getSectionName(Sec);
- if (NameOrErr)
- return *NameOrErr == ".llvmbc";
- consumeError(NameOrErr.takeError());
- return false;
-}
-
-bool ObjectFile::isSectionStripped(DataRefImpl Sec) const { return false; }
-
-bool ObjectFile::isBerkeleyText(DataRefImpl Sec) const {
- return isSectionText(Sec);
-}
-
-bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const {
- return isSectionData(Sec);
-}
-
-bool ObjectFile::isDebugSection(StringRef SectionName) const {
- return false;
-}
-
-Expected<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:
- // something we can do here is indicate that it is mach-o.
- if (isMachO()) {
- TheTriple.setObjectFormat(Triple::MachO);
- } else if (isCOFF()) {
- const auto COFFObj = cast<COFFObjectFile>(this);
- if (COFFObj->getArch() == Triple::thumb)
- TheTriple.setTriple("thumbv7-windows");
- } else if (isXCOFF()) {
- // XCOFF implies AIX.
- TheTriple.setOS(Triple::AIX);
- TheTriple.setObjectFormat(Triple::XCOFF);
- }
-
- return TheTriple;
-}
-
-Expected<std::unique_ptr<ObjectFile>>
+//===- ObjectFile.cpp - File format independent object file ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a file format independent ObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdint>
+#include <memory>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+
+raw_ostream &object::operator<<(raw_ostream &OS, const SectionedAddress &Addr) {
+ OS << "SectionedAddress{" << format_hex(Addr.Address, 10);
+ if (Addr.SectionIndex != SectionedAddress::UndefSection)
+ OS << ", " << Addr.SectionIndex;
+ return OS << "}";
+}
+
+void ObjectFile::anchor() {}
+
+ObjectFile::ObjectFile(unsigned int Type, MemoryBufferRef Source)
+ : SymbolicFile(Type, Source) {}
+
+bool SectionRef::containsSymbol(SymbolRef S) const {
+ Expected<section_iterator> SymSec = S.getSection();
+ if (!SymSec) {
+ // TODO: Actually report errors helpfully.
+ consumeError(SymSec.takeError());
+ return false;
+ }
+ return *this == **SymSec;
+}
+
+Expected<uint64_t> ObjectFile::getSymbolValue(DataRefImpl Ref) const {
+ if (Expected<uint32_t> FlagsOrErr = getSymbolFlags(Ref)) {
+ if (*FlagsOrErr & SymbolRef::SF_Undefined)
+ return 0;
+ if (*FlagsOrErr & SymbolRef::SF_Common)
+ return getCommonSymbolSize(Ref);
+ } else
+ // TODO: Test this error.
+ return FlagsOrErr.takeError();
+ return getSymbolValueImpl(Ref);
+}
+
+Error ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {
+ Expected<StringRef> Name = getSymbolName(Symb);
+ if (!Name)
+ return Name.takeError();
+ OS << *Name;
+ return Error::success();
+}
+
+uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; }
+
+bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const {
+ Expected<StringRef> NameOrErr = getSectionName(Sec);
+ if (NameOrErr)
+ return *NameOrErr == ".llvmbc";
+ consumeError(NameOrErr.takeError());
+ return false;
+}
+
+bool ObjectFile::isSectionStripped(DataRefImpl Sec) const { return false; }
+
+bool ObjectFile::isBerkeleyText(DataRefImpl Sec) const {
+ return isSectionText(Sec);
+}
+
+bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const {
+ return isSectionData(Sec);
+}
+
+bool ObjectFile::isDebugSection(StringRef SectionName) const {
+ return false;
+}
+
+Expected<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:
+ // something we can do here is indicate that it is mach-o.
+ if (isMachO()) {
+ TheTriple.setObjectFormat(Triple::MachO);
+ } else if (isCOFF()) {
+ const auto COFFObj = cast<COFFObjectFile>(this);
+ if (COFFObj->getArch() == Triple::thumb)
+ TheTriple.setTriple("thumbv7-windows");
+ } else if (isXCOFF()) {
+ // XCOFF implies AIX.
+ TheTriple.setOS(Triple::AIX);
+ TheTriple.setObjectFormat(Triple::XCOFF);
+ }
+
+ return TheTriple;
+}
+
+Expected<std::unique_ptr<ObjectFile>>
ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type,
bool InitContent) {
- StringRef Data = Object.getBuffer();
- if (Type == file_magic::unknown)
- Type = identify_magic(Data);
-
- switch (Type) {
- case file_magic::unknown:
- case file_magic::bitcode:
- case file_magic::coff_cl_gl_object:
- case file_magic::archive:
- case file_magic::macho_universal_binary:
- case file_magic::windows_resource:
- case file_magic::pdb:
- case file_magic::minidump:
- return errorCodeToError(object_error::invalid_file_type);
- case file_magic::tapi_file:
- return errorCodeToError(object_error::invalid_file_type);
- case file_magic::elf:
- case file_magic::elf_relocatable:
- case file_magic::elf_executable:
- case file_magic::elf_shared_object:
- case file_magic::elf_core:
+ StringRef Data = Object.getBuffer();
+ if (Type == file_magic::unknown)
+ Type = identify_magic(Data);
+
+ switch (Type) {
+ case file_magic::unknown:
+ case file_magic::bitcode:
+ case file_magic::coff_cl_gl_object:
+ case file_magic::archive:
+ case file_magic::macho_universal_binary:
+ case file_magic::windows_resource:
+ case file_magic::pdb:
+ case file_magic::minidump:
+ return errorCodeToError(object_error::invalid_file_type);
+ case file_magic::tapi_file:
+ return errorCodeToError(object_error::invalid_file_type);
+ case file_magic::elf:
+ case file_magic::elf_relocatable:
+ case file_magic::elf_executable:
+ case file_magic::elf_shared_object:
+ case file_magic::elf_core:
return createELFObjectFile(Object, InitContent);
- case file_magic::macho_object:
- case file_magic::macho_executable:
- case file_magic::macho_fixed_virtual_memory_shared_lib:
- case file_magic::macho_core:
- case file_magic::macho_preload_executable:
- case file_magic::macho_dynamically_linked_shared_lib:
- case file_magic::macho_dynamic_linker:
- case file_magic::macho_bundle:
- case file_magic::macho_dynamically_linked_shared_lib_stub:
- case file_magic::macho_dsym_companion:
- case file_magic::macho_kext_bundle:
- return createMachOObjectFile(Object);
- case file_magic::coff_object:
- case file_magic::coff_import_library:
- case file_magic::pecoff_executable:
- return createCOFFObjectFile(Object);
- case file_magic::xcoff_object_32:
- return createXCOFFObjectFile(Object, Binary::ID_XCOFF32);
- case file_magic::xcoff_object_64:
- return createXCOFFObjectFile(Object, Binary::ID_XCOFF64);
- case file_magic::wasm_object:
- return createWasmObjectFile(Object);
- }
- llvm_unreachable("Unexpected Object File Type");
-}
-
-Expected<OwningBinary<ObjectFile>>
-ObjectFile::createObjectFile(StringRef ObjectPath) {
- ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
- MemoryBuffer::getFile(ObjectPath);
- if (std::error_code EC = FileOrErr.getError())
- return errorCodeToError(EC);
- std::unique_ptr<MemoryBuffer> Buffer = std::move(FileOrErr.get());
-
- Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
- createObjectFile(Buffer->getMemBufferRef());
- if (Error Err = ObjOrErr.takeError())
- return std::move(Err);
- std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
-
- return OwningBinary<ObjectFile>(std::move(Obj), std::move(Buffer));
-}
+ case file_magic::macho_object:
+ case file_magic::macho_executable:
+ case file_magic::macho_fixed_virtual_memory_shared_lib:
+ case file_magic::macho_core:
+ case file_magic::macho_preload_executable:
+ case file_magic::macho_dynamically_linked_shared_lib:
+ case file_magic::macho_dynamic_linker:
+ case file_magic::macho_bundle:
+ case file_magic::macho_dynamically_linked_shared_lib_stub:
+ case file_magic::macho_dsym_companion:
+ case file_magic::macho_kext_bundle:
+ return createMachOObjectFile(Object);
+ case file_magic::coff_object:
+ case file_magic::coff_import_library:
+ case file_magic::pecoff_executable:
+ return createCOFFObjectFile(Object);
+ case file_magic::xcoff_object_32:
+ return createXCOFFObjectFile(Object, Binary::ID_XCOFF32);
+ case file_magic::xcoff_object_64:
+ return createXCOFFObjectFile(Object, Binary::ID_XCOFF64);
+ case file_magic::wasm_object:
+ return createWasmObjectFile(Object);
+ }
+ llvm_unreachable("Unexpected Object File Type");
+}
+
+Expected<OwningBinary<ObjectFile>>
+ObjectFile::createObjectFile(StringRef ObjectPath) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> FileOrErr =
+ MemoryBuffer::getFile(ObjectPath);
+ if (std::error_code EC = FileOrErr.getError())
+ return errorCodeToError(EC);
+ std::unique_ptr<MemoryBuffer> Buffer = std::move(FileOrErr.get());
+
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
+ createObjectFile(Buffer->getMemBufferRef());
+ if (Error Err = ObjOrErr.takeError())
+ return std::move(Err);
+ std::unique_ptr<ObjectFile> Obj = std::move(ObjOrErr.get());
+
+ return OwningBinary<ObjectFile>(std::move(Obj), std::move(Buffer));
+}
diff --git a/contrib/libs/llvm12/lib/Object/RecordStreamer.cpp b/contrib/libs/llvm12/lib/Object/RecordStreamer.cpp
index 5df87f6f70..b2f973eff3 100644
--- a/contrib/libs/llvm12/lib/Object/RecordStreamer.cpp
+++ b/contrib/libs/llvm12/lib/Object/RecordStreamer.cpp
@@ -1,232 +1,232 @@
-//===-- RecordStreamer.cpp - Record asm defined and used symbols ----------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "RecordStreamer.h"
-#include "llvm/IR/Mangler.h"
-#include "llvm/IR/Module.h"
-#include "llvm/MC/MCContext.h"
-#include "llvm/MC/MCSymbol.h"
-
-using namespace llvm;
-
-void RecordStreamer::markDefined(const MCSymbol &Symbol) {
- State &S = Symbols[Symbol.getName()];
- switch (S) {
- case DefinedGlobal:
- case Global:
- S = DefinedGlobal;
- break;
- case NeverSeen:
- case Defined:
- case Used:
- S = Defined;
- break;
- case DefinedWeak:
- break;
- case UndefinedWeak:
- S = DefinedWeak;
- }
-}
-
-void RecordStreamer::markGlobal(const MCSymbol &Symbol,
- MCSymbolAttr Attribute) {
- State &S = Symbols[Symbol.getName()];
- switch (S) {
- case DefinedGlobal:
- case Defined:
- S = (Attribute == MCSA_Weak) ? DefinedWeak : DefinedGlobal;
- break;
-
- case NeverSeen:
- case Global:
- case Used:
- S = (Attribute == MCSA_Weak) ? UndefinedWeak : Global;
- break;
- case UndefinedWeak:
- case DefinedWeak:
- break;
- }
-}
-
-void RecordStreamer::markUsed(const MCSymbol &Symbol) {
- State &S = Symbols[Symbol.getName()];
- switch (S) {
- case DefinedGlobal:
- case Defined:
- case Global:
- case DefinedWeak:
- case UndefinedWeak:
- break;
-
- case NeverSeen:
- case Used:
- S = Used;
- break;
- }
-}
-
-void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Sym); }
-
-RecordStreamer::RecordStreamer(MCContext &Context, const Module &M)
- : MCStreamer(Context), M(M) {}
-
-RecordStreamer::const_iterator RecordStreamer::begin() {
- return Symbols.begin();
-}
-
-RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); }
-
-void RecordStreamer::emitInstruction(const MCInst &Inst,
- const MCSubtargetInfo &STI) {
- MCStreamer::emitInstruction(Inst, STI);
-}
-
-void RecordStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
- MCStreamer::emitLabel(Symbol);
- markDefined(*Symbol);
-}
-
-void RecordStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
- markDefined(*Symbol);
- MCStreamer::emitAssignment(Symbol, Value);
-}
-
-bool RecordStreamer::emitSymbolAttribute(MCSymbol *Symbol,
- MCSymbolAttr Attribute) {
- if (Attribute == MCSA_Global || Attribute == MCSA_Weak)
- markGlobal(*Symbol, Attribute);
- if (Attribute == MCSA_LazyReference)
- markUsed(*Symbol);
- return true;
-}
-
-void RecordStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
- uint64_t Size, unsigned ByteAlignment,
- SMLoc Loc) {
- markDefined(*Symbol);
-}
-
-void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
- unsigned ByteAlignment) {
- markDefined(*Symbol);
-}
-
-RecordStreamer::State RecordStreamer::getSymbolState(const MCSymbol *Sym) {
- auto SI = Symbols.find(Sym->getName());
- if (SI == Symbols.end())
- return NeverSeen;
- return SI->second;
-}
-
-void RecordStreamer::emitELFSymverDirective(StringRef AliasName,
- const MCSymbol *Aliasee) {
- SymverAliasMap[Aliasee].push_back(AliasName);
-}
-
-iterator_range<RecordStreamer::const_symver_iterator>
-RecordStreamer::symverAliases() {
- return {SymverAliasMap.begin(), SymverAliasMap.end()};
-}
-
-void RecordStreamer::flushSymverDirectives() {
- // Mapping from mangled name to GV.
- StringMap<const GlobalValue *> MangledNameMap;
- // The name in the assembler will be mangled, but the name in the IR
- // might not, so we first compute a mapping from mangled name to GV.
- Mangler Mang;
- SmallString<64> MangledName;
- for (const GlobalValue &GV : M.global_values()) {
- if (!GV.hasName())
- continue;
- MangledName.clear();
- MangledName.reserve(GV.getName().size() + 1);
- Mang.getNameWithPrefix(MangledName, &GV, /*CannotUsePrivateLabel=*/false);
- MangledNameMap[MangledName] = &GV;
- }
-
- // Walk all the recorded .symver aliases, and set up the binding
- // for each alias.
- for (auto &Symver : SymverAliasMap) {
- const MCSymbol *Aliasee = Symver.first;
- MCSymbolAttr Attr = MCSA_Invalid;
- bool IsDefined = false;
-
- // First check if the aliasee binding was recorded in the asm.
- RecordStreamer::State state = getSymbolState(Aliasee);
- switch (state) {
- case RecordStreamer::Global:
- case RecordStreamer::DefinedGlobal:
- Attr = MCSA_Global;
- break;
- case RecordStreamer::UndefinedWeak:
- case RecordStreamer::DefinedWeak:
- Attr = MCSA_Weak;
- break;
- default:
- break;
- }
-
- switch (state) {
- case RecordStreamer::Defined:
- case RecordStreamer::DefinedGlobal:
- case RecordStreamer::DefinedWeak:
- IsDefined = true;
- break;
- case RecordStreamer::NeverSeen:
- case RecordStreamer::Global:
- case RecordStreamer::Used:
- case RecordStreamer::UndefinedWeak:
- break;
- }
-
- if (Attr == MCSA_Invalid || !IsDefined) {
- const GlobalValue *GV = M.getNamedValue(Aliasee->getName());
- if (!GV) {
- auto MI = MangledNameMap.find(Aliasee->getName());
- if (MI != MangledNameMap.end())
- GV = MI->second;
- }
- if (GV) {
- // If we don't have a symbol attribute from assembly, then check if
- // the aliasee was defined in the IR.
- if (Attr == MCSA_Invalid) {
- if (GV->hasExternalLinkage())
- Attr = MCSA_Global;
- else if (GV->hasLocalLinkage())
- Attr = MCSA_Local;
- else if (GV->isWeakForLinker())
- Attr = MCSA_Weak;
- }
- IsDefined = IsDefined || !GV->isDeclarationForLinker();
- }
- }
-
- // Set the detected binding on each alias with this aliasee.
- for (auto AliasName : Symver.second) {
- std::pair<StringRef, StringRef> Split = AliasName.split("@@@");
- SmallString<128> NewName;
- if (!Split.second.empty() && !Split.second.startswith("@")) {
- // Special processing for "@@@" according
- // https://sourceware.org/binutils/docs/as/Symver.html
- const char *Separator = IsDefined ? "@@" : "@";
- AliasName =
- (Split.first + Separator + Split.second).toStringRef(NewName);
- }
- MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
- // TODO: Handle "@@@". Depending on SymbolAttribute value it needs to be
- // converted into @ or @@.
- const MCExpr *Value = MCSymbolRefExpr::create(Aliasee, getContext());
- if (IsDefined)
- markDefined(*Alias);
- // Don't use EmitAssignment override as it always marks alias as defined.
- MCStreamer::emitAssignment(Alias, Value);
- if (Attr != MCSA_Invalid)
- emitSymbolAttribute(Alias, Attr);
- }
- }
-}
+//===-- RecordStreamer.cpp - Record asm defined and used symbols ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RecordStreamer.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCSymbol.h"
+
+using namespace llvm;
+
+void RecordStreamer::markDefined(const MCSymbol &Symbol) {
+ State &S = Symbols[Symbol.getName()];
+ switch (S) {
+ case DefinedGlobal:
+ case Global:
+ S = DefinedGlobal;
+ break;
+ case NeverSeen:
+ case Defined:
+ case Used:
+ S = Defined;
+ break;
+ case DefinedWeak:
+ break;
+ case UndefinedWeak:
+ S = DefinedWeak;
+ }
+}
+
+void RecordStreamer::markGlobal(const MCSymbol &Symbol,
+ MCSymbolAttr Attribute) {
+ State &S = Symbols[Symbol.getName()];
+ switch (S) {
+ case DefinedGlobal:
+ case Defined:
+ S = (Attribute == MCSA_Weak) ? DefinedWeak : DefinedGlobal;
+ break;
+
+ case NeverSeen:
+ case Global:
+ case Used:
+ S = (Attribute == MCSA_Weak) ? UndefinedWeak : Global;
+ break;
+ case UndefinedWeak:
+ case DefinedWeak:
+ break;
+ }
+}
+
+void RecordStreamer::markUsed(const MCSymbol &Symbol) {
+ State &S = Symbols[Symbol.getName()];
+ switch (S) {
+ case DefinedGlobal:
+ case Defined:
+ case Global:
+ case DefinedWeak:
+ case UndefinedWeak:
+ break;
+
+ case NeverSeen:
+ case Used:
+ S = Used;
+ break;
+ }
+}
+
+void RecordStreamer::visitUsedSymbol(const MCSymbol &Sym) { markUsed(Sym); }
+
+RecordStreamer::RecordStreamer(MCContext &Context, const Module &M)
+ : MCStreamer(Context), M(M) {}
+
+RecordStreamer::const_iterator RecordStreamer::begin() {
+ return Symbols.begin();
+}
+
+RecordStreamer::const_iterator RecordStreamer::end() { return Symbols.end(); }
+
+void RecordStreamer::emitInstruction(const MCInst &Inst,
+ const MCSubtargetInfo &STI) {
+ MCStreamer::emitInstruction(Inst, STI);
+}
+
+void RecordStreamer::emitLabel(MCSymbol *Symbol, SMLoc Loc) {
+ MCStreamer::emitLabel(Symbol);
+ markDefined(*Symbol);
+}
+
+void RecordStreamer::emitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
+ markDefined(*Symbol);
+ MCStreamer::emitAssignment(Symbol, Value);
+}
+
+bool RecordStreamer::emitSymbolAttribute(MCSymbol *Symbol,
+ MCSymbolAttr Attribute) {
+ if (Attribute == MCSA_Global || Attribute == MCSA_Weak)
+ markGlobal(*Symbol, Attribute);
+ if (Attribute == MCSA_LazyReference)
+ markUsed(*Symbol);
+ return true;
+}
+
+void RecordStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
+ uint64_t Size, unsigned ByteAlignment,
+ SMLoc Loc) {
+ markDefined(*Symbol);
+}
+
+void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) {
+ markDefined(*Symbol);
+}
+
+RecordStreamer::State RecordStreamer::getSymbolState(const MCSymbol *Sym) {
+ auto SI = Symbols.find(Sym->getName());
+ if (SI == Symbols.end())
+ return NeverSeen;
+ return SI->second;
+}
+
+void RecordStreamer::emitELFSymverDirective(StringRef AliasName,
+ const MCSymbol *Aliasee) {
+ SymverAliasMap[Aliasee].push_back(AliasName);
+}
+
+iterator_range<RecordStreamer::const_symver_iterator>
+RecordStreamer::symverAliases() {
+ return {SymverAliasMap.begin(), SymverAliasMap.end()};
+}
+
+void RecordStreamer::flushSymverDirectives() {
+ // Mapping from mangled name to GV.
+ StringMap<const GlobalValue *> MangledNameMap;
+ // The name in the assembler will be mangled, but the name in the IR
+ // might not, so we first compute a mapping from mangled name to GV.
+ Mangler Mang;
+ SmallString<64> MangledName;
+ for (const GlobalValue &GV : M.global_values()) {
+ if (!GV.hasName())
+ continue;
+ MangledName.clear();
+ MangledName.reserve(GV.getName().size() + 1);
+ Mang.getNameWithPrefix(MangledName, &GV, /*CannotUsePrivateLabel=*/false);
+ MangledNameMap[MangledName] = &GV;
+ }
+
+ // Walk all the recorded .symver aliases, and set up the binding
+ // for each alias.
+ for (auto &Symver : SymverAliasMap) {
+ const MCSymbol *Aliasee = Symver.first;
+ MCSymbolAttr Attr = MCSA_Invalid;
+ bool IsDefined = false;
+
+ // First check if the aliasee binding was recorded in the asm.
+ RecordStreamer::State state = getSymbolState(Aliasee);
+ switch (state) {
+ case RecordStreamer::Global:
+ case RecordStreamer::DefinedGlobal:
+ Attr = MCSA_Global;
+ break;
+ case RecordStreamer::UndefinedWeak:
+ case RecordStreamer::DefinedWeak:
+ Attr = MCSA_Weak;
+ break;
+ default:
+ break;
+ }
+
+ switch (state) {
+ case RecordStreamer::Defined:
+ case RecordStreamer::DefinedGlobal:
+ case RecordStreamer::DefinedWeak:
+ IsDefined = true;
+ break;
+ case RecordStreamer::NeverSeen:
+ case RecordStreamer::Global:
+ case RecordStreamer::Used:
+ case RecordStreamer::UndefinedWeak:
+ break;
+ }
+
+ if (Attr == MCSA_Invalid || !IsDefined) {
+ const GlobalValue *GV = M.getNamedValue(Aliasee->getName());
+ if (!GV) {
+ auto MI = MangledNameMap.find(Aliasee->getName());
+ if (MI != MangledNameMap.end())
+ GV = MI->second;
+ }
+ if (GV) {
+ // If we don't have a symbol attribute from assembly, then check if
+ // the aliasee was defined in the IR.
+ if (Attr == MCSA_Invalid) {
+ if (GV->hasExternalLinkage())
+ Attr = MCSA_Global;
+ else if (GV->hasLocalLinkage())
+ Attr = MCSA_Local;
+ else if (GV->isWeakForLinker())
+ Attr = MCSA_Weak;
+ }
+ IsDefined = IsDefined || !GV->isDeclarationForLinker();
+ }
+ }
+
+ // Set the detected binding on each alias with this aliasee.
+ for (auto AliasName : Symver.second) {
+ std::pair<StringRef, StringRef> Split = AliasName.split("@@@");
+ SmallString<128> NewName;
+ if (!Split.second.empty() && !Split.second.startswith("@")) {
+ // Special processing for "@@@" according
+ // https://sourceware.org/binutils/docs/as/Symver.html
+ const char *Separator = IsDefined ? "@@" : "@";
+ AliasName =
+ (Split.first + Separator + Split.second).toStringRef(NewName);
+ }
+ MCSymbol *Alias = getContext().getOrCreateSymbol(AliasName);
+ // TODO: Handle "@@@". Depending on SymbolAttribute value it needs to be
+ // converted into @ or @@.
+ const MCExpr *Value = MCSymbolRefExpr::create(Aliasee, getContext());
+ if (IsDefined)
+ markDefined(*Alias);
+ // Don't use EmitAssignment override as it always marks alias as defined.
+ MCStreamer::emitAssignment(Alias, Value);
+ if (Attr != MCSA_Invalid)
+ emitSymbolAttribute(Alias, Attr);
+ }
+ }
+}
diff --git a/contrib/libs/llvm12/lib/Object/RecordStreamer.h b/contrib/libs/llvm12/lib/Object/RecordStreamer.h
index 03bc7eb3c7..99d15f790a 100644
--- a/contrib/libs/llvm12/lib/Object/RecordStreamer.h
+++ b/contrib/libs/llvm12/lib/Object/RecordStreamer.h
@@ -1,85 +1,85 @@
-//===- RecordStreamer.h - Record asm defined and used symbols ---*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIB_OBJECT_RECORDSTREAMER_H
-#define LLVM_LIB_OBJECT_RECORDSTREAMER_H
-
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/MC/MCDirectives.h"
-#include "llvm/MC/MCStreamer.h"
-#include "llvm/Support/SMLoc.h"
-#include <vector>
-
-namespace llvm {
-
-class MCSymbol;
-class Module;
-
-class RecordStreamer : public MCStreamer {
-public:
- enum State { NeverSeen, Global, Defined, DefinedGlobal, DefinedWeak, Used,
- UndefinedWeak};
-
-private:
- const Module &M;
- StringMap<State> Symbols;
- // Map of aliases created by .symver directives, saved so we can update
- // their symbol binding after parsing complete. This maps from each
- // aliasee to its list of aliases.
- DenseMap<const MCSymbol *, std::vector<StringRef>> SymverAliasMap;
-
- /// Get the state recorded for the given symbol.
- State getSymbolState(const MCSymbol *Sym);
-
- void markDefined(const MCSymbol &Symbol);
- void markGlobal(const MCSymbol &Symbol, MCSymbolAttr Attribute);
- void markUsed(const MCSymbol &Symbol);
- void visitUsedSymbol(const MCSymbol &Sym) override;
-
-public:
- RecordStreamer(MCContext &Context, const Module &M);
-
- void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
- void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
- void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;
- bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
- void emitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
- unsigned ByteAlignment, SMLoc Loc = SMLoc()) override;
- void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
- unsigned ByteAlignment) override;
-
- // Ignore COFF-specific directives; we do not need any information from them,
- // but the default implementation of these methods crashes, so we override
- // them with versions that do nothing.
- void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {}
- void EmitCOFFSymbolStorageClass(int StorageClass) override {}
- void EmitCOFFSymbolType(int Type) override {}
- void EndCOFFSymbolDef() override {}
-
- /// Record .symver aliases for later processing.
- void emitELFSymverDirective(StringRef AliasName,
- const MCSymbol *Aliasee) override;
-
- // Emit ELF .symver aliases and ensure they have the same binding as the
- // defined symbol they alias with.
- void flushSymverDirectives();
-
- // Symbols iterators
- using const_iterator = StringMap<State>::const_iterator;
- const_iterator begin();
- const_iterator end();
-
- // SymverAliasMap iterators
- using const_symver_iterator = decltype(SymverAliasMap)::const_iterator;
- iterator_range<const_symver_iterator> symverAliases();
-};
-
-} // end namespace llvm
-
-#endif // LLVM_LIB_OBJECT_RECORDSTREAMER_H
+//===- RecordStreamer.h - Record asm defined and used symbols ---*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_OBJECT_RECORDSTREAMER_H
+#define LLVM_LIB_OBJECT_RECORDSTREAMER_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/MC/MCDirectives.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Support/SMLoc.h"
+#include <vector>
+
+namespace llvm {
+
+class MCSymbol;
+class Module;
+
+class RecordStreamer : public MCStreamer {
+public:
+ enum State { NeverSeen, Global, Defined, DefinedGlobal, DefinedWeak, Used,
+ UndefinedWeak};
+
+private:
+ const Module &M;
+ StringMap<State> Symbols;
+ // Map of aliases created by .symver directives, saved so we can update
+ // their symbol binding after parsing complete. This maps from each
+ // aliasee to its list of aliases.
+ DenseMap<const MCSymbol *, std::vector<StringRef>> SymverAliasMap;
+
+ /// Get the state recorded for the given symbol.
+ State getSymbolState(const MCSymbol *Sym);
+
+ void markDefined(const MCSymbol &Symbol);
+ void markGlobal(const MCSymbol &Symbol, MCSymbolAttr Attribute);
+ void markUsed(const MCSymbol &Symbol);
+ void visitUsedSymbol(const MCSymbol &Sym) override;
+
+public:
+ RecordStreamer(MCContext &Context, const Module &M);
+
+ void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI) override;
+ void emitLabel(MCSymbol *Symbol, SMLoc Loc = SMLoc()) override;
+ void emitAssignment(MCSymbol *Symbol, const MCExpr *Value) override;
+ bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
+ void emitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment, SMLoc Loc = SMLoc()) override;
+ void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
+ unsigned ByteAlignment) override;
+
+ // Ignore COFF-specific directives; we do not need any information from them,
+ // but the default implementation of these methods crashes, so we override
+ // them with versions that do nothing.
+ void BeginCOFFSymbolDef(const MCSymbol *Symbol) override {}
+ void EmitCOFFSymbolStorageClass(int StorageClass) override {}
+ void EmitCOFFSymbolType(int Type) override {}
+ void EndCOFFSymbolDef() override {}
+
+ /// Record .symver aliases for later processing.
+ void emitELFSymverDirective(StringRef AliasName,
+ const MCSymbol *Aliasee) override;
+
+ // Emit ELF .symver aliases and ensure they have the same binding as the
+ // defined symbol they alias with.
+ void flushSymverDirectives();
+
+ // Symbols iterators
+ using const_iterator = StringMap<State>::const_iterator;
+ const_iterator begin();
+ const_iterator end();
+
+ // SymverAliasMap iterators
+ using const_symver_iterator = decltype(SymverAliasMap)::const_iterator;
+ iterator_range<const_symver_iterator> symverAliases();
+};
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_OBJECT_RECORDSTREAMER_H
diff --git a/contrib/libs/llvm12/lib/Object/RelocationResolver.cpp b/contrib/libs/llvm12/lib/Object/RelocationResolver.cpp
index 26f7e7cf48..204577af72 100644
--- a/contrib/libs/llvm12/lib/Object/RelocationResolver.cpp
+++ b/contrib/libs/llvm12/lib/Object/RelocationResolver.cpp
@@ -1,307 +1,307 @@
-//===- RelocationResolver.cpp ------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines utilities to resolve relocations in object files.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/RelocationResolver.h"
-
-namespace llvm {
-namespace object {
-
-static int64_t getELFAddend(RelocationRef R) {
- Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend();
- handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) {
- report_fatal_error(EI.message());
- });
- return *AddendOrErr;
-}
-
-static bool supportsX86_64(uint64_t Type) {
- switch (Type) {
- case ELF::R_X86_64_NONE:
- case ELF::R_X86_64_64:
- case ELF::R_X86_64_DTPOFF32:
- case ELF::R_X86_64_DTPOFF64:
- case ELF::R_X86_64_PC32:
- case ELF::R_X86_64_PC64:
- case ELF::R_X86_64_32:
- case ELF::R_X86_64_32S:
- return true;
- default:
- return false;
- }
-}
-
+//===- RelocationResolver.cpp ------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines utilities to resolve relocations in object files.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/RelocationResolver.h"
+
+namespace llvm {
+namespace object {
+
+static int64_t getELFAddend(RelocationRef R) {
+ Expected<int64_t> AddendOrErr = ELFRelocationRef(R).getAddend();
+ handleAllErrors(AddendOrErr.takeError(), [](const ErrorInfoBase &EI) {
+ report_fatal_error(EI.message());
+ });
+ return *AddendOrErr;
+}
+
+static bool supportsX86_64(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_X86_64_NONE:
+ case ELF::R_X86_64_64:
+ case ELF::R_X86_64_DTPOFF32:
+ case ELF::R_X86_64_DTPOFF64:
+ case ELF::R_X86_64_PC32:
+ case ELF::R_X86_64_PC64:
+ case ELF::R_X86_64_32:
+ case ELF::R_X86_64_32S:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveX86_64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t Addend) {
switch (Type) {
- case ELF::R_X86_64_NONE:
+ case ELF::R_X86_64_NONE:
return LocData;
- case ELF::R_X86_64_64:
- case ELF::R_X86_64_DTPOFF32:
- case ELF::R_X86_64_DTPOFF64:
+ case ELF::R_X86_64_64:
+ case ELF::R_X86_64_DTPOFF32:
+ case ELF::R_X86_64_DTPOFF64:
return S + Addend;
- case ELF::R_X86_64_PC32:
- case ELF::R_X86_64_PC64:
+ case ELF::R_X86_64_PC32:
+ case ELF::R_X86_64_PC64:
return S + Addend - Offset;
- case ELF::R_X86_64_32:
- case ELF::R_X86_64_32S:
+ case ELF::R_X86_64_32:
+ case ELF::R_X86_64_32S:
return (S + Addend) & 0xFFFFFFFF;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsAArch64(uint64_t Type) {
- switch (Type) {
- case ELF::R_AARCH64_ABS32:
- case ELF::R_AARCH64_ABS64:
- case ELF::R_AARCH64_PREL32:
- case ELF::R_AARCH64_PREL64:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsAArch64(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_AARCH64_ABS32:
+ case ELF::R_AARCH64_ABS64:
+ case ELF::R_AARCH64_PREL32:
+ case ELF::R_AARCH64_PREL64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveAArch64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_AARCH64_ABS32:
+ case ELF::R_AARCH64_ABS32:
return (S + Addend) & 0xFFFFFFFF;
- case ELF::R_AARCH64_ABS64:
+ case ELF::R_AARCH64_ABS64:
return S + Addend;
- case ELF::R_AARCH64_PREL32:
+ case ELF::R_AARCH64_PREL32:
return (S + Addend - Offset) & 0xFFFFFFFF;
- case ELF::R_AARCH64_PREL64:
+ case ELF::R_AARCH64_PREL64:
return S + Addend - Offset;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsBPF(uint64_t Type) {
- switch (Type) {
- case ELF::R_BPF_64_32:
- case ELF::R_BPF_64_64:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsBPF(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_BPF_64_32:
+ case ELF::R_BPF_64_64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveBPF(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
switch (Type) {
- case ELF::R_BPF_64_32:
+ case ELF::R_BPF_64_32:
return (S + LocData) & 0xFFFFFFFF;
- case ELF::R_BPF_64_64:
+ case ELF::R_BPF_64_64:
return S + LocData;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsMips64(uint64_t Type) {
- switch (Type) {
- case ELF::R_MIPS_32:
- case ELF::R_MIPS_64:
- case ELF::R_MIPS_TLS_DTPREL64:
- case ELF::R_MIPS_PC32:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsMips64(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_MIPS_32:
+ case ELF::R_MIPS_64:
+ case ELF::R_MIPS_TLS_DTPREL64:
+ case ELF::R_MIPS_PC32:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveMips64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_MIPS_32:
+ case ELF::R_MIPS_32:
return (S + Addend) & 0xFFFFFFFF;
- case ELF::R_MIPS_64:
+ case ELF::R_MIPS_64:
return S + Addend;
- case ELF::R_MIPS_TLS_DTPREL64:
+ case ELF::R_MIPS_TLS_DTPREL64:
return S + Addend - 0x8000;
- case ELF::R_MIPS_PC32:
+ case ELF::R_MIPS_PC32:
return S + Addend - Offset;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsMSP430(uint64_t Type) {
- switch (Type) {
- case ELF::R_MSP430_32:
- case ELF::R_MSP430_16_BYTE:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsMSP430(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_MSP430_32:
+ case ELF::R_MSP430_16_BYTE:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveMSP430(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_MSP430_32:
+ case ELF::R_MSP430_32:
return (S + Addend) & 0xFFFFFFFF;
- case ELF::R_MSP430_16_BYTE:
+ case ELF::R_MSP430_16_BYTE:
return (S + Addend) & 0xFFFF;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsPPC64(uint64_t Type) {
- switch (Type) {
- case ELF::R_PPC64_ADDR32:
- case ELF::R_PPC64_ADDR64:
- case ELF::R_PPC64_REL32:
- case ELF::R_PPC64_REL64:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsPPC64(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_PPC64_ADDR32:
+ case ELF::R_PPC64_ADDR64:
+ case ELF::R_PPC64_REL32:
+ case ELF::R_PPC64_REL64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolvePPC64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_PPC64_ADDR32:
+ case ELF::R_PPC64_ADDR32:
return (S + Addend) & 0xFFFFFFFF;
- case ELF::R_PPC64_ADDR64:
+ case ELF::R_PPC64_ADDR64:
return S + Addend;
- case ELF::R_PPC64_REL32:
+ case ELF::R_PPC64_REL32:
return (S + Addend - Offset) & 0xFFFFFFFF;
- case ELF::R_PPC64_REL64:
+ case ELF::R_PPC64_REL64:
return S + Addend - Offset;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsSystemZ(uint64_t Type) {
- switch (Type) {
- case ELF::R_390_32:
- case ELF::R_390_64:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsSystemZ(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_390_32:
+ case ELF::R_390_64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveSystemZ(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_390_32:
+ case ELF::R_390_32:
return (S + Addend) & 0xFFFFFFFF;
- case ELF::R_390_64:
+ case ELF::R_390_64:
return S + Addend;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsSparc64(uint64_t Type) {
- switch (Type) {
- case ELF::R_SPARC_32:
- case ELF::R_SPARC_64:
- case ELF::R_SPARC_UA32:
- case ELF::R_SPARC_UA64:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsSparc64(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_SPARC_32:
+ case ELF::R_SPARC_64:
+ case ELF::R_SPARC_UA32:
+ case ELF::R_SPARC_UA64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveSparc64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_SPARC_32:
- case ELF::R_SPARC_64:
- case ELF::R_SPARC_UA32:
- case ELF::R_SPARC_UA64:
+ case ELF::R_SPARC_32:
+ case ELF::R_SPARC_64:
+ case ELF::R_SPARC_UA32:
+ case ELF::R_SPARC_UA64:
return S + Addend;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsAmdgpu(uint64_t Type) {
- switch (Type) {
- case ELF::R_AMDGPU_ABS32:
- case ELF::R_AMDGPU_ABS64:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsAmdgpu(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_AMDGPU_ABS32:
+ case ELF::R_AMDGPU_ABS64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveAmdgpu(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_AMDGPU_ABS32:
- case ELF::R_AMDGPU_ABS64:
+ case ELF::R_AMDGPU_ABS32:
+ case ELF::R_AMDGPU_ABS64:
return S + Addend;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsX86(uint64_t Type) {
- switch (Type) {
- case ELF::R_386_NONE:
- case ELF::R_386_32:
- case ELF::R_386_PC32:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsX86(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_386_NONE:
+ case ELF::R_386_32:
+ case ELF::R_386_PC32:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveX86(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
switch (Type) {
- case ELF::R_386_NONE:
+ case ELF::R_386_NONE:
return LocData;
- case ELF::R_386_32:
+ case ELF::R_386_32:
return S + LocData;
- case ELF::R_386_PC32:
+ case ELF::R_386_PC32:
return S - Offset + LocData;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsPPC32(uint64_t Type) {
- switch (Type) {
- case ELF::R_PPC_ADDR32:
- case ELF::R_PPC_REL32:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsPPC32(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_PPC_ADDR32:
+ case ELF::R_PPC_REL32:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolvePPC32(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_PPC_ADDR32:
+ case ELF::R_PPC_ADDR32:
return (S + Addend) & 0xFFFFFFFF;
- case ELF::R_PPC_REL32:
+ case ELF::R_PPC_REL32:
return (S + Addend - Offset) & 0xFFFFFFFF;
- }
- llvm_unreachable("Invalid relocation type");
-}
-
-static bool supportsARM(uint64_t Type) {
+ }
+ llvm_unreachable("Invalid relocation type");
+}
+
+static bool supportsARM(uint64_t Type) {
switch (Type) {
case ELF::R_ARM_ABS32:
case ELF::R_ARM_REL32:
@@ -309,8 +309,8 @@ static bool supportsARM(uint64_t Type) {
default:
return false;
}
-}
-
+}
+
static uint64_t resolveARM(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
switch (Type) {
@@ -319,413 +319,413 @@ static uint64_t resolveARM(uint64_t Type, uint64_t Offset, uint64_t S,
case ELF::R_ARM_REL32:
return (S + LocData - Offset) & 0xFFFFFFFF;
}
- llvm_unreachable("Invalid relocation type");
-}
-
-static bool supportsAVR(uint64_t Type) {
- switch (Type) {
- case ELF::R_AVR_16:
- case ELF::R_AVR_32:
- return true;
- default:
- return false;
- }
-}
-
+ llvm_unreachable("Invalid relocation type");
+}
+
+static bool supportsAVR(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_AVR_16:
+ case ELF::R_AVR_32:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveAVR(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
switch (Type) {
- case ELF::R_AVR_16:
+ case ELF::R_AVR_16:
return (S + Addend) & 0xFFFF;
- case ELF::R_AVR_32:
+ case ELF::R_AVR_32:
return (S + Addend) & 0xFFFFFFFF;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsLanai(uint64_t Type) {
- return Type == ELF::R_LANAI_32;
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsLanai(uint64_t Type) {
+ return Type == ELF::R_LANAI_32;
+}
+
static uint64_t resolveLanai(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
if (Type == ELF::R_LANAI_32)
return (S + Addend) & 0xFFFFFFFF;
- llvm_unreachable("Invalid relocation type");
-}
-
-static bool supportsMips32(uint64_t Type) {
- switch (Type) {
- case ELF::R_MIPS_32:
- case ELF::R_MIPS_TLS_DTPREL32:
- return true;
- default:
- return false;
- }
-}
-
+ llvm_unreachable("Invalid relocation type");
+}
+
+static bool supportsMips32(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_MIPS_32:
+ case ELF::R_MIPS_TLS_DTPREL32:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveMips32(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
- // FIXME: Take in account implicit addends to get correct results.
+ // FIXME: Take in account implicit addends to get correct results.
if (Type == ELF::R_MIPS_32)
return (S + LocData) & 0xFFFFFFFF;
if (Type == ELF::R_MIPS_TLS_DTPREL32)
return (S + LocData) & 0xFFFFFFFF;
- llvm_unreachable("Invalid relocation type");
-}
-
-static bool supportsSparc32(uint64_t Type) {
- switch (Type) {
- case ELF::R_SPARC_32:
- case ELF::R_SPARC_UA32:
- return true;
- default:
- return false;
- }
-}
-
+ llvm_unreachable("Invalid relocation type");
+}
+
+static bool supportsSparc32(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_SPARC_32:
+ case ELF::R_SPARC_UA32:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveSparc32(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t Addend) {
if (Type == ELF::R_SPARC_32 || Type == ELF::R_SPARC_UA32)
return S + Addend;
return LocData;
-}
-
-static bool supportsHexagon(uint64_t Type) {
- return Type == ELF::R_HEX_32;
-}
-
+}
+
+static bool supportsHexagon(uint64_t Type) {
+ return Type == ELF::R_HEX_32;
+}
+
static uint64_t resolveHexagon(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t /*LocData*/, int64_t Addend) {
if (Type == ELF::R_HEX_32)
return S + Addend;
- llvm_unreachable("Invalid relocation type");
-}
-
-static bool supportsRISCV(uint64_t Type) {
- switch (Type) {
- case ELF::R_RISCV_NONE:
- case ELF::R_RISCV_32:
- case ELF::R_RISCV_32_PCREL:
- case ELF::R_RISCV_64:
- case ELF::R_RISCV_SET6:
- case ELF::R_RISCV_SUB6:
- case ELF::R_RISCV_ADD8:
- case ELF::R_RISCV_SUB8:
- case ELF::R_RISCV_ADD16:
- case ELF::R_RISCV_SUB16:
- case ELF::R_RISCV_ADD32:
- case ELF::R_RISCV_SUB32:
- case ELF::R_RISCV_ADD64:
- case ELF::R_RISCV_SUB64:
- return true;
- default:
- return false;
- }
-}
-
+ llvm_unreachable("Invalid relocation type");
+}
+
+static bool supportsRISCV(uint64_t Type) {
+ switch (Type) {
+ case ELF::R_RISCV_NONE:
+ case ELF::R_RISCV_32:
+ case ELF::R_RISCV_32_PCREL:
+ case ELF::R_RISCV_64:
+ case ELF::R_RISCV_SET6:
+ case ELF::R_RISCV_SUB6:
+ case ELF::R_RISCV_ADD8:
+ case ELF::R_RISCV_SUB8:
+ case ELF::R_RISCV_ADD16:
+ case ELF::R_RISCV_SUB16:
+ case ELF::R_RISCV_ADD32:
+ case ELF::R_RISCV_SUB32:
+ case ELF::R_RISCV_ADD64:
+ case ELF::R_RISCV_SUB64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveRISCV(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t Addend) {
int64_t RA = Addend;
uint64_t A = LocData;
switch (Type) {
- case ELF::R_RISCV_NONE:
+ case ELF::R_RISCV_NONE:
return LocData;
- case ELF::R_RISCV_32:
- return (S + RA) & 0xFFFFFFFF;
- case ELF::R_RISCV_32_PCREL:
+ case ELF::R_RISCV_32:
+ return (S + RA) & 0xFFFFFFFF;
+ case ELF::R_RISCV_32_PCREL:
return (S + RA - Offset) & 0xFFFFFFFF;
- case ELF::R_RISCV_64:
- return S + RA;
- case ELF::R_RISCV_SET6:
- return (A & 0xC0) | ((S + RA) & 0x3F);
- case ELF::R_RISCV_SUB6:
- return (A & 0xC0) | (((A & 0x3F) - (S + RA)) & 0x3F);
- case ELF::R_RISCV_ADD8:
- return (A + (S + RA)) & 0xFF;
- case ELF::R_RISCV_SUB8:
- return (A - (S + RA)) & 0xFF;
- case ELF::R_RISCV_ADD16:
- return (A + (S + RA)) & 0xFFFF;
- case ELF::R_RISCV_SUB16:
- return (A - (S + RA)) & 0xFFFF;
- case ELF::R_RISCV_ADD32:
- return (A + (S + RA)) & 0xFFFFFFFF;
- case ELF::R_RISCV_SUB32:
- return (A - (S + RA)) & 0xFFFFFFFF;
- case ELF::R_RISCV_ADD64:
- return (A + (S + RA));
- case ELF::R_RISCV_SUB64:
- return (A - (S + RA));
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsCOFFX86(uint64_t Type) {
- switch (Type) {
- case COFF::IMAGE_REL_I386_SECREL:
- case COFF::IMAGE_REL_I386_DIR32:
- return true;
- default:
- return false;
- }
-}
-
+ case ELF::R_RISCV_64:
+ return S + RA;
+ case ELF::R_RISCV_SET6:
+ return (A & 0xC0) | ((S + RA) & 0x3F);
+ case ELF::R_RISCV_SUB6:
+ return (A & 0xC0) | (((A & 0x3F) - (S + RA)) & 0x3F);
+ case ELF::R_RISCV_ADD8:
+ return (A + (S + RA)) & 0xFF;
+ case ELF::R_RISCV_SUB8:
+ return (A - (S + RA)) & 0xFF;
+ case ELF::R_RISCV_ADD16:
+ return (A + (S + RA)) & 0xFFFF;
+ case ELF::R_RISCV_SUB16:
+ return (A - (S + RA)) & 0xFFFF;
+ case ELF::R_RISCV_ADD32:
+ return (A + (S + RA)) & 0xFFFFFFFF;
+ case ELF::R_RISCV_SUB32:
+ return (A - (S + RA)) & 0xFFFFFFFF;
+ case ELF::R_RISCV_ADD64:
+ return (A + (S + RA));
+ case ELF::R_RISCV_SUB64:
+ return (A - (S + RA));
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsCOFFX86(uint64_t Type) {
+ switch (Type) {
+ case COFF::IMAGE_REL_I386_SECREL:
+ case COFF::IMAGE_REL_I386_DIR32:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveCOFFX86(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
switch (Type) {
- case COFF::IMAGE_REL_I386_SECREL:
- case COFF::IMAGE_REL_I386_DIR32:
+ case COFF::IMAGE_REL_I386_SECREL:
+ case COFF::IMAGE_REL_I386_DIR32:
return (S + LocData) & 0xFFFFFFFF;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsCOFFX86_64(uint64_t Type) {
- switch (Type) {
- case COFF::IMAGE_REL_AMD64_SECREL:
- case COFF::IMAGE_REL_AMD64_ADDR64:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsCOFFX86_64(uint64_t Type) {
+ switch (Type) {
+ case COFF::IMAGE_REL_AMD64_SECREL:
+ case COFF::IMAGE_REL_AMD64_ADDR64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveCOFFX86_64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
switch (Type) {
- case COFF::IMAGE_REL_AMD64_SECREL:
+ case COFF::IMAGE_REL_AMD64_SECREL:
return (S + LocData) & 0xFFFFFFFF;
- case COFF::IMAGE_REL_AMD64_ADDR64:
+ case COFF::IMAGE_REL_AMD64_ADDR64:
return S + LocData;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsCOFFARM(uint64_t Type) {
- switch (Type) {
- case COFF::IMAGE_REL_ARM_SECREL:
- case COFF::IMAGE_REL_ARM_ADDR32:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsCOFFARM(uint64_t Type) {
+ switch (Type) {
+ case COFF::IMAGE_REL_ARM_SECREL:
+ case COFF::IMAGE_REL_ARM_ADDR32:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveCOFFARM(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
switch (Type) {
- case COFF::IMAGE_REL_ARM_SECREL:
- case COFF::IMAGE_REL_ARM_ADDR32:
+ case COFF::IMAGE_REL_ARM_SECREL:
+ case COFF::IMAGE_REL_ARM_ADDR32:
return (S + LocData) & 0xFFFFFFFF;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsCOFFARM64(uint64_t Type) {
- switch (Type) {
- case COFF::IMAGE_REL_ARM64_SECREL:
- case COFF::IMAGE_REL_ARM64_ADDR64:
- return true;
- default:
- return false;
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsCOFFARM64(uint64_t Type) {
+ switch (Type) {
+ case COFF::IMAGE_REL_ARM64_SECREL:
+ case COFF::IMAGE_REL_ARM64_ADDR64:
+ return true;
+ default:
+ return false;
+ }
+}
+
static uint64_t resolveCOFFARM64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
switch (Type) {
- case COFF::IMAGE_REL_ARM64_SECREL:
+ case COFF::IMAGE_REL_ARM64_SECREL:
return (S + LocData) & 0xFFFFFFFF;
- case COFF::IMAGE_REL_ARM64_ADDR64:
+ case COFF::IMAGE_REL_ARM64_ADDR64:
return S + LocData;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
-static bool supportsMachOX86_64(uint64_t Type) {
- return Type == MachO::X86_64_RELOC_UNSIGNED;
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsMachOX86_64(uint64_t Type) {
+ return Type == MachO::X86_64_RELOC_UNSIGNED;
+}
+
static uint64_t resolveMachOX86_64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
if (Type == MachO::X86_64_RELOC_UNSIGNED)
- return S;
- llvm_unreachable("Invalid relocation type");
-}
-
-static bool supportsWasm32(uint64_t Type) {
- switch (Type) {
- case wasm::R_WASM_FUNCTION_INDEX_LEB:
- case wasm::R_WASM_TABLE_INDEX_SLEB:
- case wasm::R_WASM_TABLE_INDEX_I32:
- case wasm::R_WASM_MEMORY_ADDR_LEB:
- case wasm::R_WASM_MEMORY_ADDR_SLEB:
- case wasm::R_WASM_MEMORY_ADDR_I32:
- case wasm::R_WASM_TYPE_INDEX_LEB:
- case wasm::R_WASM_GLOBAL_INDEX_LEB:
- case wasm::R_WASM_FUNCTION_OFFSET_I32:
- case wasm::R_WASM_SECTION_OFFSET_I32:
- case wasm::R_WASM_EVENT_INDEX_LEB:
- case wasm::R_WASM_GLOBAL_INDEX_I32:
+ return S;
+ llvm_unreachable("Invalid relocation type");
+}
+
+static bool supportsWasm32(uint64_t Type) {
+ switch (Type) {
+ case wasm::R_WASM_FUNCTION_INDEX_LEB:
+ case wasm::R_WASM_TABLE_INDEX_SLEB:
+ case wasm::R_WASM_TABLE_INDEX_I32:
+ case wasm::R_WASM_MEMORY_ADDR_LEB:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB:
+ case wasm::R_WASM_MEMORY_ADDR_I32:
+ case wasm::R_WASM_TYPE_INDEX_LEB:
+ case wasm::R_WASM_GLOBAL_INDEX_LEB:
+ case wasm::R_WASM_FUNCTION_OFFSET_I32:
+ case wasm::R_WASM_SECTION_OFFSET_I32:
+ case wasm::R_WASM_EVENT_INDEX_LEB:
+ case wasm::R_WASM_GLOBAL_INDEX_I32:
case wasm::R_WASM_TABLE_NUMBER_LEB:
- return true;
- default:
- return false;
- }
-}
-
-static bool supportsWasm64(uint64_t Type) {
- switch (Type) {
- case wasm::R_WASM_MEMORY_ADDR_LEB64:
- case wasm::R_WASM_MEMORY_ADDR_SLEB64:
- case wasm::R_WASM_MEMORY_ADDR_I64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool supportsWasm64(uint64_t Type) {
+ switch (Type) {
+ case wasm::R_WASM_MEMORY_ADDR_LEB64:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB64:
+ case wasm::R_WASM_MEMORY_ADDR_I64:
case wasm::R_WASM_TABLE_INDEX_SLEB64:
case wasm::R_WASM_TABLE_INDEX_I64:
case wasm::R_WASM_FUNCTION_OFFSET_I64:
- return true;
- default:
- return supportsWasm32(Type);
- }
-}
-
+ return true;
+ default:
+ return supportsWasm32(Type);
+ }
+}
+
static uint64_t resolveWasm32(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t /*Addend*/) {
switch (Type) {
- case wasm::R_WASM_FUNCTION_INDEX_LEB:
- case wasm::R_WASM_TABLE_INDEX_SLEB:
- case wasm::R_WASM_TABLE_INDEX_I32:
- case wasm::R_WASM_MEMORY_ADDR_LEB:
- case wasm::R_WASM_MEMORY_ADDR_SLEB:
- case wasm::R_WASM_MEMORY_ADDR_I32:
- case wasm::R_WASM_TYPE_INDEX_LEB:
- case wasm::R_WASM_GLOBAL_INDEX_LEB:
- case wasm::R_WASM_FUNCTION_OFFSET_I32:
- case wasm::R_WASM_SECTION_OFFSET_I32:
- case wasm::R_WASM_EVENT_INDEX_LEB:
- case wasm::R_WASM_GLOBAL_INDEX_I32:
+ case wasm::R_WASM_FUNCTION_INDEX_LEB:
+ case wasm::R_WASM_TABLE_INDEX_SLEB:
+ case wasm::R_WASM_TABLE_INDEX_I32:
+ case wasm::R_WASM_MEMORY_ADDR_LEB:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB:
+ case wasm::R_WASM_MEMORY_ADDR_I32:
+ case wasm::R_WASM_TYPE_INDEX_LEB:
+ case wasm::R_WASM_GLOBAL_INDEX_LEB:
+ case wasm::R_WASM_FUNCTION_OFFSET_I32:
+ case wasm::R_WASM_SECTION_OFFSET_I32:
+ case wasm::R_WASM_EVENT_INDEX_LEB:
+ case wasm::R_WASM_GLOBAL_INDEX_I32:
case wasm::R_WASM_TABLE_NUMBER_LEB:
- // For wasm section, its offset at 0 -- ignoring Value
+ // For wasm section, its offset at 0 -- ignoring Value
return LocData;
- default:
- llvm_unreachable("Invalid relocation type");
- }
-}
-
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
static uint64_t resolveWasm64(uint64_t Type, uint64_t Offset, uint64_t S,
uint64_t LocData, int64_t Addend) {
switch (Type) {
- case wasm::R_WASM_MEMORY_ADDR_LEB64:
- case wasm::R_WASM_MEMORY_ADDR_SLEB64:
- case wasm::R_WASM_MEMORY_ADDR_I64:
+ case wasm::R_WASM_MEMORY_ADDR_LEB64:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB64:
+ case wasm::R_WASM_MEMORY_ADDR_I64:
case wasm::R_WASM_TABLE_INDEX_SLEB64:
case wasm::R_WASM_TABLE_INDEX_I64:
case wasm::R_WASM_FUNCTION_OFFSET_I64:
- // For wasm section, its offset at 0 -- ignoring Value
+ // For wasm section, its offset at 0 -- ignoring Value
return LocData;
- default:
+ default:
return resolveWasm32(Type, Offset, S, LocData, Addend);
- }
-}
-
+ }
+}
+
std::pair<SupportsRelocation, RelocationResolver>
-getRelocationResolver(const ObjectFile &Obj) {
- if (Obj.isCOFF()) {
- switch (Obj.getArch()) {
- case Triple::x86_64:
- return {supportsCOFFX86_64, resolveCOFFX86_64};
- case Triple::x86:
- return {supportsCOFFX86, resolveCOFFX86};
- case Triple::arm:
- case Triple::thumb:
- return {supportsCOFFARM, resolveCOFFARM};
- case Triple::aarch64:
- return {supportsCOFFARM64, resolveCOFFARM64};
- default:
- return {nullptr, nullptr};
- }
- } else if (Obj.isELF()) {
- if (Obj.getBytesInAddress() == 8) {
- switch (Obj.getArch()) {
- case Triple::x86_64:
- return {supportsX86_64, resolveX86_64};
- case Triple::aarch64:
- case Triple::aarch64_be:
- return {supportsAArch64, resolveAArch64};
- case Triple::bpfel:
- case Triple::bpfeb:
- return {supportsBPF, resolveBPF};
- case Triple::mips64el:
- case Triple::mips64:
- return {supportsMips64, resolveMips64};
- case Triple::ppc64le:
- case Triple::ppc64:
- return {supportsPPC64, resolvePPC64};
- case Triple::systemz:
- return {supportsSystemZ, resolveSystemZ};
- case Triple::sparcv9:
- return {supportsSparc64, resolveSparc64};
- case Triple::amdgcn:
- return {supportsAmdgpu, resolveAmdgpu};
- case Triple::riscv64:
- return {supportsRISCV, resolveRISCV};
- default:
- return {nullptr, nullptr};
- }
- }
-
- // 32-bit object file
- assert(Obj.getBytesInAddress() == 4 &&
- "Invalid word size in object file");
-
- switch (Obj.getArch()) {
- case Triple::x86:
- return {supportsX86, resolveX86};
+getRelocationResolver(const ObjectFile &Obj) {
+ if (Obj.isCOFF()) {
+ switch (Obj.getArch()) {
+ case Triple::x86_64:
+ return {supportsCOFFX86_64, resolveCOFFX86_64};
+ case Triple::x86:
+ return {supportsCOFFX86, resolveCOFFX86};
+ case Triple::arm:
+ case Triple::thumb:
+ return {supportsCOFFARM, resolveCOFFARM};
+ case Triple::aarch64:
+ return {supportsCOFFARM64, resolveCOFFARM64};
+ default:
+ return {nullptr, nullptr};
+ }
+ } else if (Obj.isELF()) {
+ if (Obj.getBytesInAddress() == 8) {
+ switch (Obj.getArch()) {
+ case Triple::x86_64:
+ return {supportsX86_64, resolveX86_64};
+ case Triple::aarch64:
+ case Triple::aarch64_be:
+ return {supportsAArch64, resolveAArch64};
+ case Triple::bpfel:
+ case Triple::bpfeb:
+ return {supportsBPF, resolveBPF};
+ case Triple::mips64el:
+ case Triple::mips64:
+ return {supportsMips64, resolveMips64};
+ case Triple::ppc64le:
+ case Triple::ppc64:
+ return {supportsPPC64, resolvePPC64};
+ case Triple::systemz:
+ return {supportsSystemZ, resolveSystemZ};
+ case Triple::sparcv9:
+ return {supportsSparc64, resolveSparc64};
+ case Triple::amdgcn:
+ return {supportsAmdgpu, resolveAmdgpu};
+ case Triple::riscv64:
+ return {supportsRISCV, resolveRISCV};
+ default:
+ return {nullptr, nullptr};
+ }
+ }
+
+ // 32-bit object file
+ assert(Obj.getBytesInAddress() == 4 &&
+ "Invalid word size in object file");
+
+ switch (Obj.getArch()) {
+ case Triple::x86:
+ return {supportsX86, resolveX86};
case Triple::ppcle:
- case Triple::ppc:
- return {supportsPPC32, resolvePPC32};
- case Triple::arm:
- case Triple::armeb:
- return {supportsARM, resolveARM};
- case Triple::avr:
- return {supportsAVR, resolveAVR};
- case Triple::lanai:
- return {supportsLanai, resolveLanai};
- case Triple::mipsel:
- case Triple::mips:
- return {supportsMips32, resolveMips32};
- case Triple::msp430:
- return {supportsMSP430, resolveMSP430};
- case Triple::sparc:
- return {supportsSparc32, resolveSparc32};
- case Triple::hexagon:
- return {supportsHexagon, resolveHexagon};
- case Triple::riscv32:
- return {supportsRISCV, resolveRISCV};
- default:
- return {nullptr, nullptr};
- }
- } else if (Obj.isMachO()) {
- if (Obj.getArch() == Triple::x86_64)
- return {supportsMachOX86_64, resolveMachOX86_64};
- return {nullptr, nullptr};
- } else if (Obj.isWasm()) {
- if (Obj.getArch() == Triple::wasm32)
- return {supportsWasm32, resolveWasm32};
- if (Obj.getArch() == Triple::wasm64)
- return {supportsWasm64, resolveWasm64};
- return {nullptr, nullptr};
- }
-
- llvm_unreachable("Invalid object file");
-}
-
+ case Triple::ppc:
+ return {supportsPPC32, resolvePPC32};
+ case Triple::arm:
+ case Triple::armeb:
+ return {supportsARM, resolveARM};
+ case Triple::avr:
+ return {supportsAVR, resolveAVR};
+ case Triple::lanai:
+ return {supportsLanai, resolveLanai};
+ case Triple::mipsel:
+ case Triple::mips:
+ return {supportsMips32, resolveMips32};
+ case Triple::msp430:
+ return {supportsMSP430, resolveMSP430};
+ case Triple::sparc:
+ return {supportsSparc32, resolveSparc32};
+ case Triple::hexagon:
+ return {supportsHexagon, resolveHexagon};
+ case Triple::riscv32:
+ return {supportsRISCV, resolveRISCV};
+ default:
+ return {nullptr, nullptr};
+ }
+ } else if (Obj.isMachO()) {
+ if (Obj.getArch() == Triple::x86_64)
+ return {supportsMachOX86_64, resolveMachOX86_64};
+ return {nullptr, nullptr};
+ } else if (Obj.isWasm()) {
+ if (Obj.getArch() == Triple::wasm32)
+ return {supportsWasm32, resolveWasm32};
+ if (Obj.getArch() == Triple::wasm64)
+ return {supportsWasm64, resolveWasm64};
+ return {nullptr, nullptr};
+ }
+
+ llvm_unreachable("Invalid object file");
+}
+
uint64_t resolveRelocation(RelocationResolver Resolver, const RelocationRef &R,
uint64_t S, uint64_t LocData) {
if (const ObjectFile *Obj = R.getObject()) {
@@ -759,5 +759,5 @@ uint64_t resolveRelocation(RelocationResolver Resolver, const RelocationRef &R,
R.getRawDataRefImpl().p);
}
-} // namespace object
-} // namespace llvm
+} // namespace object
+} // namespace llvm
diff --git a/contrib/libs/llvm12/lib/Object/SymbolSize.cpp b/contrib/libs/llvm12/lib/Object/SymbolSize.cpp
index b786490fec..97baabec08 100644
--- a/contrib/libs/llvm12/lib/Object/SymbolSize.cpp
+++ b/contrib/libs/llvm12/lib/Object/SymbolSize.cpp
@@ -1,106 +1,106 @@
-//===- SymbolSize.cpp -----------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/SymbolSize.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/Object/MachO.h"
-#include "llvm/Object/Wasm.h"
-
-using namespace llvm;
-using namespace object;
-
-// Orders increasingly by (SectionID, Address).
-int llvm::object::compareAddress(const SymEntry *A, const SymEntry *B) {
- if (A->SectionID != B->SectionID)
- return A->SectionID < B->SectionID ? -1 : 1;
- if (A->Address != B->Address)
- return A->Address < B->Address ? -1 : 1;
- return 0;
-}
-
-static unsigned getSectionID(const ObjectFile &O, SectionRef Sec) {
- if (auto *M = dyn_cast<MachOObjectFile>(&O))
- return M->getSectionID(Sec);
- if (isa<WasmObjectFile>(&O))
- return Sec.getIndex();
-
- return cast<COFFObjectFile>(O).getSectionID(Sec);
-}
-
-static unsigned getSymbolSectionID(const ObjectFile &O, SymbolRef Sym) {
- if (auto *M = dyn_cast<MachOObjectFile>(&O))
- return M->getSymbolSectionID(Sym);
- if (const auto *M = dyn_cast<WasmObjectFile>(&O))
- return M->getSymbolSectionId(Sym);
- return cast<COFFObjectFile>(O).getSymbolSectionID(Sym);
-}
-
-std::vector<std::pair<SymbolRef, uint64_t>>
-llvm::object::computeSymbolSizes(const ObjectFile &O) {
- std::vector<std::pair<SymbolRef, uint64_t>> Ret;
-
- if (const auto *E = dyn_cast<ELFObjectFileBase>(&O)) {
- auto Syms = E->symbols();
+//===- SymbolSize.cpp -----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/SymbolSize.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/Wasm.h"
+
+using namespace llvm;
+using namespace object;
+
+// Orders increasingly by (SectionID, Address).
+int llvm::object::compareAddress(const SymEntry *A, const SymEntry *B) {
+ if (A->SectionID != B->SectionID)
+ return A->SectionID < B->SectionID ? -1 : 1;
+ if (A->Address != B->Address)
+ return A->Address < B->Address ? -1 : 1;
+ return 0;
+}
+
+static unsigned getSectionID(const ObjectFile &O, SectionRef Sec) {
+ if (auto *M = dyn_cast<MachOObjectFile>(&O))
+ return M->getSectionID(Sec);
+ if (isa<WasmObjectFile>(&O))
+ return Sec.getIndex();
+
+ return cast<COFFObjectFile>(O).getSectionID(Sec);
+}
+
+static unsigned getSymbolSectionID(const ObjectFile &O, SymbolRef Sym) {
+ if (auto *M = dyn_cast<MachOObjectFile>(&O))
+ return M->getSymbolSectionID(Sym);
+ if (const auto *M = dyn_cast<WasmObjectFile>(&O))
+ return M->getSymbolSectionId(Sym);
+ return cast<COFFObjectFile>(O).getSymbolSectionID(Sym);
+}
+
+std::vector<std::pair<SymbolRef, uint64_t>>
+llvm::object::computeSymbolSizes(const ObjectFile &O) {
+ std::vector<std::pair<SymbolRef, uint64_t>> Ret;
+
+ if (const auto *E = dyn_cast<ELFObjectFileBase>(&O)) {
+ auto Syms = E->symbols();
if (Syms.empty())
- Syms = E->getDynamicSymbolIterators();
- for (ELFSymbolRef Sym : Syms)
- Ret.push_back({Sym, Sym.getSize()});
- return Ret;
- }
-
- // Collect sorted symbol addresses. Include dummy addresses for the end
- // of each section.
- std::vector<SymEntry> Addresses;
- unsigned SymNum = 0;
- for (symbol_iterator I = O.symbol_begin(), E = O.symbol_end(); I != E; ++I) {
- SymbolRef Sym = *I;
- Expected<uint64_t> ValueOrErr = Sym.getValue();
- if (!ValueOrErr)
- // TODO: Actually report errors helpfully.
- report_fatal_error(ValueOrErr.takeError());
- Addresses.push_back({I, *ValueOrErr, SymNum, getSymbolSectionID(O, Sym)});
- ++SymNum;
- }
- for (SectionRef Sec : O.sections()) {
- uint64_t Address = Sec.getAddress();
- uint64_t Size = Sec.getSize();
- Addresses.push_back(
- {O.symbol_end(), Address + Size, 0, getSectionID(O, Sec)});
- }
-
- if (Addresses.empty())
- return Ret;
-
- array_pod_sort(Addresses.begin(), Addresses.end(), compareAddress);
-
- // Compute the size as the gap to the next symbol
- for (unsigned I = 0, N = Addresses.size() - 1; I < N; ++I) {
- auto &P = Addresses[I];
- if (P.I == O.symbol_end())
- continue;
-
- // If multiple symbol have the same address, give both the same size.
- unsigned NextI = I + 1;
- while (NextI < N && Addresses[NextI].Address == P.Address)
- ++NextI;
-
- uint64_t Size = Addresses[NextI].Address - P.Address;
- P.Address = Size;
- }
-
- // Assign the sorted symbols in the original order.
- Ret.resize(SymNum);
- for (SymEntry &P : Addresses) {
- if (P.I == O.symbol_end())
- continue;
- Ret[P.Number] = {*P.I, P.Address};
- }
- return Ret;
-}
+ Syms = E->getDynamicSymbolIterators();
+ for (ELFSymbolRef Sym : Syms)
+ Ret.push_back({Sym, Sym.getSize()});
+ return Ret;
+ }
+
+ // Collect sorted symbol addresses. Include dummy addresses for the end
+ // of each section.
+ std::vector<SymEntry> Addresses;
+ unsigned SymNum = 0;
+ for (symbol_iterator I = O.symbol_begin(), E = O.symbol_end(); I != E; ++I) {
+ SymbolRef Sym = *I;
+ Expected<uint64_t> ValueOrErr = Sym.getValue();
+ if (!ValueOrErr)
+ // TODO: Actually report errors helpfully.
+ report_fatal_error(ValueOrErr.takeError());
+ Addresses.push_back({I, *ValueOrErr, SymNum, getSymbolSectionID(O, Sym)});
+ ++SymNum;
+ }
+ for (SectionRef Sec : O.sections()) {
+ uint64_t Address = Sec.getAddress();
+ uint64_t Size = Sec.getSize();
+ Addresses.push_back(
+ {O.symbol_end(), Address + Size, 0, getSectionID(O, Sec)});
+ }
+
+ if (Addresses.empty())
+ return Ret;
+
+ array_pod_sort(Addresses.begin(), Addresses.end(), compareAddress);
+
+ // Compute the size as the gap to the next symbol
+ for (unsigned I = 0, N = Addresses.size() - 1; I < N; ++I) {
+ auto &P = Addresses[I];
+ if (P.I == O.symbol_end())
+ continue;
+
+ // If multiple symbol have the same address, give both the same size.
+ unsigned NextI = I + 1;
+ while (NextI < N && Addresses[NextI].Address == P.Address)
+ ++NextI;
+
+ uint64_t Size = Addresses[NextI].Address - P.Address;
+ P.Address = Size;
+ }
+
+ // Assign the sorted symbols in the original order.
+ Ret.resize(SymNum);
+ for (SymEntry &P : Addresses) {
+ if (P.I == O.symbol_end())
+ continue;
+ Ret[P.Number] = {*P.I, P.Address};
+ }
+ return Ret;
+}
diff --git a/contrib/libs/llvm12/lib/Object/SymbolicFile.cpp b/contrib/libs/llvm12/lib/Object/SymbolicFile.cpp
index 6136f7cdab..34a2c5e1c1 100644
--- a/contrib/libs/llvm12/lib/Object/SymbolicFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/SymbolicFile.cpp
@@ -1,98 +1,98 @@
-//===- SymbolicFile.cpp - Interface that only provides symbols ------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines a file format independent SymbolicFile class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/SymbolicFile.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/BinaryFormat/Magic.h"
-#include "llvm/Object/COFFImportFile.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/IRObjectFile.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Support/Compiler.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/ErrorOr.h"
-#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include <algorithm>
-#include <memory>
-
-using namespace llvm;
-using namespace object;
-
-SymbolicFile::SymbolicFile(unsigned int Type, MemoryBufferRef Source)
- : Binary(Type, Source) {}
-
-SymbolicFile::~SymbolicFile() = default;
-
-Expected<std::unique_ptr<SymbolicFile>>
-SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type,
+//===- SymbolicFile.cpp - Interface that only provides symbols ------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a file format independent SymbolicFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Magic.h"
+#include "llvm/Object/COFFImportFile.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/IRObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include <algorithm>
+#include <memory>
+
+using namespace llvm;
+using namespace object;
+
+SymbolicFile::SymbolicFile(unsigned int Type, MemoryBufferRef Source)
+ : Binary(Type, Source) {}
+
+SymbolicFile::~SymbolicFile() = default;
+
+Expected<std::unique_ptr<SymbolicFile>>
+SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type,
LLVMContext *Context, bool InitContent) {
- StringRef Data = Object.getBuffer();
- if (Type == file_magic::unknown)
- Type = identify_magic(Data);
-
+ StringRef Data = Object.getBuffer();
+ if (Type == file_magic::unknown)
+ Type = identify_magic(Data);
+
if (!isSymbolicFile(Type, Context))
return errorCodeToError(object_error::invalid_file_type);
- switch (Type) {
- case file_magic::bitcode:
+ switch (Type) {
+ case file_magic::bitcode:
// Context is guaranteed to be non-null here, because bitcode magic only
// indicates a symbolic file when Context is non-null.
return IRObjectFile::create(Object, *Context);
- case file_magic::elf:
- case file_magic::elf_executable:
- case file_magic::elf_shared_object:
- case file_magic::elf_core:
- case file_magic::macho_executable:
- case file_magic::macho_fixed_virtual_memory_shared_lib:
- case file_magic::macho_core:
- case file_magic::macho_preload_executable:
- case file_magic::macho_dynamically_linked_shared_lib:
- case file_magic::macho_dynamic_linker:
- case file_magic::macho_bundle:
- case file_magic::macho_dynamically_linked_shared_lib_stub:
- case file_magic::macho_dsym_companion:
- case file_magic::macho_kext_bundle:
- case file_magic::pecoff_executable:
- case file_magic::xcoff_object_32:
- case file_magic::xcoff_object_64:
- case file_magic::wasm_object:
+ case file_magic::elf:
+ case file_magic::elf_executable:
+ case file_magic::elf_shared_object:
+ case file_magic::elf_core:
+ case file_magic::macho_executable:
+ case file_magic::macho_fixed_virtual_memory_shared_lib:
+ case file_magic::macho_core:
+ case file_magic::macho_preload_executable:
+ case file_magic::macho_dynamically_linked_shared_lib:
+ case file_magic::macho_dynamic_linker:
+ case file_magic::macho_bundle:
+ case file_magic::macho_dynamically_linked_shared_lib_stub:
+ case file_magic::macho_dsym_companion:
+ case file_magic::macho_kext_bundle:
+ case file_magic::pecoff_executable:
+ case file_magic::xcoff_object_32:
+ case file_magic::xcoff_object_64:
+ case file_magic::wasm_object:
return ObjectFile::createObjectFile(Object, Type, InitContent);
- case file_magic::coff_import_library:
- return std::unique_ptr<SymbolicFile>(new COFFImportFile(Object));
- case file_magic::elf_relocatable:
- case file_magic::macho_object:
- case file_magic::coff_object: {
- Expected<std::unique_ptr<ObjectFile>> Obj =
+ case file_magic::coff_import_library:
+ return std::unique_ptr<SymbolicFile>(new COFFImportFile(Object));
+ case file_magic::elf_relocatable:
+ case file_magic::macho_object:
+ case file_magic::coff_object: {
+ Expected<std::unique_ptr<ObjectFile>> Obj =
ObjectFile::createObjectFile(Object, Type, InitContent);
- if (!Obj || !Context)
- return std::move(Obj);
-
- Expected<MemoryBufferRef> BCData =
- IRObjectFile::findBitcodeInObject(*Obj->get());
- if (!BCData) {
- consumeError(BCData.takeError());
- return std::move(Obj);
- }
-
- return IRObjectFile::create(
- MemoryBufferRef(BCData->getBuffer(), Object.getBufferIdentifier()),
- *Context);
- }
+ if (!Obj || !Context)
+ return std::move(Obj);
+
+ Expected<MemoryBufferRef> BCData =
+ IRObjectFile::findBitcodeInObject(*Obj->get());
+ if (!BCData) {
+ consumeError(BCData.takeError());
+ return std::move(Obj);
+ }
+
+ return IRObjectFile::create(
+ MemoryBufferRef(BCData->getBuffer(), Object.getBufferIdentifier()),
+ *Context);
+ }
default:
llvm_unreachable("Unexpected Binary File Type");
- }
-}
+ }
+}
bool SymbolicFile::isSymbolicFile(file_magic Type, const LLVMContext *Context) {
switch (Type) {
diff --git a/contrib/libs/llvm12/lib/Object/TapiFile.cpp b/contrib/libs/llvm12/lib/Object/TapiFile.cpp
index 560c5b046e..7a361990ba 100644
--- a/contrib/libs/llvm12/lib/Object/TapiFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/TapiFile.cpp
@@ -1,102 +1,102 @@
-//===- TapiFile.cpp -------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the Text-based Dynamcic Library Stub format.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/TapiFile.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Support/MemoryBuffer.h"
-
-using namespace llvm;
-using namespace MachO;
-using namespace object;
-
-static constexpr StringLiteral ObjC1ClassNamePrefix = ".objc_class_name_";
-static constexpr StringLiteral ObjC2ClassNamePrefix = "_OBJC_CLASS_$_";
-static constexpr StringLiteral ObjC2MetaClassNamePrefix = "_OBJC_METACLASS_$_";
-static constexpr StringLiteral ObjC2EHTypePrefix = "_OBJC_EHTYPE_$_";
-static constexpr StringLiteral ObjC2IVarPrefix = "_OBJC_IVAR_$_";
-
-static uint32_t getFlags(const Symbol *Sym) {
- uint32_t Flags = BasicSymbolRef::SF_Global;
- if (Sym->isUndefined())
- Flags |= BasicSymbolRef::SF_Undefined;
- else
- Flags |= BasicSymbolRef::SF_Exported;
-
- if (Sym->isWeakDefined() || Sym->isWeakReferenced())
- Flags |= BasicSymbolRef::SF_Weak;
-
- return Flags;
-}
-
-TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &interface,
- Architecture Arch)
- : SymbolicFile(ID_TapiFile, Source), Arch(Arch) {
- for (const auto *Symbol : interface.symbols()) {
- if (!Symbol->getArchitectures().has(Arch))
- continue;
-
- switch (Symbol->getKind()) {
- case SymbolKind::GlobalSymbol:
- Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol));
- break;
- case SymbolKind::ObjectiveCClass:
- if (interface.getPlatforms().count(PlatformKind::macOS) &&
- Arch == AK_i386) {
- Symbols.emplace_back(ObjC1ClassNamePrefix, Symbol->getName(),
- getFlags(Symbol));
- } else {
- Symbols.emplace_back(ObjC2ClassNamePrefix, Symbol->getName(),
- getFlags(Symbol));
- Symbols.emplace_back(ObjC2MetaClassNamePrefix, Symbol->getName(),
- getFlags(Symbol));
- }
- break;
- case SymbolKind::ObjectiveCClassEHType:
- Symbols.emplace_back(ObjC2EHTypePrefix, Symbol->getName(),
- getFlags(Symbol));
- break;
- case SymbolKind::ObjectiveCInstanceVariable:
- Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(),
- getFlags(Symbol));
- break;
- }
- }
-}
-
-TapiFile::~TapiFile() = default;
-
-void TapiFile::moveSymbolNext(DataRefImpl &DRI) const { DRI.d.a++; }
-
-Error TapiFile::printSymbolName(raw_ostream &OS, DataRefImpl DRI) const {
- assert(DRI.d.a < Symbols.size() && "Attempt to access symbol out of bounds");
- const Symbol &Sym = Symbols[DRI.d.a];
- OS << Sym.Prefix << Sym.Name;
- return Error::success();
-}
-
-Expected<uint32_t> TapiFile::getSymbolFlags(DataRefImpl DRI) const {
- assert(DRI.d.a < Symbols.size() && "Attempt to access symbol out of bounds");
- return Symbols[DRI.d.a].Flags;
-}
-
-basic_symbol_iterator TapiFile::symbol_begin() const {
- DataRefImpl DRI;
- DRI.d.a = 0;
- return BasicSymbolRef{DRI, this};
-}
-
-basic_symbol_iterator TapiFile::symbol_end() const {
- DataRefImpl DRI;
- DRI.d.a = Symbols.size();
- return BasicSymbolRef{DRI, this};
-}
+//===- TapiFile.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Text-based Dynamcic Library Stub format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/TapiFile.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace MachO;
+using namespace object;
+
+static constexpr StringLiteral ObjC1ClassNamePrefix = ".objc_class_name_";
+static constexpr StringLiteral ObjC2ClassNamePrefix = "_OBJC_CLASS_$_";
+static constexpr StringLiteral ObjC2MetaClassNamePrefix = "_OBJC_METACLASS_$_";
+static constexpr StringLiteral ObjC2EHTypePrefix = "_OBJC_EHTYPE_$_";
+static constexpr StringLiteral ObjC2IVarPrefix = "_OBJC_IVAR_$_";
+
+static uint32_t getFlags(const Symbol *Sym) {
+ uint32_t Flags = BasicSymbolRef::SF_Global;
+ if (Sym->isUndefined())
+ Flags |= BasicSymbolRef::SF_Undefined;
+ else
+ Flags |= BasicSymbolRef::SF_Exported;
+
+ if (Sym->isWeakDefined() || Sym->isWeakReferenced())
+ Flags |= BasicSymbolRef::SF_Weak;
+
+ return Flags;
+}
+
+TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &interface,
+ Architecture Arch)
+ : SymbolicFile(ID_TapiFile, Source), Arch(Arch) {
+ for (const auto *Symbol : interface.symbols()) {
+ if (!Symbol->getArchitectures().has(Arch))
+ continue;
+
+ switch (Symbol->getKind()) {
+ case SymbolKind::GlobalSymbol:
+ Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol));
+ break;
+ case SymbolKind::ObjectiveCClass:
+ if (interface.getPlatforms().count(PlatformKind::macOS) &&
+ Arch == AK_i386) {
+ Symbols.emplace_back(ObjC1ClassNamePrefix, Symbol->getName(),
+ getFlags(Symbol));
+ } else {
+ Symbols.emplace_back(ObjC2ClassNamePrefix, Symbol->getName(),
+ getFlags(Symbol));
+ Symbols.emplace_back(ObjC2MetaClassNamePrefix, Symbol->getName(),
+ getFlags(Symbol));
+ }
+ break;
+ case SymbolKind::ObjectiveCClassEHType:
+ Symbols.emplace_back(ObjC2EHTypePrefix, Symbol->getName(),
+ getFlags(Symbol));
+ break;
+ case SymbolKind::ObjectiveCInstanceVariable:
+ Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(),
+ getFlags(Symbol));
+ break;
+ }
+ }
+}
+
+TapiFile::~TapiFile() = default;
+
+void TapiFile::moveSymbolNext(DataRefImpl &DRI) const { DRI.d.a++; }
+
+Error TapiFile::printSymbolName(raw_ostream &OS, DataRefImpl DRI) const {
+ assert(DRI.d.a < Symbols.size() && "Attempt to access symbol out of bounds");
+ const Symbol &Sym = Symbols[DRI.d.a];
+ OS << Sym.Prefix << Sym.Name;
+ return Error::success();
+}
+
+Expected<uint32_t> TapiFile::getSymbolFlags(DataRefImpl DRI) const {
+ assert(DRI.d.a < Symbols.size() && "Attempt to access symbol out of bounds");
+ return Symbols[DRI.d.a].Flags;
+}
+
+basic_symbol_iterator TapiFile::symbol_begin() const {
+ DataRefImpl DRI;
+ DRI.d.a = 0;
+ return BasicSymbolRef{DRI, this};
+}
+
+basic_symbol_iterator TapiFile::symbol_end() const {
+ DataRefImpl DRI;
+ DRI.d.a = Symbols.size();
+ return BasicSymbolRef{DRI, this};
+}
diff --git a/contrib/libs/llvm12/lib/Object/TapiUniversal.cpp b/contrib/libs/llvm12/lib/Object/TapiUniversal.cpp
index 4cadf22fe7..48cb949cb6 100644
--- a/contrib/libs/llvm12/lib/Object/TapiUniversal.cpp
+++ b/contrib/libs/llvm12/lib/Object/TapiUniversal.cpp
@@ -1,61 +1,61 @@
-//===- TapiUniversal.cpp --------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the Text-based Dynamic Library Stub format.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/TapiUniversal.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/TextAPI/MachO/TextAPIReader.h"
-
-using namespace llvm;
-using namespace MachO;
-using namespace object;
-
-TapiUniversal::TapiUniversal(MemoryBufferRef Source, Error &Err)
- : Binary(ID_TapiUniversal, Source) {
- Expected<std::unique_ptr<InterfaceFile>> Result = TextAPIReader::get(Source);
- ErrorAsOutParameter ErrAsOuParam(&Err);
- if (!Result) {
- Err = Result.takeError();
- return;
- }
- ParsedFile = std::move(Result.get());
-
- auto FlattenObjectInfo = [this](const auto &File) {
- StringRef Name = File->getInstallName();
- for (const Architecture Arch : File->getArchitectures())
- Libraries.emplace_back(Library({Name, Arch}));
- };
-
- FlattenObjectInfo(ParsedFile);
- // Get inlined documents from tapi file.
- for (const std::shared_ptr<InterfaceFile> &File : ParsedFile->documents())
- FlattenObjectInfo(File);
-}
-
-TapiUniversal::~TapiUniversal() = default;
-
-Expected<std::unique_ptr<TapiFile>>
-TapiUniversal::ObjectForArch::getAsObjectFile() const {
- return std::unique_ptr<TapiFile>(new TapiFile(Parent->getMemoryBufferRef(),
- *Parent->ParsedFile.get(),
- Parent->Libraries[Index].Arch));
-}
-
-Expected<std::unique_ptr<TapiUniversal>>
-TapiUniversal::create(MemoryBufferRef Source) {
- Error Err = Error::success();
- std::unique_ptr<TapiUniversal> Ret(new TapiUniversal(Source, Err));
- if (Err)
- return std::move(Err);
- return std::move(Ret);
-}
+//===- TapiUniversal.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Text-based Dynamic Library Stub format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/TapiUniversal.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/TextAPI/MachO/TextAPIReader.h"
+
+using namespace llvm;
+using namespace MachO;
+using namespace object;
+
+TapiUniversal::TapiUniversal(MemoryBufferRef Source, Error &Err)
+ : Binary(ID_TapiUniversal, Source) {
+ Expected<std::unique_ptr<InterfaceFile>> Result = TextAPIReader::get(Source);
+ ErrorAsOutParameter ErrAsOuParam(&Err);
+ if (!Result) {
+ Err = Result.takeError();
+ return;
+ }
+ ParsedFile = std::move(Result.get());
+
+ auto FlattenObjectInfo = [this](const auto &File) {
+ StringRef Name = File->getInstallName();
+ for (const Architecture Arch : File->getArchitectures())
+ Libraries.emplace_back(Library({Name, Arch}));
+ };
+
+ FlattenObjectInfo(ParsedFile);
+ // Get inlined documents from tapi file.
+ for (const std::shared_ptr<InterfaceFile> &File : ParsedFile->documents())
+ FlattenObjectInfo(File);
+}
+
+TapiUniversal::~TapiUniversal() = default;
+
+Expected<std::unique_ptr<TapiFile>>
+TapiUniversal::ObjectForArch::getAsObjectFile() const {
+ return std::unique_ptr<TapiFile>(new TapiFile(Parent->getMemoryBufferRef(),
+ *Parent->ParsedFile.get(),
+ Parent->Libraries[Index].Arch));
+}
+
+Expected<std::unique_ptr<TapiUniversal>>
+TapiUniversal::create(MemoryBufferRef Source) {
+ Error Err = Error::success();
+ std::unique_ptr<TapiUniversal> Ret(new TapiUniversal(Source, Err));
+ if (Err)
+ return std::move(Err);
+ return std::move(Ret);
+}
diff --git a/contrib/libs/llvm12/lib/Object/WasmObjectFile.cpp b/contrib/libs/llvm12/lib/Object/WasmObjectFile.cpp
index 31032640f3..40f468881e 100644
--- a/contrib/libs/llvm12/lib/Object/WasmObjectFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/WasmObjectFile.cpp
@@ -1,381 +1,381 @@
-//===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/DenseSet.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSet.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
-#include "llvm/BinaryFormat/Wasm.h"
-#include "llvm/MC/SubtargetFeature.h"
-#include "llvm/Object/Binary.h"
-#include "llvm/Object/Error.h"
-#include "llvm/Object/ObjectFile.h"
-#include "llvm/Object/SymbolicFile.h"
-#include "llvm/Object/Wasm.h"
-#include "llvm/Support/Endian.h"
-#include "llvm/Support/Error.h"
-#include "llvm/Support/ErrorHandling.h"
-#include "llvm/Support/LEB128.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include <algorithm>
-#include <cassert>
-#include <cstdint>
-#include <cstring>
-#include <system_error>
-
-#define DEBUG_TYPE "wasm-object"
-
-using namespace llvm;
-using namespace object;
-
-void WasmSymbol::print(raw_ostream &Out) const {
- Out << "Name=" << Info.Name
- << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind))
- << ", Flags=" << Info.Flags;
- if (!isTypeData()) {
- Out << ", ElemIndex=" << Info.ElementIndex;
- } else if (isDefined()) {
- Out << ", Segment=" << Info.DataRef.Segment;
- Out << ", Offset=" << Info.DataRef.Offset;
- Out << ", Size=" << Info.DataRef.Size;
- }
-}
-
-#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
-LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
-#endif
-
-Expected<std::unique_ptr<WasmObjectFile>>
-ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
- Error Err = Error::success();
- auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
- if (Err)
- return std::move(Err);
-
- return std::move(ObjectFile);
-}
-
-#define VARINT7_MAX ((1 << 7) - 1)
-#define VARINT7_MIN (-(1 << 7))
-#define VARUINT7_MAX (1 << 7)
-#define VARUINT1_MAX (1)
-
-static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
- if (Ctx.Ptr == Ctx.End)
- report_fatal_error("EOF while reading uint8");
- return *Ctx.Ptr++;
-}
-
-static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
- if (Ctx.Ptr + 4 > Ctx.End)
- report_fatal_error("EOF while reading uint32");
- uint32_t Result = support::endian::read32le(Ctx.Ptr);
- Ctx.Ptr += 4;
- return Result;
-}
-
-static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
- if (Ctx.Ptr + 4 > Ctx.End)
- report_fatal_error("EOF while reading float64");
- int32_t Result = 0;
- memcpy(&Result, Ctx.Ptr, sizeof(Result));
- Ctx.Ptr += sizeof(Result);
- return Result;
-}
-
-static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
- if (Ctx.Ptr + 8 > Ctx.End)
- report_fatal_error("EOF while reading float64");
- int64_t Result = 0;
- memcpy(&Result, Ctx.Ptr, sizeof(Result));
- Ctx.Ptr += sizeof(Result);
- return Result;
-}
-
-static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
- unsigned Count;
- const char *Error = nullptr;
- uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
- if (Error)
- report_fatal_error(Error);
- Ctx.Ptr += Count;
- return Result;
-}
-
-static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
- uint32_t StringLen = readULEB128(Ctx);
- if (Ctx.Ptr + StringLen > Ctx.End)
- report_fatal_error("EOF while reading string");
- StringRef Return =
- StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
- Ctx.Ptr += StringLen;
- return Return;
-}
-
-static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
- unsigned Count;
- const char *Error = nullptr;
- uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
- if (Error)
- report_fatal_error(Error);
- Ctx.Ptr += Count;
- return Result;
-}
-
-static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
- int64_t Result = readLEB128(Ctx);
- if (Result > VARUINT1_MAX || Result < 0)
- report_fatal_error("LEB is outside Varuint1 range");
- return Result;
-}
-
-static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
- int64_t Result = readLEB128(Ctx);
- if (Result > INT32_MAX || Result < INT32_MIN)
- report_fatal_error("LEB is outside Varint32 range");
- return Result;
-}
-
-static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
- uint64_t Result = readULEB128(Ctx);
- if (Result > UINT32_MAX)
- report_fatal_error("LEB is outside Varuint32 range");
- return Result;
-}
-
-static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
- return readLEB128(Ctx);
-}
-
-static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
- return readULEB128(Ctx);
-}
-
-static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
- return readUint8(Ctx);
-}
-
-static Error readInitExpr(wasm::WasmInitExpr &Expr,
- WasmObjectFile::ReadContext &Ctx) {
- Expr.Opcode = readOpcode(Ctx);
-
- switch (Expr.Opcode) {
- case wasm::WASM_OPCODE_I32_CONST:
- Expr.Value.Int32 = readVarint32(Ctx);
- break;
- case wasm::WASM_OPCODE_I64_CONST:
- Expr.Value.Int64 = readVarint64(Ctx);
- break;
- case wasm::WASM_OPCODE_F32_CONST:
- Expr.Value.Float32 = readFloat32(Ctx);
- break;
- case wasm::WASM_OPCODE_F64_CONST:
- Expr.Value.Float64 = readFloat64(Ctx);
- break;
- case wasm::WASM_OPCODE_GLOBAL_GET:
- Expr.Value.Global = readULEB128(Ctx);
- break;
- case wasm::WASM_OPCODE_REF_NULL: {
- wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
- if (Ty != wasm::ValType::EXTERNREF) {
+//===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSet.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/Wasm.h"
+#include "llvm/MC/SubtargetFeature.h"
+#include "llvm/Object/Binary.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Object/Wasm.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <system_error>
+
+#define DEBUG_TYPE "wasm-object"
+
+using namespace llvm;
+using namespace object;
+
+void WasmSymbol::print(raw_ostream &Out) const {
+ Out << "Name=" << Info.Name
+ << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind))
+ << ", Flags=" << Info.Flags;
+ if (!isTypeData()) {
+ Out << ", ElemIndex=" << Info.ElementIndex;
+ } else if (isDefined()) {
+ Out << ", Segment=" << Info.DataRef.Segment;
+ Out << ", Offset=" << Info.DataRef.Offset;
+ Out << ", Size=" << Info.DataRef.Size;
+ }
+}
+
+#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
+LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
+#endif
+
+Expected<std::unique_ptr<WasmObjectFile>>
+ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
+ Error Err = Error::success();
+ auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
+ if (Err)
+ return std::move(Err);
+
+ return std::move(ObjectFile);
+}
+
+#define VARINT7_MAX ((1 << 7) - 1)
+#define VARINT7_MIN (-(1 << 7))
+#define VARUINT7_MAX (1 << 7)
+#define VARUINT1_MAX (1)
+
+static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
+ if (Ctx.Ptr == Ctx.End)
+ report_fatal_error("EOF while reading uint8");
+ return *Ctx.Ptr++;
+}
+
+static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
+ if (Ctx.Ptr + 4 > Ctx.End)
+ report_fatal_error("EOF while reading uint32");
+ uint32_t Result = support::endian::read32le(Ctx.Ptr);
+ Ctx.Ptr += 4;
+ return Result;
+}
+
+static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
+ if (Ctx.Ptr + 4 > Ctx.End)
+ report_fatal_error("EOF while reading float64");
+ int32_t Result = 0;
+ memcpy(&Result, Ctx.Ptr, sizeof(Result));
+ Ctx.Ptr += sizeof(Result);
+ return Result;
+}
+
+static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
+ if (Ctx.Ptr + 8 > Ctx.End)
+ report_fatal_error("EOF while reading float64");
+ int64_t Result = 0;
+ memcpy(&Result, Ctx.Ptr, sizeof(Result));
+ Ctx.Ptr += sizeof(Result);
+ return Result;
+}
+
+static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
+ unsigned Count;
+ const char *Error = nullptr;
+ uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
+ if (Error)
+ report_fatal_error(Error);
+ Ctx.Ptr += Count;
+ return Result;
+}
+
+static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
+ uint32_t StringLen = readULEB128(Ctx);
+ if (Ctx.Ptr + StringLen > Ctx.End)
+ report_fatal_error("EOF while reading string");
+ StringRef Return =
+ StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
+ Ctx.Ptr += StringLen;
+ return Return;
+}
+
+static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
+ unsigned Count;
+ const char *Error = nullptr;
+ uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
+ if (Error)
+ report_fatal_error(Error);
+ Ctx.Ptr += Count;
+ return Result;
+}
+
+static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
+ int64_t Result = readLEB128(Ctx);
+ if (Result > VARUINT1_MAX || Result < 0)
+ report_fatal_error("LEB is outside Varuint1 range");
+ return Result;
+}
+
+static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
+ int64_t Result = readLEB128(Ctx);
+ if (Result > INT32_MAX || Result < INT32_MIN)
+ report_fatal_error("LEB is outside Varint32 range");
+ return Result;
+}
+
+static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
+ uint64_t Result = readULEB128(Ctx);
+ if (Result > UINT32_MAX)
+ report_fatal_error("LEB is outside Varuint32 range");
+ return Result;
+}
+
+static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
+ return readLEB128(Ctx);
+}
+
+static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
+ return readULEB128(Ctx);
+}
+
+static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
+ return readUint8(Ctx);
+}
+
+static Error readInitExpr(wasm::WasmInitExpr &Expr,
+ WasmObjectFile::ReadContext &Ctx) {
+ Expr.Opcode = readOpcode(Ctx);
+
+ switch (Expr.Opcode) {
+ case wasm::WASM_OPCODE_I32_CONST:
+ Expr.Value.Int32 = readVarint32(Ctx);
+ break;
+ case wasm::WASM_OPCODE_I64_CONST:
+ Expr.Value.Int64 = readVarint64(Ctx);
+ break;
+ case wasm::WASM_OPCODE_F32_CONST:
+ Expr.Value.Float32 = readFloat32(Ctx);
+ break;
+ case wasm::WASM_OPCODE_F64_CONST:
+ Expr.Value.Float64 = readFloat64(Ctx);
+ break;
+ case wasm::WASM_OPCODE_GLOBAL_GET:
+ Expr.Value.Global = readULEB128(Ctx);
+ break;
+ case wasm::WASM_OPCODE_REF_NULL: {
+ wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
+ if (Ty != wasm::ValType::EXTERNREF) {
return make_error<GenericBinaryError>("invalid type for ref.null",
- object_error::parse_failed);
- }
- break;
- }
- default:
+ object_error::parse_failed);
+ }
+ break;
+ }
+ default:
return make_error<GenericBinaryError>("invalid opcode in init_expr",
- object_error::parse_failed);
- }
-
- uint8_t EndOpcode = readOpcode(Ctx);
- if (EndOpcode != wasm::WASM_OPCODE_END) {
+ object_error::parse_failed);
+ }
+
+ uint8_t EndOpcode = readOpcode(Ctx);
+ if (EndOpcode != wasm::WASM_OPCODE_END) {
return make_error<GenericBinaryError>("invalid init_expr",
- object_error::parse_failed);
- }
- return Error::success();
-}
-
-static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
- wasm::WasmLimits Result;
- Result.Flags = readVaruint32(Ctx);
- Result.Initial = readVaruint64(Ctx);
- if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
- Result.Maximum = readVaruint64(Ctx);
- return Result;
-}
-
+ object_error::parse_failed);
+ }
+ return Error::success();
+}
+
+static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
+ wasm::WasmLimits Result;
+ Result.Flags = readVaruint32(Ctx);
+ Result.Initial = readVaruint64(Ctx);
+ if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
+ Result.Maximum = readVaruint64(Ctx);
+ return Result;
+}
+
static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
wasm::WasmTableType TableType;
TableType.ElemType = readUint8(Ctx);
TableType.Limits = readLimits(Ctx);
return TableType;
-}
-
-static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
- WasmSectionOrderChecker &Checker) {
- Section.Offset = Ctx.Ptr - Ctx.Start;
- Section.Type = readUint8(Ctx);
- LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
- uint32_t Size = readVaruint32(Ctx);
- if (Size == 0)
+}
+
+static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
+ WasmSectionOrderChecker &Checker) {
+ Section.Offset = Ctx.Ptr - Ctx.Start;
+ Section.Type = readUint8(Ctx);
+ LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
+ uint32_t Size = readVaruint32(Ctx);
+ if (Size == 0)
return make_error<StringError>("zero length section",
- object_error::parse_failed);
- if (Ctx.Ptr + Size > Ctx.End)
+ object_error::parse_failed);
+ if (Ctx.Ptr + Size > Ctx.End)
return make_error<StringError>("section too large",
- object_error::parse_failed);
- if (Section.Type == wasm::WASM_SEC_CUSTOM) {
- WasmObjectFile::ReadContext SectionCtx;
- SectionCtx.Start = Ctx.Ptr;
- SectionCtx.Ptr = Ctx.Ptr;
- SectionCtx.End = Ctx.Ptr + Size;
-
- Section.Name = readString(SectionCtx);
-
- uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
- Ctx.Ptr += SectionNameSize;
- Size -= SectionNameSize;
- }
-
- if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
+ object_error::parse_failed);
+ if (Section.Type == wasm::WASM_SEC_CUSTOM) {
+ WasmObjectFile::ReadContext SectionCtx;
+ SectionCtx.Start = Ctx.Ptr;
+ SectionCtx.Ptr = Ctx.Ptr;
+ SectionCtx.End = Ctx.Ptr + Size;
+
+ Section.Name = readString(SectionCtx);
+
+ uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
+ Ctx.Ptr += SectionNameSize;
+ Size -= SectionNameSize;
+ }
+
+ if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
return make_error<StringError>("out of order section type: " +
- llvm::to_string(Section.Type),
- object_error::parse_failed);
- }
-
- Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
- Ctx.Ptr += Size;
- return Error::success();
-}
-
-WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
- : ObjectFile(Binary::ID_Wasm, Buffer) {
- ErrorAsOutParameter ErrAsOutParam(&Err);
- Header.Magic = getData().substr(0, 4);
- if (Header.Magic != StringRef("\0asm", 4)) {
+ llvm::to_string(Section.Type),
+ object_error::parse_failed);
+ }
+
+ Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
+ Ctx.Ptr += Size;
+ return Error::success();
+}
+
+WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
+ : ObjectFile(Binary::ID_Wasm, Buffer) {
+ ErrorAsOutParameter ErrAsOutParam(&Err);
+ Header.Magic = getData().substr(0, 4);
+ if (Header.Magic != StringRef("\0asm", 4)) {
Err = make_error<StringError>("invalid magic number",
object_error::parse_failed);
- return;
- }
-
- ReadContext Ctx;
- Ctx.Start = getData().bytes_begin();
- Ctx.Ptr = Ctx.Start + 4;
- Ctx.End = Ctx.Start + getData().size();
-
- if (Ctx.Ptr + 4 > Ctx.End) {
+ return;
+ }
+
+ ReadContext Ctx;
+ Ctx.Start = getData().bytes_begin();
+ Ctx.Ptr = Ctx.Start + 4;
+ Ctx.End = Ctx.Start + getData().size();
+
+ if (Ctx.Ptr + 4 > Ctx.End) {
Err = make_error<StringError>("missing version number",
- object_error::parse_failed);
- return;
- }
-
- Header.Version = readUint32(Ctx);
- if (Header.Version != wasm::WasmVersion) {
+ object_error::parse_failed);
+ return;
+ }
+
+ Header.Version = readUint32(Ctx);
+ if (Header.Version != wasm::WasmVersion) {
Err = make_error<StringError>("invalid version number: " +
Twine(Header.Version),
- object_error::parse_failed);
- return;
- }
-
- WasmSection Sec;
- WasmSectionOrderChecker Checker;
- while (Ctx.Ptr < Ctx.End) {
- if ((Err = readSection(Sec, Ctx, Checker)))
- return;
- if ((Err = parseSection(Sec)))
- return;
-
- Sections.push_back(Sec);
- }
-}
-
-Error WasmObjectFile::parseSection(WasmSection &Sec) {
- ReadContext Ctx;
- Ctx.Start = Sec.Content.data();
- Ctx.End = Ctx.Start + Sec.Content.size();
- Ctx.Ptr = Ctx.Start;
- switch (Sec.Type) {
- case wasm::WASM_SEC_CUSTOM:
- return parseCustomSection(Sec, Ctx);
- case wasm::WASM_SEC_TYPE:
- return parseTypeSection(Ctx);
- case wasm::WASM_SEC_IMPORT:
- return parseImportSection(Ctx);
- case wasm::WASM_SEC_FUNCTION:
- return parseFunctionSection(Ctx);
- case wasm::WASM_SEC_TABLE:
- return parseTableSection(Ctx);
- case wasm::WASM_SEC_MEMORY:
- return parseMemorySection(Ctx);
- case wasm::WASM_SEC_EVENT:
- return parseEventSection(Ctx);
- case wasm::WASM_SEC_GLOBAL:
- return parseGlobalSection(Ctx);
- case wasm::WASM_SEC_EXPORT:
- return parseExportSection(Ctx);
- case wasm::WASM_SEC_START:
- return parseStartSection(Ctx);
- case wasm::WASM_SEC_ELEM:
- return parseElemSection(Ctx);
- case wasm::WASM_SEC_CODE:
- return parseCodeSection(Ctx);
- case wasm::WASM_SEC_DATA:
- return parseDataSection(Ctx);
- case wasm::WASM_SEC_DATACOUNT:
- return parseDataCountSection(Ctx);
- default:
- return make_error<GenericBinaryError>(
+ object_error::parse_failed);
+ return;
+ }
+
+ WasmSection Sec;
+ WasmSectionOrderChecker Checker;
+ while (Ctx.Ptr < Ctx.End) {
+ if ((Err = readSection(Sec, Ctx, Checker)))
+ return;
+ if ((Err = parseSection(Sec)))
+ return;
+
+ Sections.push_back(Sec);
+ }
+}
+
+Error WasmObjectFile::parseSection(WasmSection &Sec) {
+ ReadContext Ctx;
+ Ctx.Start = Sec.Content.data();
+ Ctx.End = Ctx.Start + Sec.Content.size();
+ Ctx.Ptr = Ctx.Start;
+ switch (Sec.Type) {
+ case wasm::WASM_SEC_CUSTOM:
+ return parseCustomSection(Sec, Ctx);
+ case wasm::WASM_SEC_TYPE:
+ return parseTypeSection(Ctx);
+ case wasm::WASM_SEC_IMPORT:
+ return parseImportSection(Ctx);
+ case wasm::WASM_SEC_FUNCTION:
+ return parseFunctionSection(Ctx);
+ case wasm::WASM_SEC_TABLE:
+ return parseTableSection(Ctx);
+ case wasm::WASM_SEC_MEMORY:
+ return parseMemorySection(Ctx);
+ case wasm::WASM_SEC_EVENT:
+ return parseEventSection(Ctx);
+ case wasm::WASM_SEC_GLOBAL:
+ return parseGlobalSection(Ctx);
+ case wasm::WASM_SEC_EXPORT:
+ return parseExportSection(Ctx);
+ case wasm::WASM_SEC_START:
+ return parseStartSection(Ctx);
+ case wasm::WASM_SEC_ELEM:
+ return parseElemSection(Ctx);
+ case wasm::WASM_SEC_CODE:
+ return parseCodeSection(Ctx);
+ case wasm::WASM_SEC_DATA:
+ return parseDataSection(Ctx);
+ case wasm::WASM_SEC_DATACOUNT:
+ return parseDataCountSection(Ctx);
+ default:
+ return make_error<GenericBinaryError>(
"invalid section type: " + Twine(Sec.Type), object_error::parse_failed);
- }
-}
-
-Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
- // See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
- HasDylinkSection = true;
- DylinkInfo.MemorySize = readVaruint32(Ctx);
- DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
- DylinkInfo.TableSize = readVaruint32(Ctx);
- DylinkInfo.TableAlignment = readVaruint32(Ctx);
- uint32_t Count = readVaruint32(Ctx);
- while (Count--) {
- DylinkInfo.Needed.push_back(readString(Ctx));
- }
- if (Ctx.Ptr != Ctx.End)
- return make_error<GenericBinaryError>("dylink section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
+ }
+}
+
+Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
+ // See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
+ HasDylinkSection = true;
+ DylinkInfo.MemorySize = readVaruint32(Ctx);
+ DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
+ DylinkInfo.TableSize = readVaruint32(Ctx);
+ DylinkInfo.TableAlignment = readVaruint32(Ctx);
+ uint32_t Count = readVaruint32(Ctx);
+ while (Count--) {
+ DylinkInfo.Needed.push_back(readString(Ctx));
+ }
+ if (Ctx.Ptr != Ctx.End)
+ return make_error<GenericBinaryError>("dylink section ended prematurely",
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
llvm::DenseSet<uint64_t> SeenFunctions;
llvm::DenseSet<uint64_t> SeenGlobals;
llvm::DenseSet<uint64_t> SeenSegments;
- if (FunctionTypes.size() && !SeenCodeSection) {
+ if (FunctionTypes.size() && !SeenCodeSection) {
return make_error<GenericBinaryError>("names must come after code section",
- object_error::parse_failed);
- }
-
- while (Ctx.Ptr < Ctx.End) {
- uint8_t Type = readUint8(Ctx);
- uint32_t Size = readVaruint32(Ctx);
- const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
- switch (Type) {
+ object_error::parse_failed);
+ }
+
+ while (Ctx.Ptr < Ctx.End) {
+ uint8_t Type = readUint8(Ctx);
+ uint32_t Size = readVaruint32(Ctx);
+ const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
+ switch (Type) {
case wasm::WASM_NAMES_FUNCTION:
case wasm::WASM_NAMES_GLOBAL:
case wasm::WASM_NAMES_DATA_SEGMENT: {
- uint32_t Count = readVaruint32(Ctx);
- while (Count--) {
- uint32_t Index = readVaruint32(Ctx);
- StringRef Name = readString(Ctx);
+ uint32_t Count = readVaruint32(Ctx);
+ while (Count--) {
+ uint32_t Index = readVaruint32(Ctx);
+ StringRef Name = readString(Ctx);
wasm::NameType nameType = wasm::NameType::FUNCTION;
if (Type == wasm::WASM_NAMES_FUNCTION) {
if (!SeenFunctions.insert(Index).second)
@@ -405,197 +405,197 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
object_error::parse_failed);
}
DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name});
- }
- break;
- }
- // Ignore local names for now
- case wasm::WASM_NAMES_LOCAL:
- default:
- Ctx.Ptr += Size;
- break;
- }
- if (Ctx.Ptr != SubSectionEnd)
- return make_error<GenericBinaryError>(
+ }
+ break;
+ }
+ // Ignore local names for now
+ case wasm::WASM_NAMES_LOCAL:
+ default:
+ Ctx.Ptr += Size;
+ break;
+ }
+ if (Ctx.Ptr != SubSectionEnd)
+ return make_error<GenericBinaryError>(
"name sub-section ended prematurely", object_error::parse_failed);
- }
-
- if (Ctx.Ptr != Ctx.End)
+ }
+
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("name section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
- HasLinkingSection = true;
- if (FunctionTypes.size() && !SeenCodeSection) {
- return make_error<GenericBinaryError>(
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
+ HasLinkingSection = true;
+ if (FunctionTypes.size() && !SeenCodeSection) {
+ return make_error<GenericBinaryError>(
"linking data must come after code section",
- object_error::parse_failed);
- }
-
- LinkingData.Version = readVaruint32(Ctx);
- if (LinkingData.Version != wasm::WasmMetadataVersion) {
- return make_error<GenericBinaryError>(
+ object_error::parse_failed);
+ }
+
+ LinkingData.Version = readVaruint32(Ctx);
+ if (LinkingData.Version != wasm::WasmMetadataVersion) {
+ return make_error<GenericBinaryError>(
"unexpected metadata version: " + Twine(LinkingData.Version) +
- " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
- object_error::parse_failed);
- }
-
- const uint8_t *OrigEnd = Ctx.End;
- while (Ctx.Ptr < OrigEnd) {
- Ctx.End = OrigEnd;
- uint8_t Type = readUint8(Ctx);
- uint32_t Size = readVaruint32(Ctx);
- LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
- << "\n");
- Ctx.End = Ctx.Ptr + Size;
- switch (Type) {
- case wasm::WASM_SYMBOL_TABLE:
- if (Error Err = parseLinkingSectionSymtab(Ctx))
- return Err;
- break;
- case wasm::WASM_SEGMENT_INFO: {
- uint32_t Count = readVaruint32(Ctx);
- if (Count > DataSegments.size())
+ " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
+ object_error::parse_failed);
+ }
+
+ const uint8_t *OrigEnd = Ctx.End;
+ while (Ctx.Ptr < OrigEnd) {
+ Ctx.End = OrigEnd;
+ uint8_t Type = readUint8(Ctx);
+ uint32_t Size = readVaruint32(Ctx);
+ LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
+ << "\n");
+ Ctx.End = Ctx.Ptr + Size;
+ switch (Type) {
+ case wasm::WASM_SYMBOL_TABLE:
+ if (Error Err = parseLinkingSectionSymtab(Ctx))
+ return Err;
+ break;
+ case wasm::WASM_SEGMENT_INFO: {
+ uint32_t Count = readVaruint32(Ctx);
+ if (Count > DataSegments.size())
return make_error<GenericBinaryError>("too many segment names",
- object_error::parse_failed);
- for (uint32_t I = 0; I < Count; I++) {
- DataSegments[I].Data.Name = readString(Ctx);
- DataSegments[I].Data.Alignment = readVaruint32(Ctx);
- DataSegments[I].Data.LinkerFlags = readVaruint32(Ctx);
- }
- break;
- }
- case wasm::WASM_INIT_FUNCS: {
- uint32_t Count = readVaruint32(Ctx);
- LinkingData.InitFunctions.reserve(Count);
- for (uint32_t I = 0; I < Count; I++) {
- wasm::WasmInitFunc Init;
- Init.Priority = readVaruint32(Ctx);
- Init.Symbol = readVaruint32(Ctx);
- if (!isValidFunctionSymbol(Init.Symbol))
+ object_error::parse_failed);
+ for (uint32_t I = 0; I < Count; I++) {
+ DataSegments[I].Data.Name = readString(Ctx);
+ DataSegments[I].Data.Alignment = readVaruint32(Ctx);
+ DataSegments[I].Data.LinkerFlags = readVaruint32(Ctx);
+ }
+ break;
+ }
+ case wasm::WASM_INIT_FUNCS: {
+ uint32_t Count = readVaruint32(Ctx);
+ LinkingData.InitFunctions.reserve(Count);
+ for (uint32_t I = 0; I < Count; I++) {
+ wasm::WasmInitFunc Init;
+ Init.Priority = readVaruint32(Ctx);
+ Init.Symbol = readVaruint32(Ctx);
+ if (!isValidFunctionSymbol(Init.Symbol))
return make_error<GenericBinaryError>("invalid function symbol: " +
- Twine(Init.Symbol),
- object_error::parse_failed);
- LinkingData.InitFunctions.emplace_back(Init);
- }
- break;
- }
- case wasm::WASM_COMDAT_INFO:
- if (Error Err = parseLinkingSectionComdat(Ctx))
- return Err;
- break;
- default:
- Ctx.Ptr += Size;
- break;
- }
- if (Ctx.Ptr != Ctx.End)
- return make_error<GenericBinaryError>(
+ Twine(Init.Symbol),
+ object_error::parse_failed);
+ LinkingData.InitFunctions.emplace_back(Init);
+ }
+ break;
+ }
+ case wasm::WASM_COMDAT_INFO:
+ if (Error Err = parseLinkingSectionComdat(Ctx))
+ return Err;
+ break;
+ default:
+ Ctx.Ptr += Size;
+ break;
+ }
+ if (Ctx.Ptr != Ctx.End)
+ return make_error<GenericBinaryError>(
"linking sub-section ended prematurely", object_error::parse_failed);
- }
- if (Ctx.Ptr != OrigEnd)
+ }
+ if (Ctx.Ptr != OrigEnd)
return make_error<GenericBinaryError>("linking section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
- uint32_t Count = readVaruint32(Ctx);
- LinkingData.SymbolTable.reserve(Count);
- Symbols.reserve(Count);
- StringSet<> SymbolNames;
-
- std::vector<wasm::WasmImport *> ImportedGlobals;
- std::vector<wasm::WasmImport *> ImportedFunctions;
- std::vector<wasm::WasmImport *> ImportedEvents;
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
+ uint32_t Count = readVaruint32(Ctx);
+ LinkingData.SymbolTable.reserve(Count);
+ Symbols.reserve(Count);
+ StringSet<> SymbolNames;
+
+ std::vector<wasm::WasmImport *> ImportedGlobals;
+ std::vector<wasm::WasmImport *> ImportedFunctions;
+ std::vector<wasm::WasmImport *> ImportedEvents;
std::vector<wasm::WasmImport *> ImportedTables;
- ImportedGlobals.reserve(Imports.size());
- ImportedFunctions.reserve(Imports.size());
- ImportedEvents.reserve(Imports.size());
+ ImportedGlobals.reserve(Imports.size());
+ ImportedFunctions.reserve(Imports.size());
+ ImportedEvents.reserve(Imports.size());
ImportedTables.reserve(Imports.size());
- for (auto &I : Imports) {
- if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
- ImportedFunctions.emplace_back(&I);
- else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
- ImportedGlobals.emplace_back(&I);
- else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
- ImportedEvents.emplace_back(&I);
+ for (auto &I : Imports) {
+ if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
+ ImportedFunctions.emplace_back(&I);
+ else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
+ ImportedGlobals.emplace_back(&I);
+ else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
+ ImportedEvents.emplace_back(&I);
else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
ImportedTables.emplace_back(&I);
- }
-
- while (Count--) {
- wasm::WasmSymbolInfo Info;
- const wasm::WasmSignature *Signature = nullptr;
- const wasm::WasmGlobalType *GlobalType = nullptr;
+ }
+
+ while (Count--) {
+ wasm::WasmSymbolInfo Info;
+ const wasm::WasmSignature *Signature = nullptr;
+ const wasm::WasmGlobalType *GlobalType = nullptr;
const wasm::WasmTableType *TableType = nullptr;
- const wasm::WasmEventType *EventType = nullptr;
-
- Info.Kind = readUint8(Ctx);
- Info.Flags = readVaruint32(Ctx);
- bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
-
- switch (Info.Kind) {
- case wasm::WASM_SYMBOL_TYPE_FUNCTION:
- Info.ElementIndex = readVaruint32(Ctx);
- if (!isValidFunctionIndex(Info.ElementIndex) ||
- IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
- return make_error<GenericBinaryError>("invalid function symbol index",
- object_error::parse_failed);
- if (IsDefined) {
- Info.Name = readString(Ctx);
- unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
- Signature = &Signatures[FunctionTypes[FuncIndex]];
- wasm::WasmFunction &Function = Functions[FuncIndex];
- if (Function.SymbolName.empty())
- Function.SymbolName = Info.Name;
- } else {
- wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
- if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
- Info.Name = readString(Ctx);
- Info.ImportName = Import.Field;
- } else {
- Info.Name = Import.Field;
- }
- Signature = &Signatures[Import.SigIndex];
- if (!Import.Module.empty()) {
- Info.ImportModule = Import.Module;
- }
- }
- break;
-
- case wasm::WASM_SYMBOL_TYPE_GLOBAL:
- Info.ElementIndex = readVaruint32(Ctx);
- if (!isValidGlobalIndex(Info.ElementIndex) ||
- IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
- return make_error<GenericBinaryError>("invalid global symbol index",
- object_error::parse_failed);
- if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
- wasm::WASM_SYMBOL_BINDING_WEAK)
- return make_error<GenericBinaryError>("undefined weak global symbol",
- object_error::parse_failed);
- if (IsDefined) {
- Info.Name = readString(Ctx);
- unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
- wasm::WasmGlobal &Global = Globals[GlobalIndex];
- GlobalType = &Global.Type;
- if (Global.SymbolName.empty())
- Global.SymbolName = Info.Name;
- } else {
- wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
- if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
- Info.Name = readString(Ctx);
- Info.ImportName = Import.Field;
- } else {
- Info.Name = Import.Field;
- }
- GlobalType = &Import.Global;
- if (!Import.Module.empty()) {
- Info.ImportModule = Import.Module;
- }
- }
- break;
-
+ const wasm::WasmEventType *EventType = nullptr;
+
+ Info.Kind = readUint8(Ctx);
+ Info.Flags = readVaruint32(Ctx);
+ bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
+
+ switch (Info.Kind) {
+ case wasm::WASM_SYMBOL_TYPE_FUNCTION:
+ Info.ElementIndex = readVaruint32(Ctx);
+ if (!isValidFunctionIndex(Info.ElementIndex) ||
+ IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
+ return make_error<GenericBinaryError>("invalid function symbol index",
+ object_error::parse_failed);
+ if (IsDefined) {
+ Info.Name = readString(Ctx);
+ unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
+ Signature = &Signatures[FunctionTypes[FuncIndex]];
+ wasm::WasmFunction &Function = Functions[FuncIndex];
+ if (Function.SymbolName.empty())
+ Function.SymbolName = Info.Name;
+ } else {
+ wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
+ if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
+ Info.Name = readString(Ctx);
+ Info.ImportName = Import.Field;
+ } else {
+ Info.Name = Import.Field;
+ }
+ Signature = &Signatures[Import.SigIndex];
+ if (!Import.Module.empty()) {
+ Info.ImportModule = Import.Module;
+ }
+ }
+ break;
+
+ case wasm::WASM_SYMBOL_TYPE_GLOBAL:
+ Info.ElementIndex = readVaruint32(Ctx);
+ if (!isValidGlobalIndex(Info.ElementIndex) ||
+ IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
+ return make_error<GenericBinaryError>("invalid global symbol index",
+ object_error::parse_failed);
+ if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
+ wasm::WASM_SYMBOL_BINDING_WEAK)
+ return make_error<GenericBinaryError>("undefined weak global symbol",
+ object_error::parse_failed);
+ if (IsDefined) {
+ Info.Name = readString(Ctx);
+ unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
+ wasm::WasmGlobal &Global = Globals[GlobalIndex];
+ GlobalType = &Global.Type;
+ if (Global.SymbolName.empty())
+ Global.SymbolName = Info.Name;
+ } else {
+ wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
+ if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
+ Info.Name = readString(Ctx);
+ Info.ImportName = Import.Field;
+ } else {
+ Info.Name = Import.Field;
+ }
+ GlobalType = &Import.Global;
+ if (!Import.Module.empty()) {
+ Info.ImportModule = Import.Module;
+ }
+ }
+ break;
+
case wasm::WASM_SYMBOL_TYPE_TABLE:
Info.ElementIndex = readVaruint32(Ctx);
if (!isValidTableIndex(Info.ElementIndex) ||
@@ -628,133 +628,133 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
}
break;
- case wasm::WASM_SYMBOL_TYPE_DATA:
- Info.Name = readString(Ctx);
- if (IsDefined) {
- auto Index = readVaruint32(Ctx);
- if (Index >= DataSegments.size())
- return make_error<GenericBinaryError>("invalid data symbol index",
- object_error::parse_failed);
- auto Offset = readVaruint64(Ctx);
- auto Size = readVaruint64(Ctx);
- if (Offset + Size > DataSegments[Index].Data.Content.size())
- return make_error<GenericBinaryError>("invalid data symbol offset",
- object_error::parse_failed);
- Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
- }
- break;
-
- case wasm::WASM_SYMBOL_TYPE_SECTION: {
- if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
- wasm::WASM_SYMBOL_BINDING_LOCAL)
- return make_error<GenericBinaryError>(
+ case wasm::WASM_SYMBOL_TYPE_DATA:
+ Info.Name = readString(Ctx);
+ if (IsDefined) {
+ auto Index = readVaruint32(Ctx);
+ if (Index >= DataSegments.size())
+ return make_error<GenericBinaryError>("invalid data symbol index",
+ object_error::parse_failed);
+ auto Offset = readVaruint64(Ctx);
+ auto Size = readVaruint64(Ctx);
+ if (Offset + Size > DataSegments[Index].Data.Content.size())
+ return make_error<GenericBinaryError>("invalid data symbol offset",
+ object_error::parse_failed);
+ Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
+ }
+ break;
+
+ case wasm::WASM_SYMBOL_TYPE_SECTION: {
+ if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
+ wasm::WASM_SYMBOL_BINDING_LOCAL)
+ return make_error<GenericBinaryError>(
"section symbols must have local binding",
- object_error::parse_failed);
- Info.ElementIndex = readVaruint32(Ctx);
- // Use somewhat unique section name as symbol name.
- StringRef SectionName = Sections[Info.ElementIndex].Name;
- Info.Name = SectionName;
- break;
- }
-
- case wasm::WASM_SYMBOL_TYPE_EVENT: {
- Info.ElementIndex = readVaruint32(Ctx);
- if (!isValidEventIndex(Info.ElementIndex) ||
- IsDefined != isDefinedEventIndex(Info.ElementIndex))
- return make_error<GenericBinaryError>("invalid event symbol index",
- object_error::parse_failed);
- if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
- wasm::WASM_SYMBOL_BINDING_WEAK)
- return make_error<GenericBinaryError>("undefined weak global symbol",
- object_error::parse_failed);
- if (IsDefined) {
- Info.Name = readString(Ctx);
- unsigned EventIndex = Info.ElementIndex - NumImportedEvents;
- wasm::WasmEvent &Event = Events[EventIndex];
- Signature = &Signatures[Event.Type.SigIndex];
- EventType = &Event.Type;
- if (Event.SymbolName.empty())
- Event.SymbolName = Info.Name;
-
- } else {
- wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex];
- if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
- Info.Name = readString(Ctx);
- Info.ImportName = Import.Field;
- } else {
- Info.Name = Import.Field;
- }
- EventType = &Import.Event;
- Signature = &Signatures[EventType->SigIndex];
- if (!Import.Module.empty()) {
- Info.ImportModule = Import.Module;
- }
- }
- break;
- }
-
- default:
+ object_error::parse_failed);
+ Info.ElementIndex = readVaruint32(Ctx);
+ // Use somewhat unique section name as symbol name.
+ StringRef SectionName = Sections[Info.ElementIndex].Name;
+ Info.Name = SectionName;
+ break;
+ }
+
+ case wasm::WASM_SYMBOL_TYPE_EVENT: {
+ Info.ElementIndex = readVaruint32(Ctx);
+ if (!isValidEventIndex(Info.ElementIndex) ||
+ IsDefined != isDefinedEventIndex(Info.ElementIndex))
+ return make_error<GenericBinaryError>("invalid event symbol index",
+ object_error::parse_failed);
+ if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
+ wasm::WASM_SYMBOL_BINDING_WEAK)
+ return make_error<GenericBinaryError>("undefined weak global symbol",
+ object_error::parse_failed);
+ if (IsDefined) {
+ Info.Name = readString(Ctx);
+ unsigned EventIndex = Info.ElementIndex - NumImportedEvents;
+ wasm::WasmEvent &Event = Events[EventIndex];
+ Signature = &Signatures[Event.Type.SigIndex];
+ EventType = &Event.Type;
+ if (Event.SymbolName.empty())
+ Event.SymbolName = Info.Name;
+
+ } else {
+ wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex];
+ if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
+ Info.Name = readString(Ctx);
+ Info.ImportName = Import.Field;
+ } else {
+ Info.Name = Import.Field;
+ }
+ EventType = &Import.Event;
+ Signature = &Signatures[EventType->SigIndex];
+ if (!Import.Module.empty()) {
+ Info.ImportModule = Import.Module;
+ }
+ }
+ break;
+ }
+
+ default:
return make_error<GenericBinaryError>("invalid symbol type: " +
Twine(unsigned(Info.Kind)),
- object_error::parse_failed);
- }
-
- if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
- wasm::WASM_SYMBOL_BINDING_LOCAL &&
- !SymbolNames.insert(Info.Name).second)
+ object_error::parse_failed);
+ }
+
+ if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
+ wasm::WASM_SYMBOL_BINDING_LOCAL &&
+ !SymbolNames.insert(Info.Name).second)
return make_error<GenericBinaryError>("duplicate symbol name " +
- Twine(Info.Name),
- object_error::parse_failed);
- LinkingData.SymbolTable.emplace_back(Info);
+ Twine(Info.Name),
+ object_error::parse_failed);
+ LinkingData.SymbolTable.emplace_back(Info);
Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, TableType,
EventType, Signature);
- LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
- }
-
- return Error::success();
-}
-
-Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
- uint32_t ComdatCount = readVaruint32(Ctx);
- StringSet<> ComdatSet;
- for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
- StringRef Name = readString(Ctx);
- if (Name.empty() || !ComdatSet.insert(Name).second)
+ LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
+ }
+
+ return Error::success();
+}
+
+Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
+ uint32_t ComdatCount = readVaruint32(Ctx);
+ StringSet<> ComdatSet;
+ for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
+ StringRef Name = readString(Ctx);
+ if (Name.empty() || !ComdatSet.insert(Name).second)
return make_error<GenericBinaryError>("bad/duplicate COMDAT name " +
- Twine(Name),
- object_error::parse_failed);
- LinkingData.Comdats.emplace_back(Name);
- uint32_t Flags = readVaruint32(Ctx);
- if (Flags != 0)
+ Twine(Name),
+ object_error::parse_failed);
+ LinkingData.Comdats.emplace_back(Name);
+ uint32_t Flags = readVaruint32(Ctx);
+ if (Flags != 0)
return make_error<GenericBinaryError>("unsupported COMDAT flags",
- object_error::parse_failed);
-
- uint32_t EntryCount = readVaruint32(Ctx);
- while (EntryCount--) {
- unsigned Kind = readVaruint32(Ctx);
- unsigned Index = readVaruint32(Ctx);
- switch (Kind) {
- default:
+ object_error::parse_failed);
+
+ uint32_t EntryCount = readVaruint32(Ctx);
+ while (EntryCount--) {
+ unsigned Kind = readVaruint32(Ctx);
+ unsigned Index = readVaruint32(Ctx);
+ switch (Kind) {
+ default:
return make_error<GenericBinaryError>("invalid COMDAT entry type",
- object_error::parse_failed);
- case wasm::WASM_COMDAT_DATA:
- if (Index >= DataSegments.size())
- return make_error<GenericBinaryError>(
- "COMDAT data index out of range", object_error::parse_failed);
- if (DataSegments[Index].Data.Comdat != UINT32_MAX)
+ object_error::parse_failed);
+ case wasm::WASM_COMDAT_DATA:
+ if (Index >= DataSegments.size())
+ return make_error<GenericBinaryError>(
+ "COMDAT data index out of range", object_error::parse_failed);
+ if (DataSegments[Index].Data.Comdat != UINT32_MAX)
return make_error<GenericBinaryError>("data segment in two COMDATs",
- object_error::parse_failed);
- DataSegments[Index].Data.Comdat = ComdatIndex;
- break;
- case wasm::WASM_COMDAT_FUNCTION:
- if (!isDefinedFunctionIndex(Index))
- return make_error<GenericBinaryError>(
- "COMDAT function index out of range", object_error::parse_failed);
- if (getDefinedFunction(Index).Comdat != UINT32_MAX)
+ object_error::parse_failed);
+ DataSegments[Index].Data.Comdat = ComdatIndex;
+ break;
+ case wasm::WASM_COMDAT_FUNCTION:
+ if (!isDefinedFunctionIndex(Index))
+ return make_error<GenericBinaryError>(
+ "COMDAT function index out of range", object_error::parse_failed);
+ if (getDefinedFunction(Index).Comdat != UINT32_MAX)
return make_error<GenericBinaryError>("function in two COMDATs",
- object_error::parse_failed);
- getDefinedFunction(Index).Comdat = ComdatIndex;
- break;
+ object_error::parse_failed);
+ getDefinedFunction(Index).Comdat = ComdatIndex;
+ break;
case wasm::WASM_COMDAT_SECTION:
if (Index >= Sections.size())
return make_error<GenericBinaryError>(
@@ -764,290 +764,290 @@ Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
"non-custom section in a COMDAT", object_error::parse_failed);
Sections[Index].Comdat = ComdatIndex;
break;
- }
- }
- }
- return Error::success();
-}
-
-Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
- llvm::SmallSet<StringRef, 3> FieldsSeen;
- uint32_t Fields = readVaruint32(Ctx);
- for (size_t I = 0; I < Fields; ++I) {
- StringRef FieldName = readString(Ctx);
- if (!FieldsSeen.insert(FieldName).second)
- return make_error<GenericBinaryError>(
+ }
+ }
+ }
+ return Error::success();
+}
+
+Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
+ llvm::SmallSet<StringRef, 3> FieldsSeen;
+ uint32_t Fields = readVaruint32(Ctx);
+ for (size_t I = 0; I < Fields; ++I) {
+ StringRef FieldName = readString(Ctx);
+ if (!FieldsSeen.insert(FieldName).second)
+ return make_error<GenericBinaryError>(
"producers section does not have unique fields",
- object_error::parse_failed);
- std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
- if (FieldName == "language") {
- ProducerVec = &ProducerInfo.Languages;
- } else if (FieldName == "processed-by") {
- ProducerVec = &ProducerInfo.Tools;
- } else if (FieldName == "sdk") {
- ProducerVec = &ProducerInfo.SDKs;
- } else {
- return make_error<GenericBinaryError>(
+ object_error::parse_failed);
+ std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
+ if (FieldName == "language") {
+ ProducerVec = &ProducerInfo.Languages;
+ } else if (FieldName == "processed-by") {
+ ProducerVec = &ProducerInfo.Tools;
+ } else if (FieldName == "sdk") {
+ ProducerVec = &ProducerInfo.SDKs;
+ } else {
+ return make_error<GenericBinaryError>(
"producers section field is not named one of language, processed-by, "
- "or sdk",
- object_error::parse_failed);
- }
- uint32_t ValueCount = readVaruint32(Ctx);
- llvm::SmallSet<StringRef, 8> ProducersSeen;
- for (size_t J = 0; J < ValueCount; ++J) {
- StringRef Name = readString(Ctx);
- StringRef Version = readString(Ctx);
- if (!ProducersSeen.insert(Name).second) {
- return make_error<GenericBinaryError>(
+ "or sdk",
+ object_error::parse_failed);
+ }
+ uint32_t ValueCount = readVaruint32(Ctx);
+ llvm::SmallSet<StringRef, 8> ProducersSeen;
+ for (size_t J = 0; J < ValueCount; ++J) {
+ StringRef Name = readString(Ctx);
+ StringRef Version = readString(Ctx);
+ if (!ProducersSeen.insert(Name).second) {
+ return make_error<GenericBinaryError>(
"producers section contains repeated producer",
- object_error::parse_failed);
- }
- ProducerVec->emplace_back(std::string(Name), std::string(Version));
- }
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ }
+ ProducerVec->emplace_back(std::string(Name), std::string(Version));
+ }
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("producers section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
- llvm::SmallSet<std::string, 8> FeaturesSeen;
- uint32_t FeatureCount = readVaruint32(Ctx);
- for (size_t I = 0; I < FeatureCount; ++I) {
- wasm::WasmFeatureEntry Feature;
- Feature.Prefix = readUint8(Ctx);
- switch (Feature.Prefix) {
- case wasm::WASM_FEATURE_PREFIX_USED:
- case wasm::WASM_FEATURE_PREFIX_REQUIRED:
- case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
- break;
- default:
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
+ llvm::SmallSet<std::string, 8> FeaturesSeen;
+ uint32_t FeatureCount = readVaruint32(Ctx);
+ for (size_t I = 0; I < FeatureCount; ++I) {
+ wasm::WasmFeatureEntry Feature;
+ Feature.Prefix = readUint8(Ctx);
+ switch (Feature.Prefix) {
+ case wasm::WASM_FEATURE_PREFIX_USED:
+ case wasm::WASM_FEATURE_PREFIX_REQUIRED:
+ case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
+ break;
+ default:
return make_error<GenericBinaryError>("unknown feature policy prefix",
- object_error::parse_failed);
- }
- Feature.Name = std::string(readString(Ctx));
- if (!FeaturesSeen.insert(Feature.Name).second)
- return make_error<GenericBinaryError>(
+ object_error::parse_failed);
+ }
+ Feature.Name = std::string(readString(Ctx));
+ if (!FeaturesSeen.insert(Feature.Name).second)
+ return make_error<GenericBinaryError>(
"target features section contains repeated feature \"" +
- Feature.Name + "\"",
- object_error::parse_failed);
- TargetFeatures.push_back(Feature);
- }
- if (Ctx.Ptr != Ctx.End)
- return make_error<GenericBinaryError>(
+ Feature.Name + "\"",
+ object_error::parse_failed);
+ TargetFeatures.push_back(Feature);
+ }
+ if (Ctx.Ptr != Ctx.End)
+ return make_error<GenericBinaryError>(
"target features section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
- uint32_t SectionIndex = readVaruint32(Ctx);
- if (SectionIndex >= Sections.size())
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
+ uint32_t SectionIndex = readVaruint32(Ctx);
+ if (SectionIndex >= Sections.size())
return make_error<GenericBinaryError>("invalid section index",
- object_error::parse_failed);
- WasmSection &Section = Sections[SectionIndex];
- uint32_t RelocCount = readVaruint32(Ctx);
- uint32_t EndOffset = Section.Content.size();
- uint32_t PreviousOffset = 0;
- while (RelocCount--) {
- wasm::WasmRelocation Reloc = {};
+ object_error::parse_failed);
+ WasmSection &Section = Sections[SectionIndex];
+ uint32_t RelocCount = readVaruint32(Ctx);
+ uint32_t EndOffset = Section.Content.size();
+ uint32_t PreviousOffset = 0;
+ while (RelocCount--) {
+ wasm::WasmRelocation Reloc = {};
uint32_t type = readVaruint32(Ctx);
Reloc.Type = type;
- Reloc.Offset = readVaruint32(Ctx);
- if (Reloc.Offset < PreviousOffset)
+ Reloc.Offset = readVaruint32(Ctx);
+ if (Reloc.Offset < PreviousOffset)
return make_error<GenericBinaryError>("relocations not in offset order",
- object_error::parse_failed);
- PreviousOffset = Reloc.Offset;
- Reloc.Index = readVaruint32(Ctx);
+ object_error::parse_failed);
+ PreviousOffset = Reloc.Offset;
+ Reloc.Index = readVaruint32(Ctx);
switch (type) {
- case wasm::R_WASM_FUNCTION_INDEX_LEB:
- case wasm::R_WASM_TABLE_INDEX_SLEB:
+ case wasm::R_WASM_FUNCTION_INDEX_LEB:
+ case wasm::R_WASM_TABLE_INDEX_SLEB:
case wasm::R_WASM_TABLE_INDEX_SLEB64:
- case wasm::R_WASM_TABLE_INDEX_I32:
+ case wasm::R_WASM_TABLE_INDEX_I32:
case wasm::R_WASM_TABLE_INDEX_I64:
- case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
- if (!isValidFunctionSymbol(Reloc.Index))
+ case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
+ if (!isValidFunctionSymbol(Reloc.Index))
return make_error<GenericBinaryError>(
"invalid relocation function index", object_error::parse_failed);
break;
case wasm::R_WASM_TABLE_NUMBER_LEB:
if (!isValidTableSymbol(Reloc.Index))
return make_error<GenericBinaryError>("invalid relocation table index",
- object_error::parse_failed);
- break;
- case wasm::R_WASM_TYPE_INDEX_LEB:
- if (Reloc.Index >= Signatures.size())
+ object_error::parse_failed);
+ break;
+ case wasm::R_WASM_TYPE_INDEX_LEB:
+ if (Reloc.Index >= Signatures.size())
return make_error<GenericBinaryError>("invalid relocation type index",
- object_error::parse_failed);
- break;
- case wasm::R_WASM_GLOBAL_INDEX_LEB:
- // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
- // symbols to refer to their GOT entries.
- if (!isValidGlobalSymbol(Reloc.Index) &&
- !isValidDataSymbol(Reloc.Index) &&
- !isValidFunctionSymbol(Reloc.Index))
+ object_error::parse_failed);
+ break;
+ case wasm::R_WASM_GLOBAL_INDEX_LEB:
+ // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
+ // symbols to refer to their GOT entries.
+ if (!isValidGlobalSymbol(Reloc.Index) &&
+ !isValidDataSymbol(Reloc.Index) &&
+ !isValidFunctionSymbol(Reloc.Index))
return make_error<GenericBinaryError>("invalid relocation global index",
- object_error::parse_failed);
- break;
- case wasm::R_WASM_GLOBAL_INDEX_I32:
- if (!isValidGlobalSymbol(Reloc.Index))
+ object_error::parse_failed);
+ break;
+ case wasm::R_WASM_GLOBAL_INDEX_I32:
+ if (!isValidGlobalSymbol(Reloc.Index))
return make_error<GenericBinaryError>("invalid relocation global index",
- object_error::parse_failed);
- break;
- case wasm::R_WASM_EVENT_INDEX_LEB:
- if (!isValidEventSymbol(Reloc.Index))
+ object_error::parse_failed);
+ break;
+ case wasm::R_WASM_EVENT_INDEX_LEB:
+ if (!isValidEventSymbol(Reloc.Index))
return make_error<GenericBinaryError>("invalid relocation event index",
- object_error::parse_failed);
- break;
- case wasm::R_WASM_MEMORY_ADDR_LEB:
- case wasm::R_WASM_MEMORY_ADDR_SLEB:
- case wasm::R_WASM_MEMORY_ADDR_I32:
- case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
+ object_error::parse_failed);
+ break;
+ case wasm::R_WASM_MEMORY_ADDR_LEB:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB:
+ case wasm::R_WASM_MEMORY_ADDR_I32:
+ case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
- if (!isValidDataSymbol(Reloc.Index))
+ if (!isValidDataSymbol(Reloc.Index))
return make_error<GenericBinaryError>("invalid relocation data index",
- object_error::parse_failed);
- Reloc.Addend = readVarint32(Ctx);
- break;
- case wasm::R_WASM_MEMORY_ADDR_LEB64:
- case wasm::R_WASM_MEMORY_ADDR_SLEB64:
- case wasm::R_WASM_MEMORY_ADDR_I64:
- case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
- if (!isValidDataSymbol(Reloc.Index))
+ object_error::parse_failed);
+ Reloc.Addend = readVarint32(Ctx);
+ break;
+ case wasm::R_WASM_MEMORY_ADDR_LEB64:
+ case wasm::R_WASM_MEMORY_ADDR_SLEB64:
+ case wasm::R_WASM_MEMORY_ADDR_I64:
+ case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
+ if (!isValidDataSymbol(Reloc.Index))
return make_error<GenericBinaryError>("invalid relocation data index",
- object_error::parse_failed);
- Reloc.Addend = readVarint64(Ctx);
- break;
- case wasm::R_WASM_FUNCTION_OFFSET_I32:
- if (!isValidFunctionSymbol(Reloc.Index))
+ object_error::parse_failed);
+ Reloc.Addend = readVarint64(Ctx);
+ break;
+ case wasm::R_WASM_FUNCTION_OFFSET_I32:
+ if (!isValidFunctionSymbol(Reloc.Index))
return make_error<GenericBinaryError>(
"invalid relocation function index", object_error::parse_failed);
- Reloc.Addend = readVarint32(Ctx);
- break;
+ Reloc.Addend = readVarint32(Ctx);
+ break;
case wasm::R_WASM_FUNCTION_OFFSET_I64:
if (!isValidFunctionSymbol(Reloc.Index))
return make_error<GenericBinaryError>(
"invalid relocation function index", object_error::parse_failed);
Reloc.Addend = readVarint64(Ctx);
break;
- case wasm::R_WASM_SECTION_OFFSET_I32:
- if (!isValidSectionSymbol(Reloc.Index))
+ case wasm::R_WASM_SECTION_OFFSET_I32:
+ if (!isValidSectionSymbol(Reloc.Index))
return make_error<GenericBinaryError>(
"invalid relocation section index", object_error::parse_failed);
- Reloc.Addend = readVarint32(Ctx);
- break;
- default:
+ Reloc.Addend = readVarint32(Ctx);
+ break;
+ default:
return make_error<GenericBinaryError>("invalid relocation type: " +
Twine(type),
- object_error::parse_failed);
- }
-
- // Relocations must fit inside the section, and must appear in order. They
- // also shouldn't overlap a function/element boundary, but we don't bother
- // to check that.
- uint64_t Size = 5;
- if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
- Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
- Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
- Size = 10;
- if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
- Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
- Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
- Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
- Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
- Size = 4;
+ object_error::parse_failed);
+ }
+
+ // Relocations must fit inside the section, and must appear in order. They
+ // also shouldn't overlap a function/element boundary, but we don't bother
+ // to check that.
+ uint64_t Size = 5;
+ if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
+ Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
+ Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
+ Size = 10;
+ if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
+ Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
+ Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
+ Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
+ Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
+ Size = 4;
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)
- Size = 8;
- if (Reloc.Offset + Size > EndOffset)
+ Size = 8;
+ if (Reloc.Offset + Size > EndOffset)
return make_error<GenericBinaryError>("invalid relocation offset",
- object_error::parse_failed);
-
- Section.Relocations.push_back(Reloc);
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+
+ Section.Relocations.push_back(Reloc);
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("reloc section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
- if (Sec.Name == "dylink") {
- if (Error Err = parseDylinkSection(Ctx))
- return Err;
- } else if (Sec.Name == "name") {
- if (Error Err = parseNameSection(Ctx))
- return Err;
- } else if (Sec.Name == "linking") {
- if (Error Err = parseLinkingSection(Ctx))
- return Err;
- } else if (Sec.Name == "producers") {
- if (Error Err = parseProducersSection(Ctx))
- return Err;
- } else if (Sec.Name == "target_features") {
- if (Error Err = parseTargetFeaturesSection(Ctx))
- return Err;
- } else if (Sec.Name.startswith("reloc.")) {
- if (Error Err = parseRelocSection(Sec.Name, Ctx))
- return Err;
- }
- return Error::success();
-}
-
-Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
- uint32_t Count = readVaruint32(Ctx);
- Signatures.reserve(Count);
- while (Count--) {
- wasm::WasmSignature Sig;
- uint8_t Form = readUint8(Ctx);
- if (Form != wasm::WASM_TYPE_FUNC) {
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
+ if (Sec.Name == "dylink") {
+ if (Error Err = parseDylinkSection(Ctx))
+ return Err;
+ } else if (Sec.Name == "name") {
+ if (Error Err = parseNameSection(Ctx))
+ return Err;
+ } else if (Sec.Name == "linking") {
+ if (Error Err = parseLinkingSection(Ctx))
+ return Err;
+ } else if (Sec.Name == "producers") {
+ if (Error Err = parseProducersSection(Ctx))
+ return Err;
+ } else if (Sec.Name == "target_features") {
+ if (Error Err = parseTargetFeaturesSection(Ctx))
+ return Err;
+ } else if (Sec.Name.startswith("reloc.")) {
+ if (Error Err = parseRelocSection(Sec.Name, Ctx))
+ return Err;
+ }
+ return Error::success();
+}
+
+Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
+ uint32_t Count = readVaruint32(Ctx);
+ Signatures.reserve(Count);
+ while (Count--) {
+ wasm::WasmSignature Sig;
+ uint8_t Form = readUint8(Ctx);
+ if (Form != wasm::WASM_TYPE_FUNC) {
return make_error<GenericBinaryError>("invalid signature type",
- object_error::parse_failed);
- }
- uint32_t ParamCount = readVaruint32(Ctx);
- Sig.Params.reserve(ParamCount);
- while (ParamCount--) {
- uint32_t ParamType = readUint8(Ctx);
- Sig.Params.push_back(wasm::ValType(ParamType));
- }
- uint32_t ReturnCount = readVaruint32(Ctx);
- while (ReturnCount--) {
- uint32_t ReturnType = readUint8(Ctx);
- Sig.Returns.push_back(wasm::ValType(ReturnType));
- }
- Signatures.push_back(std::move(Sig));
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ }
+ uint32_t ParamCount = readVaruint32(Ctx);
+ Sig.Params.reserve(ParamCount);
+ while (ParamCount--) {
+ uint32_t ParamType = readUint8(Ctx);
+ Sig.Params.push_back(wasm::ValType(ParamType));
+ }
+ uint32_t ReturnCount = readVaruint32(Ctx);
+ while (ReturnCount--) {
+ uint32_t ReturnType = readUint8(Ctx);
+ Sig.Returns.push_back(wasm::ValType(ReturnType));
+ }
+ Signatures.push_back(std::move(Sig));
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("type section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
- uint32_t Count = readVaruint32(Ctx);
- Imports.reserve(Count);
- for (uint32_t I = 0; I < Count; I++) {
- wasm::WasmImport Im;
- Im.Module = readString(Ctx);
- Im.Field = readString(Ctx);
- Im.Kind = readUint8(Ctx);
- switch (Im.Kind) {
- case wasm::WASM_EXTERNAL_FUNCTION:
- NumImportedFunctions++;
- Im.SigIndex = readVaruint32(Ctx);
- break;
- case wasm::WASM_EXTERNAL_GLOBAL:
- NumImportedGlobals++;
- Im.Global.Type = readUint8(Ctx);
- Im.Global.Mutable = readVaruint1(Ctx);
- break;
- case wasm::WASM_EXTERNAL_MEMORY:
- Im.Memory = readLimits(Ctx);
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
+ uint32_t Count = readVaruint32(Ctx);
+ Imports.reserve(Count);
+ for (uint32_t I = 0; I < Count; I++) {
+ wasm::WasmImport Im;
+ Im.Module = readString(Ctx);
+ Im.Field = readString(Ctx);
+ Im.Kind = readUint8(Ctx);
+ switch (Im.Kind) {
+ case wasm::WASM_EXTERNAL_FUNCTION:
+ NumImportedFunctions++;
+ Im.SigIndex = readVaruint32(Ctx);
+ break;
+ case wasm::WASM_EXTERNAL_GLOBAL:
+ NumImportedGlobals++;
+ Im.Global.Type = readUint8(Ctx);
+ Im.Global.Mutable = readVaruint1(Ctx);
+ break;
+ case wasm::WASM_EXTERNAL_MEMORY:
+ Im.Memory = readLimits(Ctx);
if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
HasMemory64 = true;
- break;
+ break;
case wasm::WASM_EXTERNAL_TABLE: {
Im.Table = readTableType(Ctx);
NumImportedTables++;
@@ -1055,49 +1055,49 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
if (ElemType != wasm::WASM_TYPE_FUNCREF &&
ElemType != wasm::WASM_TYPE_EXTERNREF)
return make_error<GenericBinaryError>("invalid table element type",
- object_error::parse_failed);
- break;
+ object_error::parse_failed);
+ break;
}
- case wasm::WASM_EXTERNAL_EVENT:
- NumImportedEvents++;
- Im.Event.Attribute = readVarint32(Ctx);
- Im.Event.SigIndex = readVarint32(Ctx);
- break;
- default:
+ case wasm::WASM_EXTERNAL_EVENT:
+ NumImportedEvents++;
+ Im.Event.Attribute = readVarint32(Ctx);
+ Im.Event.SigIndex = readVarint32(Ctx);
+ break;
+ default:
return make_error<GenericBinaryError>("unexpected import kind",
- object_error::parse_failed);
- }
- Imports.push_back(Im);
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ }
+ Imports.push_back(Im);
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("import section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
- uint32_t Count = readVaruint32(Ctx);
- FunctionTypes.reserve(Count);
- Functions.resize(Count);
- uint32_t NumTypes = Signatures.size();
- while (Count--) {
- uint32_t Type = readVaruint32(Ctx);
- if (Type >= NumTypes)
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
+ uint32_t Count = readVaruint32(Ctx);
+ FunctionTypes.reserve(Count);
+ Functions.resize(Count);
+ uint32_t NumTypes = Signatures.size();
+ while (Count--) {
+ uint32_t Type = readVaruint32(Ctx);
+ if (Type >= NumTypes)
return make_error<GenericBinaryError>("invalid function type",
- object_error::parse_failed);
- FunctionTypes.push_back(Type);
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ FunctionTypes.push_back(Type);
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("function section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
TableSection = Sections.size();
- uint32_t Count = readVaruint32(Ctx);
- Tables.reserve(Count);
- while (Count--) {
+ uint32_t Count = readVaruint32(Ctx);
+ Tables.reserve(Count);
+ while (Count--) {
wasm::WasmTable T;
T.Type = readTableType(Ctx);
T.Index = NumImportedTables + Tables.size();
@@ -1106,765 +1106,765 @@ Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
if (ElemType != wasm::WASM_TYPE_FUNCREF &&
ElemType != wasm::WASM_TYPE_EXTERNREF) {
return make_error<GenericBinaryError>("invalid table element type",
- object_error::parse_failed);
- }
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ }
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("table section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
- uint32_t Count = readVaruint32(Ctx);
- Memories.reserve(Count);
- while (Count--) {
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
+ uint32_t Count = readVaruint32(Ctx);
+ Memories.reserve(Count);
+ while (Count--) {
auto Limits = readLimits(Ctx);
if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
HasMemory64 = true;
Memories.push_back(Limits);
- }
- if (Ctx.Ptr != Ctx.End)
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("memory section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseEventSection(ReadContext &Ctx) {
- EventSection = Sections.size();
- uint32_t Count = readVarint32(Ctx);
- Events.reserve(Count);
- while (Count--) {
- wasm::WasmEvent Event;
- Event.Index = NumImportedEvents + Events.size();
- Event.Type.Attribute = readVaruint32(Ctx);
- Event.Type.SigIndex = readVarint32(Ctx);
- Events.push_back(Event);
- }
-
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseEventSection(ReadContext &Ctx) {
+ EventSection = Sections.size();
+ uint32_t Count = readVarint32(Ctx);
+ Events.reserve(Count);
+ while (Count--) {
+ wasm::WasmEvent Event;
+ Event.Index = NumImportedEvents + Events.size();
+ Event.Type.Attribute = readVaruint32(Ctx);
+ Event.Type.SigIndex = readVarint32(Ctx);
+ Events.push_back(Event);
+ }
+
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("event section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
- GlobalSection = Sections.size();
- uint32_t Count = readVaruint32(Ctx);
- Globals.reserve(Count);
- while (Count--) {
- wasm::WasmGlobal Global;
- Global.Index = NumImportedGlobals + Globals.size();
- Global.Type.Type = readUint8(Ctx);
- Global.Type.Mutable = readVaruint1(Ctx);
- if (Error Err = readInitExpr(Global.InitExpr, Ctx))
- return Err;
- Globals.push_back(Global);
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
+ GlobalSection = Sections.size();
+ uint32_t Count = readVaruint32(Ctx);
+ Globals.reserve(Count);
+ while (Count--) {
+ wasm::WasmGlobal Global;
+ Global.Index = NumImportedGlobals + Globals.size();
+ Global.Type.Type = readUint8(Ctx);
+ Global.Type.Mutable = readVaruint1(Ctx);
+ if (Error Err = readInitExpr(Global.InitExpr, Ctx))
+ return Err;
+ Globals.push_back(Global);
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("global section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
- uint32_t Count = readVaruint32(Ctx);
- Exports.reserve(Count);
- for (uint32_t I = 0; I < Count; I++) {
- wasm::WasmExport Ex;
- Ex.Name = readString(Ctx);
- Ex.Kind = readUint8(Ctx);
- Ex.Index = readVaruint32(Ctx);
- switch (Ex.Kind) {
- case wasm::WASM_EXTERNAL_FUNCTION:
-
- if (!isDefinedFunctionIndex(Ex.Index))
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
+ uint32_t Count = readVaruint32(Ctx);
+ Exports.reserve(Count);
+ for (uint32_t I = 0; I < Count; I++) {
+ wasm::WasmExport Ex;
+ Ex.Name = readString(Ctx);
+ Ex.Kind = readUint8(Ctx);
+ Ex.Index = readVaruint32(Ctx);
+ switch (Ex.Kind) {
+ case wasm::WASM_EXTERNAL_FUNCTION:
+
+ if (!isDefinedFunctionIndex(Ex.Index))
return make_error<GenericBinaryError>("invalid function export",
- object_error::parse_failed);
- getDefinedFunction(Ex.Index).ExportName = Ex.Name;
- break;
- case wasm::WASM_EXTERNAL_GLOBAL:
- if (!isValidGlobalIndex(Ex.Index))
+ object_error::parse_failed);
+ getDefinedFunction(Ex.Index).ExportName = Ex.Name;
+ break;
+ case wasm::WASM_EXTERNAL_GLOBAL:
+ if (!isValidGlobalIndex(Ex.Index))
return make_error<GenericBinaryError>("invalid global export",
- object_error::parse_failed);
- break;
- case wasm::WASM_EXTERNAL_EVENT:
- if (!isValidEventIndex(Ex.Index))
+ object_error::parse_failed);
+ break;
+ case wasm::WASM_EXTERNAL_EVENT:
+ if (!isValidEventIndex(Ex.Index))
return make_error<GenericBinaryError>("invalid event export",
- object_error::parse_failed);
- break;
- case wasm::WASM_EXTERNAL_MEMORY:
- case wasm::WASM_EXTERNAL_TABLE:
- break;
- default:
+ object_error::parse_failed);
+ break;
+ case wasm::WASM_EXTERNAL_MEMORY:
+ case wasm::WASM_EXTERNAL_TABLE:
+ break;
+ default:
return make_error<GenericBinaryError>("unexpected export kind",
- object_error::parse_failed);
- }
- Exports.push_back(Ex);
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ }
+ Exports.push_back(Ex);
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("export section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
- return Index < NumImportedFunctions + FunctionTypes.size();
-}
-
-bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
- return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
-}
-
-bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
- return Index < NumImportedGlobals + Globals.size();
-}
-
+ object_error::parse_failed);
+ return Error::success();
+}
+
+bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
+ return Index < NumImportedFunctions + FunctionTypes.size();
+}
+
+bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
+ return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
+}
+
+bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
+ return Index < NumImportedGlobals + Globals.size();
+}
+
bool WasmObjectFile::isValidTableIndex(uint32_t Index) const {
return Index < NumImportedTables + Tables.size();
}
-bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
- return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
-}
-
+bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
+ return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
+}
+
bool WasmObjectFile::isDefinedTableIndex(uint32_t Index) const {
return Index >= NumImportedTables && isValidTableIndex(Index);
}
-bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
- return Index < NumImportedEvents + Events.size();
-}
-
-bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const {
- return Index >= NumImportedEvents && isValidEventIndex(Index);
-}
-
-bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
- return Index < Symbols.size() && Symbols[Index].isTypeFunction();
-}
-
+bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
+ return Index < NumImportedEvents + Events.size();
+}
+
+bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const {
+ return Index >= NumImportedEvents && isValidEventIndex(Index);
+}
+
+bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
+ return Index < Symbols.size() && Symbols[Index].isTypeFunction();
+}
+
bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
return Index < Symbols.size() && Symbols[Index].isTypeTable();
}
-bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
- return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
-}
-
-bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const {
- return Index < Symbols.size() && Symbols[Index].isTypeEvent();
-}
-
-bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
- return Index < Symbols.size() && Symbols[Index].isTypeData();
-}
-
-bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
- return Index < Symbols.size() && Symbols[Index].isTypeSection();
-}
-
-wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
- assert(isDefinedFunctionIndex(Index));
- return Functions[Index - NumImportedFunctions];
-}
-
-const wasm::WasmFunction &
-WasmObjectFile::getDefinedFunction(uint32_t Index) const {
- assert(isDefinedFunctionIndex(Index));
- return Functions[Index - NumImportedFunctions];
-}
-
-wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
- assert(isDefinedGlobalIndex(Index));
- return Globals[Index - NumImportedGlobals];
-}
-
-wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) {
- assert(isDefinedEventIndex(Index));
- return Events[Index - NumImportedEvents];
-}
-
-Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
- StartFunction = readVaruint32(Ctx);
- if (!isValidFunctionIndex(StartFunction))
+bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
+ return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
+}
+
+bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const {
+ return Index < Symbols.size() && Symbols[Index].isTypeEvent();
+}
+
+bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
+ return Index < Symbols.size() && Symbols[Index].isTypeData();
+}
+
+bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
+ return Index < Symbols.size() && Symbols[Index].isTypeSection();
+}
+
+wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
+ assert(isDefinedFunctionIndex(Index));
+ return Functions[Index - NumImportedFunctions];
+}
+
+const wasm::WasmFunction &
+WasmObjectFile::getDefinedFunction(uint32_t Index) const {
+ assert(isDefinedFunctionIndex(Index));
+ return Functions[Index - NumImportedFunctions];
+}
+
+wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
+ assert(isDefinedGlobalIndex(Index));
+ return Globals[Index - NumImportedGlobals];
+}
+
+wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) {
+ assert(isDefinedEventIndex(Index));
+ return Events[Index - NumImportedEvents];
+}
+
+Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
+ StartFunction = readVaruint32(Ctx);
+ if (!isValidFunctionIndex(StartFunction))
return make_error<GenericBinaryError>("invalid start function",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
- SeenCodeSection = true;
- CodeSection = Sections.size();
- uint32_t FunctionCount = readVaruint32(Ctx);
- if (FunctionCount != FunctionTypes.size()) {
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
+ SeenCodeSection = true;
+ CodeSection = Sections.size();
+ uint32_t FunctionCount = readVaruint32(Ctx);
+ if (FunctionCount != FunctionTypes.size()) {
return make_error<GenericBinaryError>("invalid function count",
- object_error::parse_failed);
- }
-
- for (uint32_t i = 0; i < FunctionCount; i++) {
- wasm::WasmFunction& Function = Functions[i];
- const uint8_t *FunctionStart = Ctx.Ptr;
- uint32_t Size = readVaruint32(Ctx);
- const uint8_t *FunctionEnd = Ctx.Ptr + Size;
-
- Function.CodeOffset = Ctx.Ptr - FunctionStart;
- Function.Index = NumImportedFunctions + i;
- Function.CodeSectionOffset = FunctionStart - Ctx.Start;
- Function.Size = FunctionEnd - FunctionStart;
-
- uint32_t NumLocalDecls = readVaruint32(Ctx);
- Function.Locals.reserve(NumLocalDecls);
- while (NumLocalDecls--) {
- wasm::WasmLocalDecl Decl;
- Decl.Count = readVaruint32(Ctx);
- Decl.Type = readUint8(Ctx);
- Function.Locals.push_back(Decl);
- }
-
- uint32_t BodySize = FunctionEnd - Ctx.Ptr;
- Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
- // This will be set later when reading in the linking metadata section.
- Function.Comdat = UINT32_MAX;
- Ctx.Ptr += BodySize;
- assert(Ctx.Ptr == FunctionEnd);
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ }
+
+ for (uint32_t i = 0; i < FunctionCount; i++) {
+ wasm::WasmFunction& Function = Functions[i];
+ const uint8_t *FunctionStart = Ctx.Ptr;
+ uint32_t Size = readVaruint32(Ctx);
+ const uint8_t *FunctionEnd = Ctx.Ptr + Size;
+
+ Function.CodeOffset = Ctx.Ptr - FunctionStart;
+ Function.Index = NumImportedFunctions + i;
+ Function.CodeSectionOffset = FunctionStart - Ctx.Start;
+ Function.Size = FunctionEnd - FunctionStart;
+
+ uint32_t NumLocalDecls = readVaruint32(Ctx);
+ Function.Locals.reserve(NumLocalDecls);
+ while (NumLocalDecls--) {
+ wasm::WasmLocalDecl Decl;
+ Decl.Count = readVaruint32(Ctx);
+ Decl.Type = readUint8(Ctx);
+ Function.Locals.push_back(Decl);
+ }
+
+ uint32_t BodySize = FunctionEnd - Ctx.Ptr;
+ Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
+ // This will be set later when reading in the linking metadata section.
+ Function.Comdat = UINT32_MAX;
+ Ctx.Ptr += BodySize;
+ assert(Ctx.Ptr == FunctionEnd);
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("code section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
- uint32_t Count = readVaruint32(Ctx);
- ElemSegments.reserve(Count);
- while (Count--) {
- wasm::WasmElemSegment Segment;
- Segment.TableIndex = readVaruint32(Ctx);
- if (Segment.TableIndex != 0) {
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
+ uint32_t Count = readVaruint32(Ctx);
+ ElemSegments.reserve(Count);
+ while (Count--) {
+ wasm::WasmElemSegment Segment;
+ Segment.TableIndex = readVaruint32(Ctx);
+ if (Segment.TableIndex != 0) {
return make_error<GenericBinaryError>("invalid TableIndex",
- object_error::parse_failed);
- }
- if (Error Err = readInitExpr(Segment.Offset, Ctx))
- return Err;
- uint32_t NumElems = readVaruint32(Ctx);
- while (NumElems--) {
- Segment.Functions.push_back(readVaruint32(Ctx));
- }
- ElemSegments.push_back(Segment);
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ }
+ if (Error Err = readInitExpr(Segment.Offset, Ctx))
+ return Err;
+ uint32_t NumElems = readVaruint32(Ctx);
+ while (NumElems--) {
+ Segment.Functions.push_back(readVaruint32(Ctx));
+ }
+ ElemSegments.push_back(Segment);
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("elem section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
- DataSection = Sections.size();
- uint32_t Count = readVaruint32(Ctx);
- if (DataCount && Count != DataCount.getValue())
- return make_error<GenericBinaryError>(
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
+ DataSection = Sections.size();
+ uint32_t Count = readVaruint32(Ctx);
+ if (DataCount && Count != DataCount.getValue())
+ return make_error<GenericBinaryError>(
"number of data segments does not match DataCount section");
- DataSegments.reserve(Count);
- while (Count--) {
- WasmSegment Segment;
- Segment.Data.InitFlags = readVaruint32(Ctx);
+ DataSegments.reserve(Count);
+ while (Count--) {
+ WasmSegment Segment;
+ Segment.Data.InitFlags = readVaruint32(Ctx);
Segment.Data.MemoryIndex =
(Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
? readVaruint32(Ctx)
: 0;
if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
- if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
- return Err;
- } else {
- Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
- Segment.Data.Offset.Value.Int32 = 0;
- }
- uint32_t Size = readVaruint32(Ctx);
- if (Size > (size_t)(Ctx.End - Ctx.Ptr))
+ if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
+ return Err;
+ } else {
+ Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
+ Segment.Data.Offset.Value.Int32 = 0;
+ }
+ uint32_t Size = readVaruint32(Ctx);
+ if (Size > (size_t)(Ctx.End - Ctx.Ptr))
return make_error<GenericBinaryError>("invalid segment size",
- object_error::parse_failed);
- Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
- // The rest of these Data fields are set later, when reading in the linking
- // metadata section.
- Segment.Data.Alignment = 0;
- Segment.Data.LinkerFlags = 0;
- Segment.Data.Comdat = UINT32_MAX;
- Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
- Ctx.Ptr += Size;
- DataSegments.push_back(Segment);
- }
- if (Ctx.Ptr != Ctx.End)
+ object_error::parse_failed);
+ Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
+ // The rest of these Data fields are set later, when reading in the linking
+ // metadata section.
+ Segment.Data.Alignment = 0;
+ Segment.Data.LinkerFlags = 0;
+ Segment.Data.Comdat = UINT32_MAX;
+ Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
+ Ctx.Ptr += Size;
+ DataSegments.push_back(Segment);
+ }
+ if (Ctx.Ptr != Ctx.End)
return make_error<GenericBinaryError>("data section ended prematurely",
- object_error::parse_failed);
- return Error::success();
-}
-
-Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
- DataCount = readVaruint32(Ctx);
- return Error::success();
-}
-
-const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
- return Header;
-}
-
-void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
-
-Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
- uint32_t Result = SymbolRef::SF_None;
- const WasmSymbol &Sym = getWasmSymbol(Symb);
-
- LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
- if (Sym.isBindingWeak())
- Result |= SymbolRef::SF_Weak;
- if (!Sym.isBindingLocal())
- Result |= SymbolRef::SF_Global;
- if (Sym.isHidden())
- Result |= SymbolRef::SF_Hidden;
- if (!Sym.isDefined())
- Result |= SymbolRef::SF_Undefined;
- if (Sym.isTypeFunction())
- Result |= SymbolRef::SF_Executable;
- return Result;
-}
-
-basic_symbol_iterator WasmObjectFile::symbol_begin() const {
- DataRefImpl Ref;
- Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
- Ref.d.b = 0; // Symbol index
- return BasicSymbolRef(Ref, this);
-}
-
-basic_symbol_iterator WasmObjectFile::symbol_end() const {
- DataRefImpl Ref;
- Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
- Ref.d.b = Symbols.size(); // Symbol index
- return BasicSymbolRef(Ref, this);
-}
-
-const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
- return Symbols[Symb.d.b];
-}
-
-const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
- return getWasmSymbol(Symb.getRawDataRefImpl());
-}
-
-Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
- return getWasmSymbol(Symb).Info.Name;
-}
-
-Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
- auto &Sym = getWasmSymbol(Symb);
- if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
- isDefinedFunctionIndex(Sym.Info.ElementIndex))
- return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
- else
- return getSymbolValue(Symb);
-}
-
-uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
- switch (Sym.Info.Kind) {
- case wasm::WASM_SYMBOL_TYPE_FUNCTION:
- case wasm::WASM_SYMBOL_TYPE_GLOBAL:
- case wasm::WASM_SYMBOL_TYPE_EVENT:
+ object_error::parse_failed);
+ return Error::success();
+}
+
+Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
+ DataCount = readVaruint32(Ctx);
+ return Error::success();
+}
+
+const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
+ return Header;
+}
+
+void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
+
+Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
+ uint32_t Result = SymbolRef::SF_None;
+ const WasmSymbol &Sym = getWasmSymbol(Symb);
+
+ LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
+ if (Sym.isBindingWeak())
+ Result |= SymbolRef::SF_Weak;
+ if (!Sym.isBindingLocal())
+ Result |= SymbolRef::SF_Global;
+ if (Sym.isHidden())
+ Result |= SymbolRef::SF_Hidden;
+ if (!Sym.isDefined())
+ Result |= SymbolRef::SF_Undefined;
+ if (Sym.isTypeFunction())
+ Result |= SymbolRef::SF_Executable;
+ return Result;
+}
+
+basic_symbol_iterator WasmObjectFile::symbol_begin() const {
+ DataRefImpl Ref;
+ Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
+ Ref.d.b = 0; // Symbol index
+ return BasicSymbolRef(Ref, this);
+}
+
+basic_symbol_iterator WasmObjectFile::symbol_end() const {
+ DataRefImpl Ref;
+ Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
+ Ref.d.b = Symbols.size(); // Symbol index
+ return BasicSymbolRef(Ref, this);
+}
+
+const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
+ return Symbols[Symb.d.b];
+}
+
+const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
+ return getWasmSymbol(Symb.getRawDataRefImpl());
+}
+
+Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
+ return getWasmSymbol(Symb).Info.Name;
+}
+
+Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
+ auto &Sym = getWasmSymbol(Symb);
+ if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
+ isDefinedFunctionIndex(Sym.Info.ElementIndex))
+ return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
+ else
+ return getSymbolValue(Symb);
+}
+
+uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
+ switch (Sym.Info.Kind) {
+ case wasm::WASM_SYMBOL_TYPE_FUNCTION:
+ case wasm::WASM_SYMBOL_TYPE_GLOBAL:
+ case wasm::WASM_SYMBOL_TYPE_EVENT:
case wasm::WASM_SYMBOL_TYPE_TABLE:
- return Sym.Info.ElementIndex;
- case wasm::WASM_SYMBOL_TYPE_DATA: {
- // The value of a data symbol is the segment offset, plus the symbol
- // offset within the segment.
- uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
- const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
- if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) {
- return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
- } else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) {
- return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset;
- } else {
- llvm_unreachable("unknown init expr opcode");
- }
- }
- case wasm::WASM_SYMBOL_TYPE_SECTION:
- return 0;
- }
- 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;
-}
-
-uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
- llvm_unreachable("not yet implemented");
- return 0;
-}
-
-Expected<SymbolRef::Type>
-WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
- const WasmSymbol &Sym = getWasmSymbol(Symb);
-
- switch (Sym.Info.Kind) {
- case wasm::WASM_SYMBOL_TYPE_FUNCTION:
- return SymbolRef::ST_Function;
- case wasm::WASM_SYMBOL_TYPE_GLOBAL:
- return SymbolRef::ST_Other;
- case wasm::WASM_SYMBOL_TYPE_DATA:
- return SymbolRef::ST_Data;
- case wasm::WASM_SYMBOL_TYPE_SECTION:
- return SymbolRef::ST_Debug;
- case wasm::WASM_SYMBOL_TYPE_EVENT:
- return SymbolRef::ST_Other;
+ return Sym.Info.ElementIndex;
+ case wasm::WASM_SYMBOL_TYPE_DATA: {
+ // The value of a data symbol is the segment offset, plus the symbol
+ // offset within the segment.
+ uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
+ const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
+ if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) {
+ return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
+ } else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) {
+ return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset;
+ } else {
+ llvm_unreachable("unknown init expr opcode");
+ }
+ }
+ case wasm::WASM_SYMBOL_TYPE_SECTION:
+ return 0;
+ }
+ 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;
+}
+
+uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
+ llvm_unreachable("not yet implemented");
+ return 0;
+}
+
+Expected<SymbolRef::Type>
+WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
+ const WasmSymbol &Sym = getWasmSymbol(Symb);
+
+ switch (Sym.Info.Kind) {
+ case wasm::WASM_SYMBOL_TYPE_FUNCTION:
+ return SymbolRef::ST_Function;
+ case wasm::WASM_SYMBOL_TYPE_GLOBAL:
+ return SymbolRef::ST_Other;
+ case wasm::WASM_SYMBOL_TYPE_DATA:
+ return SymbolRef::ST_Data;
+ case wasm::WASM_SYMBOL_TYPE_SECTION:
+ return SymbolRef::ST_Debug;
+ case wasm::WASM_SYMBOL_TYPE_EVENT:
+ return SymbolRef::ST_Other;
case wasm::WASM_SYMBOL_TYPE_TABLE:
return SymbolRef::ST_Other;
- }
-
+ }
+
llvm_unreachable("unknown WasmSymbol::SymbolType");
- return SymbolRef::ST_Other;
-}
-
-Expected<section_iterator>
-WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
- const WasmSymbol &Sym = getWasmSymbol(Symb);
- if (Sym.isUndefined())
- return section_end();
-
- DataRefImpl Ref;
- Ref.d.a = getSymbolSectionIdImpl(Sym);
- return section_iterator(SectionRef(Ref, this));
-}
-
-uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
- const WasmSymbol &Sym = getWasmSymbol(Symb);
- return getSymbolSectionIdImpl(Sym);
-}
-
-uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
- switch (Sym.Info.Kind) {
- case wasm::WASM_SYMBOL_TYPE_FUNCTION:
- return CodeSection;
- case wasm::WASM_SYMBOL_TYPE_GLOBAL:
- return GlobalSection;
- case wasm::WASM_SYMBOL_TYPE_DATA:
- return DataSection;
- case wasm::WASM_SYMBOL_TYPE_SECTION:
- return Sym.Info.ElementIndex;
- case wasm::WASM_SYMBOL_TYPE_EVENT:
- return EventSection;
+ return SymbolRef::ST_Other;
+}
+
+Expected<section_iterator>
+WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
+ const WasmSymbol &Sym = getWasmSymbol(Symb);
+ if (Sym.isUndefined())
+ return section_end();
+
+ DataRefImpl Ref;
+ Ref.d.a = getSymbolSectionIdImpl(Sym);
+ return section_iterator(SectionRef(Ref, this));
+}
+
+uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
+ const WasmSymbol &Sym = getWasmSymbol(Symb);
+ return getSymbolSectionIdImpl(Sym);
+}
+
+uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
+ switch (Sym.Info.Kind) {
+ case wasm::WASM_SYMBOL_TYPE_FUNCTION:
+ return CodeSection;
+ case wasm::WASM_SYMBOL_TYPE_GLOBAL:
+ return GlobalSection;
+ case wasm::WASM_SYMBOL_TYPE_DATA:
+ return DataSection;
+ case wasm::WASM_SYMBOL_TYPE_SECTION:
+ return Sym.Info.ElementIndex;
+ case wasm::WASM_SYMBOL_TYPE_EVENT:
+ return EventSection;
case wasm::WASM_SYMBOL_TYPE_TABLE:
return TableSection;
- default:
+ default:
llvm_unreachable("unknown WasmSymbol::SymbolType");
- }
-}
-
-void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
-
-Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
- const WasmSection &S = Sections[Sec.d.a];
-#define ECase(X) \
- case wasm::WASM_SEC_##X: \
- return #X;
- switch (S.Type) {
- ECase(TYPE);
- ECase(IMPORT);
- ECase(FUNCTION);
- ECase(TABLE);
- ECase(MEMORY);
- ECase(GLOBAL);
- ECase(EVENT);
- ECase(EXPORT);
- ECase(START);
- ECase(ELEM);
- ECase(CODE);
- ECase(DATA);
- ECase(DATACOUNT);
- case wasm::WASM_SEC_CUSTOM:
- return S.Name;
- default:
- return createStringError(object_error::invalid_section_index, "");
- }
-#undef ECase
-}
-
-uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
-
-uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
- return Sec.d.a;
-}
-
-uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
- const WasmSection &S = Sections[Sec.d.a];
- return S.Content.size();
-}
-
-Expected<ArrayRef<uint8_t>>
-WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
- const WasmSection &S = Sections[Sec.d.a];
- // This will never fail since wasm sections can never be empty (user-sections
- // must have a name and non-user sections each have a defined structure).
- return S.Content;
-}
-
-uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
- return 1;
-}
-
-bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
- return false;
-}
-
-bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
- return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
-}
-
-bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
- return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
-}
-
-bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
-
-bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
-
-relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
- DataRefImpl RelocRef;
- RelocRef.d.a = Ref.d.a;
- RelocRef.d.b = 0;
- return relocation_iterator(RelocationRef(RelocRef, this));
-}
-
-relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
- const WasmSection &Sec = getWasmSection(Ref);
- DataRefImpl RelocRef;
- RelocRef.d.a = Ref.d.a;
- RelocRef.d.b = Sec.Relocations.size();
- return relocation_iterator(RelocationRef(RelocRef, this));
-}
-
-void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
-
-uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
- const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
- return Rel.Offset;
-}
-
-symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
- const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
- if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
- return symbol_end();
- DataRefImpl Sym;
- Sym.d.a = 1;
- Sym.d.b = Rel.Index;
- return symbol_iterator(SymbolRef(Sym, this));
-}
-
-uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
- const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
- return Rel.Type;
-}
-
-void WasmObjectFile::getRelocationTypeName(
- DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
- const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
- StringRef Res = "Unknown";
-
-#define WASM_RELOC(name, value) \
- case wasm::name: \
- Res = #name; \
- break;
-
- switch (Rel.Type) {
-#include "llvm/BinaryFormat/WasmRelocs.def"
- }
-
-#undef WASM_RELOC
-
- Result.append(Res.begin(), Res.end());
-}
-
-section_iterator WasmObjectFile::section_begin() const {
- DataRefImpl Ref;
- Ref.d.a = 0;
- return section_iterator(SectionRef(Ref, this));
-}
-
-section_iterator WasmObjectFile::section_end() const {
- DataRefImpl Ref;
- Ref.d.a = Sections.size();
- return section_iterator(SectionRef(Ref, this));
-}
-
+ }
+}
+
+void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
+
+Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
+ const WasmSection &S = Sections[Sec.d.a];
+#define ECase(X) \
+ case wasm::WASM_SEC_##X: \
+ return #X;
+ switch (S.Type) {
+ ECase(TYPE);
+ ECase(IMPORT);
+ ECase(FUNCTION);
+ ECase(TABLE);
+ ECase(MEMORY);
+ ECase(GLOBAL);
+ ECase(EVENT);
+ ECase(EXPORT);
+ ECase(START);
+ ECase(ELEM);
+ ECase(CODE);
+ ECase(DATA);
+ ECase(DATACOUNT);
+ case wasm::WASM_SEC_CUSTOM:
+ return S.Name;
+ default:
+ return createStringError(object_error::invalid_section_index, "");
+ }
+#undef ECase
+}
+
+uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
+
+uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
+ return Sec.d.a;
+}
+
+uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
+ const WasmSection &S = Sections[Sec.d.a];
+ return S.Content.size();
+}
+
+Expected<ArrayRef<uint8_t>>
+WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
+ const WasmSection &S = Sections[Sec.d.a];
+ // This will never fail since wasm sections can never be empty (user-sections
+ // must have a name and non-user sections each have a defined structure).
+ return S.Content;
+}
+
+uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
+ return 1;
+}
+
+bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
+ return false;
+}
+
+bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
+ return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
+}
+
+bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
+ return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
+}
+
+bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
+
+bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
+
+relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
+ DataRefImpl RelocRef;
+ RelocRef.d.a = Ref.d.a;
+ RelocRef.d.b = 0;
+ return relocation_iterator(RelocationRef(RelocRef, this));
+}
+
+relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
+ const WasmSection &Sec = getWasmSection(Ref);
+ DataRefImpl RelocRef;
+ RelocRef.d.a = Ref.d.a;
+ RelocRef.d.b = Sec.Relocations.size();
+ return relocation_iterator(RelocationRef(RelocRef, this));
+}
+
+void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
+
+uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
+ const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
+ return Rel.Offset;
+}
+
+symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
+ const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
+ if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
+ return symbol_end();
+ DataRefImpl Sym;
+ Sym.d.a = 1;
+ Sym.d.b = Rel.Index;
+ return symbol_iterator(SymbolRef(Sym, this));
+}
+
+uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
+ const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
+ return Rel.Type;
+}
+
+void WasmObjectFile::getRelocationTypeName(
+ DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
+ const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
+ StringRef Res = "Unknown";
+
+#define WASM_RELOC(name, value) \
+ case wasm::name: \
+ Res = #name; \
+ break;
+
+ switch (Rel.Type) {
+#include "llvm/BinaryFormat/WasmRelocs.def"
+ }
+
+#undef WASM_RELOC
+
+ Result.append(Res.begin(), Res.end());
+}
+
+section_iterator WasmObjectFile::section_begin() const {
+ DataRefImpl Ref;
+ Ref.d.a = 0;
+ return section_iterator(SectionRef(Ref, this));
+}
+
+section_iterator WasmObjectFile::section_end() const {
+ DataRefImpl Ref;
+ Ref.d.a = Sections.size();
+ return section_iterator(SectionRef(Ref, this));
+}
+
uint8_t WasmObjectFile::getBytesInAddress() const {
return HasMemory64 ? 8 : 4;
}
-
-StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
-
+
+StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
+
Triple::ArchType WasmObjectFile::getArch() const {
return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
}
-
-SubtargetFeatures WasmObjectFile::getFeatures() const {
- return SubtargetFeatures();
-}
-
-bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
-
-bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
-
-const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
- assert(Ref.d.a < Sections.size());
- return Sections[Ref.d.a];
-}
-
-const WasmSection &
-WasmObjectFile::getWasmSection(const SectionRef &Section) const {
- return getWasmSection(Section.getRawDataRefImpl());
-}
-
-const wasm::WasmRelocation &
-WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
- return getWasmRelocation(Ref.getRawDataRefImpl());
-}
-
-const wasm::WasmRelocation &
-WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
- assert(Ref.d.a < Sections.size());
- const WasmSection &Sec = Sections[Ref.d.a];
- assert(Ref.d.b < Sec.Relocations.size());
- return Sec.Relocations[Ref.d.b];
-}
-
-int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
- StringRef CustomSectionName) {
- switch (ID) {
- case wasm::WASM_SEC_CUSTOM:
- return StringSwitch<unsigned>(CustomSectionName)
- .Case("dylink", WASM_SEC_ORDER_DYLINK)
- .Case("linking", WASM_SEC_ORDER_LINKING)
- .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
- .Case("name", WASM_SEC_ORDER_NAME)
- .Case("producers", WASM_SEC_ORDER_PRODUCERS)
- .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
- .Default(WASM_SEC_ORDER_NONE);
- case wasm::WASM_SEC_TYPE:
- return WASM_SEC_ORDER_TYPE;
- case wasm::WASM_SEC_IMPORT:
- return WASM_SEC_ORDER_IMPORT;
- case wasm::WASM_SEC_FUNCTION:
- return WASM_SEC_ORDER_FUNCTION;
- case wasm::WASM_SEC_TABLE:
- return WASM_SEC_ORDER_TABLE;
- case wasm::WASM_SEC_MEMORY:
- return WASM_SEC_ORDER_MEMORY;
- case wasm::WASM_SEC_GLOBAL:
- return WASM_SEC_ORDER_GLOBAL;
- case wasm::WASM_SEC_EXPORT:
- return WASM_SEC_ORDER_EXPORT;
- case wasm::WASM_SEC_START:
- return WASM_SEC_ORDER_START;
- case wasm::WASM_SEC_ELEM:
- return WASM_SEC_ORDER_ELEM;
- case wasm::WASM_SEC_CODE:
- return WASM_SEC_ORDER_CODE;
- case wasm::WASM_SEC_DATA:
- return WASM_SEC_ORDER_DATA;
- case wasm::WASM_SEC_DATACOUNT:
- return WASM_SEC_ORDER_DATACOUNT;
- case wasm::WASM_SEC_EVENT:
- return WASM_SEC_ORDER_EVENT;
- default:
- return WASM_SEC_ORDER_NONE;
- }
-}
-
-// Represents the edges in a directed graph where any node B reachable from node
-// A is not allowed to appear before A in the section ordering, but may appear
-// afterward.
-int WasmSectionOrderChecker::DisallowedPredecessors
- [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
- // WASM_SEC_ORDER_NONE
- {},
- // WASM_SEC_ORDER_TYPE
- {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
- // WASM_SEC_ORDER_IMPORT
- {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
- // WASM_SEC_ORDER_FUNCTION
- {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
- // WASM_SEC_ORDER_TABLE
- {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
- // WASM_SEC_ORDER_MEMORY
- {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_EVENT},
- // WASM_SEC_ORDER_EVENT
- {WASM_SEC_ORDER_EVENT, WASM_SEC_ORDER_GLOBAL},
- // WASM_SEC_ORDER_GLOBAL
- {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
- // WASM_SEC_ORDER_EXPORT
- {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
- // WASM_SEC_ORDER_START
- {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
- // WASM_SEC_ORDER_ELEM
- {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
- // WASM_SEC_ORDER_DATACOUNT
- {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
- // WASM_SEC_ORDER_CODE
- {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
- // WASM_SEC_ORDER_DATA
- {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
-
- // Custom Sections
- // WASM_SEC_ORDER_DYLINK
- {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
- // WASM_SEC_ORDER_LINKING
- {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
- // WASM_SEC_ORDER_RELOC (can be repeated)
- {},
- // WASM_SEC_ORDER_NAME
- {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
- // WASM_SEC_ORDER_PRODUCERS
- {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
- // WASM_SEC_ORDER_TARGET_FEATURES
- {WASM_SEC_ORDER_TARGET_FEATURES}};
-
-bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
- StringRef CustomSectionName) {
- int Order = getSectionOrder(ID, CustomSectionName);
- if (Order == WASM_SEC_ORDER_NONE)
- return true;
-
- // Disallowed predecessors we need to check for
- SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
-
- // Keep track of completed checks to avoid repeating work
- bool Checked[WASM_NUM_SEC_ORDERS] = {};
-
- int Curr = Order;
- while (true) {
- // Add new disallowed predecessors to work list
- for (size_t I = 0;; ++I) {
- int Next = DisallowedPredecessors[Curr][I];
- if (Next == WASM_SEC_ORDER_NONE)
- break;
- if (Checked[Next])
- continue;
- WorkList.push_back(Next);
- Checked[Next] = true;
- }
-
- if (WorkList.empty())
- break;
-
- // Consider next disallowed predecessor
- Curr = WorkList.pop_back_val();
- if (Seen[Curr])
- return false;
- }
-
- // Have not seen any disallowed predecessors
- Seen[Order] = true;
- return true;
-}
+
+SubtargetFeatures WasmObjectFile::getFeatures() const {
+ return SubtargetFeatures();
+}
+
+bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
+
+bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
+
+const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
+ assert(Ref.d.a < Sections.size());
+ return Sections[Ref.d.a];
+}
+
+const WasmSection &
+WasmObjectFile::getWasmSection(const SectionRef &Section) const {
+ return getWasmSection(Section.getRawDataRefImpl());
+}
+
+const wasm::WasmRelocation &
+WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
+ return getWasmRelocation(Ref.getRawDataRefImpl());
+}
+
+const wasm::WasmRelocation &
+WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
+ assert(Ref.d.a < Sections.size());
+ const WasmSection &Sec = Sections[Ref.d.a];
+ assert(Ref.d.b < Sec.Relocations.size());
+ return Sec.Relocations[Ref.d.b];
+}
+
+int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
+ StringRef CustomSectionName) {
+ switch (ID) {
+ case wasm::WASM_SEC_CUSTOM:
+ return StringSwitch<unsigned>(CustomSectionName)
+ .Case("dylink", WASM_SEC_ORDER_DYLINK)
+ .Case("linking", WASM_SEC_ORDER_LINKING)
+ .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
+ .Case("name", WASM_SEC_ORDER_NAME)
+ .Case("producers", WASM_SEC_ORDER_PRODUCERS)
+ .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
+ .Default(WASM_SEC_ORDER_NONE);
+ case wasm::WASM_SEC_TYPE:
+ return WASM_SEC_ORDER_TYPE;
+ case wasm::WASM_SEC_IMPORT:
+ return WASM_SEC_ORDER_IMPORT;
+ case wasm::WASM_SEC_FUNCTION:
+ return WASM_SEC_ORDER_FUNCTION;
+ case wasm::WASM_SEC_TABLE:
+ return WASM_SEC_ORDER_TABLE;
+ case wasm::WASM_SEC_MEMORY:
+ return WASM_SEC_ORDER_MEMORY;
+ case wasm::WASM_SEC_GLOBAL:
+ return WASM_SEC_ORDER_GLOBAL;
+ case wasm::WASM_SEC_EXPORT:
+ return WASM_SEC_ORDER_EXPORT;
+ case wasm::WASM_SEC_START:
+ return WASM_SEC_ORDER_START;
+ case wasm::WASM_SEC_ELEM:
+ return WASM_SEC_ORDER_ELEM;
+ case wasm::WASM_SEC_CODE:
+ return WASM_SEC_ORDER_CODE;
+ case wasm::WASM_SEC_DATA:
+ return WASM_SEC_ORDER_DATA;
+ case wasm::WASM_SEC_DATACOUNT:
+ return WASM_SEC_ORDER_DATACOUNT;
+ case wasm::WASM_SEC_EVENT:
+ return WASM_SEC_ORDER_EVENT;
+ default:
+ return WASM_SEC_ORDER_NONE;
+ }
+}
+
+// Represents the edges in a directed graph where any node B reachable from node
+// A is not allowed to appear before A in the section ordering, but may appear
+// afterward.
+int WasmSectionOrderChecker::DisallowedPredecessors
+ [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
+ // WASM_SEC_ORDER_NONE
+ {},
+ // WASM_SEC_ORDER_TYPE
+ {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
+ // WASM_SEC_ORDER_IMPORT
+ {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
+ // WASM_SEC_ORDER_FUNCTION
+ {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
+ // WASM_SEC_ORDER_TABLE
+ {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
+ // WASM_SEC_ORDER_MEMORY
+ {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_EVENT},
+ // WASM_SEC_ORDER_EVENT
+ {WASM_SEC_ORDER_EVENT, WASM_SEC_ORDER_GLOBAL},
+ // WASM_SEC_ORDER_GLOBAL
+ {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
+ // WASM_SEC_ORDER_EXPORT
+ {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
+ // WASM_SEC_ORDER_START
+ {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
+ // WASM_SEC_ORDER_ELEM
+ {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
+ // WASM_SEC_ORDER_DATACOUNT
+ {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
+ // WASM_SEC_ORDER_CODE
+ {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
+ // WASM_SEC_ORDER_DATA
+ {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
+
+ // Custom Sections
+ // WASM_SEC_ORDER_DYLINK
+ {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
+ // WASM_SEC_ORDER_LINKING
+ {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
+ // WASM_SEC_ORDER_RELOC (can be repeated)
+ {},
+ // WASM_SEC_ORDER_NAME
+ {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
+ // WASM_SEC_ORDER_PRODUCERS
+ {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
+ // WASM_SEC_ORDER_TARGET_FEATURES
+ {WASM_SEC_ORDER_TARGET_FEATURES}};
+
+bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
+ StringRef CustomSectionName) {
+ int Order = getSectionOrder(ID, CustomSectionName);
+ if (Order == WASM_SEC_ORDER_NONE)
+ return true;
+
+ // Disallowed predecessors we need to check for
+ SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
+
+ // Keep track of completed checks to avoid repeating work
+ bool Checked[WASM_NUM_SEC_ORDERS] = {};
+
+ int Curr = Order;
+ while (true) {
+ // Add new disallowed predecessors to work list
+ for (size_t I = 0;; ++I) {
+ int Next = DisallowedPredecessors[Curr][I];
+ if (Next == WASM_SEC_ORDER_NONE)
+ break;
+ if (Checked[Next])
+ continue;
+ WorkList.push_back(Next);
+ Checked[Next] = true;
+ }
+
+ if (WorkList.empty())
+ break;
+
+ // Consider next disallowed predecessor
+ Curr = WorkList.pop_back_val();
+ if (Seen[Curr])
+ return false;
+ }
+
+ // Have not seen any disallowed predecessors
+ Seen[Order] = true;
+ return true;
+}
diff --git a/contrib/libs/llvm12/lib/Object/WindowsMachineFlag.cpp b/contrib/libs/llvm12/lib/Object/WindowsMachineFlag.cpp
index 65a33eb5be..f7f2b20ae1 100644
--- a/contrib/libs/llvm12/lib/Object/WindowsMachineFlag.cpp
+++ b/contrib/libs/llvm12/lib/Object/WindowsMachineFlag.cpp
@@ -1,44 +1,44 @@
-//===- WindowsMachineFlag.cpp ---------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// Functions for implementing the /machine: flag.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/WindowsMachineFlag.h"
-
-#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
-#include "llvm/BinaryFormat/COFF.h"
-
-using namespace llvm;
-
-// Returns /machine's value.
-COFF::MachineTypes llvm::getMachineType(StringRef S) {
- return StringSwitch<COFF::MachineTypes>(S.lower())
- .Cases("x64", "amd64", COFF::IMAGE_FILE_MACHINE_AMD64)
- .Cases("x86", "i386", COFF::IMAGE_FILE_MACHINE_I386)
- .Case("arm", COFF::IMAGE_FILE_MACHINE_ARMNT)
- .Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64)
- .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
-}
-
-StringRef llvm::machineToStr(COFF::MachineTypes MT) {
- switch (MT) {
- case COFF::IMAGE_FILE_MACHINE_ARMNT:
- return "arm";
- case COFF::IMAGE_FILE_MACHINE_ARM64:
- return "arm64";
- case COFF::IMAGE_FILE_MACHINE_AMD64:
- return "x64";
- case COFF::IMAGE_FILE_MACHINE_I386:
- return "x86";
- default:
- llvm_unreachable("unknown machine type");
- }
-}
+//===- WindowsMachineFlag.cpp ---------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Functions for implementing the /machine: flag.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/WindowsMachineFlag.h"
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/COFF.h"
+
+using namespace llvm;
+
+// Returns /machine's value.
+COFF::MachineTypes llvm::getMachineType(StringRef S) {
+ return StringSwitch<COFF::MachineTypes>(S.lower())
+ .Cases("x64", "amd64", COFF::IMAGE_FILE_MACHINE_AMD64)
+ .Cases("x86", "i386", COFF::IMAGE_FILE_MACHINE_I386)
+ .Case("arm", COFF::IMAGE_FILE_MACHINE_ARMNT)
+ .Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64)
+ .Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
+}
+
+StringRef llvm::machineToStr(COFF::MachineTypes MT) {
+ switch (MT) {
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ return "arm";
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ return "arm64";
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ return "x64";
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ return "x86";
+ default:
+ llvm_unreachable("unknown machine type");
+ }
+}
diff --git a/contrib/libs/llvm12/lib/Object/WindowsResource.cpp b/contrib/libs/llvm12/lib/Object/WindowsResource.cpp
index 2ec1a86509..2a69c6c46b 100644
--- a/contrib/libs/llvm12/lib/Object/WindowsResource.cpp
+++ b/contrib/libs/llvm12/lib/Object/WindowsResource.cpp
@@ -1,1015 +1,1015 @@
-//===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file implements the .res file class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/WindowsResource.h"
-#include "llvm/Object/COFF.h"
-#include "llvm/Support/FileOutputBuffer.h"
-#include "llvm/Support/FormatVariadic.h"
-#include "llvm/Support/MathExtras.h"
-#include "llvm/Support/ScopedPrinter.h"
-#include <ctime>
-#include <queue>
-#include <system_error>
-
-using namespace llvm;
-using namespace object;
-
-namespace llvm {
-namespace object {
-
-#define RETURN_IF_ERROR(X) \
- if (auto EC = X) \
- return EC;
-
-#define UNWRAP_REF_OR_RETURN(Name, Expr) \
- auto Name##OrErr = Expr; \
- if (!Name##OrErr) \
- return Name##OrErr.takeError(); \
- const auto &Name = *Name##OrErr;
-
-#define UNWRAP_OR_RETURN(Name, Expr) \
- auto Name##OrErr = Expr; \
- if (!Name##OrErr) \
- return Name##OrErr.takeError(); \
- auto Name = *Name##OrErr;
-
-const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
-
-// COFF files seem to be inconsistent with alignment between sections, just use
-// 8-byte because it makes everyone happy.
-const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
-
-WindowsResource::WindowsResource(MemoryBufferRef Source)
- : Binary(Binary::ID_WinRes, Source) {
- size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
- BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
- support::little);
-}
-
-// static
-Expected<std::unique_ptr<WindowsResource>>
-WindowsResource::createWindowsResource(MemoryBufferRef Source) {
- if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
- return make_error<GenericBinaryError>(
- Source.getBufferIdentifier() + ": too small to be a resource file",
- object_error::invalid_file_type);
- std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
- return std::move(Ret);
-}
-
-Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
- if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix))
- return make_error<EmptyResError>(getFileName() + " contains no entries",
- object_error::unexpected_eof);
- return ResourceEntryRef::create(BinaryStreamRef(BBS), this);
-}
-
-ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
- const WindowsResource *Owner)
- : Reader(Ref), Owner(Owner) {}
-
-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) {
- // Reached end of all the entries.
- if (Reader.bytesRemaining() == 0) {
- End = true;
- return Error::success();
- }
- RETURN_IF_ERROR(loadNext());
-
- return Error::success();
-}
-
-static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
- ArrayRef<UTF16> &Str, bool &IsString) {
- uint16_t IDFlag;
- RETURN_IF_ERROR(Reader.readInteger(IDFlag));
- IsString = IDFlag != 0xffff;
-
- if (IsString) {
- Reader.setOffset(
- Reader.getOffset() -
- sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
- RETURN_IF_ERROR(Reader.readWideString(Str));
- } else
- RETURN_IF_ERROR(Reader.readInteger(ID));
-
- return Error::success();
-}
-
-Error ResourceEntryRef::loadNext() {
- const WinResHeaderPrefix *Prefix;
- RETURN_IF_ERROR(Reader.readObject(Prefix));
-
- if (Prefix->HeaderSize < MIN_HEADER_SIZE)
- return make_error<GenericBinaryError>(Owner->getFileName() +
- ": header size too small",
- object_error::parse_failed);
-
- RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
-
- RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
-
- RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
-
- RETURN_IF_ERROR(Reader.readObject(Suffix));
-
- RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
-
- RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
-
- return Error::success();
-}
-
-WindowsResourceParser::WindowsResourceParser(bool MinGW)
- : Root(false), MinGW(MinGW) {}
-
-void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) {
- switch (TypeID) {
- case 1: OS << "CURSOR (ID 1)"; break;
- case 2: OS << "BITMAP (ID 2)"; break;
- case 3: OS << "ICON (ID 3)"; break;
- case 4: OS << "MENU (ID 4)"; break;
- case 5: OS << "DIALOG (ID 5)"; break;
- case 6: OS << "STRINGTABLE (ID 6)"; break;
- case 7: OS << "FONTDIR (ID 7)"; break;
- case 8: OS << "FONT (ID 8)"; break;
- case 9: OS << "ACCELERATOR (ID 9)"; break;
- case 10: OS << "RCDATA (ID 10)"; break;
- case 11: OS << "MESSAGETABLE (ID 11)"; break;
- case 12: OS << "GROUP_CURSOR (ID 12)"; break;
- case 14: OS << "GROUP_ICON (ID 14)"; break;
- case 16: OS << "VERSIONINFO (ID 16)"; break;
- case 17: OS << "DLGINCLUDE (ID 17)"; break;
- case 19: OS << "PLUGPLAY (ID 19)"; break;
- case 20: OS << "VXD (ID 20)"; break;
- case 21: OS << "ANICURSOR (ID 21)"; break;
- case 22: OS << "ANIICON (ID 22)"; break;
- case 23: OS << "HTML (ID 23)"; break;
- case 24: OS << "MANIFEST (ID 24)"; break;
- default: OS << "ID " << TypeID; break;
- }
-}
-
-static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) {
- if (!sys::IsBigEndianHost)
- return convertUTF16ToUTF8String(Src, Out);
-
- std::vector<UTF16> EndianCorrectedSrc;
- EndianCorrectedSrc.resize(Src.size() + 1);
- llvm::copy(Src, EndianCorrectedSrc.begin() + 1);
- EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
- return convertUTF16ToUTF8String(makeArrayRef(EndianCorrectedSrc), Out);
-}
-
-static std::string makeDuplicateResourceError(
- const ResourceEntryRef &Entry, StringRef File1, StringRef File2) {
- std::string Ret;
- raw_string_ostream OS(Ret);
-
- OS << "duplicate resource:";
-
- OS << " type ";
- if (Entry.checkTypeString()) {
- std::string UTF8;
- if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8))
- UTF8 = "(failed conversion from UTF16)";
- OS << '\"' << UTF8 << '\"';
- } else
- printResourceTypeName(Entry.getTypeID(), OS);
-
- OS << "/name ";
- if (Entry.checkNameString()) {
- std::string UTF8;
- if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8))
- UTF8 = "(failed conversion from UTF16)";
- OS << '\"' << UTF8 << '\"';
- } else {
- OS << "ID " << Entry.getNameID();
- }
-
- OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in "
- << File2;
-
- return OS.str();
-}
-
-static void printStringOrID(const WindowsResourceParser::StringOrID &S,
- raw_string_ostream &OS, bool IsType, bool IsID) {
- if (S.IsString) {
- std::string UTF8;
- if (!convertUTF16LEToUTF8String(S.String, UTF8))
- UTF8 = "(failed conversion from UTF16)";
- OS << '\"' << UTF8 << '\"';
- } else if (IsType)
- printResourceTypeName(S.ID, OS);
- else if (IsID)
- OS << "ID " << S.ID;
- else
- OS << S.ID;
-}
-
-static std::string makeDuplicateResourceError(
- const std::vector<WindowsResourceParser::StringOrID> &Context,
- StringRef File1, StringRef File2) {
- std::string Ret;
- raw_string_ostream OS(Ret);
-
- OS << "duplicate resource:";
-
- if (Context.size() >= 1) {
- OS << " type ";
- printStringOrID(Context[0], OS, /* IsType */ true, /* IsID */ true);
- }
-
- if (Context.size() >= 2) {
- OS << "/name ";
- printStringOrID(Context[1], OS, /* IsType */ false, /* IsID */ true);
- }
-
- if (Context.size() >= 3) {
- OS << "/language ";
- printStringOrID(Context[2], OS, /* IsType */ false, /* IsID */ false);
- }
- OS << ", in " << File1 << " and in " << File2;
-
- return OS.str();
-}
-
-// MinGW specific. Remove default manifests (with language zero) if there are
-// other manifests present, and report an error if there are more than one
-// manifest with a non-zero language code.
-// GCC has the concept of a default manifest resource object, which gets
-// linked in implicitly if present. This default manifest has got language
-// id zero, and should be dropped silently if there's another manifest present.
-// If the user resources surprisignly had a manifest with language id zero,
-// we should also ignore the duplicate default manifest.
-void WindowsResourceParser::cleanUpManifests(
- std::vector<std::string> &Duplicates) {
- auto TypeIt = Root.IDChildren.find(/* RT_MANIFEST */ 24);
- if (TypeIt == Root.IDChildren.end())
- return;
-
- TreeNode *TypeNode = TypeIt->second.get();
- auto NameIt =
- TypeNode->IDChildren.find(/* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1);
- if (NameIt == TypeNode->IDChildren.end())
- return;
-
- TreeNode *NameNode = NameIt->second.get();
- if (NameNode->IDChildren.size() <= 1)
- return; // None or one manifest present, all good.
-
- // If we have more than one manifest, drop the language zero one if present,
- // and check again.
- auto LangZeroIt = NameNode->IDChildren.find(0);
- if (LangZeroIt != NameNode->IDChildren.end() &&
- LangZeroIt->second->IsDataNode) {
- uint32_t RemovedIndex = LangZeroIt->second->DataIndex;
- NameNode->IDChildren.erase(LangZeroIt);
- Data.erase(Data.begin() + RemovedIndex);
- Root.shiftDataIndexDown(RemovedIndex);
-
- // If we're now down to one manifest, all is good.
- if (NameNode->IDChildren.size() <= 1)
- return;
- }
-
- // More than one non-language-zero manifest
- auto FirstIt = NameNode->IDChildren.begin();
- uint32_t FirstLang = FirstIt->first;
- TreeNode *FirstNode = FirstIt->second.get();
- auto LastIt = NameNode->IDChildren.rbegin();
- uint32_t LastLang = LastIt->first;
- TreeNode *LastNode = LastIt->second.get();
- Duplicates.push_back(
- ("duplicate non-default manifests with languages " + Twine(FirstLang) +
- " in " + InputFilenames[FirstNode->Origin] + " and " + Twine(LastLang) +
- " in " + InputFilenames[LastNode->Origin])
- .str());
-}
-
-// Ignore duplicates of manifests with language zero (the default manifest),
-// in case the user has provided a manifest with that language id. See
-// the function comment above for context. Only returns true if MinGW is set
-// to true.
-bool WindowsResourceParser::shouldIgnoreDuplicate(
- const ResourceEntryRef &Entry) const {
- return MinGW && !Entry.checkTypeString() &&
- Entry.getTypeID() == /* RT_MANIFEST */ 24 &&
- !Entry.checkNameString() &&
- Entry.getNameID() == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
- Entry.getLanguage() == 0;
-}
-
-bool WindowsResourceParser::shouldIgnoreDuplicate(
- const std::vector<StringOrID> &Context) const {
- return MinGW && Context.size() == 3 && !Context[0].IsString &&
- Context[0].ID == /* RT_MANIFEST */ 24 && !Context[1].IsString &&
- Context[1].ID == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
- !Context[2].IsString && Context[2].ID == 0;
-}
-
-Error WindowsResourceParser::parse(WindowsResource *WR,
- std::vector<std::string> &Duplicates) {
- auto EntryOrErr = WR->getHeadEntry();
- 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();
- uint32_t Origin = InputFilenames.size();
- InputFilenames.push_back(std::string(WR->getFileName()));
- bool End = false;
- while (!End) {
-
- TreeNode *Node;
- bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node);
- if (!IsNewNode) {
- if (!shouldIgnoreDuplicate(Entry))
- Duplicates.push_back(makeDuplicateResourceError(
- Entry, InputFilenames[Node->Origin], WR->getFileName()));
- }
-
- RETURN_IF_ERROR(Entry.moveNext(End));
- }
-
- return Error::success();
-}
-
-Error WindowsResourceParser::parse(ResourceSectionRef &RSR, StringRef Filename,
- std::vector<std::string> &Duplicates) {
- UNWRAP_REF_OR_RETURN(BaseTable, RSR.getBaseTable());
- uint32_t Origin = InputFilenames.size();
- InputFilenames.push_back(std::string(Filename));
- std::vector<StringOrID> Context;
- return addChildren(Root, RSR, BaseTable, Origin, Context, Duplicates);
-}
-
-void WindowsResourceParser::printTree(raw_ostream &OS) const {
- ScopedPrinter Writer(OS);
- Root.print(Writer, "Resource Tree");
-}
-
-bool WindowsResourceParser::TreeNode::addEntry(
- const ResourceEntryRef &Entry, uint32_t Origin,
- std::vector<std::vector<uint8_t>> &Data,
- std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) {
- TreeNode &TypeNode = addTypeNode(Entry, StringTable);
- TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable);
- return NameNode.addLanguageNode(Entry, Origin, Data, Result);
-}
-
-Error WindowsResourceParser::addChildren(TreeNode &Node,
- ResourceSectionRef &RSR,
- const coff_resource_dir_table &Table,
- uint32_t Origin,
- std::vector<StringOrID> &Context,
- std::vector<std::string> &Duplicates) {
-
- for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
- i++) {
- UNWRAP_REF_OR_RETURN(Entry, RSR.getTableEntry(Table, i));
- TreeNode *Child;
-
- if (Entry.Offset.isSubDir()) {
-
- // Create a new subdirectory and recurse
- if (i < Table.NumberOfNameEntries) {
- UNWRAP_OR_RETURN(NameString, RSR.getEntryNameString(Entry));
- Child = &Node.addNameChild(NameString, StringTable);
- Context.push_back(StringOrID(NameString));
- } else {
- Child = &Node.addIDChild(Entry.Identifier.ID);
- Context.push_back(StringOrID(Entry.Identifier.ID));
- }
-
- UNWRAP_REF_OR_RETURN(NextTable, RSR.getEntrySubDir(Entry));
- Error E =
- addChildren(*Child, RSR, NextTable, Origin, Context, Duplicates);
- if (E)
- return E;
- Context.pop_back();
-
- } else {
-
- // Data leaves are supposed to have a numeric ID as identifier (language).
- if (Table.NumberOfNameEntries > 0)
- return createStringError(object_error::parse_failed,
- "unexpected string key for data object");
-
- // Try adding a data leaf
- UNWRAP_REF_OR_RETURN(DataEntry, RSR.getEntryData(Entry));
- TreeNode *Child;
- Context.push_back(StringOrID(Entry.Identifier.ID));
- bool Added = Node.addDataChild(Entry.Identifier.ID, Table.MajorVersion,
- Table.MinorVersion, Table.Characteristics,
- Origin, Data.size(), Child);
- if (Added) {
- UNWRAP_OR_RETURN(Contents, RSR.getContents(DataEntry));
- Data.push_back(ArrayRef<uint8_t>(
- reinterpret_cast<const uint8_t *>(Contents.data()),
- Contents.size()));
- } else {
- if (!shouldIgnoreDuplicate(Context))
- Duplicates.push_back(makeDuplicateResourceError(
- Context, InputFilenames[Child->Origin], InputFilenames.back()));
- }
- Context.pop_back();
-
- }
- }
- return Error::success();
-}
-
-WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex)
- : StringIndex(StringIndex) {}
-
-WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
- uint16_t MinorVersion,
- uint32_t Characteristics,
- uint32_t Origin, uint32_t DataIndex)
- : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion),
- MinorVersion(MinorVersion), Characteristics(Characteristics),
- Origin(Origin) {}
-
-std::unique_ptr<WindowsResourceParser::TreeNode>
-WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) {
- return std::unique_ptr<TreeNode>(new TreeNode(Index));
-}
-
-std::unique_ptr<WindowsResourceParser::TreeNode>
-WindowsResourceParser::TreeNode::createIDNode() {
- return std::unique_ptr<TreeNode>(new TreeNode(0));
-}
-
-std::unique_ptr<WindowsResourceParser::TreeNode>
-WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
- uint16_t MinorVersion,
- uint32_t Characteristics,
- uint32_t Origin,
- uint32_t DataIndex) {
- return std::unique_ptr<TreeNode>(new TreeNode(
- MajorVersion, MinorVersion, Characteristics, Origin, DataIndex));
-}
-
-WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode(
- const ResourceEntryRef &Entry,
- std::vector<std::vector<UTF16>> &StringTable) {
- if (Entry.checkTypeString())
- return addNameChild(Entry.getTypeString(), StringTable);
- else
- return addIDChild(Entry.getTypeID());
-}
-
-WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode(
- const ResourceEntryRef &Entry,
- std::vector<std::vector<UTF16>> &StringTable) {
- if (Entry.checkNameString())
- return addNameChild(Entry.getNameString(), StringTable);
- else
- return addIDChild(Entry.getNameID());
-}
-
-bool WindowsResourceParser::TreeNode::addLanguageNode(
- const ResourceEntryRef &Entry, uint32_t Origin,
- std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) {
- bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
- Entry.getMinorVersion(), Entry.getCharacteristics(),
- Origin, Data.size(), Result);
- if (Added)
- Data.push_back(Entry.getData());
- return Added;
-}
-
-bool WindowsResourceParser::TreeNode::addDataChild(
- uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
- uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex,
- TreeNode *&Result) {
- auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics,
- Origin, DataIndex);
- auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild));
- Result = ElementInserted.first->second.get();
- return ElementInserted.second;
-}
-
-WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild(
- uint32_t ID) {
- auto Child = IDChildren.find(ID);
- if (Child == IDChildren.end()) {
- auto NewChild = createIDNode();
- WindowsResourceParser::TreeNode &Node = *NewChild;
- IDChildren.emplace(ID, std::move(NewChild));
- return Node;
- } else
- return *(Child->second);
-}
-
-WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild(
- ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) {
- std::string NameString;
- convertUTF16LEToUTF8String(NameRef, NameString);
-
- auto Child = StringChildren.find(NameString);
- if (Child == StringChildren.end()) {
- auto NewChild = createStringNode(StringTable.size());
- StringTable.push_back(NameRef);
- WindowsResourceParser::TreeNode &Node = *NewChild;
- StringChildren.emplace(NameString, std::move(NewChild));
- return Node;
- } else
- return *(Child->second);
-}
-
-void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
- StringRef Name) const {
- ListScope NodeScope(Writer, Name);
- for (auto const &Child : StringChildren) {
- Child.second->print(Writer, Child.first);
- }
- for (auto const &Child : IDChildren) {
- Child.second->print(Writer, to_string(Child.first));
- }
-}
-
-// This function returns the size of the entire resource tree, including
-// directory tables, directory entries, and data entries. It does not include
-// the directory strings or the relocations of the .rsrc section.
-uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
- uint32_t Size = (IDChildren.size() + StringChildren.size()) *
- sizeof(coff_resource_dir_entry);
-
- // Reached a node pointing to a data entry.
- if (IsDataNode) {
- Size += sizeof(coff_resource_data_entry);
- return Size;
- }
-
- // If the node does not point to data, it must have a directory table pointing
- // to other nodes.
- Size += sizeof(coff_resource_dir_table);
-
- for (auto const &Child : StringChildren) {
- Size += Child.second->getTreeSize();
- }
- for (auto const &Child : IDChildren) {
- Size += Child.second->getTreeSize();
- }
- return Size;
-}
-
-// Shift DataIndex of all data children with an Index greater or equal to the
-// given one, to fill a gap from removing an entry from the Data vector.
-void WindowsResourceParser::TreeNode::shiftDataIndexDown(uint32_t Index) {
- if (IsDataNode && DataIndex >= Index) {
- DataIndex--;
- } else {
- for (auto &Child : IDChildren)
- Child.second->shiftDataIndexDown(Index);
- for (auto &Child : StringChildren)
- Child.second->shiftDataIndexDown(Index);
- }
-}
-
-class WindowsResourceCOFFWriter {
-public:
- WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,
- const WindowsResourceParser &Parser, Error &E);
- std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp);
-
-private:
- void performFileLayout();
- void performSectionOneLayout();
- void performSectionTwoLayout();
- void writeCOFFHeader(uint32_t TimeDateStamp);
- void writeFirstSectionHeader();
- void writeSecondSectionHeader();
- void writeFirstSection();
- void writeSecondSection();
- void writeSymbolTable();
- void writeStringTable();
- void writeDirectoryTree();
- void writeDirectoryStringTable();
- void writeFirstSectionRelocations();
- std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
- char *BufferStart;
- uint64_t CurrentOffset = 0;
- COFF::MachineTypes MachineType;
- const WindowsResourceParser::TreeNode &Resources;
- const ArrayRef<std::vector<uint8_t>> Data;
- uint64_t FileSize;
- uint32_t SymbolTableOffset;
- uint32_t SectionOneSize;
- uint32_t SectionOneOffset;
- uint32_t SectionOneRelocations;
- uint32_t SectionTwoSize;
- uint32_t SectionTwoOffset;
- const ArrayRef<std::vector<UTF16>> StringTable;
- std::vector<uint32_t> StringTableOffsets;
- std::vector<uint32_t> DataOffsets;
- std::vector<uint32_t> RelocationAddresses;
-};
-
-WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
- COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
- Error &E)
- : MachineType(MachineType), Resources(Parser.getTree()),
- Data(Parser.getData()), StringTable(Parser.getStringTable()) {
- performFileLayout();
-
- OutputBuffer = WritableMemoryBuffer::getNewMemBuffer(
- FileSize, "internal .obj file created from .res files");
-}
-
-void WindowsResourceCOFFWriter::performFileLayout() {
- // Add size of COFF header.
- FileSize = COFF::Header16Size;
-
- // one .rsrc section header for directory tree, another for resource data.
- FileSize += 2 * COFF::SectionSize;
-
- performSectionOneLayout();
- performSectionTwoLayout();
-
- // We have reached the address of the symbol table.
- SymbolTableOffset = FileSize;
-
- FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol.
- FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
- FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
- FileSize += 4; // four null bytes for the string table.
-}
-
-void WindowsResourceCOFFWriter::performSectionOneLayout() {
- SectionOneOffset = FileSize;
-
- SectionOneSize = Resources.getTreeSize();
- uint32_t CurrentStringOffset = SectionOneSize;
- uint32_t TotalStringTableSize = 0;
- for (auto const &String : StringTable) {
- StringTableOffsets.push_back(CurrentStringOffset);
- uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
- CurrentStringOffset += StringSize;
- TotalStringTableSize += StringSize;
- }
- SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
-
- // account for the relocations of section one.
- SectionOneRelocations = FileSize + SectionOneSize;
- FileSize += SectionOneSize;
- FileSize +=
- Data.size() * COFF::RelocationSize; // one relocation for each resource.
- FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
-}
-
-void WindowsResourceCOFFWriter::performSectionTwoLayout() {
- // add size of .rsrc$2 section, which contains all resource data on 8-byte
- // alignment.
- SectionTwoOffset = FileSize;
- SectionTwoSize = 0;
- for (auto const &Entry : Data) {
- DataOffsets.push_back(SectionTwoSize);
- SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
- }
- FileSize += SectionTwoSize;
- FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
-}
-
-std::unique_ptr<MemoryBuffer>
-WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) {
- BufferStart = OutputBuffer->getBufferStart();
-
- writeCOFFHeader(TimeDateStamp);
- writeFirstSectionHeader();
- writeSecondSectionHeader();
- writeFirstSection();
- writeSecondSection();
- writeSymbolTable();
- writeStringTable();
-
- return std::move(OutputBuffer);
-}
-
-// According to COFF specification, if the Src has a size equal to Dest,
-// it's okay to *not* copy the trailing zero.
-static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) {
- assert(Src.size() <= COFF::NameSize &&
- "Src is larger than COFF::NameSize");
- assert((Src.size() == COFF::NameSize || Dest[Src.size()] == '\0') &&
- "Dest not zeroed upon initialization");
- memcpy(Dest, Src.data(), Src.size());
-}
-
-void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) {
- // Write the COFF header.
- auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
- Header->Machine = MachineType;
- Header->NumberOfSections = 2;
- Header->TimeDateStamp = TimeDateStamp;
- Header->PointerToSymbolTable = SymbolTableOffset;
- // One symbol for every resource plus 2 for each section and 1 for @feat.00
- Header->NumberOfSymbols = Data.size() + 5;
- Header->SizeOfOptionalHeader = 0;
- // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it.
- Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
-}
-
-void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
- // Write the first section header.
- CurrentOffset += sizeof(coff_file_header);
- auto *SectionOneHeader =
- reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
- coffnamecpy(SectionOneHeader->Name, ".rsrc$01");
- SectionOneHeader->VirtualSize = 0;
- SectionOneHeader->VirtualAddress = 0;
- SectionOneHeader->SizeOfRawData = SectionOneSize;
- SectionOneHeader->PointerToRawData = SectionOneOffset;
- SectionOneHeader->PointerToRelocations = SectionOneRelocations;
- SectionOneHeader->PointerToLinenumbers = 0;
- SectionOneHeader->NumberOfRelocations = Data.size();
- SectionOneHeader->NumberOfLinenumbers = 0;
- SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
- SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
-}
-
-void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
- // Write the second section header.
- CurrentOffset += sizeof(coff_section);
- auto *SectionTwoHeader =
- reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
- coffnamecpy(SectionTwoHeader->Name, ".rsrc$02");
- SectionTwoHeader->VirtualSize = 0;
- SectionTwoHeader->VirtualAddress = 0;
- SectionTwoHeader->SizeOfRawData = SectionTwoSize;
- SectionTwoHeader->PointerToRawData = SectionTwoOffset;
- SectionTwoHeader->PointerToRelocations = 0;
- SectionTwoHeader->PointerToLinenumbers = 0;
- SectionTwoHeader->NumberOfRelocations = 0;
- SectionTwoHeader->NumberOfLinenumbers = 0;
- SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
- SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
-}
-
-void WindowsResourceCOFFWriter::writeFirstSection() {
- // Write section one.
- CurrentOffset += sizeof(coff_section);
-
- writeDirectoryTree();
- writeDirectoryStringTable();
- writeFirstSectionRelocations();
-
- CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
-}
-
-void WindowsResourceCOFFWriter::writeSecondSection() {
- // Now write the .rsrc$02 section.
- for (auto const &RawDataEntry : Data) {
- llvm::copy(RawDataEntry, BufferStart + CurrentOffset);
- CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
- }
-
- CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
-}
-
-void WindowsResourceCOFFWriter::writeSymbolTable() {
- // Now write the symbol table.
- // First, the feat symbol.
- auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- coffnamecpy(Symbol->Name.ShortName, "@feat.00");
- Symbol->Value = 0x11;
- Symbol->SectionNumber = 0xffff;
- Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
- Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- Symbol->NumberOfAuxSymbols = 0;
- CurrentOffset += sizeof(coff_symbol16);
-
- // Now write the .rsrc1 symbol + aux.
- Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- coffnamecpy(Symbol->Name.ShortName, ".rsrc$01");
- Symbol->Value = 0;
- Symbol->SectionNumber = 1;
- Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
- Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- Symbol->NumberOfAuxSymbols = 1;
- CurrentOffset += sizeof(coff_symbol16);
- auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
- CurrentOffset);
- Aux->Length = SectionOneSize;
- Aux->NumberOfRelocations = Data.size();
- Aux->NumberOfLinenumbers = 0;
- Aux->CheckSum = 0;
- Aux->NumberLowPart = 0;
- Aux->Selection = 0;
- CurrentOffset += sizeof(coff_aux_section_definition);
-
- // Now write the .rsrc2 symbol + aux.
- Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- coffnamecpy(Symbol->Name.ShortName, ".rsrc$02");
- Symbol->Value = 0;
- Symbol->SectionNumber = 2;
- Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
- Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- Symbol->NumberOfAuxSymbols = 1;
- CurrentOffset += sizeof(coff_symbol16);
- Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
- CurrentOffset);
- Aux->Length = SectionTwoSize;
- Aux->NumberOfRelocations = 0;
- Aux->NumberOfLinenumbers = 0;
- Aux->CheckSum = 0;
- Aux->NumberLowPart = 0;
- Aux->Selection = 0;
- CurrentOffset += sizeof(coff_aux_section_definition);
-
- // Now write a symbol for each relocation.
- for (unsigned i = 0; i < Data.size(); i++) {
- auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
- Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- coffnamecpy(Symbol->Name.ShortName, RelocationName);
- Symbol->Value = DataOffsets[i];
- Symbol->SectionNumber = 2;
- Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
- Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
- Symbol->NumberOfAuxSymbols = 0;
- CurrentOffset += sizeof(coff_symbol16);
- }
-}
-
-void WindowsResourceCOFFWriter::writeStringTable() {
- // Just 4 null bytes for the string table.
- auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
- memset(COFFStringTable, 0, 4);
-}
-
-void WindowsResourceCOFFWriter::writeDirectoryTree() {
- // Traverse parsed resource tree breadth-first and write the corresponding
- // COFF objects.
- std::queue<const WindowsResourceParser::TreeNode *> Queue;
- Queue.push(&Resources);
- uint32_t NextLevelOffset =
- sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
- Resources.getIDChildren().size()) *
- sizeof(coff_resource_dir_entry);
- std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
- uint32_t CurrentRelativeOffset = 0;
-
- while (!Queue.empty()) {
- auto CurrentNode = Queue.front();
- Queue.pop();
- auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
- CurrentOffset);
- Table->Characteristics = CurrentNode->getCharacteristics();
- Table->TimeDateStamp = 0;
- Table->MajorVersion = CurrentNode->getMajorVersion();
- Table->MinorVersion = CurrentNode->getMinorVersion();
- auto &IDChildren = CurrentNode->getIDChildren();
- auto &StringChildren = CurrentNode->getStringChildren();
- Table->NumberOfNameEntries = StringChildren.size();
- Table->NumberOfIDEntries = IDChildren.size();
- CurrentOffset += sizeof(coff_resource_dir_table);
- CurrentRelativeOffset += sizeof(coff_resource_dir_table);
-
- // Write the directory entries immediately following each directory table.
- for (auto const &Child : StringChildren) {
- auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
- CurrentOffset);
- Entry->Identifier.setNameOffset(
- StringTableOffsets[Child.second->getStringIndex()]);
- if (Child.second->checkIsDataNode()) {
- Entry->Offset.DataEntryOffset = NextLevelOffset;
- NextLevelOffset += sizeof(coff_resource_data_entry);
- DataEntriesTreeOrder.push_back(Child.second.get());
- } else {
- Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
- NextLevelOffset += sizeof(coff_resource_dir_table) +
- (Child.second->getStringChildren().size() +
- Child.second->getIDChildren().size()) *
- sizeof(coff_resource_dir_entry);
- Queue.push(Child.second.get());
- }
- CurrentOffset += sizeof(coff_resource_dir_entry);
- CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
- }
- for (auto const &Child : IDChildren) {
- auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
- CurrentOffset);
- Entry->Identifier.ID = Child.first;
- if (Child.second->checkIsDataNode()) {
- Entry->Offset.DataEntryOffset = NextLevelOffset;
- NextLevelOffset += sizeof(coff_resource_data_entry);
- DataEntriesTreeOrder.push_back(Child.second.get());
- } else {
- Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
- NextLevelOffset += sizeof(coff_resource_dir_table) +
- (Child.second->getStringChildren().size() +
- Child.second->getIDChildren().size()) *
- sizeof(coff_resource_dir_entry);
- Queue.push(Child.second.get());
- }
- CurrentOffset += sizeof(coff_resource_dir_entry);
- CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
- }
- }
-
- RelocationAddresses.resize(Data.size());
- // Now write all the resource data entries.
- for (auto DataNodes : DataEntriesTreeOrder) {
- auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
- CurrentOffset);
- RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
- Entry->DataRVA = 0; // Set to zero because it is a relocation.
- Entry->DataSize = Data[DataNodes->getDataIndex()].size();
- Entry->Codepage = 0;
- Entry->Reserved = 0;
- CurrentOffset += sizeof(coff_resource_data_entry);
- CurrentRelativeOffset += sizeof(coff_resource_data_entry);
- }
-}
-
-void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
- // Now write the directory string table for .rsrc$01
- uint32_t TotalStringTableSize = 0;
- for (auto &String : StringTable) {
- uint16_t Length = String.size();
- support::endian::write16le(BufferStart + CurrentOffset, Length);
- CurrentOffset += sizeof(uint16_t);
- auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
- llvm::copy(String, Start);
- CurrentOffset += Length * sizeof(UTF16);
- TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
- }
- CurrentOffset +=
- alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
-}
-
-void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
-
- // Now write the relocations for .rsrc$01
- // Five symbols already in table before we start, @feat.00 and 2 for each
- // .rsrc section.
- uint32_t NextSymbolIndex = 5;
- for (unsigned i = 0; i < Data.size(); i++) {
- auto *Reloc =
- reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
- Reloc->VirtualAddress = RelocationAddresses[i];
- Reloc->SymbolTableIndex = NextSymbolIndex++;
- switch (MachineType) {
- case COFF::IMAGE_FILE_MACHINE_ARMNT:
- Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
- break;
- case COFF::IMAGE_FILE_MACHINE_AMD64:
- Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
- break;
- 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:
- llvm_unreachable("unknown machine type");
- }
- CurrentOffset += sizeof(coff_relocation);
- }
-}
-
-Expected<std::unique_ptr<MemoryBuffer>>
-writeWindowsResourceCOFF(COFF::MachineTypes MachineType,
- const WindowsResourceParser &Parser,
- uint32_t TimeDateStamp) {
- Error E = Error::success();
- WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
- if (E)
- return std::move(E);
- return Writer.write(TimeDateStamp);
-}
-
-} // namespace object
-} // namespace llvm
+//===-- WindowsResource.cpp -------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the .res file class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/WindowsResource.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include <ctime>
+#include <queue>
+#include <system_error>
+
+using namespace llvm;
+using namespace object;
+
+namespace llvm {
+namespace object {
+
+#define RETURN_IF_ERROR(X) \
+ if (auto EC = X) \
+ return EC;
+
+#define UNWRAP_REF_OR_RETURN(Name, Expr) \
+ auto Name##OrErr = Expr; \
+ if (!Name##OrErr) \
+ return Name##OrErr.takeError(); \
+ const auto &Name = *Name##OrErr;
+
+#define UNWRAP_OR_RETURN(Name, Expr) \
+ auto Name##OrErr = Expr; \
+ if (!Name##OrErr) \
+ return Name##OrErr.takeError(); \
+ auto Name = *Name##OrErr;
+
+const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
+
+// COFF files seem to be inconsistent with alignment between sections, just use
+// 8-byte because it makes everyone happy.
+const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
+
+WindowsResource::WindowsResource(MemoryBufferRef Source)
+ : Binary(Binary::ID_WinRes, Source) {
+ size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
+ BBS = BinaryByteStream(Data.getBuffer().drop_front(LeadingSize),
+ support::little);
+}
+
+// static
+Expected<std::unique_ptr<WindowsResource>>
+WindowsResource::createWindowsResource(MemoryBufferRef Source) {
+ if (Source.getBufferSize() < WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE)
+ return make_error<GenericBinaryError>(
+ Source.getBufferIdentifier() + ": too small to be a resource file",
+ object_error::invalid_file_type);
+ std::unique_ptr<WindowsResource> Ret(new WindowsResource(Source));
+ return std::move(Ret);
+}
+
+Expected<ResourceEntryRef> WindowsResource::getHeadEntry() {
+ if (BBS.getLength() < sizeof(WinResHeaderPrefix) + sizeof(WinResHeaderSuffix))
+ return make_error<EmptyResError>(getFileName() + " contains no entries",
+ object_error::unexpected_eof);
+ return ResourceEntryRef::create(BinaryStreamRef(BBS), this);
+}
+
+ResourceEntryRef::ResourceEntryRef(BinaryStreamRef Ref,
+ const WindowsResource *Owner)
+ : Reader(Ref), Owner(Owner) {}
+
+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) {
+ // Reached end of all the entries.
+ if (Reader.bytesRemaining() == 0) {
+ End = true;
+ return Error::success();
+ }
+ RETURN_IF_ERROR(loadNext());
+
+ return Error::success();
+}
+
+static Error readStringOrId(BinaryStreamReader &Reader, uint16_t &ID,
+ ArrayRef<UTF16> &Str, bool &IsString) {
+ uint16_t IDFlag;
+ RETURN_IF_ERROR(Reader.readInteger(IDFlag));
+ IsString = IDFlag != 0xffff;
+
+ if (IsString) {
+ Reader.setOffset(
+ Reader.getOffset() -
+ sizeof(uint16_t)); // Re-read the bytes which we used to check the flag.
+ RETURN_IF_ERROR(Reader.readWideString(Str));
+ } else
+ RETURN_IF_ERROR(Reader.readInteger(ID));
+
+ return Error::success();
+}
+
+Error ResourceEntryRef::loadNext() {
+ const WinResHeaderPrefix *Prefix;
+ RETURN_IF_ERROR(Reader.readObject(Prefix));
+
+ if (Prefix->HeaderSize < MIN_HEADER_SIZE)
+ return make_error<GenericBinaryError>(Owner->getFileName() +
+ ": header size too small",
+ object_error::parse_failed);
+
+ RETURN_IF_ERROR(readStringOrId(Reader, TypeID, Type, IsStringType));
+
+ RETURN_IF_ERROR(readStringOrId(Reader, NameID, Name, IsStringName));
+
+ RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_HEADER_ALIGNMENT));
+
+ RETURN_IF_ERROR(Reader.readObject(Suffix));
+
+ RETURN_IF_ERROR(Reader.readArray(Data, Prefix->DataSize));
+
+ RETURN_IF_ERROR(Reader.padToAlignment(WIN_RES_DATA_ALIGNMENT));
+
+ return Error::success();
+}
+
+WindowsResourceParser::WindowsResourceParser(bool MinGW)
+ : Root(false), MinGW(MinGW) {}
+
+void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) {
+ switch (TypeID) {
+ case 1: OS << "CURSOR (ID 1)"; break;
+ case 2: OS << "BITMAP (ID 2)"; break;
+ case 3: OS << "ICON (ID 3)"; break;
+ case 4: OS << "MENU (ID 4)"; break;
+ case 5: OS << "DIALOG (ID 5)"; break;
+ case 6: OS << "STRINGTABLE (ID 6)"; break;
+ case 7: OS << "FONTDIR (ID 7)"; break;
+ case 8: OS << "FONT (ID 8)"; break;
+ case 9: OS << "ACCELERATOR (ID 9)"; break;
+ case 10: OS << "RCDATA (ID 10)"; break;
+ case 11: OS << "MESSAGETABLE (ID 11)"; break;
+ case 12: OS << "GROUP_CURSOR (ID 12)"; break;
+ case 14: OS << "GROUP_ICON (ID 14)"; break;
+ case 16: OS << "VERSIONINFO (ID 16)"; break;
+ case 17: OS << "DLGINCLUDE (ID 17)"; break;
+ case 19: OS << "PLUGPLAY (ID 19)"; break;
+ case 20: OS << "VXD (ID 20)"; break;
+ case 21: OS << "ANICURSOR (ID 21)"; break;
+ case 22: OS << "ANIICON (ID 22)"; break;
+ case 23: OS << "HTML (ID 23)"; break;
+ case 24: OS << "MANIFEST (ID 24)"; break;
+ default: OS << "ID " << TypeID; break;
+ }
+}
+
+static bool convertUTF16LEToUTF8String(ArrayRef<UTF16> Src, std::string &Out) {
+ if (!sys::IsBigEndianHost)
+ return convertUTF16ToUTF8String(Src, Out);
+
+ std::vector<UTF16> EndianCorrectedSrc;
+ EndianCorrectedSrc.resize(Src.size() + 1);
+ llvm::copy(Src, EndianCorrectedSrc.begin() + 1);
+ EndianCorrectedSrc[0] = UNI_UTF16_BYTE_ORDER_MARK_SWAPPED;
+ return convertUTF16ToUTF8String(makeArrayRef(EndianCorrectedSrc), Out);
+}
+
+static std::string makeDuplicateResourceError(
+ const ResourceEntryRef &Entry, StringRef File1, StringRef File2) {
+ std::string Ret;
+ raw_string_ostream OS(Ret);
+
+ OS << "duplicate resource:";
+
+ OS << " type ";
+ if (Entry.checkTypeString()) {
+ std::string UTF8;
+ if (!convertUTF16LEToUTF8String(Entry.getTypeString(), UTF8))
+ UTF8 = "(failed conversion from UTF16)";
+ OS << '\"' << UTF8 << '\"';
+ } else
+ printResourceTypeName(Entry.getTypeID(), OS);
+
+ OS << "/name ";
+ if (Entry.checkNameString()) {
+ std::string UTF8;
+ if (!convertUTF16LEToUTF8String(Entry.getNameString(), UTF8))
+ UTF8 = "(failed conversion from UTF16)";
+ OS << '\"' << UTF8 << '\"';
+ } else {
+ OS << "ID " << Entry.getNameID();
+ }
+
+ OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in "
+ << File2;
+
+ return OS.str();
+}
+
+static void printStringOrID(const WindowsResourceParser::StringOrID &S,
+ raw_string_ostream &OS, bool IsType, bool IsID) {
+ if (S.IsString) {
+ std::string UTF8;
+ if (!convertUTF16LEToUTF8String(S.String, UTF8))
+ UTF8 = "(failed conversion from UTF16)";
+ OS << '\"' << UTF8 << '\"';
+ } else if (IsType)
+ printResourceTypeName(S.ID, OS);
+ else if (IsID)
+ OS << "ID " << S.ID;
+ else
+ OS << S.ID;
+}
+
+static std::string makeDuplicateResourceError(
+ const std::vector<WindowsResourceParser::StringOrID> &Context,
+ StringRef File1, StringRef File2) {
+ std::string Ret;
+ raw_string_ostream OS(Ret);
+
+ OS << "duplicate resource:";
+
+ if (Context.size() >= 1) {
+ OS << " type ";
+ printStringOrID(Context[0], OS, /* IsType */ true, /* IsID */ true);
+ }
+
+ if (Context.size() >= 2) {
+ OS << "/name ";
+ printStringOrID(Context[1], OS, /* IsType */ false, /* IsID */ true);
+ }
+
+ if (Context.size() >= 3) {
+ OS << "/language ";
+ printStringOrID(Context[2], OS, /* IsType */ false, /* IsID */ false);
+ }
+ OS << ", in " << File1 << " and in " << File2;
+
+ return OS.str();
+}
+
+// MinGW specific. Remove default manifests (with language zero) if there are
+// other manifests present, and report an error if there are more than one
+// manifest with a non-zero language code.
+// GCC has the concept of a default manifest resource object, which gets
+// linked in implicitly if present. This default manifest has got language
+// id zero, and should be dropped silently if there's another manifest present.
+// If the user resources surprisignly had a manifest with language id zero,
+// we should also ignore the duplicate default manifest.
+void WindowsResourceParser::cleanUpManifests(
+ std::vector<std::string> &Duplicates) {
+ auto TypeIt = Root.IDChildren.find(/* RT_MANIFEST */ 24);
+ if (TypeIt == Root.IDChildren.end())
+ return;
+
+ TreeNode *TypeNode = TypeIt->second.get();
+ auto NameIt =
+ TypeNode->IDChildren.find(/* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1);
+ if (NameIt == TypeNode->IDChildren.end())
+ return;
+
+ TreeNode *NameNode = NameIt->second.get();
+ if (NameNode->IDChildren.size() <= 1)
+ return; // None or one manifest present, all good.
+
+ // If we have more than one manifest, drop the language zero one if present,
+ // and check again.
+ auto LangZeroIt = NameNode->IDChildren.find(0);
+ if (LangZeroIt != NameNode->IDChildren.end() &&
+ LangZeroIt->second->IsDataNode) {
+ uint32_t RemovedIndex = LangZeroIt->second->DataIndex;
+ NameNode->IDChildren.erase(LangZeroIt);
+ Data.erase(Data.begin() + RemovedIndex);
+ Root.shiftDataIndexDown(RemovedIndex);
+
+ // If we're now down to one manifest, all is good.
+ if (NameNode->IDChildren.size() <= 1)
+ return;
+ }
+
+ // More than one non-language-zero manifest
+ auto FirstIt = NameNode->IDChildren.begin();
+ uint32_t FirstLang = FirstIt->first;
+ TreeNode *FirstNode = FirstIt->second.get();
+ auto LastIt = NameNode->IDChildren.rbegin();
+ uint32_t LastLang = LastIt->first;
+ TreeNode *LastNode = LastIt->second.get();
+ Duplicates.push_back(
+ ("duplicate non-default manifests with languages " + Twine(FirstLang) +
+ " in " + InputFilenames[FirstNode->Origin] + " and " + Twine(LastLang) +
+ " in " + InputFilenames[LastNode->Origin])
+ .str());
+}
+
+// Ignore duplicates of manifests with language zero (the default manifest),
+// in case the user has provided a manifest with that language id. See
+// the function comment above for context. Only returns true if MinGW is set
+// to true.
+bool WindowsResourceParser::shouldIgnoreDuplicate(
+ const ResourceEntryRef &Entry) const {
+ return MinGW && !Entry.checkTypeString() &&
+ Entry.getTypeID() == /* RT_MANIFEST */ 24 &&
+ !Entry.checkNameString() &&
+ Entry.getNameID() == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
+ Entry.getLanguage() == 0;
+}
+
+bool WindowsResourceParser::shouldIgnoreDuplicate(
+ const std::vector<StringOrID> &Context) const {
+ return MinGW && Context.size() == 3 && !Context[0].IsString &&
+ Context[0].ID == /* RT_MANIFEST */ 24 && !Context[1].IsString &&
+ Context[1].ID == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
+ !Context[2].IsString && Context[2].ID == 0;
+}
+
+Error WindowsResourceParser::parse(WindowsResource *WR,
+ std::vector<std::string> &Duplicates) {
+ auto EntryOrErr = WR->getHeadEntry();
+ 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();
+ uint32_t Origin = InputFilenames.size();
+ InputFilenames.push_back(std::string(WR->getFileName()));
+ bool End = false;
+ while (!End) {
+
+ TreeNode *Node;
+ bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node);
+ if (!IsNewNode) {
+ if (!shouldIgnoreDuplicate(Entry))
+ Duplicates.push_back(makeDuplicateResourceError(
+ Entry, InputFilenames[Node->Origin], WR->getFileName()));
+ }
+
+ RETURN_IF_ERROR(Entry.moveNext(End));
+ }
+
+ return Error::success();
+}
+
+Error WindowsResourceParser::parse(ResourceSectionRef &RSR, StringRef Filename,
+ std::vector<std::string> &Duplicates) {
+ UNWRAP_REF_OR_RETURN(BaseTable, RSR.getBaseTable());
+ uint32_t Origin = InputFilenames.size();
+ InputFilenames.push_back(std::string(Filename));
+ std::vector<StringOrID> Context;
+ return addChildren(Root, RSR, BaseTable, Origin, Context, Duplicates);
+}
+
+void WindowsResourceParser::printTree(raw_ostream &OS) const {
+ ScopedPrinter Writer(OS);
+ Root.print(Writer, "Resource Tree");
+}
+
+bool WindowsResourceParser::TreeNode::addEntry(
+ const ResourceEntryRef &Entry, uint32_t Origin,
+ std::vector<std::vector<uint8_t>> &Data,
+ std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) {
+ TreeNode &TypeNode = addTypeNode(Entry, StringTable);
+ TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable);
+ return NameNode.addLanguageNode(Entry, Origin, Data, Result);
+}
+
+Error WindowsResourceParser::addChildren(TreeNode &Node,
+ ResourceSectionRef &RSR,
+ const coff_resource_dir_table &Table,
+ uint32_t Origin,
+ std::vector<StringOrID> &Context,
+ std::vector<std::string> &Duplicates) {
+
+ for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
+ i++) {
+ UNWRAP_REF_OR_RETURN(Entry, RSR.getTableEntry(Table, i));
+ TreeNode *Child;
+
+ if (Entry.Offset.isSubDir()) {
+
+ // Create a new subdirectory and recurse
+ if (i < Table.NumberOfNameEntries) {
+ UNWRAP_OR_RETURN(NameString, RSR.getEntryNameString(Entry));
+ Child = &Node.addNameChild(NameString, StringTable);
+ Context.push_back(StringOrID(NameString));
+ } else {
+ Child = &Node.addIDChild(Entry.Identifier.ID);
+ Context.push_back(StringOrID(Entry.Identifier.ID));
+ }
+
+ UNWRAP_REF_OR_RETURN(NextTable, RSR.getEntrySubDir(Entry));
+ Error E =
+ addChildren(*Child, RSR, NextTable, Origin, Context, Duplicates);
+ if (E)
+ return E;
+ Context.pop_back();
+
+ } else {
+
+ // Data leaves are supposed to have a numeric ID as identifier (language).
+ if (Table.NumberOfNameEntries > 0)
+ return createStringError(object_error::parse_failed,
+ "unexpected string key for data object");
+
+ // Try adding a data leaf
+ UNWRAP_REF_OR_RETURN(DataEntry, RSR.getEntryData(Entry));
+ TreeNode *Child;
+ Context.push_back(StringOrID(Entry.Identifier.ID));
+ bool Added = Node.addDataChild(Entry.Identifier.ID, Table.MajorVersion,
+ Table.MinorVersion, Table.Characteristics,
+ Origin, Data.size(), Child);
+ if (Added) {
+ UNWRAP_OR_RETURN(Contents, RSR.getContents(DataEntry));
+ Data.push_back(ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(Contents.data()),
+ Contents.size()));
+ } else {
+ if (!shouldIgnoreDuplicate(Context))
+ Duplicates.push_back(makeDuplicateResourceError(
+ Context, InputFilenames[Child->Origin], InputFilenames.back()));
+ }
+ Context.pop_back();
+
+ }
+ }
+ return Error::success();
+}
+
+WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex)
+ : StringIndex(StringIndex) {}
+
+WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
+ uint16_t MinorVersion,
+ uint32_t Characteristics,
+ uint32_t Origin, uint32_t DataIndex)
+ : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion),
+ MinorVersion(MinorVersion), Characteristics(Characteristics),
+ Origin(Origin) {}
+
+std::unique_ptr<WindowsResourceParser::TreeNode>
+WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) {
+ return std::unique_ptr<TreeNode>(new TreeNode(Index));
+}
+
+std::unique_ptr<WindowsResourceParser::TreeNode>
+WindowsResourceParser::TreeNode::createIDNode() {
+ return std::unique_ptr<TreeNode>(new TreeNode(0));
+}
+
+std::unique_ptr<WindowsResourceParser::TreeNode>
+WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
+ uint16_t MinorVersion,
+ uint32_t Characteristics,
+ uint32_t Origin,
+ uint32_t DataIndex) {
+ return std::unique_ptr<TreeNode>(new TreeNode(
+ MajorVersion, MinorVersion, Characteristics, Origin, DataIndex));
+}
+
+WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode(
+ const ResourceEntryRef &Entry,
+ std::vector<std::vector<UTF16>> &StringTable) {
+ if (Entry.checkTypeString())
+ return addNameChild(Entry.getTypeString(), StringTable);
+ else
+ return addIDChild(Entry.getTypeID());
+}
+
+WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode(
+ const ResourceEntryRef &Entry,
+ std::vector<std::vector<UTF16>> &StringTable) {
+ if (Entry.checkNameString())
+ return addNameChild(Entry.getNameString(), StringTable);
+ else
+ return addIDChild(Entry.getNameID());
+}
+
+bool WindowsResourceParser::TreeNode::addLanguageNode(
+ const ResourceEntryRef &Entry, uint32_t Origin,
+ std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) {
+ bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
+ Entry.getMinorVersion(), Entry.getCharacteristics(),
+ Origin, Data.size(), Result);
+ if (Added)
+ Data.push_back(Entry.getData());
+ return Added;
+}
+
+bool WindowsResourceParser::TreeNode::addDataChild(
+ uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
+ uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex,
+ TreeNode *&Result) {
+ auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics,
+ Origin, DataIndex);
+ auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild));
+ Result = ElementInserted.first->second.get();
+ return ElementInserted.second;
+}
+
+WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild(
+ uint32_t ID) {
+ auto Child = IDChildren.find(ID);
+ if (Child == IDChildren.end()) {
+ auto NewChild = createIDNode();
+ WindowsResourceParser::TreeNode &Node = *NewChild;
+ IDChildren.emplace(ID, std::move(NewChild));
+ return Node;
+ } else
+ return *(Child->second);
+}
+
+WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild(
+ ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) {
+ std::string NameString;
+ convertUTF16LEToUTF8String(NameRef, NameString);
+
+ auto Child = StringChildren.find(NameString);
+ if (Child == StringChildren.end()) {
+ auto NewChild = createStringNode(StringTable.size());
+ StringTable.push_back(NameRef);
+ WindowsResourceParser::TreeNode &Node = *NewChild;
+ StringChildren.emplace(NameString, std::move(NewChild));
+ return Node;
+ } else
+ return *(Child->second);
+}
+
+void WindowsResourceParser::TreeNode::print(ScopedPrinter &Writer,
+ StringRef Name) const {
+ ListScope NodeScope(Writer, Name);
+ for (auto const &Child : StringChildren) {
+ Child.second->print(Writer, Child.first);
+ }
+ for (auto const &Child : IDChildren) {
+ Child.second->print(Writer, to_string(Child.first));
+ }
+}
+
+// This function returns the size of the entire resource tree, including
+// directory tables, directory entries, and data entries. It does not include
+// the directory strings or the relocations of the .rsrc section.
+uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
+ uint32_t Size = (IDChildren.size() + StringChildren.size()) *
+ sizeof(coff_resource_dir_entry);
+
+ // Reached a node pointing to a data entry.
+ if (IsDataNode) {
+ Size += sizeof(coff_resource_data_entry);
+ return Size;
+ }
+
+ // If the node does not point to data, it must have a directory table pointing
+ // to other nodes.
+ Size += sizeof(coff_resource_dir_table);
+
+ for (auto const &Child : StringChildren) {
+ Size += Child.second->getTreeSize();
+ }
+ for (auto const &Child : IDChildren) {
+ Size += Child.second->getTreeSize();
+ }
+ return Size;
+}
+
+// Shift DataIndex of all data children with an Index greater or equal to the
+// given one, to fill a gap from removing an entry from the Data vector.
+void WindowsResourceParser::TreeNode::shiftDataIndexDown(uint32_t Index) {
+ if (IsDataNode && DataIndex >= Index) {
+ DataIndex--;
+ } else {
+ for (auto &Child : IDChildren)
+ Child.second->shiftDataIndexDown(Index);
+ for (auto &Child : StringChildren)
+ Child.second->shiftDataIndexDown(Index);
+ }
+}
+
+class WindowsResourceCOFFWriter {
+public:
+ WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,
+ const WindowsResourceParser &Parser, Error &E);
+ std::unique_ptr<MemoryBuffer> write(uint32_t TimeDateStamp);
+
+private:
+ void performFileLayout();
+ void performSectionOneLayout();
+ void performSectionTwoLayout();
+ void writeCOFFHeader(uint32_t TimeDateStamp);
+ void writeFirstSectionHeader();
+ void writeSecondSectionHeader();
+ void writeFirstSection();
+ void writeSecondSection();
+ void writeSymbolTable();
+ void writeStringTable();
+ void writeDirectoryTree();
+ void writeDirectoryStringTable();
+ void writeFirstSectionRelocations();
+ std::unique_ptr<WritableMemoryBuffer> OutputBuffer;
+ char *BufferStart;
+ uint64_t CurrentOffset = 0;
+ COFF::MachineTypes MachineType;
+ const WindowsResourceParser::TreeNode &Resources;
+ const ArrayRef<std::vector<uint8_t>> Data;
+ uint64_t FileSize;
+ uint32_t SymbolTableOffset;
+ uint32_t SectionOneSize;
+ uint32_t SectionOneOffset;
+ uint32_t SectionOneRelocations;
+ uint32_t SectionTwoSize;
+ uint32_t SectionTwoOffset;
+ const ArrayRef<std::vector<UTF16>> StringTable;
+ std::vector<uint32_t> StringTableOffsets;
+ std::vector<uint32_t> DataOffsets;
+ std::vector<uint32_t> RelocationAddresses;
+};
+
+WindowsResourceCOFFWriter::WindowsResourceCOFFWriter(
+ COFF::MachineTypes MachineType, const WindowsResourceParser &Parser,
+ Error &E)
+ : MachineType(MachineType), Resources(Parser.getTree()),
+ Data(Parser.getData()), StringTable(Parser.getStringTable()) {
+ performFileLayout();
+
+ OutputBuffer = WritableMemoryBuffer::getNewMemBuffer(
+ FileSize, "internal .obj file created from .res files");
+}
+
+void WindowsResourceCOFFWriter::performFileLayout() {
+ // Add size of COFF header.
+ FileSize = COFF::Header16Size;
+
+ // one .rsrc section header for directory tree, another for resource data.
+ FileSize += 2 * COFF::SectionSize;
+
+ performSectionOneLayout();
+ performSectionTwoLayout();
+
+ // We have reached the address of the symbol table.
+ SymbolTableOffset = FileSize;
+
+ FileSize += COFF::Symbol16Size; // size of the @feat.00 symbol.
+ FileSize += 4 * COFF::Symbol16Size; // symbol + aux for each section.
+ FileSize += Data.size() * COFF::Symbol16Size; // 1 symbol per resource.
+ FileSize += 4; // four null bytes for the string table.
+}
+
+void WindowsResourceCOFFWriter::performSectionOneLayout() {
+ SectionOneOffset = FileSize;
+
+ SectionOneSize = Resources.getTreeSize();
+ uint32_t CurrentStringOffset = SectionOneSize;
+ uint32_t TotalStringTableSize = 0;
+ for (auto const &String : StringTable) {
+ StringTableOffsets.push_back(CurrentStringOffset);
+ uint32_t StringSize = String.size() * sizeof(UTF16) + sizeof(uint16_t);
+ CurrentStringOffset += StringSize;
+ TotalStringTableSize += StringSize;
+ }
+ SectionOneSize += alignTo(TotalStringTableSize, sizeof(uint32_t));
+
+ // account for the relocations of section one.
+ SectionOneRelocations = FileSize + SectionOneSize;
+ FileSize += SectionOneSize;
+ FileSize +=
+ Data.size() * COFF::RelocationSize; // one relocation for each resource.
+ FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
+}
+
+void WindowsResourceCOFFWriter::performSectionTwoLayout() {
+ // add size of .rsrc$2 section, which contains all resource data on 8-byte
+ // alignment.
+ SectionTwoOffset = FileSize;
+ SectionTwoSize = 0;
+ for (auto const &Entry : Data) {
+ DataOffsets.push_back(SectionTwoSize);
+ SectionTwoSize += alignTo(Entry.size(), sizeof(uint64_t));
+ }
+ FileSize += SectionTwoSize;
+ FileSize = alignTo(FileSize, SECTION_ALIGNMENT);
+}
+
+std::unique_ptr<MemoryBuffer>
+WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) {
+ BufferStart = OutputBuffer->getBufferStart();
+
+ writeCOFFHeader(TimeDateStamp);
+ writeFirstSectionHeader();
+ writeSecondSectionHeader();
+ writeFirstSection();
+ writeSecondSection();
+ writeSymbolTable();
+ writeStringTable();
+
+ return std::move(OutputBuffer);
+}
+
+// According to COFF specification, if the Src has a size equal to Dest,
+// it's okay to *not* copy the trailing zero.
+static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) {
+ assert(Src.size() <= COFF::NameSize &&
+ "Src is larger than COFF::NameSize");
+ assert((Src.size() == COFF::NameSize || Dest[Src.size()] == '\0') &&
+ "Dest not zeroed upon initialization");
+ memcpy(Dest, Src.data(), Src.size());
+}
+
+void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) {
+ // Write the COFF header.
+ auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
+ Header->Machine = MachineType;
+ Header->NumberOfSections = 2;
+ Header->TimeDateStamp = TimeDateStamp;
+ Header->PointerToSymbolTable = SymbolTableOffset;
+ // One symbol for every resource plus 2 for each section and 1 for @feat.00
+ Header->NumberOfSymbols = Data.size() + 5;
+ Header->SizeOfOptionalHeader = 0;
+ // cvtres.exe sets 32BIT_MACHINE even for 64-bit machine types. Match it.
+ Header->Characteristics = COFF::IMAGE_FILE_32BIT_MACHINE;
+}
+
+void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
+ // Write the first section header.
+ CurrentOffset += sizeof(coff_file_header);
+ auto *SectionOneHeader =
+ reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
+ coffnamecpy(SectionOneHeader->Name, ".rsrc$01");
+ SectionOneHeader->VirtualSize = 0;
+ SectionOneHeader->VirtualAddress = 0;
+ SectionOneHeader->SizeOfRawData = SectionOneSize;
+ SectionOneHeader->PointerToRawData = SectionOneOffset;
+ SectionOneHeader->PointerToRelocations = SectionOneRelocations;
+ SectionOneHeader->PointerToLinenumbers = 0;
+ SectionOneHeader->NumberOfRelocations = Data.size();
+ SectionOneHeader->NumberOfLinenumbers = 0;
+ SectionOneHeader->Characteristics += COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
+ SectionOneHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
+}
+
+void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
+ // Write the second section header.
+ CurrentOffset += sizeof(coff_section);
+ auto *SectionTwoHeader =
+ reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
+ coffnamecpy(SectionTwoHeader->Name, ".rsrc$02");
+ SectionTwoHeader->VirtualSize = 0;
+ SectionTwoHeader->VirtualAddress = 0;
+ SectionTwoHeader->SizeOfRawData = SectionTwoSize;
+ SectionTwoHeader->PointerToRawData = SectionTwoOffset;
+ SectionTwoHeader->PointerToRelocations = 0;
+ SectionTwoHeader->PointerToLinenumbers = 0;
+ SectionTwoHeader->NumberOfRelocations = 0;
+ SectionTwoHeader->NumberOfLinenumbers = 0;
+ SectionTwoHeader->Characteristics = COFF::IMAGE_SCN_CNT_INITIALIZED_DATA;
+ SectionTwoHeader->Characteristics += COFF::IMAGE_SCN_MEM_READ;
+}
+
+void WindowsResourceCOFFWriter::writeFirstSection() {
+ // Write section one.
+ CurrentOffset += sizeof(coff_section);
+
+ writeDirectoryTree();
+ writeDirectoryStringTable();
+ writeFirstSectionRelocations();
+
+ CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
+}
+
+void WindowsResourceCOFFWriter::writeSecondSection() {
+ // Now write the .rsrc$02 section.
+ for (auto const &RawDataEntry : Data) {
+ llvm::copy(RawDataEntry, BufferStart + CurrentOffset);
+ CurrentOffset += alignTo(RawDataEntry.size(), sizeof(uint64_t));
+ }
+
+ CurrentOffset = alignTo(CurrentOffset, SECTION_ALIGNMENT);
+}
+
+void WindowsResourceCOFFWriter::writeSymbolTable() {
+ // Now write the symbol table.
+ // First, the feat symbol.
+ auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
+ coffnamecpy(Symbol->Name.ShortName, "@feat.00");
+ Symbol->Value = 0x11;
+ Symbol->SectionNumber = 0xffff;
+ Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
+ Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
+ Symbol->NumberOfAuxSymbols = 0;
+ CurrentOffset += sizeof(coff_symbol16);
+
+ // Now write the .rsrc1 symbol + aux.
+ Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
+ coffnamecpy(Symbol->Name.ShortName, ".rsrc$01");
+ Symbol->Value = 0;
+ Symbol->SectionNumber = 1;
+ Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
+ Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
+ Symbol->NumberOfAuxSymbols = 1;
+ CurrentOffset += sizeof(coff_symbol16);
+ auto *Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
+ CurrentOffset);
+ Aux->Length = SectionOneSize;
+ Aux->NumberOfRelocations = Data.size();
+ Aux->NumberOfLinenumbers = 0;
+ Aux->CheckSum = 0;
+ Aux->NumberLowPart = 0;
+ Aux->Selection = 0;
+ CurrentOffset += sizeof(coff_aux_section_definition);
+
+ // Now write the .rsrc2 symbol + aux.
+ Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
+ coffnamecpy(Symbol->Name.ShortName, ".rsrc$02");
+ Symbol->Value = 0;
+ Symbol->SectionNumber = 2;
+ Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
+ Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
+ Symbol->NumberOfAuxSymbols = 1;
+ CurrentOffset += sizeof(coff_symbol16);
+ Aux = reinterpret_cast<coff_aux_section_definition *>(BufferStart +
+ CurrentOffset);
+ Aux->Length = SectionTwoSize;
+ Aux->NumberOfRelocations = 0;
+ Aux->NumberOfLinenumbers = 0;
+ Aux->CheckSum = 0;
+ Aux->NumberLowPart = 0;
+ Aux->Selection = 0;
+ CurrentOffset += sizeof(coff_aux_section_definition);
+
+ // Now write a symbol for each relocation.
+ for (unsigned i = 0; i < Data.size(); i++) {
+ auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
+ Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
+ coffnamecpy(Symbol->Name.ShortName, RelocationName);
+ Symbol->Value = DataOffsets[i];
+ Symbol->SectionNumber = 2;
+ Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
+ Symbol->StorageClass = COFF::IMAGE_SYM_CLASS_STATIC;
+ Symbol->NumberOfAuxSymbols = 0;
+ CurrentOffset += sizeof(coff_symbol16);
+ }
+}
+
+void WindowsResourceCOFFWriter::writeStringTable() {
+ // Just 4 null bytes for the string table.
+ auto COFFStringTable = reinterpret_cast<void *>(BufferStart + CurrentOffset);
+ memset(COFFStringTable, 0, 4);
+}
+
+void WindowsResourceCOFFWriter::writeDirectoryTree() {
+ // Traverse parsed resource tree breadth-first and write the corresponding
+ // COFF objects.
+ std::queue<const WindowsResourceParser::TreeNode *> Queue;
+ Queue.push(&Resources);
+ uint32_t NextLevelOffset =
+ sizeof(coff_resource_dir_table) + (Resources.getStringChildren().size() +
+ Resources.getIDChildren().size()) *
+ sizeof(coff_resource_dir_entry);
+ std::vector<const WindowsResourceParser::TreeNode *> DataEntriesTreeOrder;
+ uint32_t CurrentRelativeOffset = 0;
+
+ while (!Queue.empty()) {
+ auto CurrentNode = Queue.front();
+ Queue.pop();
+ auto *Table = reinterpret_cast<coff_resource_dir_table *>(BufferStart +
+ CurrentOffset);
+ Table->Characteristics = CurrentNode->getCharacteristics();
+ Table->TimeDateStamp = 0;
+ Table->MajorVersion = CurrentNode->getMajorVersion();
+ Table->MinorVersion = CurrentNode->getMinorVersion();
+ auto &IDChildren = CurrentNode->getIDChildren();
+ auto &StringChildren = CurrentNode->getStringChildren();
+ Table->NumberOfNameEntries = StringChildren.size();
+ Table->NumberOfIDEntries = IDChildren.size();
+ CurrentOffset += sizeof(coff_resource_dir_table);
+ CurrentRelativeOffset += sizeof(coff_resource_dir_table);
+
+ // Write the directory entries immediately following each directory table.
+ for (auto const &Child : StringChildren) {
+ auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
+ CurrentOffset);
+ Entry->Identifier.setNameOffset(
+ StringTableOffsets[Child.second->getStringIndex()]);
+ if (Child.second->checkIsDataNode()) {
+ Entry->Offset.DataEntryOffset = NextLevelOffset;
+ NextLevelOffset += sizeof(coff_resource_data_entry);
+ DataEntriesTreeOrder.push_back(Child.second.get());
+ } else {
+ Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
+ NextLevelOffset += sizeof(coff_resource_dir_table) +
+ (Child.second->getStringChildren().size() +
+ Child.second->getIDChildren().size()) *
+ sizeof(coff_resource_dir_entry);
+ Queue.push(Child.second.get());
+ }
+ CurrentOffset += sizeof(coff_resource_dir_entry);
+ CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
+ }
+ for (auto const &Child : IDChildren) {
+ auto *Entry = reinterpret_cast<coff_resource_dir_entry *>(BufferStart +
+ CurrentOffset);
+ Entry->Identifier.ID = Child.first;
+ if (Child.second->checkIsDataNode()) {
+ Entry->Offset.DataEntryOffset = NextLevelOffset;
+ NextLevelOffset += sizeof(coff_resource_data_entry);
+ DataEntriesTreeOrder.push_back(Child.second.get());
+ } else {
+ Entry->Offset.SubdirOffset = NextLevelOffset + (1 << 31);
+ NextLevelOffset += sizeof(coff_resource_dir_table) +
+ (Child.second->getStringChildren().size() +
+ Child.second->getIDChildren().size()) *
+ sizeof(coff_resource_dir_entry);
+ Queue.push(Child.second.get());
+ }
+ CurrentOffset += sizeof(coff_resource_dir_entry);
+ CurrentRelativeOffset += sizeof(coff_resource_dir_entry);
+ }
+ }
+
+ RelocationAddresses.resize(Data.size());
+ // Now write all the resource data entries.
+ for (auto DataNodes : DataEntriesTreeOrder) {
+ auto *Entry = reinterpret_cast<coff_resource_data_entry *>(BufferStart +
+ CurrentOffset);
+ RelocationAddresses[DataNodes->getDataIndex()] = CurrentRelativeOffset;
+ Entry->DataRVA = 0; // Set to zero because it is a relocation.
+ Entry->DataSize = Data[DataNodes->getDataIndex()].size();
+ Entry->Codepage = 0;
+ Entry->Reserved = 0;
+ CurrentOffset += sizeof(coff_resource_data_entry);
+ CurrentRelativeOffset += sizeof(coff_resource_data_entry);
+ }
+}
+
+void WindowsResourceCOFFWriter::writeDirectoryStringTable() {
+ // Now write the directory string table for .rsrc$01
+ uint32_t TotalStringTableSize = 0;
+ for (auto &String : StringTable) {
+ uint16_t Length = String.size();
+ support::endian::write16le(BufferStart + CurrentOffset, Length);
+ CurrentOffset += sizeof(uint16_t);
+ auto *Start = reinterpret_cast<UTF16 *>(BufferStart + CurrentOffset);
+ llvm::copy(String, Start);
+ CurrentOffset += Length * sizeof(UTF16);
+ TotalStringTableSize += Length * sizeof(UTF16) + sizeof(uint16_t);
+ }
+ CurrentOffset +=
+ alignTo(TotalStringTableSize, sizeof(uint32_t)) - TotalStringTableSize;
+}
+
+void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
+
+ // Now write the relocations for .rsrc$01
+ // Five symbols already in table before we start, @feat.00 and 2 for each
+ // .rsrc section.
+ uint32_t NextSymbolIndex = 5;
+ for (unsigned i = 0; i < Data.size(); i++) {
+ auto *Reloc =
+ reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset);
+ Reloc->VirtualAddress = RelocationAddresses[i];
+ Reloc->SymbolTableIndex = NextSymbolIndex++;
+ switch (MachineType) {
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB;
+ break;
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB;
+ break;
+ 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:
+ llvm_unreachable("unknown machine type");
+ }
+ CurrentOffset += sizeof(coff_relocation);
+ }
+}
+
+Expected<std::unique_ptr<MemoryBuffer>>
+writeWindowsResourceCOFF(COFF::MachineTypes MachineType,
+ const WindowsResourceParser &Parser,
+ uint32_t TimeDateStamp) {
+ Error E = Error::success();
+ WindowsResourceCOFFWriter Writer(MachineType, Parser, E);
+ if (E)
+ return std::move(E);
+ return Writer.write(TimeDateStamp);
+}
+
+} // namespace object
+} // namespace llvm
diff --git a/contrib/libs/llvm12/lib/Object/XCOFFObjectFile.cpp b/contrib/libs/llvm12/lib/Object/XCOFFObjectFile.cpp
index d7e876e3a1..a16a458168 100644
--- a/contrib/libs/llvm12/lib/Object/XCOFFObjectFile.cpp
+++ b/contrib/libs/llvm12/lib/Object/XCOFFObjectFile.cpp
@@ -1,844 +1,844 @@
-//===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// This file defines the XCOFFObjectFile class.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/Object/XCOFFObjectFile.h"
-#include "llvm/MC/SubtargetFeature.h"
+//===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the XCOFFObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/XCOFFObjectFile.h"
+#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/DataExtractor.h"
-#include <cstddef>
-#include <cstring>
-
-namespace llvm {
+#include <cstddef>
+#include <cstring>
+
+namespace llvm {
using namespace XCOFF;
-namespace object {
-
-static const uint8_t FunctionSym = 0x20;
-static const uint8_t SymTypeMask = 0x07;
-static const uint16_t NoRelMask = 0x0001;
-
-// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer
-// 'M'. Returns a pointer to the underlying object on success.
-template <typename T>
-static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr,
- const uint64_t Size = sizeof(T)) {
+namespace object {
+
+static const uint8_t FunctionSym = 0x20;
+static const uint8_t SymTypeMask = 0x07;
+static const uint16_t NoRelMask = 0x0001;
+
+// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer
+// 'M'. Returns a pointer to the underlying object on success.
+template <typename T>
+static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr,
+ const uint64_t Size = sizeof(T)) {
uintptr_t Addr = reinterpret_cast<uintptr_t>(Ptr);
- if (Error E = Binary::checkOffset(M, Addr, Size))
- return std::move(E);
- return reinterpret_cast<const T *>(Addr);
-}
-
-static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {
- return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +
- Offset);
-}
-
-template <typename T> static const T *viewAs(uintptr_t in) {
- return reinterpret_cast<const T *>(in);
-}
-
-static StringRef generateXCOFFFixedNameStringRef(const char *Name) {
- auto NulCharPtr =
- static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize));
- return NulCharPtr ? StringRef(Name, NulCharPtr - Name)
- : StringRef(Name, XCOFF::NameSize);
-}
-
-template <typename T> StringRef XCOFFSectionHeader<T>::getName() const {
- const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
- return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name);
-}
-
-template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const {
- const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
- return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask;
-}
-
-template <typename T>
-bool XCOFFSectionHeader<T>::isReservedSectionType() const {
- return getSectionType() & SectionFlagsReservedMask;
-}
-
-bool XCOFFRelocation32::isRelocationSigned() const {
- return Info & XR_SIGN_INDICATOR_MASK;
-}
-
-bool XCOFFRelocation32::isFixupIndicated() const {
- return Info & XR_FIXUP_INDICATOR_MASK;
-}
-
-uint8_t XCOFFRelocation32::getRelocatedLength() const {
- // The relocation encodes the bit length being relocated minus 1. Add back
- // the 1 to get the actual length being relocated.
- return (Info & XR_BIASED_LENGTH_MASK) + 1;
-}
-
-void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,
- uintptr_t TableAddress) const {
- if (Addr < TableAddress)
- report_fatal_error("Section header outside of section header table.");
-
- uintptr_t Offset = Addr - TableAddress;
- if (Offset >= getSectionHeaderSize() * getNumberOfSections())
- report_fatal_error("Section header outside of section header table.");
-
- if (Offset % getSectionHeaderSize() != 0)
- report_fatal_error(
- "Section header pointer does not point to a valid section header.");
-}
-
-const XCOFFSectionHeader32 *
-XCOFFObjectFile::toSection32(DataRefImpl Ref) const {
- assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
-#ifndef NDEBUG
- checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
-#endif
- return viewAs<XCOFFSectionHeader32>(Ref.p);
-}
-
-const XCOFFSectionHeader64 *
-XCOFFObjectFile::toSection64(DataRefImpl Ref) const {
- assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
-#ifndef NDEBUG
- checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
-#endif
- return viewAs<XCOFFSectionHeader64>(Ref.p);
-}
-
-const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const {
- assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
- assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!");
-#ifndef NDEBUG
- checkSymbolEntryPointer(Ref.p);
-#endif
- auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p);
- return SymEntPtr;
-}
-
-const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const {
- assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
- return static_cast<const XCOFFFileHeader32 *>(FileHeader);
-}
-
-const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {
- assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
- return static_cast<const XCOFFFileHeader64 *>(FileHeader);
-}
-
-const XCOFFSectionHeader32 *
-XCOFFObjectFile::sectionHeaderTable32() const {
- assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
- return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable);
-}
-
-const XCOFFSectionHeader64 *
-XCOFFObjectFile::sectionHeaderTable64() const {
- assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
- return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);
-}
-
-void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
- const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
- SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1;
-#ifndef NDEBUG
- // This function is used by basic_symbol_iterator, which allows to
- // point to the end-of-symbol-table address.
- if (reinterpret_cast<uintptr_t>(SymEntPtr) != getEndOfSymbolTableAddress())
- checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(SymEntPtr));
-#endif
- Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr);
-}
-
-Expected<StringRef>
-XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const {
- // The byte offset is relative to the start of the string table.
- // A byte offset value of 0 is a null or zero-length symbol
- // name. A byte offset in the range 1 to 3 (inclusive) points into the length
- // field; as a soft-error recovery mechanism, we treat such cases as having an
- // offset of 0.
- if (Offset < 4)
- return StringRef(nullptr, 0);
-
- if (StringTable.Data != nullptr && StringTable.Size > Offset)
- return (StringTable.Data + Offset);
-
- return make_error<GenericBinaryError>("Bad offset for string table entry",
- object_error::parse_failed);
-}
-
-Expected<StringRef>
-XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const {
- if (CFileEntPtr->NameInStrTbl.Magic !=
- XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
- return generateXCOFFFixedNameStringRef(CFileEntPtr->Name);
- return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset);
-}
-
-Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
- const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
-
- // A storage class value with the high-order bit on indicates that the name is
- // a symbolic debugger stabstring.
- if (SymEntPtr->StorageClass & 0x80)
- return StringRef("Unimplemented Debug Name");
-
- if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
- return generateXCOFFFixedNameStringRef(SymEntPtr->SymbolName);
-
- return getStringTableEntry(SymEntPtr->NameInStrTbl.Offset);
-}
-
-Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
- assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
- return toSymbolEntry(Symb)->Value;
-}
-
-uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
- assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
- return toSymbolEntry(Symb)->Value;
-}
-
-uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
- uint64_t Result = 0;
- llvm_unreachable("Not yet implemented!");
- return Result;
-}
-
-Expected<SymbolRef::Type>
-XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
- llvm_unreachable("Not yet implemented!");
- return SymbolRef::ST_Other;
-}
-
-Expected<section_iterator>
-XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
- const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
- int16_t SectNum = SymEntPtr->SectionNumber;
-
- if (isReservedSectionNumber(SectNum))
- return section_end();
-
- Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum);
- if (!ExpSec)
- return ExpSec.takeError();
-
- return section_iterator(SectionRef(ExpSec.get(), this));
-}
-
-void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
- const char *Ptr = reinterpret_cast<const char *>(Sec.p);
- Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());
-}
-
-Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
- return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));
-}
-
-uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
- // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
- // with MSVC.
- if (is64Bit())
- return toSection64(Sec)->VirtualAddress;
-
- return toSection32(Sec)->VirtualAddress;
-}
-
-uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
- // Section numbers in XCOFF are numbered beginning at 1. A section number of
- // zero is used to indicate that a symbol is being imported or is undefined.
- if (is64Bit())
- return toSection64(Sec) - sectionHeaderTable64() + 1;
- else
- return toSection32(Sec) - sectionHeaderTable32() + 1;
-}
-
-uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
- // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
- // with MSVC.
- if (is64Bit())
- return toSection64(Sec)->SectionSize;
-
- return toSection32(Sec)->SectionSize;
-}
-
-Expected<ArrayRef<uint8_t>>
-XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
- if (isSectionVirtual(Sec))
- return ArrayRef<uint8_t>();
-
- uint64_t OffsetToRaw;
- if (is64Bit())
- OffsetToRaw = toSection64(Sec)->FileOffsetToRawData;
- else
- OffsetToRaw = toSection32(Sec)->FileOffsetToRawData;
-
- const uint8_t * ContentStart = base() + OffsetToRaw;
- uint64_t SectionSize = getSectionSize(Sec);
+ if (Error E = Binary::checkOffset(M, Addr, Size))
+ return std::move(E);
+ return reinterpret_cast<const T *>(Addr);
+}
+
+static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) {
+ return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) +
+ Offset);
+}
+
+template <typename T> static const T *viewAs(uintptr_t in) {
+ return reinterpret_cast<const T *>(in);
+}
+
+static StringRef generateXCOFFFixedNameStringRef(const char *Name) {
+ auto NulCharPtr =
+ static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize));
+ return NulCharPtr ? StringRef(Name, NulCharPtr - Name)
+ : StringRef(Name, XCOFF::NameSize);
+}
+
+template <typename T> StringRef XCOFFSectionHeader<T>::getName() const {
+ const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
+ return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name);
+}
+
+template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const {
+ const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this);
+ return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask;
+}
+
+template <typename T>
+bool XCOFFSectionHeader<T>::isReservedSectionType() const {
+ return getSectionType() & SectionFlagsReservedMask;
+}
+
+bool XCOFFRelocation32::isRelocationSigned() const {
+ return Info & XR_SIGN_INDICATOR_MASK;
+}
+
+bool XCOFFRelocation32::isFixupIndicated() const {
+ return Info & XR_FIXUP_INDICATOR_MASK;
+}
+
+uint8_t XCOFFRelocation32::getRelocatedLength() const {
+ // The relocation encodes the bit length being relocated minus 1. Add back
+ // the 1 to get the actual length being relocated.
+ return (Info & XR_BIASED_LENGTH_MASK) + 1;
+}
+
+void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,
+ uintptr_t TableAddress) const {
+ if (Addr < TableAddress)
+ report_fatal_error("Section header outside of section header table.");
+
+ uintptr_t Offset = Addr - TableAddress;
+ if (Offset >= getSectionHeaderSize() * getNumberOfSections())
+ report_fatal_error("Section header outside of section header table.");
+
+ if (Offset % getSectionHeaderSize() != 0)
+ report_fatal_error(
+ "Section header pointer does not point to a valid section header.");
+}
+
+const XCOFFSectionHeader32 *
+XCOFFObjectFile::toSection32(DataRefImpl Ref) const {
+ assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
+#ifndef NDEBUG
+ checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
+#endif
+ return viewAs<XCOFFSectionHeader32>(Ref.p);
+}
+
+const XCOFFSectionHeader64 *
+XCOFFObjectFile::toSection64(DataRefImpl Ref) const {
+ assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
+#ifndef NDEBUG
+ checkSectionAddress(Ref.p, getSectionHeaderTableAddress());
+#endif
+ return viewAs<XCOFFSectionHeader64>(Ref.p);
+}
+
+const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const {
+ assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
+ assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!");
+#ifndef NDEBUG
+ checkSymbolEntryPointer(Ref.p);
+#endif
+ auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p);
+ return SymEntPtr;
+}
+
+const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const {
+ assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
+ return static_cast<const XCOFFFileHeader32 *>(FileHeader);
+}
+
+const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const {
+ assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
+ return static_cast<const XCOFFFileHeader64 *>(FileHeader);
+}
+
+const XCOFFSectionHeader32 *
+XCOFFObjectFile::sectionHeaderTable32() const {
+ assert(!is64Bit() && "32-bit interface called on 64-bit object file.");
+ return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable);
+}
+
+const XCOFFSectionHeader64 *
+XCOFFObjectFile::sectionHeaderTable64() const {
+ assert(is64Bit() && "64-bit interface called on a 32-bit object file.");
+ return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable);
+}
+
+void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
+ const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
+ SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1;
+#ifndef NDEBUG
+ // This function is used by basic_symbol_iterator, which allows to
+ // point to the end-of-symbol-table address.
+ if (reinterpret_cast<uintptr_t>(SymEntPtr) != getEndOfSymbolTableAddress())
+ checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(SymEntPtr));
+#endif
+ Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr);
+}
+
+Expected<StringRef>
+XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const {
+ // The byte offset is relative to the start of the string table.
+ // A byte offset value of 0 is a null or zero-length symbol
+ // name. A byte offset in the range 1 to 3 (inclusive) points into the length
+ // field; as a soft-error recovery mechanism, we treat such cases as having an
+ // offset of 0.
+ if (Offset < 4)
+ return StringRef(nullptr, 0);
+
+ if (StringTable.Data != nullptr && StringTable.Size > Offset)
+ return (StringTable.Data + Offset);
+
+ return make_error<GenericBinaryError>("Bad offset for string table entry",
+ object_error::parse_failed);
+}
+
+Expected<StringRef>
+XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const {
+ if (CFileEntPtr->NameInStrTbl.Magic !=
+ XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
+ return generateXCOFFFixedNameStringRef(CFileEntPtr->Name);
+ return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset);
+}
+
+Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
+ const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
+
+ // A storage class value with the high-order bit on indicates that the name is
+ // a symbolic debugger stabstring.
+ if (SymEntPtr->StorageClass & 0x80)
+ return StringRef("Unimplemented Debug Name");
+
+ if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
+ return generateXCOFFFixedNameStringRef(SymEntPtr->SymbolName);
+
+ return getStringTableEntry(SymEntPtr->NameInStrTbl.Offset);
+}
+
+Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
+ assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
+ return toSymbolEntry(Symb)->Value;
+}
+
+uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
+ assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
+ return toSymbolEntry(Symb)->Value;
+}
+
+uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
+ uint64_t Result = 0;
+ llvm_unreachable("Not yet implemented!");
+ return Result;
+}
+
+Expected<SymbolRef::Type>
+XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
+ llvm_unreachable("Not yet implemented!");
+ return SymbolRef::ST_Other;
+}
+
+Expected<section_iterator>
+XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
+ const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
+ int16_t SectNum = SymEntPtr->SectionNumber;
+
+ if (isReservedSectionNumber(SectNum))
+ return section_end();
+
+ Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum);
+ if (!ExpSec)
+ return ExpSec.takeError();
+
+ return section_iterator(SectionRef(ExpSec.get(), this));
+}
+
+void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
+ const char *Ptr = reinterpret_cast<const char *>(Sec.p);
+ Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize());
+}
+
+Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
+ return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));
+}
+
+uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
+ // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
+ // with MSVC.
+ if (is64Bit())
+ return toSection64(Sec)->VirtualAddress;
+
+ return toSection32(Sec)->VirtualAddress;
+}
+
+uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const {
+ // Section numbers in XCOFF are numbered beginning at 1. A section number of
+ // zero is used to indicate that a symbol is being imported or is undefined.
+ if (is64Bit())
+ return toSection64(Sec) - sectionHeaderTable64() + 1;
+ else
+ return toSection32(Sec) - sectionHeaderTable32() + 1;
+}
+
+uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const {
+ // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t
+ // with MSVC.
+ if (is64Bit())
+ return toSection64(Sec)->SectionSize;
+
+ return toSection32(Sec)->SectionSize;
+}
+
+Expected<ArrayRef<uint8_t>>
+XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const {
+ if (isSectionVirtual(Sec))
+ return ArrayRef<uint8_t>();
+
+ uint64_t OffsetToRaw;
+ if (is64Bit())
+ OffsetToRaw = toSection64(Sec)->FileOffsetToRawData;
+ else
+ OffsetToRaw = toSection32(Sec)->FileOffsetToRawData;
+
+ const uint8_t * ContentStart = base() + OffsetToRaw;
+ uint64_t SectionSize = getSectionSize(Sec);
if (checkOffset(Data, reinterpret_cast<uintptr_t>(ContentStart), SectionSize))
- return make_error<BinaryError>();
-
- return makeArrayRef(ContentStart,SectionSize);
-}
-
-uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
- uint64_t Result = 0;
- llvm_unreachable("Not yet implemented!");
- return Result;
-}
-
-bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
- bool Result = false;
- llvm_unreachable("Not yet implemented!");
- return Result;
-}
-
-bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
- return getSectionFlags(Sec) & XCOFF::STYP_TEXT;
-}
-
-bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
- uint32_t Flags = getSectionFlags(Sec);
- return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
-}
-
-bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
- uint32_t Flags = getSectionFlags(Sec);
- return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
-}
-
-bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
- return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0
- : toSection32(Sec)->FileOffsetToRawData == 0;
-}
-
-relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);
- auto RelocationsOrErr = relocations(*SectionEntPtr);
- if (Error E = RelocationsOrErr.takeError())
- return relocation_iterator(RelocationRef());
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());
- return relocation_iterator(RelocationRef(Ret, this));
-}
-
-relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);
- auto RelocationsOrErr = relocations(*SectionEntPtr);
- if (Error E = RelocationsOrErr.takeError())
- return relocation_iterator(RelocationRef());
- DataRefImpl Ret;
- Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());
- return relocation_iterator(RelocationRef(Ret, this));
-}
-
-void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
- Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1);
-}
-
-uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
- const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32();
- const uint32_t RelocAddress = Reloc->VirtualAddress;
- const uint16_t NumberOfSections = getNumberOfSections();
- for (uint16_t i = 0; i < NumberOfSections; ++i) {
- // Find which section this relocation is belonging to, and get the
- // relocation offset relative to the start of the section.
- if (Sec32->VirtualAddress <= RelocAddress &&
- RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) {
- return RelocAddress - Sec32->VirtualAddress;
- }
- ++Sec32;
- }
- return InvalidRelocOffset;
-}
-
-symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
- const uint32_t Index = Reloc->SymbolIndex;
-
- if (Index >= getLogicalNumberOfSymbolTableEntries32())
- return symbol_end();
-
- DataRefImpl SymDRI;
- SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index);
- return symbol_iterator(SymbolRef(SymDRI, this));
-}
-
-uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- return viewAs<XCOFFRelocation32>(Rel.p)->Type;
-}
-
-void XCOFFObjectFile::getRelocationTypeName(
- DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
- StringRef Res = XCOFF::getRelocationTypeString(Reloc->Type);
- Result.append(Res.begin(), Res.end());
-}
-
-Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
- uint32_t Result = 0;
- llvm_unreachable("Not yet implemented!");
- return Result;
-}
-
-basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- DataRefImpl SymDRI;
- SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr);
- return basic_symbol_iterator(SymbolRef(SymDRI, this));
-}
-
-basic_symbol_iterator XCOFFObjectFile::symbol_end() const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- DataRefImpl SymDRI;
- SymDRI.p = reinterpret_cast<uintptr_t>(
- SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32());
- return basic_symbol_iterator(SymbolRef(SymDRI, this));
-}
-
-section_iterator XCOFFObjectFile::section_begin() const {
- DataRefImpl DRI;
- DRI.p = getSectionHeaderTableAddress();
- return section_iterator(SectionRef(DRI, this));
-}
-
-section_iterator XCOFFObjectFile::section_end() const {
- DataRefImpl DRI;
- DRI.p = getWithOffset(getSectionHeaderTableAddress(),
- getNumberOfSections() * getSectionHeaderSize());
- return section_iterator(SectionRef(DRI, this));
-}
-
-uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }
-
-StringRef XCOFFObjectFile::getFileFormatName() const {
- return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";
-}
-
-Triple::ArchType XCOFFObjectFile::getArch() const {
- return is64Bit() ? Triple::ppc64 : Triple::ppc;
-}
-
-SubtargetFeatures XCOFFObjectFile::getFeatures() const {
- return SubtargetFeatures();
-}
-
-bool XCOFFObjectFile::isRelocatableObject() const {
- if (is64Bit())
- report_fatal_error("64-bit support not implemented yet");
- return !(fileHeader32()->Flags & NoRelMask);
-}
-
-Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {
- // TODO FIXME Should get from auxiliary_header->o_entry when support for the
- // auxiliary_header is added.
- return 0;
-}
-
-size_t XCOFFObjectFile::getFileHeaderSize() const {
- return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);
-}
-
-size_t XCOFFObjectFile::getSectionHeaderSize() const {
- return is64Bit() ? sizeof(XCOFFSectionHeader64) :
- sizeof(XCOFFSectionHeader32);
-}
-
-bool XCOFFObjectFile::is64Bit() const {
- return Binary::ID_XCOFF64 == getType();
-}
-
-uint16_t XCOFFObjectFile::getMagic() const {
- return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;
-}
-
-Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {
- if (Num <= 0 || Num > getNumberOfSections())
- return errorCodeToError(object_error::invalid_section_index);
-
- DataRefImpl DRI;
- DRI.p = getWithOffset(getSectionHeaderTableAddress(),
- getSectionHeaderSize() * (Num - 1));
- return DRI;
-}
-
-Expected<StringRef>
-XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const {
- assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
- int16_t SectionNum = SymEntPtr->SectionNumber;
-
- switch (SectionNum) {
- case XCOFF::N_DEBUG:
- return "N_DEBUG";
- case XCOFF::N_ABS:
- return "N_ABS";
- case XCOFF::N_UNDEF:
- return "N_UNDEF";
- default:
- Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum);
- if (SecRef)
- return generateXCOFFFixedNameStringRef(
- getSectionNameInternal(SecRef.get()));
- return SecRef.takeError();
- }
-}
-
-bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {
- return (SectionNumber <= 0 && SectionNumber >= -2);
-}
-
-uint16_t XCOFFObjectFile::getNumberOfSections() const {
- return is64Bit() ? fileHeader64()->NumberOfSections
- : fileHeader32()->NumberOfSections;
-}
-
-int32_t XCOFFObjectFile::getTimeStamp() const {
- return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;
-}
-
-uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
- return is64Bit() ? fileHeader64()->AuxHeaderSize
- : fileHeader32()->AuxHeaderSize;
-}
-
-uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {
- return fileHeader32()->SymbolTableOffset;
-}
-
-int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const {
- // As far as symbol table size is concerned, if this field is negative it is
- // to be treated as a 0. However since this field is also used for printing we
- // don't want to truncate any negative values.
- return fileHeader32()->NumberOfSymTableEntries;
-}
-
-uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {
- return (fileHeader32()->NumberOfSymTableEntries >= 0
- ? fileHeader32()->NumberOfSymTableEntries
- : 0);
-}
-
-uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {
- return fileHeader64()->SymbolTableOffset;
-}
-
-uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
- return fileHeader64()->NumberOfSymTableEntries;
-}
-
-uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {
- uint32_t NumberOfSymTableEntries =
- is64Bit() ? getNumberOfSymbolTableEntries64()
- : getLogicalNumberOfSymbolTableEntries32();
- return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),
- XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);
-}
-
-void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const {
- if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr))
- report_fatal_error("Symbol table entry is outside of symbol table.");
-
- if (SymbolEntPtr >= getEndOfSymbolTableAddress())
- report_fatal_error("Symbol table entry is outside of symbol table.");
-
- ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) -
- reinterpret_cast<const char *>(SymbolTblPtr);
-
- if (Offset % XCOFF::SymbolTableEntrySize != 0)
- report_fatal_error(
- "Symbol table entry position is not valid inside of symbol table.");
-}
-
-uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {
- return (reinterpret_cast<const char *>(SymbolEntPtr) -
- reinterpret_cast<const char *>(SymbolTblPtr)) /
- XCOFF::SymbolTableEntrySize;
-}
-
-Expected<StringRef>
-XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const {
- if (is64Bit())
- report_fatal_error("64-bit symbol table support not implemented yet.");
-
- if (Index >= getLogicalNumberOfSymbolTableEntries32())
- return errorCodeToError(object_error::invalid_symbol_index);
-
- DataRefImpl SymDRI;
- SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index);
- return getSymbolName(SymDRI);
-}
-
-uint16_t XCOFFObjectFile::getFlags() const {
- return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
-}
-
-const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {
- return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;
-}
-
-uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {
- return reinterpret_cast<uintptr_t>(SectionHeaderTable);
-}
-
-int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {
- return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;
-}
-
-XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)
- : ObjectFile(Type, Object) {
- assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64);
-}
-
-ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {
- assert(is64Bit() && "64-bit interface called for non 64-bit file.");
- const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();
- return ArrayRef<XCOFFSectionHeader64>(TablePtr,
- TablePtr + getNumberOfSections());
-}
-
-ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
- assert(!is64Bit() && "32-bit interface called for non 32-bit file.");
- const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32();
- return ArrayRef<XCOFFSectionHeader32>(TablePtr,
- TablePtr + getNumberOfSections());
-}
-
-// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO
-// section header contains the actual count of relocation entries in the s_paddr
-// field. STYP_OVRFLO headers contain the section index of their corresponding
-// sections as their raw "NumberOfRelocations" field value.
-Expected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries(
- const XCOFFSectionHeader32 &Sec) const {
-
- uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1;
-
- if (Sec.NumberOfRelocations < XCOFF::RelocOverflow)
- return Sec.NumberOfRelocations;
- for (const auto &Sec : sections32()) {
- if (Sec.Flags == XCOFF::STYP_OVRFLO &&
- Sec.NumberOfRelocations == SectionIndex)
- return Sec.PhysicalAddress;
- }
- return errorCodeToError(object_error::parse_failed);
-}
-
-Expected<ArrayRef<XCOFFRelocation32>>
-XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const {
- uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),
- Sec.FileOffsetToRelocationInfo);
- auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec);
- if (Error E = NumRelocEntriesOrErr.takeError())
- return std::move(E);
-
- uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();
-
+ return make_error<BinaryError>();
+
+ return makeArrayRef(ContentStart,SectionSize);
+}
+
+uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const {
+ uint64_t Result = 0;
+ llvm_unreachable("Not yet implemented!");
+ return Result;
+}
+
+bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const {
+ bool Result = false;
+ llvm_unreachable("Not yet implemented!");
+ return Result;
+}
+
+bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const {
+ return getSectionFlags(Sec) & XCOFF::STYP_TEXT;
+}
+
+bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const {
+ uint32_t Flags = getSectionFlags(Sec);
+ return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA);
+}
+
+bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const {
+ uint32_t Flags = getSectionFlags(Sec);
+ return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS);
+}
+
+bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const {
+ return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0
+ : toSection32(Sec)->FileOffsetToRawData == 0;
+}
+
+relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);
+ auto RelocationsOrErr = relocations(*SectionEntPtr);
+ if (Error E = RelocationsOrErr.takeError())
+ return relocation_iterator(RelocationRef());
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin());
+ return relocation_iterator(RelocationRef(Ret, this));
+}
+
+relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec);
+ auto RelocationsOrErr = relocations(*SectionEntPtr);
+ if (Error E = RelocationsOrErr.takeError())
+ return relocation_iterator(RelocationRef());
+ DataRefImpl Ret;
+ Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end());
+ return relocation_iterator(RelocationRef(Ret, this));
+}
+
+void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const {
+ Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1);
+}
+
+uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
+ const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32();
+ const uint32_t RelocAddress = Reloc->VirtualAddress;
+ const uint16_t NumberOfSections = getNumberOfSections();
+ for (uint16_t i = 0; i < NumberOfSections; ++i) {
+ // Find which section this relocation is belonging to, and get the
+ // relocation offset relative to the start of the section.
+ if (Sec32->VirtualAddress <= RelocAddress &&
+ RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) {
+ return RelocAddress - Sec32->VirtualAddress;
+ }
+ ++Sec32;
+ }
+ return InvalidRelocOffset;
+}
+
+symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
+ const uint32_t Index = Reloc->SymbolIndex;
+
+ if (Index >= getLogicalNumberOfSymbolTableEntries32())
+ return symbol_end();
+
+ DataRefImpl SymDRI;
+ SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index);
+ return symbol_iterator(SymbolRef(SymDRI, this));
+}
+
+uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ return viewAs<XCOFFRelocation32>(Rel.p)->Type;
+}
+
+void XCOFFObjectFile::getRelocationTypeName(
+ DataRefImpl Rel, SmallVectorImpl<char> &Result) const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p);
+ StringRef Res = XCOFF::getRelocationTypeString(Reloc->Type);
+ Result.append(Res.begin(), Res.end());
+}
+
+Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
+ uint32_t Result = 0;
+ llvm_unreachable("Not yet implemented!");
+ return Result;
+}
+
+basic_symbol_iterator XCOFFObjectFile::symbol_begin() const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ DataRefImpl SymDRI;
+ SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr);
+ return basic_symbol_iterator(SymbolRef(SymDRI, this));
+}
+
+basic_symbol_iterator XCOFFObjectFile::symbol_end() const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ DataRefImpl SymDRI;
+ SymDRI.p = reinterpret_cast<uintptr_t>(
+ SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32());
+ return basic_symbol_iterator(SymbolRef(SymDRI, this));
+}
+
+section_iterator XCOFFObjectFile::section_begin() const {
+ DataRefImpl DRI;
+ DRI.p = getSectionHeaderTableAddress();
+ return section_iterator(SectionRef(DRI, this));
+}
+
+section_iterator XCOFFObjectFile::section_end() const {
+ DataRefImpl DRI;
+ DRI.p = getWithOffset(getSectionHeaderTableAddress(),
+ getNumberOfSections() * getSectionHeaderSize());
+ return section_iterator(SectionRef(DRI, this));
+}
+
+uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; }
+
+StringRef XCOFFObjectFile::getFileFormatName() const {
+ return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000";
+}
+
+Triple::ArchType XCOFFObjectFile::getArch() const {
+ return is64Bit() ? Triple::ppc64 : Triple::ppc;
+}
+
+SubtargetFeatures XCOFFObjectFile::getFeatures() const {
+ return SubtargetFeatures();
+}
+
+bool XCOFFObjectFile::isRelocatableObject() const {
+ if (is64Bit())
+ report_fatal_error("64-bit support not implemented yet");
+ return !(fileHeader32()->Flags & NoRelMask);
+}
+
+Expected<uint64_t> XCOFFObjectFile::getStartAddress() const {
+ // TODO FIXME Should get from auxiliary_header->o_entry when support for the
+ // auxiliary_header is added.
+ return 0;
+}
+
+size_t XCOFFObjectFile::getFileHeaderSize() const {
+ return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32);
+}
+
+size_t XCOFFObjectFile::getSectionHeaderSize() const {
+ return is64Bit() ? sizeof(XCOFFSectionHeader64) :
+ sizeof(XCOFFSectionHeader32);
+}
+
+bool XCOFFObjectFile::is64Bit() const {
+ return Binary::ID_XCOFF64 == getType();
+}
+
+uint16_t XCOFFObjectFile::getMagic() const {
+ return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic;
+}
+
+Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const {
+ if (Num <= 0 || Num > getNumberOfSections())
+ return errorCodeToError(object_error::invalid_section_index);
+
+ DataRefImpl DRI;
+ DRI.p = getWithOffset(getSectionHeaderTableAddress(),
+ getSectionHeaderSize() * (Num - 1));
+ return DRI;
+}
+
+Expected<StringRef>
+XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const {
+ assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
+ int16_t SectionNum = SymEntPtr->SectionNumber;
+
+ switch (SectionNum) {
+ case XCOFF::N_DEBUG:
+ return "N_DEBUG";
+ case XCOFF::N_ABS:
+ return "N_ABS";
+ case XCOFF::N_UNDEF:
+ return "N_UNDEF";
+ default:
+ Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum);
+ if (SecRef)
+ return generateXCOFFFixedNameStringRef(
+ getSectionNameInternal(SecRef.get()));
+ return SecRef.takeError();
+ }
+}
+
+bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) {
+ return (SectionNumber <= 0 && SectionNumber >= -2);
+}
+
+uint16_t XCOFFObjectFile::getNumberOfSections() const {
+ return is64Bit() ? fileHeader64()->NumberOfSections
+ : fileHeader32()->NumberOfSections;
+}
+
+int32_t XCOFFObjectFile::getTimeStamp() const {
+ return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp;
+}
+
+uint16_t XCOFFObjectFile::getOptionalHeaderSize() const {
+ return is64Bit() ? fileHeader64()->AuxHeaderSize
+ : fileHeader32()->AuxHeaderSize;
+}
+
+uint32_t XCOFFObjectFile::getSymbolTableOffset32() const {
+ return fileHeader32()->SymbolTableOffset;
+}
+
+int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const {
+ // As far as symbol table size is concerned, if this field is negative it is
+ // to be treated as a 0. However since this field is also used for printing we
+ // don't want to truncate any negative values.
+ return fileHeader32()->NumberOfSymTableEntries;
+}
+
+uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const {
+ return (fileHeader32()->NumberOfSymTableEntries >= 0
+ ? fileHeader32()->NumberOfSymTableEntries
+ : 0);
+}
+
+uint64_t XCOFFObjectFile::getSymbolTableOffset64() const {
+ return fileHeader64()->SymbolTableOffset;
+}
+
+uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
+ return fileHeader64()->NumberOfSymTableEntries;
+}
+
+uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {
+ uint32_t NumberOfSymTableEntries =
+ is64Bit() ? getNumberOfSymbolTableEntries64()
+ : getLogicalNumberOfSymbolTableEntries32();
+ return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),
+ XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);
+}
+
+void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const {
+ if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr))
+ report_fatal_error("Symbol table entry is outside of symbol table.");
+
+ if (SymbolEntPtr >= getEndOfSymbolTableAddress())
+ report_fatal_error("Symbol table entry is outside of symbol table.");
+
+ ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) -
+ reinterpret_cast<const char *>(SymbolTblPtr);
+
+ if (Offset % XCOFF::SymbolTableEntrySize != 0)
+ report_fatal_error(
+ "Symbol table entry position is not valid inside of symbol table.");
+}
+
+uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {
+ return (reinterpret_cast<const char *>(SymbolEntPtr) -
+ reinterpret_cast<const char *>(SymbolTblPtr)) /
+ XCOFF::SymbolTableEntrySize;
+}
+
+Expected<StringRef>
+XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const {
+ if (is64Bit())
+ report_fatal_error("64-bit symbol table support not implemented yet.");
+
+ if (Index >= getLogicalNumberOfSymbolTableEntries32())
+ return errorCodeToError(object_error::invalid_symbol_index);
+
+ DataRefImpl SymDRI;
+ SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index);
+ return getSymbolName(SymDRI);
+}
+
+uint16_t XCOFFObjectFile::getFlags() const {
+ return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
+}
+
+const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const {
+ return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name;
+}
+
+uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const {
+ return reinterpret_cast<uintptr_t>(SectionHeaderTable);
+}
+
+int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const {
+ return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags;
+}
+
+XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object)
+ : ObjectFile(Type, Object) {
+ assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64);
+}
+
+ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const {
+ assert(is64Bit() && "64-bit interface called for non 64-bit file.");
+ const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64();
+ return ArrayRef<XCOFFSectionHeader64>(TablePtr,
+ TablePtr + getNumberOfSections());
+}
+
+ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
+ assert(!is64Bit() && "32-bit interface called for non 32-bit file.");
+ const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32();
+ return ArrayRef<XCOFFSectionHeader32>(TablePtr,
+ TablePtr + getNumberOfSections());
+}
+
+// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO
+// section header contains the actual count of relocation entries in the s_paddr
+// field. STYP_OVRFLO headers contain the section index of their corresponding
+// sections as their raw "NumberOfRelocations" field value.
+Expected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries(
+ const XCOFFSectionHeader32 &Sec) const {
+
+ uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1;
+
+ if (Sec.NumberOfRelocations < XCOFF::RelocOverflow)
+ return Sec.NumberOfRelocations;
+ for (const auto &Sec : sections32()) {
+ if (Sec.Flags == XCOFF::STYP_OVRFLO &&
+ Sec.NumberOfRelocations == SectionIndex)
+ return Sec.PhysicalAddress;
+ }
+ return errorCodeToError(object_error::parse_failed);
+}
+
+Expected<ArrayRef<XCOFFRelocation32>>
+XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const {
+ uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),
+ Sec.FileOffsetToRelocationInfo);
+ auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec);
+ if (Error E = NumRelocEntriesOrErr.takeError())
+ return std::move(E);
+
+ uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();
+
static_assert(
sizeof(XCOFFRelocation32) == XCOFF::RelocationSerializationSize32, "");
- auto RelocationOrErr =
- getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr),
- NumRelocEntries * sizeof(XCOFFRelocation32));
- if (Error E = RelocationOrErr.takeError())
- return std::move(E);
-
- const XCOFFRelocation32 *StartReloc = RelocationOrErr.get();
-
- return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries);
-}
-
-Expected<XCOFFStringTable>
-XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
- // If there is a string table, then the buffer must contain at least 4 bytes
- // for the string table's size. Not having a string table is not an error.
- if (Error E = Binary::checkOffset(
- Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) {
- consumeError(std::move(E));
- return XCOFFStringTable{0, nullptr};
- }
-
- // Read the size out of the buffer.
- uint32_t Size = support::endian::read32be(Obj->base() + Offset);
-
- // If the size is less then 4, then the string table is just a size and no
- // string data.
- if (Size <= 4)
- return XCOFFStringTable{4, nullptr};
-
- auto StringTableOrErr =
- getObject<char>(Obj->Data, Obj->base() + Offset, Size);
- if (Error E = StringTableOrErr.takeError())
- return std::move(E);
-
- const char *StringTablePtr = StringTableOrErr.get();
- if (StringTablePtr[Size - 1] != '\0')
- return errorCodeToError(object_error::string_table_non_null_end);
-
- return XCOFFStringTable{Size, StringTablePtr};
-}
-
-Expected<std::unique_ptr<XCOFFObjectFile>>
-XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
- // Can't use std::make_unique because of the private constructor.
- std::unique_ptr<XCOFFObjectFile> Obj;
- Obj.reset(new XCOFFObjectFile(Type, MBR));
-
- uint64_t CurOffset = 0;
- const auto *Base = Obj->base();
- MemoryBufferRef Data = Obj->Data;
-
- // Parse file header.
- auto FileHeaderOrErr =
- getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize());
- if (Error E = FileHeaderOrErr.takeError())
- return std::move(E);
- Obj->FileHeader = FileHeaderOrErr.get();
-
- CurOffset += Obj->getFileHeaderSize();
- // TODO FIXME we don't have support for an optional header yet, so just skip
- // past it.
- CurOffset += Obj->getOptionalHeaderSize();
-
- // Parse the section header table if it is present.
- if (Obj->getNumberOfSections()) {
- auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset,
- Obj->getNumberOfSections() *
- Obj->getSectionHeaderSize());
- if (Error E = SecHeadersOrErr.takeError())
- return std::move(E);
- Obj->SectionHeaderTable = SecHeadersOrErr.get();
- }
-
- // 64-bit object supports only file header and section headers for now.
- if (Obj->is64Bit())
- return std::move(Obj);
-
- // If there is no symbol table we are done parsing the memory buffer.
- if (Obj->getLogicalNumberOfSymbolTableEntries32() == 0)
- return std::move(Obj);
-
- // Parse symbol table.
- CurOffset = Obj->fileHeader32()->SymbolTableOffset;
- uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) *
- Obj->getLogicalNumberOfSymbolTableEntries32();
- auto SymTableOrErr =
- getObject<XCOFFSymbolEntry>(Data, Base + CurOffset, SymbolTableSize);
- if (Error E = SymTableOrErr.takeError())
- return std::move(E);
- Obj->SymbolTblPtr = SymTableOrErr.get();
- CurOffset += SymbolTableSize;
-
- // Parse String table.
- Expected<XCOFFStringTable> StringTableOrErr =
- parseStringTable(Obj.get(), CurOffset);
- if (Error E = StringTableOrErr.takeError())
- return std::move(E);
- Obj->StringTable = StringTableOrErr.get();
-
- return std::move(Obj);
-}
-
-Expected<std::unique_ptr<ObjectFile>>
-ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
- unsigned FileType) {
- return XCOFFObjectFile::create(FileType, MemBufRef);
-}
-
-XCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const {
- return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass;
-}
-
-uint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const {
- return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries;
-}
-
-// TODO: The function needs to return an error if there is no csect auxiliary
-// entry.
-const XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const {
- assert(!OwningObjectPtr->is64Bit() &&
- "32-bit interface called on 64-bit object file.");
- assert(hasCsectAuxEnt() && "No Csect Auxiliary Entry is found.");
-
- // In XCOFF32, the csect auxilliary entry is always the last auxiliary
- // entry for the symbol.
- uintptr_t AuxAddr = getWithOffset(
- SymEntDataRef.p, XCOFF::SymbolTableEntrySize * getNumberOfAuxEntries());
-
-#ifndef NDEBUG
- OwningObjectPtr->checkSymbolEntryPointer(AuxAddr);
-#endif
-
- return reinterpret_cast<const XCOFFCsectAuxEnt32 *>(AuxAddr);
-}
-
-uint16_t XCOFFSymbolRef::getType() const {
- return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType;
-}
-
-int16_t XCOFFSymbolRef::getSectionNumber() const {
- return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber;
-}
-
-// TODO: The function name needs to be changed to express the purpose of the
-// function.
-bool XCOFFSymbolRef::hasCsectAuxEnt() const {
- XCOFF::StorageClass SC = getStorageClass();
- return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT ||
- SC == XCOFF::C_HIDEXT);
-}
-
-bool XCOFFSymbolRef::isFunction() const {
- if (OwningObjectPtr->is64Bit())
- report_fatal_error("64-bit support is unimplemented yet.");
-
- if (getType() & FunctionSym)
- return true;
-
- if (!hasCsectAuxEnt())
- return false;
-
- const XCOFFCsectAuxEnt32 *CsectAuxEnt = getXCOFFCsectAuxEnt32();
-
- // A function definition should be a label definition.
- if ((CsectAuxEnt->SymbolAlignmentAndType & SymTypeMask) != XCOFF::XTY_LD)
- return false;
-
- if (CsectAuxEnt->StorageMappingClass != XCOFF::XMC_PR)
- return false;
-
- int16_t SectNum = getSectionNumber();
- Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum);
- if (!SI)
- return false;
-
- return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT);
-}
-
-// Explictly instantiate template classes.
-template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
-template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
-
+ auto RelocationOrErr =
+ getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr),
+ NumRelocEntries * sizeof(XCOFFRelocation32));
+ if (Error E = RelocationOrErr.takeError())
+ return std::move(E);
+
+ const XCOFFRelocation32 *StartReloc = RelocationOrErr.get();
+
+ return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries);
+}
+
+Expected<XCOFFStringTable>
+XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
+ // If there is a string table, then the buffer must contain at least 4 bytes
+ // for the string table's size. Not having a string table is not an error.
+ if (Error E = Binary::checkOffset(
+ Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) {
+ consumeError(std::move(E));
+ return XCOFFStringTable{0, nullptr};
+ }
+
+ // Read the size out of the buffer.
+ uint32_t Size = support::endian::read32be(Obj->base() + Offset);
+
+ // If the size is less then 4, then the string table is just a size and no
+ // string data.
+ if (Size <= 4)
+ return XCOFFStringTable{4, nullptr};
+
+ auto StringTableOrErr =
+ getObject<char>(Obj->Data, Obj->base() + Offset, Size);
+ if (Error E = StringTableOrErr.takeError())
+ return std::move(E);
+
+ const char *StringTablePtr = StringTableOrErr.get();
+ if (StringTablePtr[Size - 1] != '\0')
+ return errorCodeToError(object_error::string_table_non_null_end);
+
+ return XCOFFStringTable{Size, StringTablePtr};
+}
+
+Expected<std::unique_ptr<XCOFFObjectFile>>
+XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
+ // Can't use std::make_unique because of the private constructor.
+ std::unique_ptr<XCOFFObjectFile> Obj;
+ Obj.reset(new XCOFFObjectFile(Type, MBR));
+
+ uint64_t CurOffset = 0;
+ const auto *Base = Obj->base();
+ MemoryBufferRef Data = Obj->Data;
+
+ // Parse file header.
+ auto FileHeaderOrErr =
+ getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize());
+ if (Error E = FileHeaderOrErr.takeError())
+ return std::move(E);
+ Obj->FileHeader = FileHeaderOrErr.get();
+
+ CurOffset += Obj->getFileHeaderSize();
+ // TODO FIXME we don't have support for an optional header yet, so just skip
+ // past it.
+ CurOffset += Obj->getOptionalHeaderSize();
+
+ // Parse the section header table if it is present.
+ if (Obj->getNumberOfSections()) {
+ auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset,
+ Obj->getNumberOfSections() *
+ Obj->getSectionHeaderSize());
+ if (Error E = SecHeadersOrErr.takeError())
+ return std::move(E);
+ Obj->SectionHeaderTable = SecHeadersOrErr.get();
+ }
+
+ // 64-bit object supports only file header and section headers for now.
+ if (Obj->is64Bit())
+ return std::move(Obj);
+
+ // If there is no symbol table we are done parsing the memory buffer.
+ if (Obj->getLogicalNumberOfSymbolTableEntries32() == 0)
+ return std::move(Obj);
+
+ // Parse symbol table.
+ CurOffset = Obj->fileHeader32()->SymbolTableOffset;
+ uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) *
+ Obj->getLogicalNumberOfSymbolTableEntries32();
+ auto SymTableOrErr =
+ getObject<XCOFFSymbolEntry>(Data, Base + CurOffset, SymbolTableSize);
+ if (Error E = SymTableOrErr.takeError())
+ return std::move(E);
+ Obj->SymbolTblPtr = SymTableOrErr.get();
+ CurOffset += SymbolTableSize;
+
+ // Parse String table.
+ Expected<XCOFFStringTable> StringTableOrErr =
+ parseStringTable(Obj.get(), CurOffset);
+ if (Error E = StringTableOrErr.takeError())
+ return std::move(E);
+ Obj->StringTable = StringTableOrErr.get();
+
+ return std::move(Obj);
+}
+
+Expected<std::unique_ptr<ObjectFile>>
+ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
+ unsigned FileType) {
+ return XCOFFObjectFile::create(FileType, MemBufRef);
+}
+
+XCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const {
+ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass;
+}
+
+uint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const {
+ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries;
+}
+
+// TODO: The function needs to return an error if there is no csect auxiliary
+// entry.
+const XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const {
+ assert(!OwningObjectPtr->is64Bit() &&
+ "32-bit interface called on 64-bit object file.");
+ assert(hasCsectAuxEnt() && "No Csect Auxiliary Entry is found.");
+
+ // In XCOFF32, the csect auxilliary entry is always the last auxiliary
+ // entry for the symbol.
+ uintptr_t AuxAddr = getWithOffset(
+ SymEntDataRef.p, XCOFF::SymbolTableEntrySize * getNumberOfAuxEntries());
+
+#ifndef NDEBUG
+ OwningObjectPtr->checkSymbolEntryPointer(AuxAddr);
+#endif
+
+ return reinterpret_cast<const XCOFFCsectAuxEnt32 *>(AuxAddr);
+}
+
+uint16_t XCOFFSymbolRef::getType() const {
+ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType;
+}
+
+int16_t XCOFFSymbolRef::getSectionNumber() const {
+ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber;
+}
+
+// TODO: The function name needs to be changed to express the purpose of the
+// function.
+bool XCOFFSymbolRef::hasCsectAuxEnt() const {
+ XCOFF::StorageClass SC = getStorageClass();
+ return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT ||
+ SC == XCOFF::C_HIDEXT);
+}
+
+bool XCOFFSymbolRef::isFunction() const {
+ if (OwningObjectPtr->is64Bit())
+ report_fatal_error("64-bit support is unimplemented yet.");
+
+ if (getType() & FunctionSym)
+ return true;
+
+ if (!hasCsectAuxEnt())
+ return false;
+
+ const XCOFFCsectAuxEnt32 *CsectAuxEnt = getXCOFFCsectAuxEnt32();
+
+ // A function definition should be a label definition.
+ if ((CsectAuxEnt->SymbolAlignmentAndType & SymTypeMask) != XCOFF::XTY_LD)
+ return false;
+
+ if (CsectAuxEnt->StorageMappingClass != XCOFF::XMC_PR)
+ return false;
+
+ int16_t SectNum = getSectionNumber();
+ Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum);
+ if (!SI)
+ return false;
+
+ return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT);
+}
+
+// Explictly instantiate template classes.
+template struct XCOFFSectionHeader<XCOFFSectionHeader32>;
+template struct XCOFFSectionHeader<XCOFFSectionHeader64>;
+
bool doesXCOFFTracebackTableBegin(ArrayRef<uint8_t> Bytes) {
if (Bytes.size() < 4)
return false;
@@ -1131,5 +1131,5 @@ bool XCOFFTracebackTable::hasParmsOnStack() const {
#undef GETBITWITHMASK
#undef GETBITWITHMASKSHIFT
-} // namespace object
-} // namespace llvm
+} // namespace object
+} // namespace llvm
diff --git a/contrib/libs/llvm12/lib/Object/ya.make b/contrib/libs/llvm12/lib/Object/ya.make
index 295047e90e..3d746aaa36 100644
--- a/contrib/libs/llvm12/lib/Object/ya.make
+++ b/contrib/libs/llvm12/lib/Object/ya.make
@@ -1,17 +1,17 @@
-# Generated by devtools/yamaker.
-
-LIBRARY()
-
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
OWNER(
orivej
g:cpp-contrib
)
-
+
LICENSE(Apache-2.0 WITH LLVM-exception)
LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
-PEERDIR(
+PEERDIR(
contrib/libs/llvm12
contrib/libs/llvm12/include
contrib/libs/llvm12/lib/BinaryFormat
@@ -21,46 +21,46 @@ PEERDIR(
contrib/libs/llvm12/lib/MC/MCParser
contrib/libs/llvm12/lib/Support
contrib/libs/llvm12/lib/TextAPI/MachO
-)
-
+)
+
ADDINCL(
contrib/libs/llvm12/lib/Object
)
-
-NO_COMPILER_WARNINGS()
-
-NO_UTIL()
-
-SRCS(
- Archive.cpp
- ArchiveWriter.cpp
- Binary.cpp
- COFFImportFile.cpp
- COFFModuleDefinition.cpp
- COFFObjectFile.cpp
- Decompressor.cpp
- ELF.cpp
- ELFObjectFile.cpp
- Error.cpp
- IRObjectFile.cpp
- IRSymtab.cpp
- MachOObjectFile.cpp
- MachOUniversal.cpp
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ Archive.cpp
+ ArchiveWriter.cpp
+ Binary.cpp
+ COFFImportFile.cpp
+ COFFModuleDefinition.cpp
+ COFFObjectFile.cpp
+ Decompressor.cpp
+ ELF.cpp
+ ELFObjectFile.cpp
+ Error.cpp
+ IRObjectFile.cpp
+ IRSymtab.cpp
+ MachOObjectFile.cpp
+ MachOUniversal.cpp
MachOUniversalWriter.cpp
- Minidump.cpp
- ModuleSymbolTable.cpp
- Object.cpp
- ObjectFile.cpp
- RecordStreamer.cpp
- RelocationResolver.cpp
- SymbolSize.cpp
- SymbolicFile.cpp
- TapiFile.cpp
- TapiUniversal.cpp
- WasmObjectFile.cpp
- WindowsMachineFlag.cpp
- WindowsResource.cpp
- XCOFFObjectFile.cpp
-)
-
-END()
+ Minidump.cpp
+ ModuleSymbolTable.cpp
+ Object.cpp
+ ObjectFile.cpp
+ RecordStreamer.cpp
+ RelocationResolver.cpp
+ SymbolSize.cpp
+ SymbolicFile.cpp
+ TapiFile.cpp
+ TapiUniversal.cpp
+ WasmObjectFile.cpp
+ WindowsMachineFlag.cpp
+ WindowsResource.cpp
+ XCOFFObjectFile.cpp
+)
+
+END()