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