aboutsummaryrefslogtreecommitdiff
path: root/lib/Object
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-10-23 17:51:42 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-10-23 17:51:42 +0000
commit1d5ae1026e831016fc29fd927877c86af904481f (patch)
tree2cdfd12620fcfa5d9e4a0389f85368e8e36f63f9 /lib/Object
parente6d1592492a3a379186bfb02bd0f4eda0669c0d5 (diff)
Notes
Diffstat (limited to 'lib/Object')
-rw-r--r--lib/Object/Archive.cpp6
-rw-r--r--lib/Object/ArchiveWriter.cpp35
-rw-r--r--lib/Object/Binary.cpp3
-rw-r--r--lib/Object/COFFObjectFile.cpp198
-rw-r--r--lib/Object/Decompressor.cpp15
-rw-r--r--lib/Object/ELF.cpp2
-rw-r--r--lib/Object/ELFObjectFile.cpp38
-rw-r--r--lib/Object/MachOObjectFile.cpp48
-rw-r--r--lib/Object/MachOUniversal.cpp38
-rw-r--r--lib/Object/Minidump.cpp46
-rw-r--r--lib/Object/Object.cpp10
-rw-r--r--lib/Object/ObjectFile.cpp11
-rw-r--r--lib/Object/RelocationResolver.cpp67
-rw-r--r--lib/Object/SymbolicFile.cpp1
-rw-r--r--lib/Object/TapiFile.cpp104
-rw-r--r--lib/Object/TapiUniversal.cpp54
-rw-r--r--lib/Object/WasmObjectFile.cpp13
-rw-r--r--lib/Object/WindowsResource.cpp346
-rw-r--r--lib/Object/XCOFFObjectFile.cpp240
19 files changed, 1059 insertions, 216 deletions
diff --git a/lib/Object/Archive.cpp b/lib/Object/Archive.cpp
index 49e66f46ab3f..148c011d9cd4 100644
--- a/lib/Object/Archive.cpp
+++ b/lib/Object/Archive.cpp
@@ -223,8 +223,8 @@ Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const {
return Name.drop_back(1);
}
-Expected<uint32_t> ArchiveMemberHeader::getSize() const {
- uint32_t Ret;
+Expected<uint64_t> ArchiveMemberHeader::getSize() const {
+ uint64_t Ret;
if (StringRef(ArMemHdr->Size,
sizeof(ArMemHdr->Size)).rtrim(" ").getAsInteger(10, Ret)) {
std::string Buf;
@@ -550,7 +550,7 @@ Archive::Archive(MemoryBufferRef Source, Error &Err)
} else if (Buffer.startswith(Magic)) {
IsThin = false;
} else {
- Err = make_error<GenericBinaryError>("File too small to be an archive",
+ Err = make_error<GenericBinaryError>("file too small to be an archive",
object_error::invalid_file_type);
return;
}
diff --git a/lib/Object/ArchiveWriter.cpp b/lib/Object/ArchiveWriter.cpp
index 228f6b40c5ec..5234b0e18233 100644
--- a/lib/Object/ArchiveWriter.cpp
+++ b/lib/Object/ArchiveWriter.cpp
@@ -16,8 +16,10 @@
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/Error.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Object/SymbolicFile.h"
+#include "llvm/Support/Alignment.h"
#include "llvm/Support/EndianStream.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/ErrorHandling.h"
@@ -147,7 +149,7 @@ static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
static void printRestOfMemberHeader(
raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
- unsigned UID, unsigned GID, unsigned Perms, unsigned Size) {
+ unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
printWithSpacePadding(Out, sys::toTimeT(ModTime), 12);
// The format has only 6 chars for uid and gid. Truncate if the provided
@@ -164,7 +166,7 @@ static void
printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
const sys::TimePoint<std::chrono::seconds> &ModTime,
unsigned UID, unsigned GID, unsigned Perms,
- unsigned Size) {
+ uint64_t Size) {
printWithSpacePadding(Out, Twine(Name) + "/", 16);
printRestOfMemberHeader(Out, ModTime, UID, GID, Perms, Size);
}
@@ -172,11 +174,10 @@ printGNUSmallMemberHeader(raw_ostream &Out, StringRef Name,
static void
printBSDMemberHeader(raw_ostream &Out, uint64_t Pos, StringRef Name,
const sys::TimePoint<std::chrono::seconds> &ModTime,
- unsigned UID, unsigned GID, unsigned Perms,
- unsigned Size) {
+ unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
uint64_t PosAfterHeader = Pos + 60 + Name.size();
// Pad so that even 64 bit object files are aligned.
- unsigned Pad = OffsetToAlignment(PosAfterHeader, 8);
+ unsigned Pad = offsetToAlignment(PosAfterHeader, Align(8));
unsigned NameWithPadding = Name.size() + Pad;
printWithSpacePadding(Out, Twine("#1/") + Twine(NameWithPadding), 16);
printRestOfMemberHeader(Out, ModTime, UID, GID, Perms,
@@ -208,7 +209,7 @@ 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) {
+ sys::TimePoint<std::chrono::seconds> ModTime, uint64_t Size) {
if (isBSDLike(Kind))
return printBSDMemberHeader(Out, Pos, M.MemberName, ModTime, M.UID, M.GID,
M.Perms, Size);
@@ -243,7 +244,7 @@ struct MemberData {
static MemberData computeStringTable(StringRef Names) {
unsigned Size = Names.size();
- unsigned Pad = OffsetToAlignment(Size, 2);
+ unsigned Pad = offsetToAlignment(Size, Align(2));
std::string Header;
raw_string_ostream Out(Header);
printWithSpacePadding(Out, "//", 48);
@@ -307,8 +308,8 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
// uniformly.
// We do this for all bsd formats because it simplifies aligning members.
- unsigned Alignment = isBSDLike(Kind) ? 8 : 2;
- unsigned Pad = OffsetToAlignment(Size, Alignment);
+ const Align Alignment(isBSDLike(Kind) ? 8 : 2);
+ unsigned Pad = offsetToAlignment(Size, Alignment);
Size += Pad;
if (isBSDLike(Kind)) {
@@ -464,8 +465,9 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
// uniformly. This matches the behaviour with cctools and ensures that ld64
// is happy with archives that we generate.
unsigned MemberPadding =
- isDarwin(Kind) ? OffsetToAlignment(Data.size(), 8) : 0;
- unsigned TailPadding = OffsetToAlignment(Data.size() + MemberPadding, 2);
+ isDarwin(Kind) ? offsetToAlignment(Data.size(), Align(8)) : 0;
+ unsigned TailPadding =
+ offsetToAlignment(Data.size() + MemberPadding, Align(2));
StringRef Padding = StringRef(PaddingData, MemberPadding + TailPadding);
sys::TimePoint<std::chrono::seconds> ModTime;
@@ -474,8 +476,17 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
ModTime = sys::toTimePoint(FilenameCount[M.MemberName]++);
else
ModTime = M.ModTime;
+
+ uint64_t Size = Buf.getBufferSize() + MemberPadding;
+ if (Size > object::Archive::MaxMemberSize) {
+ std::string StringMsg =
+ "File " + M.MemberName.str() + " exceeds size limit";
+ return make_error<object::GenericBinaryError>(
+ std::move(StringMsg), object::object_error::parse_failed);
+ }
+
printMemberHeader(Out, Pos, StringTable, MemberNames, Kind, Thin, M,
- ModTime, Buf.getBufferSize() + MemberPadding);
+ ModTime, Size);
Out.flush();
Expected<std::vector<unsigned>> Symbols =
diff --git a/lib/Object/Binary.cpp b/lib/Object/Binary.cpp
index a953c1d8cb80..944d2bc1bca7 100644
--- a/lib/Object/Binary.cpp
+++ b/lib/Object/Binary.cpp
@@ -18,6 +18,7 @@
#include "llvm/Object/MachOUniversal.h"
#include "llvm/Object/Minidump.h"
#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/TapiUniversal.h"
#include "llvm/Object/WindowsResource.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
@@ -86,6 +87,8 @@ Expected<std::unique_ptr<Binary>> object::createBinary(MemoryBufferRef Buffer,
return errorCodeToError(object_error::invalid_file_type);
case file_magic::minidump:
return MinidumpFile::create(Buffer);
+ case file_magic::tapi_file:
+ return TapiUniversal::create(Buffer);
}
llvm_unreachable("Unexpected Binary File Type");
}
diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp
index 854664e679df..2c0f6dc2b1e9 100644
--- a/lib/Object/COFFObjectFile.cpp
+++ b/lib/Object/COFFObjectFile.cpp
@@ -937,29 +937,6 @@ iterator_range<base_reloc_iterator> COFFObjectFile::base_relocs() const {
}
std::error_code
-COFFObjectFile::getCOFFHeader(const coff_file_header *&Res) const {
- Res = COFFHeader;
- return std::error_code();
-}
-
-std::error_code
-COFFObjectFile::getCOFFBigObjHeader(const coff_bigobj_file_header *&Res) const {
- Res = COFFBigObjHeader;
- return std::error_code();
-}
-
-std::error_code COFFObjectFile::getPE32Header(const pe32_header *&Res) const {
- Res = PE32Header;
- return std::error_code();
-}
-
-std::error_code
-COFFObjectFile::getPE32PlusHeader(const pe32plus_header *&Res) const {
- Res = PE32PlusHeader;
- return std::error_code();
-}
-
-std::error_code
COFFObjectFile::getDataDirectory(uint32_t Index,
const data_directory *&Res) const {
// Error if there's no data directory or the index is out of range.
@@ -994,11 +971,12 @@ std::error_code COFFObjectFile::getSection(int32_t Index,
std::error_code COFFObjectFile::getSection(StringRef SectionName,
const coff_section *&Result) const {
Result = nullptr;
- StringRef SecName;
for (const SectionRef &Section : sections()) {
- if (std::error_code E = Section.getName(SecName))
- return E;
- if (SecName == SectionName) {
+ auto NameOrErr = Section.getName();
+ if (!NameOrErr)
+ return errorToErrorCode(NameOrErr.takeError());
+
+ if (*NameOrErr == SectionName) {
Result = getCOFFSection(Section);
return std::error_code();
}
@@ -1684,9 +1662,12 @@ std::error_code BaseRelocRef::getRVA(uint32_t &Result) const {
return std::error_code();
}
-#define RETURN_IF_ERROR(E) \
- if (E) \
- return E;
+#define RETURN_IF_ERROR(Expr) \
+ do { \
+ Error E = (Expr); \
+ if (E) \
+ return std::move(E); \
+ } while (0)
Expected<ArrayRef<UTF16>>
ResourceSectionRef::getDirStringAtOffset(uint32_t Offset) {
@@ -1715,11 +1696,168 @@ ResourceSectionRef::getTableAtOffset(uint32_t Offset) {
return *Table;
}
+Expected<const coff_resource_dir_entry &>
+ResourceSectionRef::getTableEntryAtOffset(uint32_t Offset) {
+ const coff_resource_dir_entry *Entry = nullptr;
+
+ BinaryStreamReader Reader(BBS);
+ Reader.setOffset(Offset);
+ RETURN_IF_ERROR(Reader.readObject(Entry));
+ assert(Entry != nullptr);
+ return *Entry;
+}
+
+Expected<const coff_resource_data_entry &>
+ResourceSectionRef::getDataEntryAtOffset(uint32_t Offset) {
+ const coff_resource_data_entry *Entry = nullptr;
+
+ BinaryStreamReader Reader(BBS);
+ Reader.setOffset(Offset);
+ RETURN_IF_ERROR(Reader.readObject(Entry));
+ assert(Entry != nullptr);
+ return *Entry;
+}
+
Expected<const coff_resource_dir_table &>
ResourceSectionRef::getEntrySubDir(const coff_resource_dir_entry &Entry) {
+ assert(Entry.Offset.isSubDir());
return getTableAtOffset(Entry.Offset.value());
}
+Expected<const coff_resource_data_entry &>
+ResourceSectionRef::getEntryData(const coff_resource_dir_entry &Entry) {
+ assert(!Entry.Offset.isSubDir());
+ return getDataEntryAtOffset(Entry.Offset.value());
+}
+
Expected<const coff_resource_dir_table &> ResourceSectionRef::getBaseTable() {
return getTableAtOffset(0);
}
+
+Expected<const coff_resource_dir_entry &>
+ResourceSectionRef::getTableEntry(const coff_resource_dir_table &Table,
+ uint32_t Index) {
+ if (Index >= (uint32_t)(Table.NumberOfNameEntries + Table.NumberOfIDEntries))
+ return createStringError(object_error::parse_failed, "index out of range");
+ const uint8_t *TablePtr = reinterpret_cast<const uint8_t *>(&Table);
+ ptrdiff_t TableOffset = TablePtr - BBS.data().data();
+ return getTableEntryAtOffset(TableOffset + sizeof(Table) +
+ Index * sizeof(coff_resource_dir_entry));
+}
+
+Error ResourceSectionRef::load(const COFFObjectFile *O) {
+ for (const SectionRef &S : O->sections()) {
+ Expected<StringRef> Name = S.getName();
+ if (!Name)
+ return Name.takeError();
+
+ if (*Name == ".rsrc" || *Name == ".rsrc$01")
+ return load(O, S);
+ }
+ return createStringError(object_error::parse_failed,
+ "no resource section found");
+}
+
+Error ResourceSectionRef::load(const COFFObjectFile *O, const SectionRef &S) {
+ Obj = O;
+ Section = S;
+ Expected<StringRef> Contents = Section.getContents();
+ if (!Contents)
+ return Contents.takeError();
+ BBS = BinaryByteStream(*Contents, support::little);
+ const coff_section *COFFSect = Obj->getCOFFSection(Section);
+ ArrayRef<coff_relocation> OrigRelocs = Obj->getRelocations(COFFSect);
+ Relocs.reserve(OrigRelocs.size());
+ for (const coff_relocation &R : OrigRelocs)
+ Relocs.push_back(&R);
+ std::sort(Relocs.begin(), Relocs.end(),
+ [](const coff_relocation *A, const coff_relocation *B) {
+ return A->VirtualAddress < B->VirtualAddress;
+ });
+ return Error::success();
+}
+
+Expected<StringRef>
+ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
+ if (!Obj)
+ return createStringError(object_error::parse_failed, "no object provided");
+
+ // Find a potential relocation at the DataRVA field (first member of
+ // the coff_resource_data_entry struct).
+ const uint8_t *EntryPtr = reinterpret_cast<const uint8_t *>(&Entry);
+ ptrdiff_t EntryOffset = EntryPtr - BBS.data().data();
+ coff_relocation RelocTarget{ulittle32_t(EntryOffset), ulittle32_t(0),
+ ulittle16_t(0)};
+ auto RelocsForOffset =
+ std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,
+ [](const coff_relocation *A, const coff_relocation *B) {
+ return A->VirtualAddress < B->VirtualAddress;
+ });
+
+ if (RelocsForOffset.first != RelocsForOffset.second) {
+ // We found a relocation with the right offset. Check that it does have
+ // the expected type.
+ const coff_relocation &R = **RelocsForOffset.first;
+ uint16_t RVAReloc;
+ switch (Obj->getMachine()) {
+ case COFF::IMAGE_FILE_MACHINE_I386:
+ RVAReloc = COFF::IMAGE_REL_I386_DIR32NB;
+ break;
+ case COFF::IMAGE_FILE_MACHINE_AMD64:
+ RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB;
+ break;
+ case COFF::IMAGE_FILE_MACHINE_ARMNT:
+ RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB;
+ break;
+ case COFF::IMAGE_FILE_MACHINE_ARM64:
+ RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
+ break;
+ default:
+ return createStringError(object_error::parse_failed,
+ "unsupported architecture");
+ }
+ if (R.Type != RVAReloc)
+ return createStringError(object_error::parse_failed,
+ "unexpected relocation type");
+ // Get the relocation's symbol
+ Expected<COFFSymbolRef> Sym = Obj->getSymbol(R.SymbolTableIndex);
+ if (!Sym)
+ return Sym.takeError();
+ const coff_section *Section = nullptr;
+ // And the symbol's section
+ if (std::error_code EC = Obj->getSection(Sym->getSectionNumber(), Section))
+ return errorCodeToError(EC);
+ // Add the initial value of DataRVA to the symbol's offset to find the
+ // data it points at.
+ uint64_t Offset = Entry.DataRVA + Sym->getValue();
+ ArrayRef<uint8_t> Contents;
+ if (Error E = Obj->getSectionContents(Section, Contents))
+ return std::move(E);
+ if (Offset + Entry.DataSize > Contents.size())
+ return createStringError(object_error::parse_failed,
+ "data outside of section");
+ // Return a reference to the data inside the section.
+ return StringRef(reinterpret_cast<const char *>(Contents.data()) + Offset,
+ Entry.DataSize);
+ } else {
+ // Relocatable objects need a relocation for the DataRVA field.
+ if (Obj->isRelocatableObject())
+ return createStringError(object_error::parse_failed,
+ "no relocation found for DataRVA");
+
+ // Locate the section that contains the address that DataRVA points at.
+ uint64_t VA = Entry.DataRVA + Obj->getImageBase();
+ for (const SectionRef &S : Obj->sections()) {
+ if (VA >= S.getAddress() &&
+ VA + Entry.DataSize <= S.getAddress() + S.getSize()) {
+ uint64_t Offset = VA - S.getAddress();
+ Expected<StringRef> Contents = S.getContents();
+ if (!Contents)
+ return Contents.takeError();
+ return Contents->slice(Offset, Offset + Entry.DataSize);
+ }
+ }
+ return createStringError(object_error::parse_failed,
+ "address not found in image");
+ }
+}
diff --git a/lib/Object/Decompressor.cpp b/lib/Object/Decompressor.cpp
index ec15e6f69ada..11efd857d1a1 100644
--- a/lib/Object/Decompressor.cpp
+++ b/lib/Object/Decompressor.cpp
@@ -56,7 +56,7 @@ Error Decompressor::consumeCompressedZLibHeader(bool Is64Bit,
return createError("corrupted compressed section header");
DataExtractor Extractor(SectionData, IsLittleEndian, 0);
- uint32_t Offset = 0;
+ uint64_t Offset = 0;
if (Extractor.getUnsigned(&Offset, Is64Bit ? sizeof(Elf64_Word)
: sizeof(Elf32_Word)) !=
ELFCOMPRESS_ZLIB)
@@ -77,10 +77,15 @@ bool Decompressor::isGnuStyle(StringRef Name) {
}
bool Decompressor::isCompressed(const object::SectionRef &Section) {
- StringRef Name;
- if (Section.getName(Name))
- return false;
- return Section.isCompressed() || isGnuStyle(Name);
+ if (Section.isCompressed())
+ return true;
+
+ Expected<StringRef> SecNameOrErr = Section.getName();
+ if (SecNameOrErr)
+ return isGnuStyle(*SecNameOrErr);
+
+ consumeError(SecNameOrErr.takeError());
+ return false;
}
bool Decompressor::isCompressedELFSection(uint64_t Flags, StringRef Name) {
diff --git a/lib/Object/ELF.cpp b/lib/Object/ELF.cpp
index 8660b1a64bdd..d491288579df 100644
--- a/lib/Object/ELF.cpp
+++ b/lib/Object/ELF.cpp
@@ -255,6 +255,8 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_ADDRSIG);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_DEPENDENT_LIBRARIES);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_SYMPART);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_EHDR);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_PART_PHDR);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
diff --git a/lib/Object/ELFObjectFile.cpp b/lib/Object/ELFObjectFile.cpp
index c7b715793048..bf6ffd6c37b9 100644
--- a/lib/Object/ELFObjectFile.cpp
+++ b/lib/Object/ELFObjectFile.cpp
@@ -43,7 +43,16 @@ const EnumEntry<unsigned> llvm::object::ElfSymbolTypes[NumElfSymbolTypes] = {
{"File", "FILE", ELF::STT_FILE},
{"Common", "COMMON", ELF::STT_COMMON},
{"TLS", "TLS", ELF::STT_TLS},
- {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC}};
+ {"Unknown", "<unknown>: 7", 7},
+ {"Unknown", "<unknown>: 8", 8},
+ {"Unknown", "<unknown>: 9", 9},
+ {"GNU_IFunc", "IFUNC", ELF::STT_GNU_IFUNC},
+ {"OS Specific", "<OS specific>: 11", 11},
+ {"OS Specific", "<OS specific>: 12", 12},
+ {"Proc Specific", "<processor specific>: 13", 13},
+ {"Proc Specific", "<processor specific>: 14", 14},
+ {"Proc Specific", "<processor specific>: 15", 15}
+};
ELFObjectFileBase::ELFObjectFileBase(unsigned int Type, MemoryBufferRef Source)
: ObjectFile(Type, Source) {}
@@ -54,7 +63,7 @@ createPtr(MemoryBufferRef Object) {
auto Ret = ELFObjectFile<ELFT>::create(Object);
if (Error E = Ret.takeError())
return std::move(E);
- return make_unique<ELFObjectFile<ELFT>>(std::move(*Ret));
+ return std::make_unique<ELFObjectFile<ELFT>>(std::move(*Ret));
}
Expected<std::unique_ptr<ObjectFile>>
@@ -194,7 +203,7 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const {
default:
break;
case ARMBuildAttrs::Not_Allowed:
- Features.AddFeature("vfp2d16sp", false);
+ Features.AddFeature("vfp2sp", false);
Features.AddFeature("vfp3d16sp", false);
Features.AddFeature("vfp4d16sp", false);
break;
@@ -347,6 +356,21 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const {
case ARMBuildAttrs::v7E_M:
Triple += "v7em";
break;
+ case ARMBuildAttrs::v8_A:
+ Triple += "v8a";
+ break;
+ case ARMBuildAttrs::v8_R:
+ Triple += "v8r";
+ break;
+ case ARMBuildAttrs::v8_M_Base:
+ Triple += "v8m.base";
+ break;
+ case ARMBuildAttrs::v8_M_Main:
+ Triple += "v8m.main";
+ break;
+ case ARMBuildAttrs::v8_1_M_Main:
+ Triple += "v8.1m.main";
+ break;
}
}
if (!isLittleEndian())
@@ -383,9 +407,13 @@ ELFObjectFileBase::getPltAddresses() const {
return {};
Optional<SectionRef> Plt = None, RelaPlt = None, GotPlt = None;
for (const SectionRef &Section : sections()) {
- StringRef Name;
- if (Section.getName(Name))
+ Expected<StringRef> NameOrErr = Section.getName();
+ if (!NameOrErr) {
+ consumeError(NameOrErr.takeError());
continue;
+ }
+ StringRef Name = *NameOrErr;
+
if (Name == ".plt")
Plt = Section;
else if (Name == ".rela.plt" || Name == ".rel.plt")
diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp
index 5aec844003c0..c0c873f97354 100644
--- a/lib/Object/MachOObjectFile.cpp
+++ b/lib/Object/MachOObjectFile.cpp
@@ -57,12 +57,6 @@ 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 + ")",
@@ -1951,6 +1945,11 @@ uint64_t MachOObjectFile::getSectionSize(DataRefImpl Sec) const {
return SectSize;
}
+ArrayRef<uint8_t> MachOObjectFile::getSectionContents(uint32_t Offset,
+ uint64_t Size) const {
+ return arrayRefFromStringRef(getData().substr(Offset, Size));
+}
+
Expected<ArrayRef<uint8_t>>
MachOObjectFile::getSectionContents(DataRefImpl Sec) const {
uint32_t Offset;
@@ -1966,7 +1965,7 @@ MachOObjectFile::getSectionContents(DataRefImpl Sec) const {
Size = Sect.size;
}
- return arrayRefFromStringRef(getData().substr(Offset, Size));
+ return getSectionContents(Offset, Size);
}
uint64_t MachOObjectFile::getSectionAlignment(DataRefImpl Sec) const {
@@ -1992,13 +1991,12 @@ Expected<SectionRef> MachOObjectFile::getSection(unsigned SectionIndex) const {
}
Expected<SectionRef> MachOObjectFile::getSection(StringRef SectionName) const {
- StringRef SecName;
for (const SectionRef &Section : sections()) {
- if (std::error_code E = Section.getName(SecName))
- return errorCodeToError(E);
- if (SecName == SectionName) {
+ auto NameOrErr = Section.getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+ if (*NameOrErr == SectionName)
return Section;
- }
}
return errorCodeToError(object_error::parse_failed);
}
@@ -2724,11 +2722,19 @@ Triple MachOObjectFile::getHostArch() {
}
bool MachOObjectFile::isValidArch(StringRef ArchFlag) {
- return std::find(validArchs.cbegin(), validArchs.cend(), ArchFlag) !=
- validArchs.cend();
+ auto validArchs = getValidArchs();
+ return llvm::find(validArchs, ArchFlag) != validArchs.end();
}
-ArrayRef<StringRef> MachOObjectFile::getValidArchs() { return validArchs; }
+ArrayRef<StringRef> MachOObjectFile::getValidArchs() {
+ 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",
+ }};
+
+ return validArchs;
+}
Triple::ArchType MachOObjectFile::getArch() const {
return getArch(getCPUType(*this));
@@ -3427,7 +3433,7 @@ iterator_range<rebase_iterator>
MachOObjectFile::rebaseTable(Error &Err, MachOObjectFile *O,
ArrayRef<uint8_t> Opcodes, bool is64) {
if (O->BindRebaseSectionTable == nullptr)
- O->BindRebaseSectionTable = llvm::make_unique<BindRebaseSegInfo>(O);
+ O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);
MachORebaseEntry Start(&Err, O, Opcodes, is64);
Start.moveToFirst();
@@ -3993,7 +3999,11 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) {
uint64_t CurSegAddress;
for (const SectionRef &Section : Obj->sections()) {
SectionInfo Info;
- Section.getName(Info.SectionName);
+ Expected<StringRef> NameOrErr = Section.getName();
+ if (!NameOrErr)
+ consumeError(NameOrErr.takeError());
+ else
+ Info.SectionName = *NameOrErr;
Info.Address = Section.getAddress();
Info.Size = Section.getSize();
Info.SegmentName =
@@ -4094,7 +4104,7 @@ MachOObjectFile::bindTable(Error &Err, MachOObjectFile *O,
ArrayRef<uint8_t> Opcodes, bool is64,
MachOBindEntry::Kind BKind) {
if (O->BindRebaseSectionTable == nullptr)
- O->BindRebaseSectionTable = llvm::make_unique<BindRebaseSegInfo>(O);
+ O->BindRebaseSectionTable = std::make_unique<BindRebaseSegInfo>(O);
MachOBindEntry Start(&Err, O, Opcodes, is64, BKind);
Start.moveToFirst();
@@ -4610,7 +4620,7 @@ void MachOObjectFile::ReadULEB128s(uint64_t Index,
SmallVectorImpl<uint64_t> &Out) const {
DataExtractor extractor(ObjectFile::getData(), true, 0);
- uint32_t offset = Index;
+ uint64_t offset = Index;
uint64_t data = 0;
while (uint64_t delta = extractor.getULEB128(&offset)) {
data += delta;
diff --git a/lib/Object/MachOUniversal.cpp b/lib/Object/MachOUniversal.cpp
index b3f0993412c6..a178ecde949e 100644
--- a/lib/Object/MachOUniversal.cpp
+++ b/lib/Object/MachOUniversal.cpp
@@ -155,15 +155,16 @@ MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, Error &Err)
") extends past the end of the file");
return;
}
-#define MAXSECTALIGN 15 /* 2**15 or 0x8000 */
- if (A.getAlign() > MAXSECTALIGN) {
- Err = malformedError("align (2^" + Twine(A.getAlign()) + ") too large "
- "for cputype (" + Twine(A.getCPUType()) + ") cpusubtype (" +
- Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
- ") (maximum 2^" + Twine(MAXSECTALIGN) + ")");
+
+ if (A.getAlign() > MaxSectionAlignment) {
+ Err = malformedError("align (2^" + Twine(A.getAlign()) +
+ ") too large for cputype (" + Twine(A.getCPUType()) +
+ ") cpusubtype (" +
+ Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
+ ") (maximum 2^" + Twine(MaxSectionAlignment) + ")");
return;
}
- if(A.getOffset() % (1 << A.getAlign()) != 0){
+ if(A.getOffset() % (1ull << A.getAlign()) != 0){
Err = malformedError("offset: " + Twine(A.getOffset()) +
" for cputype (" + Twine(A.getCPUType()) + ") cpusubtype (" +
Twine(A.getCPUSubType() & ~MachO::CPU_SUBTYPE_MASK) +
@@ -209,19 +210,34 @@ MachOUniversalBinary::MachOUniversalBinary(MemoryBufferRef Source, Error &Err)
Err = Error::success();
}
-Expected<std::unique_ptr<MachOObjectFile>>
+Expected<MachOUniversalBinary::ObjectForArch>
MachOUniversalBinary::getObjectForArch(StringRef ArchName) const {
if (Triple(ArchName).getArch() == Triple::ArchType::UnknownArch)
return make_error<GenericBinaryError>("Unknown architecture "
"named: " +
ArchName,
object_error::arch_not_found);
-
- for (auto &Obj : objects())
+ for (const auto &Obj : objects())
if (Obj.getArchFlagName() == ArchName)
- return Obj.getAsObjectFile();
+ return Obj;
return make_error<GenericBinaryError>("fat file does not "
"contain " +
ArchName,
object_error::arch_not_found);
}
+
+Expected<std::unique_ptr<MachOObjectFile>>
+MachOUniversalBinary::getMachOObjectForArch(StringRef ArchName) const {
+ Expected<ObjectForArch> O = getObjectForArch(ArchName);
+ if (!O)
+ return O.takeError();
+ return O->getAsObjectFile();
+}
+
+Expected<std::unique_ptr<Archive>>
+MachOUniversalBinary::getArchiveForArch(StringRef ArchName) const {
+ Expected<ObjectForArch> O = getObjectForArch(ArchName);
+ if (!O)
+ return O.takeError();
+ return O->getAsArchive();
+}
diff --git a/lib/Object/Minidump.cpp b/lib/Object/Minidump.cpp
index 7b5b21558699..3e932fe7be28 100644
--- a/lib/Object/Minidump.cpp
+++ b/lib/Object/Minidump.cpp
@@ -53,13 +53,30 @@ Expected<std::string> MinidumpFile::getString(size_t Offset) const {
return Result;
}
+Expected<iterator_range<MinidumpFile::MemoryInfoIterator>>
+MinidumpFile::getMemoryInfoList() const {
+ Optional<ArrayRef<uint8_t>> Stream = getRawStream(StreamType::MemoryInfoList);
+ if (!Stream)
+ return createError("No such stream");
+ auto ExpectedHeader =
+ getDataSliceAs<minidump::MemoryInfoListHeader>(*Stream, 0, 1);
+ if (!ExpectedHeader)
+ return ExpectedHeader.takeError();
+ const minidump::MemoryInfoListHeader &H = ExpectedHeader.get()[0];
+ Expected<ArrayRef<uint8_t>> Data =
+ getDataSlice(*Stream, H.SizeOfHeader, H.SizeOfEntry * H.NumberOfEntries);
+ if (!Data)
+ return Data.takeError();
+ return make_range(MemoryInfoIterator(*Data, H.SizeOfEntry),
+ MemoryInfoIterator({}, H.SizeOfEntry));
+}
+
template <typename T>
-Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Stream) const {
- auto OptionalStream = getRawStream(Stream);
- if (!OptionalStream)
+Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Type) const {
+ Optional<ArrayRef<uint8_t>> Stream = getRawStream(Type);
+ if (!Stream)
return createError("No such stream");
- auto ExpectedSize =
- getDataSliceAs<support::ulittle32_t>(*OptionalStream, 0, 1);
+ auto ExpectedSize = getDataSliceAs<support::ulittle32_t>(*Stream, 0, 1);
if (!ExpectedSize)
return ExpectedSize.takeError();
@@ -69,10 +86,10 @@ Expected<ArrayRef<T>> MinidumpFile::getListStream(StreamType Stream) const {
// 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())
+ if (ListOffset + sizeof(T) * ListSize < Stream->size())
ListOffset = 8;
- return getDataSliceAs<T>(*OptionalStream, ListOffset, ListSize);
+ return getDataSliceAs<T>(*Stream, ListOffset, ListSize);
}
template Expected<ArrayRef<Module>>
MinidumpFile::getListStream(StreamType) const;
@@ -109,13 +126,14 @@ MinidumpFile::create(MemoryBufferRef Source) {
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;
+ for (const auto &StreamDescriptor : llvm::enumerate(*ExpectedStreams)) {
+ StreamType Type = StreamDescriptor.value().Type;
+ const LocationDescriptor &Loc = StreamDescriptor.value().Location;
- auto ExpectedStream = getDataSlice(Data, Loc.RVA, Loc.DataSize);
- if (!ExpectedStream)
- return ExpectedStream.takeError();
+ Expected<ArrayRef<uint8_t>> Stream =
+ getDataSlice(Data, Loc.RVA, Loc.DataSize);
+ if (!Stream)
+ return Stream.takeError();
if (Type == StreamType::Unused && Loc.DataSize == 0) {
// Ignore dummy streams. This is technically ill-formed, but a number of
@@ -128,7 +146,7 @@ MinidumpFile::create(MemoryBufferRef Source) {
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)
+ if (!StreamMap.try_emplace(Type, StreamDescriptor.index()).second)
return createError("Duplicate stream type");
}
diff --git a/lib/Object/Object.cpp b/lib/Object/Object.cpp
index d84798cc6dd0..b486e9f5c9a8 100644
--- a/lib/Object/Object.cpp
+++ b/lib/Object/Object.cpp
@@ -138,7 +138,7 @@ LLVMBinaryRef LLVMMachOUniversalBinaryCopyObjectForArch(LLVMBinaryRef BR,
char **ErrorMessage) {
auto universal = cast<MachOUniversalBinary>(unwrap(BR));
Expected<std::unique_ptr<ObjectFile>> ObjOrErr(
- universal->getObjectForArch({Arch, ArchLen}));
+ universal->getMachOObjectForArch({Arch, ArchLen}));
if (!ObjOrErr) {
*ErrorMessage = strdup(toString(ObjOrErr.takeError()).c_str());
return nullptr;
@@ -251,10 +251,10 @@ void LLVMMoveToNextSymbol(LLVMSymbolIteratorRef SI) {
// SectionRef accessors
const char *LLVMGetSectionName(LLVMSectionIteratorRef SI) {
- StringRef ret;
- if (std::error_code ec = (*unwrap(SI))->getName(ret))
- report_fatal_error(ec.message());
- return ret.data();
+ auto NameOrErr = (*unwrap(SI))->getName();
+ if (!NameOrErr)
+ report_fatal_error(NameOrErr.takeError());
+ return NameOrErr->data();
}
uint64_t LLVMGetSectionSize(LLVMSectionIteratorRef SI) {
diff --git a/lib/Object/ObjectFile.cpp b/lib/Object/ObjectFile.cpp
index 101f5dcc0821..e0e63a5a7d76 100644
--- a/lib/Object/ObjectFile.cpp
+++ b/lib/Object/ObjectFile.cpp
@@ -67,8 +67,10 @@ Error ObjectFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const {
uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; }
bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const {
- if (Expected<StringRef> NameOrErr = getSectionName(Sec))
+ Expected<StringRef> NameOrErr = getSectionName(Sec);
+ if (NameOrErr)
return *NameOrErr == ".llvmbc";
+ consumeError(NameOrErr.takeError());
return false;
}
@@ -82,7 +84,8 @@ bool ObjectFile::isBerkeleyData(DataRefImpl Sec) const {
return isSectionData(Sec);
}
-section_iterator ObjectFile::getRelocatedSection(DataRefImpl Sec) const {
+Expected<section_iterator>
+ObjectFile::getRelocatedSection(DataRefImpl Sec) const {
return section_iterator(SectionRef(Sec, this));
}
@@ -103,7 +106,7 @@ Triple ObjectFile::makeTriple() const {
TheTriple.setObjectFormat(Triple::MachO);
if (isCOFF()) {
- const auto COFFObj = dyn_cast<COFFObjectFile>(this);
+ const auto COFFObj = cast<COFFObjectFile>(this);
if (COFFObj->getArch() == Triple::thumb)
TheTriple.setTriple("thumbv7-windows");
}
@@ -127,6 +130,8 @@ ObjectFile::createObjectFile(MemoryBufferRef Object, file_magic Type) {
case file_magic::pdb:
case file_magic::minidump:
return errorCodeToError(object_error::invalid_file_type);
+ case file_magic::tapi_file:
+ return errorCodeToError(object_error::invalid_file_type);
case file_magic::elf:
case file_magic::elf_relocatable:
case file_magic::elf_executable:
diff --git a/lib/Object/RelocationResolver.cpp b/lib/Object/RelocationResolver.cpp
index 0a243f32e12c..ca89f5671b8a 100644
--- a/lib/Object/RelocationResolver.cpp
+++ b/lib/Object/RelocationResolver.cpp
@@ -30,6 +30,7 @@ static bool supportsX86_64(uint64_t Type) {
case ELF::R_X86_64_DTPOFF32:
case ELF::R_X86_64_DTPOFF64:
case ELF::R_X86_64_PC32:
+ case ELF::R_X86_64_PC64:
case ELF::R_X86_64_32:
case ELF::R_X86_64_32S:
return true;
@@ -47,6 +48,7 @@ static uint64_t resolveX86_64(RelocationRef R, uint64_t S, uint64_t A) {
case ELF::R_X86_64_DTPOFF64:
return S + getELFAddend(R);
case ELF::R_X86_64_PC32:
+ case ELF::R_X86_64_PC64:
return S + getELFAddend(R) - R.getOffset();
case ELF::R_X86_64_32:
case ELF::R_X86_64_32S:
@@ -90,9 +92,9 @@ static bool supportsBPF(uint64_t Type) {
static uint64_t resolveBPF(RelocationRef R, uint64_t S, uint64_t A) {
switch (R.getType()) {
case ELF::R_BPF_64_32:
- return S & 0xFFFFFFFF;
+ return (S + A) & 0xFFFFFFFF;
case ELF::R_BPF_64_64:
- return S;
+ return S + A;
default:
llvm_unreachable("Invalid relocation type");
}
@@ -335,6 +337,8 @@ static bool supportsRISCV(uint64_t Type) {
case ELF::R_RISCV_NONE:
case ELF::R_RISCV_32:
case ELF::R_RISCV_64:
+ case ELF::R_RISCV_SET6:
+ case ELF::R_RISCV_SUB6:
case ELF::R_RISCV_ADD8:
case ELF::R_RISCV_SUB8:
case ELF::R_RISCV_ADD16:
@@ -358,6 +362,10 @@ static uint64_t resolveRISCV(RelocationRef R, uint64_t S, uint64_t A) {
return (S + RA) & 0xFFFFFFFF;
case ELF::R_RISCV_64:
return S + RA;
+ case ELF::R_RISCV_SET6:
+ return (A + (S + RA)) & 0xFF;
+ case ELF::R_RISCV_SUB6:
+ return (A - (S + RA)) & 0xFF;
case ELF::R_RISCV_ADD8:
return (A + (S + RA)) & 0xFF;
case ELF::R_RISCV_SUB8:
@@ -420,6 +428,47 @@ static uint64_t resolveCOFFX86_64(RelocationRef R, uint64_t S, uint64_t A) {
}
}
+static bool supportsCOFFARM(uint64_t Type) {
+ switch (Type) {
+ case COFF::IMAGE_REL_ARM_SECREL:
+ case COFF::IMAGE_REL_ARM_ADDR32:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static uint64_t resolveCOFFARM(RelocationRef R, uint64_t S, uint64_t A) {
+ switch (R.getType()) {
+ case COFF::IMAGE_REL_ARM_SECREL:
+ case COFF::IMAGE_REL_ARM_ADDR32:
+ return (S + A) & 0xFFFFFFFF;
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
+static bool supportsCOFFARM64(uint64_t Type) {
+ switch (Type) {
+ case COFF::IMAGE_REL_ARM64_SECREL:
+ case COFF::IMAGE_REL_ARM64_ADDR64:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static uint64_t resolveCOFFARM64(RelocationRef R, uint64_t S, uint64_t A) {
+ switch (R.getType()) {
+ case COFF::IMAGE_REL_ARM64_SECREL:
+ return (S + A) & 0xFFFFFFFF;
+ case COFF::IMAGE_REL_ARM64_ADDR64:
+ return S + A;
+ default:
+ llvm_unreachable("Invalid relocation type");
+ }
+}
+
static bool supportsMachOX86_64(uint64_t Type) {
return Type == MachO::X86_64_RELOC_UNSIGNED;
}
@@ -472,9 +521,19 @@ static uint64_t resolveWasm32(RelocationRef R, uint64_t S, uint64_t A) {
std::pair<bool (*)(uint64_t), RelocationResolver>
getRelocationResolver(const ObjectFile &Obj) {
if (Obj.isCOFF()) {
- if (Obj.getBytesInAddress() == 8)
+ switch (Obj.getArch()) {
+ case Triple::x86_64:
return {supportsCOFFX86_64, resolveCOFFX86_64};
- return {supportsCOFFX86, resolveCOFFX86};
+ case Triple::x86:
+ return {supportsCOFFX86, resolveCOFFX86};
+ case Triple::arm:
+ case Triple::thumb:
+ return {supportsCOFFARM, resolveCOFFARM};
+ case Triple::aarch64:
+ return {supportsCOFFARM64, resolveCOFFARM64};
+ default:
+ return {nullptr, nullptr};
+ }
} else if (Obj.isELF()) {
if (Obj.getBytesInAddress() == 8) {
switch (Obj.getArch()) {
diff --git a/lib/Object/SymbolicFile.cpp b/lib/Object/SymbolicFile.cpp
index 2b152b7d8da3..3db4ad9ed14b 100644
--- a/lib/Object/SymbolicFile.cpp
+++ b/lib/Object/SymbolicFile.cpp
@@ -53,6 +53,7 @@ SymbolicFile::createSymbolicFile(MemoryBufferRef Object, file_magic Type,
case file_magic::windows_resource:
case file_magic::pdb:
case file_magic::minidump:
+ case file_magic::tapi_file:
return errorCodeToError(object_error::invalid_file_type);
case file_magic::elf:
case file_magic::elf_executable:
diff --git a/lib/Object/TapiFile.cpp b/lib/Object/TapiFile.cpp
new file mode 100644
index 000000000000..c409bd8e5995
--- /dev/null
+++ b/lib/Object/TapiFile.cpp
@@ -0,0 +1,104 @@
+//===- TapiFile.cpp -------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Text-based Dynamcic Library Stub format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/TapiFile.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace MachO;
+using namespace object;
+
+static constexpr StringLiteral ObjC1ClassNamePrefix = ".objc_class_name_";
+static constexpr StringLiteral ObjC2ClassNamePrefix = "_OBJC_CLASS_$_";
+static constexpr StringLiteral ObjC2MetaClassNamePrefix = "_OBJC_METACLASS_$_";
+static constexpr StringLiteral ObjC2EHTypePrefix = "_OBJC_EHTYPE_$_";
+static constexpr StringLiteral ObjC2IVarPrefix = "_OBJC_IVAR_$_";
+
+static uint32_t getFlags(const Symbol *Sym) {
+ uint32_t Flags = BasicSymbolRef::SF_Global;
+ if (Sym->isUndefined())
+ Flags |= BasicSymbolRef::SF_Undefined;
+ else
+ Flags |= BasicSymbolRef::SF_Exported;
+
+ if (Sym->isWeakDefined() || Sym->isWeakReferenced())
+ Flags |= BasicSymbolRef::SF_Weak;
+
+ return Flags;
+}
+
+TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &interface,
+ Architecture Arch)
+ : SymbolicFile(ID_TapiFile, Source) {
+ for (const auto *Symbol : interface.symbols()) {
+ if (!Symbol->getArchitectures().has(Arch))
+ continue;
+
+ switch (Symbol->getKind()) {
+ case SymbolKind::GlobalSymbol:
+ Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol));
+ break;
+ case SymbolKind::ObjectiveCClass:
+ if (interface.getPlatforms().count(PlatformKind::macOS) &&
+ Arch == AK_i386) {
+ Symbols.emplace_back(ObjC1ClassNamePrefix, Symbol->getName(),
+ getFlags(Symbol));
+ } else {
+ Symbols.emplace_back(ObjC2ClassNamePrefix, Symbol->getName(),
+ getFlags(Symbol));
+ Symbols.emplace_back(ObjC2MetaClassNamePrefix, Symbol->getName(),
+ getFlags(Symbol));
+ }
+ break;
+ case SymbolKind::ObjectiveCClassEHType:
+ Symbols.emplace_back(ObjC2EHTypePrefix, Symbol->getName(),
+ getFlags(Symbol));
+ break;
+ case SymbolKind::ObjectiveCInstanceVariable:
+ Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(),
+ getFlags(Symbol));
+ break;
+ }
+ }
+}
+
+TapiFile::~TapiFile() = default;
+
+void TapiFile::moveSymbolNext(DataRefImpl &DRI) const {
+ const auto *Sym = reinterpret_cast<const Symbol *>(DRI.p);
+ DRI.p = reinterpret_cast<uintptr_t>(++Sym);
+}
+
+Error TapiFile::printSymbolName(raw_ostream &OS, DataRefImpl DRI) const {
+ const auto *Sym = reinterpret_cast<const Symbol *>(DRI.p);
+ OS << Sym->Prefix << Sym->Name;
+ return Error::success();
+}
+
+uint32_t TapiFile::getSymbolFlags(DataRefImpl DRI) const {
+ const auto *Sym = reinterpret_cast<const Symbol *>(DRI.p);
+ return Sym->Flags;
+}
+
+basic_symbol_iterator TapiFile::symbol_begin() const {
+ DataRefImpl DRI;
+ DRI.p = reinterpret_cast<uintptr_t>(&*Symbols.begin());
+ return BasicSymbolRef{DRI, this};
+}
+
+basic_symbol_iterator TapiFile::symbol_end() const {
+ DataRefImpl DRI;
+ DRI.p = reinterpret_cast<uintptr_t>(&*Symbols.end());
+ return BasicSymbolRef{DRI, this};
+}
diff --git a/lib/Object/TapiUniversal.cpp b/lib/Object/TapiUniversal.cpp
new file mode 100644
index 000000000000..b3273e345a61
--- /dev/null
+++ b/lib/Object/TapiUniversal.cpp
@@ -0,0 +1,54 @@
+//===- TapiUniversal.cpp --------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Text-based Dynamic Library Stub format.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/TapiUniversal.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Object/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/TextAPI/MachO/TextAPIReader.h"
+
+using namespace llvm;
+using namespace MachO;
+using namespace object;
+
+TapiUniversal::TapiUniversal(MemoryBufferRef Source, Error &Err)
+ : Binary(ID_TapiUniversal, Source) {
+ auto Result = TextAPIReader::get(Source);
+ ErrorAsOutParameter ErrAsOuParam(&Err);
+ if (!Result) {
+ Err = Result.takeError();
+ return;
+ }
+ ParsedFile = std::move(Result.get());
+
+ auto Archs = ParsedFile->getArchitectures();
+ for (auto Arch : Archs)
+ Architectures.emplace_back(Arch);
+}
+
+TapiUniversal::~TapiUniversal() = default;
+
+Expected<std::unique_ptr<TapiFile>>
+TapiUniversal::ObjectForArch::getAsObjectFile() const {
+ return std::unique_ptr<TapiFile>(new TapiFile(Parent->getMemoryBufferRef(),
+ *Parent->ParsedFile.get(),
+ Parent->Architectures[Index]));
+}
+
+Expected<std::unique_ptr<TapiUniversal>>
+TapiUniversal::create(MemoryBufferRef Source) {
+ Error Err = Error::success();
+ std::unique_ptr<TapiUniversal> Ret(new TapiUniversal(Source, Err));
+ if (Err)
+ return std::move(Err);
+ return std::move(Ret);
+}
diff --git a/lib/Object/WasmObjectFile.cpp b/lib/Object/WasmObjectFile.cpp
index 82aa1830dced..014b403556df 100644
--- a/lib/Object/WasmObjectFile.cpp
+++ b/lib/Object/WasmObjectFile.cpp
@@ -56,7 +56,7 @@ LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
Expected<std::unique_ptr<WasmObjectFile>>
ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
Error Err = Error::success();
- auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err);
+ auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
if (Err)
return std::move(Err);
@@ -781,7 +781,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
break;
case wasm::R_WASM_GLOBAL_INDEX_LEB:
// R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
- // symbols to refer to thier GOT enties.
+ // symbols to refer to their GOT entries.
if (!isValidGlobalSymbol(Reloc.Index) &&
!isValidDataSymbol(Reloc.Index) &&
!isValidFunctionSymbol(Reloc.Index))
@@ -881,12 +881,9 @@ Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
Sig.Params.push_back(wasm::ValType(ParamType));
}
uint32_t ReturnCount = readVaruint32(Ctx);
- if (ReturnCount) {
- if (ReturnCount != 1) {
- return make_error<GenericBinaryError>(
- "Multiple return types not supported", object_error::parse_failed);
- }
- Sig.Returns.push_back(wasm::ValType(readUint8(Ctx)));
+ while (ReturnCount--) {
+ uint32_t ReturnType = readUint8(Ctx);
+ Sig.Returns.push_back(wasm::ValType(ReturnType));
}
Signatures.push_back(std::move(Sig));
}
diff --git a/lib/Object/WindowsResource.cpp b/lib/Object/WindowsResource.cpp
index d76e1231684c..10717718b201 100644
--- a/lib/Object/WindowsResource.cpp
+++ b/lib/Object/WindowsResource.cpp
@@ -30,15 +30,24 @@ namespace object {
if (auto EC = X) \
return EC;
+#define UNWRAP_REF_OR_RETURN(Name, Expr) \
+ auto Name##OrErr = Expr; \
+ if (!Name##OrErr) \
+ return Name##OrErr.takeError(); \
+ const auto &Name = *Name##OrErr;
+
+#define UNWRAP_OR_RETURN(Name, Expr) \
+ auto Name##OrErr = Expr; \
+ if (!Name##OrErr) \
+ return Name##OrErr.takeError(); \
+ auto Name = *Name##OrErr;
+
const uint32_t MIN_HEADER_SIZE = 7 * sizeof(uint32_t) + 2 * sizeof(uint16_t);
// COFF files seem to be inconsistent with alignment between sections, just use
// 8-byte because it makes everyone happy.
const uint32_t SECTION_ALIGNMENT = sizeof(uint64_t);
-uint32_t WindowsResourceParser::TreeNode::StringCount = 0;
-uint32_t WindowsResourceParser::TreeNode::DataCount = 0;
-
WindowsResource::WindowsResource(MemoryBufferRef Source)
: Binary(Binary::ID_WinRes, Source) {
size_t LeadingSize = WIN_RES_MAGIC_SIZE + WIN_RES_NULL_ENTRY_SIZE;
@@ -128,7 +137,8 @@ Error ResourceEntryRef::loadNext() {
return Error::success();
}
-WindowsResourceParser::WindowsResourceParser() : Root(false) {}
+WindowsResourceParser::WindowsResourceParser(bool MinGW)
+ : Root(false), MinGW(MinGW) {}
void printResourceTypeName(uint16_t TypeID, raw_ostream &OS) {
switch (TypeID) {
@@ -200,6 +210,122 @@ static std::string makeDuplicateResourceError(
return OS.str();
}
+static void printStringOrID(const WindowsResourceParser::StringOrID &S,
+ raw_string_ostream &OS, bool IsType, bool IsID) {
+ if (S.IsString) {
+ std::string UTF8;
+ if (!convertUTF16LEToUTF8String(S.String, UTF8))
+ UTF8 = "(failed conversion from UTF16)";
+ OS << '\"' << UTF8 << '\"';
+ } else if (IsType)
+ printResourceTypeName(S.ID, OS);
+ else if (IsID)
+ OS << "ID " << S.ID;
+ else
+ OS << S.ID;
+}
+
+static std::string makeDuplicateResourceError(
+ const std::vector<WindowsResourceParser::StringOrID> &Context,
+ StringRef File1, StringRef File2) {
+ std::string Ret;
+ raw_string_ostream OS(Ret);
+
+ OS << "duplicate resource:";
+
+ if (Context.size() >= 1) {
+ OS << " type ";
+ printStringOrID(Context[0], OS, /* IsType */ true, /* IsID */ true);
+ }
+
+ if (Context.size() >= 2) {
+ OS << "/name ";
+ printStringOrID(Context[1], OS, /* IsType */ false, /* IsID */ true);
+ }
+
+ if (Context.size() >= 3) {
+ OS << "/language ";
+ printStringOrID(Context[2], OS, /* IsType */ false, /* IsID */ false);
+ }
+ OS << ", in " << File1 << " and in " << File2;
+
+ return OS.str();
+}
+
+// MinGW specific. Remove default manifests (with language zero) if there are
+// other manifests present, and report an error if there are more than one
+// manifest with a non-zero language code.
+// GCC has the concept of a default manifest resource object, which gets
+// linked in implicitly if present. This default manifest has got language
+// id zero, and should be dropped silently if there's another manifest present.
+// If the user resources surprisignly had a manifest with language id zero,
+// we should also ignore the duplicate default manifest.
+void WindowsResourceParser::cleanUpManifests(
+ std::vector<std::string> &Duplicates) {
+ auto TypeIt = Root.IDChildren.find(/* RT_MANIFEST */ 24);
+ if (TypeIt == Root.IDChildren.end())
+ return;
+
+ TreeNode *TypeNode = TypeIt->second.get();
+ auto NameIt =
+ TypeNode->IDChildren.find(/* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1);
+ if (NameIt == TypeNode->IDChildren.end())
+ return;
+
+ TreeNode *NameNode = NameIt->second.get();
+ if (NameNode->IDChildren.size() <= 1)
+ return; // None or one manifest present, all good.
+
+ // If we have more than one manifest, drop the language zero one if present,
+ // and check again.
+ auto LangZeroIt = NameNode->IDChildren.find(0);
+ if (LangZeroIt != NameNode->IDChildren.end() &&
+ LangZeroIt->second->IsDataNode) {
+ uint32_t RemovedIndex = LangZeroIt->second->DataIndex;
+ NameNode->IDChildren.erase(LangZeroIt);
+ Data.erase(Data.begin() + RemovedIndex);
+ Root.shiftDataIndexDown(RemovedIndex);
+
+ // If we're now down to one manifest, all is good.
+ if (NameNode->IDChildren.size() <= 1)
+ return;
+ }
+
+ // More than one non-language-zero manifest
+ auto FirstIt = NameNode->IDChildren.begin();
+ uint32_t FirstLang = FirstIt->first;
+ TreeNode *FirstNode = FirstIt->second.get();
+ auto LastIt = NameNode->IDChildren.rbegin();
+ uint32_t LastLang = LastIt->first;
+ TreeNode *LastNode = LastIt->second.get();
+ Duplicates.push_back(
+ ("duplicate non-default manifests with languages " + Twine(FirstLang) +
+ " in " + InputFilenames[FirstNode->Origin] + " and " + Twine(LastLang) +
+ " in " + InputFilenames[LastNode->Origin])
+ .str());
+}
+
+// Ignore duplicates of manifests with language zero (the default manifest),
+// in case the user has provided a manifest with that language id. See
+// the function comment above for context. Only returns true if MinGW is set
+// to true.
+bool WindowsResourceParser::shouldIgnoreDuplicate(
+ const ResourceEntryRef &Entry) const {
+ return MinGW && !Entry.checkTypeString() &&
+ Entry.getTypeID() == /* RT_MANIFEST */ 24 &&
+ !Entry.checkNameString() &&
+ Entry.getNameID() == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
+ Entry.getLanguage() == 0;
+}
+
+bool WindowsResourceParser::shouldIgnoreDuplicate(
+ const std::vector<StringOrID> &Context) const {
+ return MinGW && Context.size() == 3 && !Context[0].IsString &&
+ Context[0].ID == /* RT_MANIFEST */ 24 && !Context[1].IsString &&
+ Context[1].ID == /* CREATEPROCESS_MANIFEST_RESOURCE_ID */ 1 &&
+ !Context[2].IsString && Context[2].ID == 0;
+}
+
Error WindowsResourceParser::parse(WindowsResource *WR,
std::vector<std::string> &Duplicates) {
auto EntryOrErr = WR->getHeadEntry();
@@ -219,112 +345,176 @@ Error WindowsResourceParser::parse(WindowsResource *WR,
}
ResourceEntryRef Entry = EntryOrErr.get();
+ uint32_t Origin = InputFilenames.size();
+ InputFilenames.push_back(WR->getFileName());
bool End = false;
while (!End) {
- Data.push_back(Entry.getData());
- bool IsNewTypeString = false;
- bool IsNewNameString = false;
-
- TreeNode* Node;
- bool IsNewNode = Root.addEntry(Entry, InputFilenames.size(),
- IsNewTypeString, IsNewNameString, Node);
- InputFilenames.push_back(WR->getFileName());
+ TreeNode *Node;
+ bool IsNewNode = Root.addEntry(Entry, Origin, Data, StringTable, Node);
if (!IsNewNode) {
- Duplicates.push_back(makeDuplicateResourceError(
- Entry, InputFilenames[Node->Origin], WR->getFileName()));
+ if (!shouldIgnoreDuplicate(Entry))
+ Duplicates.push_back(makeDuplicateResourceError(
+ Entry, InputFilenames[Node->Origin], WR->getFileName()));
}
- if (IsNewTypeString)
- StringTable.push_back(Entry.getTypeString());
-
- if (IsNewNameString)
- StringTable.push_back(Entry.getNameString());
-
RETURN_IF_ERROR(Entry.moveNext(End));
}
return Error::success();
}
+Error WindowsResourceParser::parse(ResourceSectionRef &RSR, StringRef Filename,
+ std::vector<std::string> &Duplicates) {
+ UNWRAP_REF_OR_RETURN(BaseTable, RSR.getBaseTable());
+ uint32_t Origin = InputFilenames.size();
+ InputFilenames.push_back(Filename);
+ std::vector<StringOrID> Context;
+ return addChildren(Root, RSR, BaseTable, Origin, Context, Duplicates);
+}
+
void WindowsResourceParser::printTree(raw_ostream &OS) const {
ScopedPrinter Writer(OS);
Root.print(Writer, "Resource Tree");
}
-bool WindowsResourceParser::TreeNode::addEntry(const ResourceEntryRef &Entry,
- uint32_t Origin,
- bool &IsNewTypeString,
- bool &IsNewNameString,
- TreeNode *&Result) {
- TreeNode &TypeNode = addTypeNode(Entry, IsNewTypeString);
- TreeNode &NameNode = TypeNode.addNameNode(Entry, IsNewNameString);
- return NameNode.addLanguageNode(Entry, Origin, Result);
+bool WindowsResourceParser::TreeNode::addEntry(
+ const ResourceEntryRef &Entry, uint32_t Origin,
+ std::vector<std::vector<uint8_t>> &Data,
+ std::vector<std::vector<UTF16>> &StringTable, TreeNode *&Result) {
+ TreeNode &TypeNode = addTypeNode(Entry, StringTable);
+ TreeNode &NameNode = TypeNode.addNameNode(Entry, StringTable);
+ return NameNode.addLanguageNode(Entry, Origin, Data, Result);
}
-WindowsResourceParser::TreeNode::TreeNode(bool IsStringNode) {
- if (IsStringNode)
- StringIndex = StringCount++;
+Error WindowsResourceParser::addChildren(TreeNode &Node,
+ ResourceSectionRef &RSR,
+ const coff_resource_dir_table &Table,
+ uint32_t Origin,
+ std::vector<StringOrID> &Context,
+ std::vector<std::string> &Duplicates) {
+
+ for (int i = 0; i < Table.NumberOfNameEntries + Table.NumberOfIDEntries;
+ i++) {
+ UNWRAP_REF_OR_RETURN(Entry, RSR.getTableEntry(Table, i));
+ TreeNode *Child;
+
+ if (Entry.Offset.isSubDir()) {
+
+ // Create a new subdirectory and recurse
+ if (i < Table.NumberOfNameEntries) {
+ UNWRAP_OR_RETURN(NameString, RSR.getEntryNameString(Entry));
+ Child = &Node.addNameChild(NameString, StringTable);
+ Context.push_back(StringOrID(NameString));
+ } else {
+ Child = &Node.addIDChild(Entry.Identifier.ID);
+ Context.push_back(StringOrID(Entry.Identifier.ID));
+ }
+
+ UNWRAP_REF_OR_RETURN(NextTable, RSR.getEntrySubDir(Entry));
+ Error E =
+ addChildren(*Child, RSR, NextTable, Origin, Context, Duplicates);
+ if (E)
+ return E;
+ Context.pop_back();
+
+ } else {
+
+ // Data leaves are supposed to have a numeric ID as identifier (language).
+ if (Table.NumberOfNameEntries > 0)
+ return createStringError(object_error::parse_failed,
+ "unexpected string key for data object");
+
+ // Try adding a data leaf
+ UNWRAP_REF_OR_RETURN(DataEntry, RSR.getEntryData(Entry));
+ TreeNode *Child;
+ Context.push_back(StringOrID(Entry.Identifier.ID));
+ bool Added = Node.addDataChild(Entry.Identifier.ID, Table.MajorVersion,
+ Table.MinorVersion, Table.Characteristics,
+ Origin, Data.size(), Child);
+ if (Added) {
+ UNWRAP_OR_RETURN(Contents, RSR.getContents(DataEntry));
+ Data.push_back(ArrayRef<uint8_t>(
+ reinterpret_cast<const uint8_t *>(Contents.data()),
+ Contents.size()));
+ } else {
+ if (!shouldIgnoreDuplicate(Context))
+ Duplicates.push_back(makeDuplicateResourceError(
+ Context, InputFilenames[Child->Origin], InputFilenames.back()));
+ }
+ Context.pop_back();
+
+ }
+ }
+ return Error::success();
}
+WindowsResourceParser::TreeNode::TreeNode(uint32_t StringIndex)
+ : StringIndex(StringIndex) {}
+
WindowsResourceParser::TreeNode::TreeNode(uint16_t MajorVersion,
uint16_t MinorVersion,
uint32_t Characteristics,
- uint32_t Origin)
- : IsDataNode(true), MajorVersion(MajorVersion), MinorVersion(MinorVersion),
- Characteristics(Characteristics), Origin(Origin) {
- DataIndex = DataCount++;
-}
+ uint32_t Origin, uint32_t DataIndex)
+ : IsDataNode(true), DataIndex(DataIndex), MajorVersion(MajorVersion),
+ MinorVersion(MinorVersion), Characteristics(Characteristics),
+ Origin(Origin) {}
std::unique_ptr<WindowsResourceParser::TreeNode>
-WindowsResourceParser::TreeNode::createStringNode() {
- return std::unique_ptr<TreeNode>(new TreeNode(true));
+WindowsResourceParser::TreeNode::createStringNode(uint32_t Index) {
+ return std::unique_ptr<TreeNode>(new TreeNode(Index));
}
std::unique_ptr<WindowsResourceParser::TreeNode>
WindowsResourceParser::TreeNode::createIDNode() {
- return std::unique_ptr<TreeNode>(new TreeNode(false));
+ return std::unique_ptr<TreeNode>(new TreeNode(0));
}
std::unique_ptr<WindowsResourceParser::TreeNode>
WindowsResourceParser::TreeNode::createDataNode(uint16_t MajorVersion,
uint16_t MinorVersion,
uint32_t Characteristics,
- uint32_t Origin) {
- return std::unique_ptr<TreeNode>(
- new TreeNode(MajorVersion, MinorVersion, Characteristics, Origin));
+ uint32_t Origin,
+ uint32_t DataIndex) {
+ return std::unique_ptr<TreeNode>(new TreeNode(
+ MajorVersion, MinorVersion, Characteristics, Origin, DataIndex));
}
-WindowsResourceParser::TreeNode &
-WindowsResourceParser::TreeNode::addTypeNode(const ResourceEntryRef &Entry,
- bool &IsNewTypeString) {
+WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addTypeNode(
+ const ResourceEntryRef &Entry,
+ std::vector<std::vector<UTF16>> &StringTable) {
if (Entry.checkTypeString())
- return addNameChild(Entry.getTypeString(), IsNewTypeString);
+ return addNameChild(Entry.getTypeString(), StringTable);
else
return addIDChild(Entry.getTypeID());
}
-WindowsResourceParser::TreeNode &
-WindowsResourceParser::TreeNode::addNameNode(const ResourceEntryRef &Entry,
- bool &IsNewNameString) {
+WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameNode(
+ const ResourceEntryRef &Entry,
+ std::vector<std::vector<UTF16>> &StringTable) {
if (Entry.checkNameString())
- return addNameChild(Entry.getNameString(), IsNewNameString);
+ return addNameChild(Entry.getNameString(), StringTable);
else
return addIDChild(Entry.getNameID());
}
bool WindowsResourceParser::TreeNode::addLanguageNode(
- const ResourceEntryRef &Entry, uint32_t Origin, TreeNode *&Result) {
- return addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
- Entry.getMinorVersion(), Entry.getCharacteristics(),
- Origin, Result);
+ const ResourceEntryRef &Entry, uint32_t Origin,
+ std::vector<std::vector<uint8_t>> &Data, TreeNode *&Result) {
+ bool Added = addDataChild(Entry.getLanguage(), Entry.getMajorVersion(),
+ Entry.getMinorVersion(), Entry.getCharacteristics(),
+ Origin, Data.size(), Result);
+ if (Added)
+ Data.push_back(Entry.getData());
+ return Added;
}
bool WindowsResourceParser::TreeNode::addDataChild(
uint32_t ID, uint16_t MajorVersion, uint16_t MinorVersion,
- uint32_t Characteristics, uint32_t Origin, TreeNode *&Result) {
- auto NewChild =
- createDataNode(MajorVersion, MinorVersion, Characteristics, Origin);
+ uint32_t Characteristics, uint32_t Origin, uint32_t DataIndex,
+ TreeNode *&Result) {
+ auto NewChild = createDataNode(MajorVersion, MinorVersion, Characteristics,
+ Origin, DataIndex);
auto ElementInserted = IDChildren.emplace(ID, std::move(NewChild));
Result = ElementInserted.first->second.get();
return ElementInserted.second;
@@ -342,16 +532,15 @@ WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addIDChild(
return *(Child->second);
}
-WindowsResourceParser::TreeNode &
-WindowsResourceParser::TreeNode::addNameChild(ArrayRef<UTF16> NameRef,
- bool &IsNewString) {
+WindowsResourceParser::TreeNode &WindowsResourceParser::TreeNode::addNameChild(
+ ArrayRef<UTF16> NameRef, std::vector<std::vector<UTF16>> &StringTable) {
std::string NameString;
convertUTF16LEToUTF8String(NameRef, NameString);
auto Child = StringChildren.find(NameString);
if (Child == StringChildren.end()) {
- auto NewChild = createStringNode();
- IsNewString = true;
+ auto NewChild = createStringNode(StringTable.size());
+ StringTable.push_back(NameRef);
WindowsResourceParser::TreeNode &Node = *NewChild;
StringChildren.emplace(NameString, std::move(NewChild));
return Node;
@@ -396,6 +585,19 @@ uint32_t WindowsResourceParser::TreeNode::getTreeSize() const {
return Size;
}
+// Shift DataIndex of all data children with an Index greater or equal to the
+// given one, to fill a gap from removing an entry from the Data vector.
+void WindowsResourceParser::TreeNode::shiftDataIndexDown(uint32_t Index) {
+ if (IsDataNode && DataIndex >= Index) {
+ DataIndex--;
+ } else {
+ for (auto &Child : IDChildren)
+ Child.second->shiftDataIndexDown(Index);
+ for (auto &Child : StringChildren)
+ Child.second->shiftDataIndexDown(Index);
+ }
+}
+
class WindowsResourceCOFFWriter {
public:
WindowsResourceCOFFWriter(COFF::MachineTypes MachineType,
@@ -515,6 +717,14 @@ WindowsResourceCOFFWriter::write(uint32_t TimeDateStamp) {
return std::move(OutputBuffer);
}
+// According to COFF specification, if the Src has a size equal to Dest,
+// it's okay to *not* copy the trailing zero.
+static void coffnamecpy(char (&Dest)[COFF::NameSize], StringRef Src) {
+ assert(Src.size() <= COFF::NameSize &&
+ "Src is not larger than COFF::NameSize");
+ strncpy(Dest, Src.data(), (size_t)COFF::NameSize);
+}
+
void WindowsResourceCOFFWriter::writeCOFFHeader(uint32_t TimeDateStamp) {
// Write the COFF header.
auto *Header = reinterpret_cast<coff_file_header *>(BufferStart);
@@ -534,7 +744,7 @@ void WindowsResourceCOFFWriter::writeFirstSectionHeader() {
CurrentOffset += sizeof(coff_file_header);
auto *SectionOneHeader =
reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
- strncpy(SectionOneHeader->Name, ".rsrc$01", (size_t)COFF::NameSize);
+ coffnamecpy(SectionOneHeader->Name, ".rsrc$01");
SectionOneHeader->VirtualSize = 0;
SectionOneHeader->VirtualAddress = 0;
SectionOneHeader->SizeOfRawData = SectionOneSize;
@@ -552,7 +762,7 @@ void WindowsResourceCOFFWriter::writeSecondSectionHeader() {
CurrentOffset += sizeof(coff_section);
auto *SectionTwoHeader =
reinterpret_cast<coff_section *>(BufferStart + CurrentOffset);
- strncpy(SectionTwoHeader->Name, ".rsrc$02", (size_t)COFF::NameSize);
+ coffnamecpy(SectionTwoHeader->Name, ".rsrc$02");
SectionTwoHeader->VirtualSize = 0;
SectionTwoHeader->VirtualAddress = 0;
SectionTwoHeader->SizeOfRawData = SectionTwoSize;
@@ -590,7 +800,7 @@ void WindowsResourceCOFFWriter::writeSymbolTable() {
// Now write the symbol table.
// First, the feat symbol.
auto *Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- strncpy(Symbol->Name.ShortName, "@feat.00", (size_t)COFF::NameSize);
+ coffnamecpy(Symbol->Name.ShortName, "@feat.00");
Symbol->Value = 0x11;
Symbol->SectionNumber = 0xffff;
Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
@@ -600,7 +810,7 @@ void WindowsResourceCOFFWriter::writeSymbolTable() {
// Now write the .rsrc1 symbol + aux.
Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- strncpy(Symbol->Name.ShortName, ".rsrc$01", (size_t)COFF::NameSize);
+ coffnamecpy(Symbol->Name.ShortName, ".rsrc$01");
Symbol->Value = 0;
Symbol->SectionNumber = 1;
Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
@@ -619,7 +829,7 @@ void WindowsResourceCOFFWriter::writeSymbolTable() {
// Now write the .rsrc2 symbol + aux.
Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- strncpy(Symbol->Name.ShortName, ".rsrc$02", (size_t)COFF::NameSize);
+ coffnamecpy(Symbol->Name.ShortName, ".rsrc$02");
Symbol->Value = 0;
Symbol->SectionNumber = 2;
Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
@@ -640,7 +850,7 @@ void WindowsResourceCOFFWriter::writeSymbolTable() {
for (unsigned i = 0; i < Data.size(); i++) {
auto RelocationName = formatv("$R{0:X-6}", i & 0xffffff).sstr<COFF::NameSize>();
Symbol = reinterpret_cast<coff_symbol16 *>(BufferStart + CurrentOffset);
- memcpy(Symbol->Name.ShortName, RelocationName.data(), (size_t) COFF::NameSize);
+ coffnamecpy(Symbol->Name.ShortName, RelocationName);
Symbol->Value = DataOffsets[i];
Symbol->SectionNumber = 2;
Symbol->Type = COFF::IMAGE_SYM_DTYPE_NULL;
diff --git a/lib/Object/XCOFFObjectFile.cpp b/lib/Object/XCOFFObjectFile.cpp
index 602b7357986a..98782c2701c1 100644
--- a/lib/Object/XCOFFObjectFile.cpp
+++ b/lib/Object/XCOFFObjectFile.cpp
@@ -11,17 +11,14 @@
//===----------------------------------------------------------------------===//
#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 {
+enum { FUNCTION_SYM = 0x20, SYM_TYPE_MASK = 0x07, RELOC_OVERFLOW = 65535 };
+
// Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer
// 'M'. Returns a pointer to the underlying object on success.
template <typename T>
@@ -42,10 +39,25 @@ 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));
+static StringRef generateXCOFFFixedNameStringRef(const char *Name) {
+ auto NulCharPtr =
+ static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize));
return NulCharPtr ? StringRef(Name, NulCharPtr - Name)
- : StringRef(Name, Size);
+ : StringRef(Name, XCOFF::NameSize);
+}
+
+bool XCOFFRelocation32::isRelocationSigned() const {
+ return Info & XR_SIGN_INDICATOR_MASK;
+}
+
+bool XCOFFRelocation32::isFixupIndicated() const {
+ return Info & XR_FIXUP_INDICATOR_MASK;
+}
+
+uint8_t XCOFFRelocation32::getRelocatedLength() const {
+ // The relocation encodes the bit length being relocated minus 1. Add back
+ // the 1 to get the actual length being relocated.
+ return (Info & XR_BIASED_LENGTH_MASK) + 1;
}
void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr,
@@ -83,6 +95,9 @@ XCOFFObjectFile::toSection64(DataRefImpl Ref) const {
const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const {
assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!");
+#ifndef NDEBUG
+ checkSymbolEntryPointer(Ref.p);
+#endif
auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p);
return SymEntPtr;
}
@@ -112,23 +127,19 @@ XCOFFObjectFile::sectionHeaderTable64() const {
void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1;
+#ifndef NDEBUG
+ // This function is used by basic_symbol_iterator, which allows to
+ // point to the end-of-symbol-table address.
+ if (reinterpret_cast<uintptr_t>(SymEntPtr) != getEndOfSymbolTableAddress())
+ checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(SymEntPtr));
+#endif
Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr);
}
-Expected<StringRef> XCOFFObjectFile::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
+Expected<StringRef>
+XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const {
+ // The byte offset is relative to the start of the string table.
+ // A byte offset value of 0 is a null or zero-length symbol
// name. A byte offset in the range 1 to 3 (inclusive) points into the length
// field; as a soft-error recovery mechanism, we treat such cases as having an
// offset of 0.
@@ -138,10 +149,32 @@ Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
if (StringTable.Data != nullptr && StringTable.Size > Offset)
return (StringTable.Data + Offset);
- return make_error<GenericBinaryError>("Symbol Name parse failed",
+ return make_error<GenericBinaryError>("Bad offset for string table entry",
object_error::parse_failed);
}
+Expected<StringRef>
+XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const {
+ if (CFileEntPtr->NameInStrTbl.Magic !=
+ XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
+ return generateXCOFFFixedNameStringRef(CFileEntPtr->Name);
+ return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset);
+}
+
+Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
+ const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb);
+
+ // A storage class value with the high-order bit on indicates that the name is
+ // a symbolic debugger stabstring.
+ if (SymEntPtr->StorageClass & 0x80)
+ return StringRef("Unimplemented Debug Name");
+
+ if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC)
+ return generateXCOFFFixedNameStringRef(SymEntPtr->SymbolName);
+
+ return getStringTableEntry(SymEntPtr->NameInStrTbl.Offset);
+}
+
Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
uint64_t Result = 0;
llvm_unreachable("Not yet implemented!");
@@ -149,6 +182,7 @@ Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
}
uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
+ assert(!is64Bit() && "Symbol table support not implemented for 64-bit.");
return toSymbolEntry(Symb)->Value;
}
@@ -185,7 +219,7 @@ void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const {
}
Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const {
- return generateStringRef(getSectionNameInternal(Sec), XCOFF::SectionNameSize);
+ return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec));
}
uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const {
@@ -393,8 +427,8 @@ XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const {
default:
Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum);
if (SecRef)
- return generateStringRef(getSectionNameInternal(SecRef.get()),
- XCOFF::SectionNameSize);
+ return generateXCOFFFixedNameStringRef(
+ getSectionNameInternal(SecRef.get()));
return SecRef.takeError();
}
}
@@ -442,6 +476,48 @@ uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const {
return fileHeader64()->NumberOfSymTableEntries;
}
+uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const {
+ uint32_t NumberOfSymTableEntries =
+ is64Bit() ? getNumberOfSymbolTableEntries64()
+ : getLogicalNumberOfSymbolTableEntries32();
+ return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr),
+ XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries);
+}
+
+void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const {
+ if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr))
+ report_fatal_error("Symbol table entry is outside of symbol table.");
+
+ if (SymbolEntPtr >= getEndOfSymbolTableAddress())
+ report_fatal_error("Symbol table entry is outside of symbol table.");
+
+ ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) -
+ reinterpret_cast<const char *>(SymbolTblPtr);
+
+ if (Offset % XCOFF::SymbolTableEntrySize != 0)
+ report_fatal_error(
+ "Symbol table entry position is not valid inside of symbol table.");
+}
+
+uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const {
+ return (reinterpret_cast<const char *>(SymbolEntPtr) -
+ reinterpret_cast<const char *>(SymbolTblPtr)) /
+ XCOFF::SymbolTableEntrySize;
+}
+
+Expected<StringRef>
+XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const {
+ if (is64Bit())
+ report_fatal_error("64-bit symbol table support not implemented yet.");
+
+ if (Index >= getLogicalNumberOfSymbolTableEntries32())
+ return errorCodeToError(object_error::invalid_symbol_index);
+
+ DataRefImpl SymDRI;
+ SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index);
+ return getSymbolName(SymDRI);
+}
+
uint16_t XCOFFObjectFile::getFlags() const {
return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags;
}
@@ -477,6 +553,46 @@ ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const {
TablePtr + getNumberOfSections());
}
+// In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO
+// section header contains the actual count of relocation entries in the s_paddr
+// field. STYP_OVRFLO headers contain the section index of their corresponding
+// sections as their raw "NumberOfRelocations" field value.
+Expected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries(
+ const XCOFFSectionHeader32 &Sec) const {
+
+ uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1;
+
+ if (Sec.NumberOfRelocations < RELOC_OVERFLOW)
+ return Sec.NumberOfRelocations;
+ for (const auto &Sec : sections32()) {
+ if (Sec.Flags == XCOFF::STYP_OVRFLO &&
+ Sec.NumberOfRelocations == SectionIndex)
+ return Sec.PhysicalAddress;
+ }
+ return errorCodeToError(object_error::parse_failed);
+}
+
+Expected<ArrayRef<XCOFFRelocation32>>
+XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const {
+ uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader),
+ Sec.FileOffsetToRelocationInfo);
+ auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec);
+ if (Error E = NumRelocEntriesOrErr.takeError())
+ return std::move(E);
+
+ uint32_t NumRelocEntries = NumRelocEntriesOrErr.get();
+
+ auto RelocationOrErr =
+ getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr),
+ NumRelocEntries * sizeof(XCOFFRelocation32));
+ if (Error E = RelocationOrErr.takeError())
+ return std::move(E);
+
+ const XCOFFRelocation32 *StartReloc = RelocationOrErr.get();
+
+ return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries);
+}
+
Expected<XCOFFStringTable>
XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
// If there is a string table, then the buffer must contain at least 4 bytes
@@ -507,7 +623,7 @@ XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) {
Expected<std::unique_ptr<XCOFFObjectFile>>
XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) {
- // Can't use make_unique because of the private constructor.
+ // Can't use std::make_unique because of the private constructor.
std::unique_ptr<XCOFFObjectFile> Obj;
Obj.reset(new XCOFFObjectFile(Type, MBR));
@@ -573,11 +689,77 @@ ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
}
StringRef XCOFFSectionHeader32::getName() const {
- return generateStringRef(Name, XCOFF::SectionNameSize);
+ return generateXCOFFFixedNameStringRef(Name);
}
StringRef XCOFFSectionHeader64::getName() const {
- return generateStringRef(Name, XCOFF::SectionNameSize);
+ return generateXCOFFFixedNameStringRef(Name);
+}
+
+XCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const {
+ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass;
+}
+
+uint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const {
+ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries;
+}
+
+const XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const {
+ assert(!OwningObjectPtr->is64Bit() &&
+ "32-bit interface called on 64-bit object file.");
+ assert(hasCsectAuxEnt() && "No Csect Auxiliary Entry is found.");
+
+ // In XCOFF32, the csect auxilliary entry is always the last auxiliary
+ // entry for the symbol.
+ uintptr_t AuxAddr = getWithOffset(
+ SymEntDataRef.p, XCOFF::SymbolTableEntrySize * getNumberOfAuxEntries());
+
+#ifndef NDEBUG
+ OwningObjectPtr->checkSymbolEntryPointer(AuxAddr);
+#endif
+
+ return reinterpret_cast<const XCOFFCsectAuxEnt32 *>(AuxAddr);
+}
+
+uint16_t XCOFFSymbolRef::getType() const {
+ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType;
+}
+
+int16_t XCOFFSymbolRef::getSectionNumber() const {
+ return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber;
+}
+
+bool XCOFFSymbolRef::hasCsectAuxEnt() const {
+ XCOFF::StorageClass SC = getStorageClass();
+ return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT ||
+ SC == XCOFF::C_HIDEXT);
+}
+
+bool XCOFFSymbolRef::isFunction() const {
+ if (OwningObjectPtr->is64Bit())
+ report_fatal_error("64-bit support is unimplemented yet.");
+
+ if (getType() & FUNCTION_SYM)
+ return true;
+
+ if (!hasCsectAuxEnt())
+ return false;
+
+ const XCOFFCsectAuxEnt32 *CsectAuxEnt = getXCOFFCsectAuxEnt32();
+
+ // A function definition should be a label definition.
+ if ((CsectAuxEnt->SymbolAlignmentAndType & SYM_TYPE_MASK) != XCOFF::XTY_LD)
+ return false;
+
+ if (CsectAuxEnt->StorageMappingClass != XCOFF::XMC_PR)
+ return false;
+
+ int16_t SectNum = getSectionNumber();
+ Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum);
+ if (!SI)
+ return false;
+
+ return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT);
}
} // namespace object