mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-12 18:02:43 +00:00
Revert "[ORC] Add a MachOBuilder utility, use it to build MachO debug objects."
This reverts commit 75c487602a
while I
investigate some build failures, e.g.
https://lab.llvm.org/buildbot/#/builders/217/builds/27769
This commit is contained in:
parent
4427407a29
commit
99e70cc3a5
@ -1,525 +0,0 @@
|
||||
//===------------ MachOBuilder.h -- Build MachO Objects ---------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Build MachO object files for interaction with the ObjC runtime and debugger.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_EXECUTIONENGINE_ORC_MACHOBUILDER_H
|
||||
#define LLVM_EXECUTIONENGINE_ORC_MACHOBUILDER_H
|
||||
|
||||
#include "llvm/BinaryFormat/MachO.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace orc {
|
||||
|
||||
// Builds MachO objects.
|
||||
template <typename MachOTraits> class MachOBuilder {
|
||||
private:
|
||||
struct BufferWriter {
|
||||
public:
|
||||
BufferWriter(MutableArrayRef<char> Buffer)
|
||||
: Data(Buffer.data()), Size(Buffer.size()) {}
|
||||
|
||||
size_t tell() const { return Offset; }
|
||||
|
||||
void write(char C) {
|
||||
assert(Offset < Size && "Buffer overflow");
|
||||
Data[Offset++] = C;
|
||||
}
|
||||
|
||||
void write(const char *Src, size_t SrcSize) {
|
||||
assert(Offset + SrcSize <= Size && "Buffer overflow");
|
||||
memcpy(&Data[Offset], Src, SrcSize);
|
||||
Offset += SrcSize;
|
||||
}
|
||||
|
||||
template <typename T> void write(const T &Value) {
|
||||
assert(Offset + sizeof(T) <= Size && "Buffer overflow");
|
||||
memcpy(&Data[Offset], reinterpret_cast<const char *>(&Value), sizeof(T));
|
||||
Offset += sizeof(T);
|
||||
}
|
||||
|
||||
private:
|
||||
char *Data = 0;
|
||||
size_t Offset = 0;
|
||||
size_t Size = 0;
|
||||
};
|
||||
|
||||
struct SymbolContainer {
|
||||
size_t SymbolIndexBase = 0;
|
||||
std::vector<typename MachOTraits::NList> Symbols;
|
||||
};
|
||||
|
||||
static void writeMachOStruct(BufferWriter &BW, MachO::relocation_info RI) {
|
||||
BW.write(RI);
|
||||
}
|
||||
|
||||
template <typename MachOStruct>
|
||||
static void writeMachOStruct(BufferWriter &BW, MachOStruct S) {
|
||||
if (MachOTraits::Endianness != support::endian::system_endianness())
|
||||
MachO::swapStruct(S);
|
||||
BW.write(S);
|
||||
}
|
||||
|
||||
struct LoadCommandBase {
|
||||
virtual ~LoadCommandBase() {}
|
||||
virtual size_t size() const = 0;
|
||||
virtual void write(BufferWriter &BW) = 0;
|
||||
};
|
||||
|
||||
template <MachO::LoadCommandType LCType> struct LoadCommand;
|
||||
|
||||
#define HANDLE_LOAD_COMMAND(Name, Value, LCStruct) \
|
||||
template <> \
|
||||
struct LoadCommand<MachO::Name> : public MachO::LCStruct, \
|
||||
public LoadCommandBase { \
|
||||
using CmdStruct = LCStruct; \
|
||||
LoadCommand() { \
|
||||
memset(&rawStruct(), 0, sizeof(CmdStruct)); \
|
||||
cmd = Value; \
|
||||
cmdsize = sizeof(CmdStruct); \
|
||||
} \
|
||||
template <typename... ArgTs> \
|
||||
LoadCommand(ArgTs &&...Args) \
|
||||
: CmdStruct{Value, sizeof(CmdStruct), std::forward<ArgTs>(Args)...} {} \
|
||||
CmdStruct &rawStruct() { return static_cast<CmdStruct &>(*this); } \
|
||||
size_t size() const override { return cmdsize; } \
|
||||
void write(BufferWriter &BW) override { \
|
||||
writeMachOStruct(BW, rawStruct()); \
|
||||
} \
|
||||
};
|
||||
|
||||
#include "llvm/BinaryFormat/MachO.def"
|
||||
|
||||
#undef HANDLE_LOAD_COMMAND
|
||||
|
||||
struct StringTableEntry {
|
||||
StringRef S;
|
||||
size_t Offset;
|
||||
};
|
||||
|
||||
using StringTable = std::vector<StringTableEntry>;
|
||||
|
||||
public:
|
||||
using StringId = size_t;
|
||||
|
||||
struct Section;
|
||||
|
||||
// Points to either an nlist entry (as a (symbol-container, index) pair), or
|
||||
// a section.
|
||||
class RelocTarget {
|
||||
public:
|
||||
RelocTarget(const Section &S) : S(&S), Idx(~0U) {}
|
||||
RelocTarget(SymbolContainer &SC, size_t Idx) : SC(&SC), Idx(Idx) {}
|
||||
|
||||
bool isSymbol() { return Idx != ~0U; }
|
||||
|
||||
uint32_t getSymbolNum() {
|
||||
assert(isSymbol() && "Target is not a symbol");
|
||||
return SC->SymbolIndexBase + Idx;
|
||||
}
|
||||
|
||||
uint32_t getSectionId() {
|
||||
assert(!isSymbol() && "Target is not a section");
|
||||
return S->SectionNumber;
|
||||
}
|
||||
|
||||
typename MachOTraits::NList &nlist() {
|
||||
assert(isSymbol() && "Target is not a symbol");
|
||||
return SC->Symbols[Idx];
|
||||
}
|
||||
|
||||
private:
|
||||
union {
|
||||
const Section *S;
|
||||
SymbolContainer *SC;
|
||||
};
|
||||
size_t Idx;
|
||||
};
|
||||
|
||||
struct Reloc : public MachO::relocation_info {
|
||||
RelocTarget Target;
|
||||
|
||||
Reloc(int32_t Offset, RelocTarget Target, bool PCRel, unsigned Length,
|
||||
unsigned Type)
|
||||
: Target(Target) {
|
||||
assert(Type < 16 && "Relocation type out of range");
|
||||
r_address = Offset; // Will slide to account for sec addr during layout
|
||||
r_symbolnum = 0;
|
||||
r_pcrel = PCRel;
|
||||
r_length = Length;
|
||||
r_extern = Target.isSymbol();
|
||||
r_type = Type;
|
||||
}
|
||||
|
||||
MachO::relocation_info &rawStruct() {
|
||||
return static_cast<MachO::relocation_info &>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
struct SectionContent {
|
||||
const char *Data = nullptr;
|
||||
size_t Size = 0;
|
||||
};
|
||||
|
||||
struct Section : public MachOTraits::Section, public RelocTarget {
|
||||
MachOBuilder &Builder;
|
||||
SectionContent Content;
|
||||
size_t SectionNumber = 0;
|
||||
SymbolContainer SC;
|
||||
std::vector<Reloc> Relocs;
|
||||
|
||||
Section(MachOBuilder &Builder, StringRef SecName, StringRef SegName)
|
||||
: RelocTarget(*this), Builder(Builder) {
|
||||
memset(&rawStruct(), 0, sizeof(typename MachOTraits::Section));
|
||||
assert(SecName.size() <= 16 && "SecName too long");
|
||||
assert(SegName.size() <= 16 && "SegName too long");
|
||||
memcpy(this->sectname, SecName.data(), SecName.size());
|
||||
memcpy(this->segname, SegName.data(), SegName.size());
|
||||
}
|
||||
|
||||
RelocTarget addSymbol(int32_t Offset, StringRef Name, uint8_t Type,
|
||||
uint16_t Desc) {
|
||||
StringId SI = Builder.addString(Name);
|
||||
typename MachOTraits::NList Sym;
|
||||
Sym.n_strx = SI;
|
||||
Sym.n_type = Type | MachO::N_SECT;
|
||||
Sym.n_sect = MachO::NO_SECT; // Will be filled in later.
|
||||
Sym.n_desc = Desc;
|
||||
Sym.n_value = Offset;
|
||||
SC.Symbols.push_back(Sym);
|
||||
return {SC, SC.Symbols.size() - 1};
|
||||
}
|
||||
|
||||
void addReloc(int32_t Offset, RelocTarget Target, bool PCRel,
|
||||
unsigned Length, unsigned Type) {
|
||||
Relocs.push_back({Offset, Target, PCRel, Length, Type});
|
||||
}
|
||||
|
||||
auto &rawStruct() {
|
||||
return static_cast<typename MachOTraits::Section &>(*this);
|
||||
}
|
||||
};
|
||||
|
||||
struct Segment : public LoadCommand<MachOTraits::SegmentCmd> {
|
||||
MachOBuilder &Builder;
|
||||
std::vector<std::unique_ptr<Section>> Sections;
|
||||
|
||||
Segment(MachOBuilder &Builder, StringRef SegName)
|
||||
: LoadCommand<MachOTraits::SegmentCmd>(), Builder(Builder) {
|
||||
assert(SegName.size() <= 16 && "SegName too long");
|
||||
memcpy(this->segname, SegName.data(), SegName.size());
|
||||
this->maxprot =
|
||||
MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
|
||||
this->initprot = this->maxprot;
|
||||
}
|
||||
|
||||
Section &addSection(StringRef SecName, StringRef SegName) {
|
||||
Sections.push_back(std::make_unique<Section>(Builder, SecName, SegName));
|
||||
return *Sections.back();
|
||||
}
|
||||
|
||||
void write(BufferWriter &BW) override {
|
||||
writeMachOStruct(BW, this->rawStruct());
|
||||
for (auto &Sec : Sections)
|
||||
writeMachOStruct(BW, Sec->rawStruct());
|
||||
}
|
||||
};
|
||||
|
||||
MachOBuilder(size_t PageSize) : PageSize(PageSize) {
|
||||
memset((char *)&Header, 0, sizeof(Header));
|
||||
Header.magic = MachOTraits::Magic;
|
||||
}
|
||||
|
||||
template <MachO::LoadCommandType LCType, typename... ArgTs>
|
||||
LoadCommand<LCType> &addLoadCommand(ArgTs &&...Args) {
|
||||
static_assert(LCType != MachOTraits::SegmentCmd,
|
||||
"Use addSegment to add segment load command");
|
||||
auto LC =
|
||||
std::make_unique<LoadCommand<LCType>>(std::forward<ArgTs>(Args)...);
|
||||
auto &Tmp = *LC;
|
||||
LoadCommands.push_back(std::move(LC));
|
||||
return Tmp;
|
||||
}
|
||||
|
||||
StringId addString(StringRef Str) {
|
||||
if (Strings.empty() && !Str.empty())
|
||||
addString("");
|
||||
return Strings.insert(std::make_pair(Str, Strings.size())).first->second;
|
||||
}
|
||||
|
||||
Segment &addSegment(StringRef SegName) {
|
||||
Segments.push_back(Segment(*this, SegName));
|
||||
return Segments.back();
|
||||
}
|
||||
|
||||
RelocTarget addSymbol(StringRef Name, uint8_t Type, uint8_t Sect,
|
||||
uint16_t Desc, typename MachOTraits::UIntPtr Value) {
|
||||
StringId SI = addString(Name);
|
||||
typename MachOTraits::NList Sym;
|
||||
Sym.n_strx = SI;
|
||||
Sym.n_type = Type;
|
||||
Sym.n_sect = Sect;
|
||||
Sym.n_desc = Desc;
|
||||
Sym.n_value = Value;
|
||||
SC.Symbols.push_back(Sym);
|
||||
return {SC, SC.Symbols.size() - 1};
|
||||
}
|
||||
|
||||
// Call to perform layout on the MachO. Returns the total size of the
|
||||
// resulting file.
|
||||
// This method will automatically insert some load commands (e.g.
|
||||
// LC_SYMTAB) and fill in load command fields.
|
||||
size_t layout() {
|
||||
|
||||
// Build symbol table and add LC_SYMTAB command.
|
||||
makeStringTable();
|
||||
LoadCommand<MachOTraits::SymTabCmd> *SymTabLC = nullptr;
|
||||
if (!StrTab.empty())
|
||||
SymTabLC = &addLoadCommand<MachOTraits::SymTabCmd>();
|
||||
|
||||
// Lay out header, segment load command, and other load commands.
|
||||
size_t Offset = sizeof(Header);
|
||||
for (auto &Seg : Segments) {
|
||||
Seg.cmdsize +=
|
||||
Seg.Sections.size() * sizeof(typename MachOTraits::Section);
|
||||
Seg.nsects = Seg.Sections.size();
|
||||
Offset += Seg.cmdsize;
|
||||
}
|
||||
for (auto &LC : LoadCommands)
|
||||
Offset += LC->size();
|
||||
|
||||
Header.sizeofcmds = Offset - sizeof(Header);
|
||||
|
||||
// Lay out content, set segment / section addrs and offsets.
|
||||
size_t SegVMAddr = 0;
|
||||
for (auto &Seg : Segments) {
|
||||
Seg.vmaddr = SegVMAddr;
|
||||
Seg.fileoff = Offset;
|
||||
for (auto &Sec : Seg.Sections) {
|
||||
Offset = alignTo(Offset, 1 << Sec->align);
|
||||
if (Sec->Content.Size)
|
||||
Sec->offset = Offset;
|
||||
Sec->size = Sec->Content.Size;
|
||||
Sec->addr = SegVMAddr + Sec->offset - Seg.fileoff;
|
||||
Offset += Sec->Content.Size;
|
||||
}
|
||||
size_t SegContentSize = Offset - Seg.fileoff;
|
||||
Seg.filesize = SegContentSize;
|
||||
Seg.vmsize = Header.filetype == MachO::MH_OBJECT
|
||||
? SegContentSize
|
||||
: alignTo(SegContentSize, PageSize);
|
||||
SegVMAddr += Seg.vmsize;
|
||||
}
|
||||
|
||||
// Set string table offsets for non-section symbols.
|
||||
for (auto &Sym : SC.Symbols)
|
||||
Sym.n_strx = StrTab[Sym.n_strx].Offset;
|
||||
|
||||
// Number sections, set symbol section numbers and string table offsets,
|
||||
// count relocations.
|
||||
size_t NumSymbols = SC.Symbols.size();
|
||||
size_t SectionNumber = 0;
|
||||
for (auto &Seg : Segments) {
|
||||
for (auto &Sec : Seg.Sections) {
|
||||
++SectionNumber;
|
||||
Sec->SectionNumber = SectionNumber;
|
||||
Sec->SC.SymbolIndexBase = NumSymbols;
|
||||
NumSymbols += Sec->SC.Symbols.size();
|
||||
for (auto &Sym : Sec->SC.Symbols) {
|
||||
Sym.n_sect = SectionNumber;
|
||||
Sym.n_strx = StrTab[Sym.n_strx].Offset;
|
||||
Sym.n_value += Sec->addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle relocations
|
||||
bool OffsetAlignedForRelocs = false;
|
||||
for (auto &Seg : Segments) {
|
||||
for (auto &Sec : Seg.Sections) {
|
||||
if (!Sec->Relocs.empty()) {
|
||||
if (!OffsetAlignedForRelocs) {
|
||||
Offset = alignTo(Offset, sizeof(MachO::relocation_info));
|
||||
OffsetAlignedForRelocs = true;
|
||||
}
|
||||
Sec->reloff = Offset;
|
||||
Sec->nreloc = Sec->Relocs.size();
|
||||
Offset += Sec->Relocs.size() * sizeof(MachO::relocation_info);
|
||||
for (auto &R : Sec->Relocs)
|
||||
R.r_symbolnum = R.Target.isSymbol() ? R.Target.getSymbolNum()
|
||||
: R.Target.getSectionId();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate offset to start of nlist and update symtab command.
|
||||
if (NumSymbols > 0) {
|
||||
Offset = alignTo(Offset, sizeof(typename MachOTraits::NList));
|
||||
SymTabLC->symoff = Offset;
|
||||
SymTabLC->nsyms = NumSymbols;
|
||||
|
||||
// Calculate string table bounds and update symtab command.
|
||||
if (!StrTab.empty()) {
|
||||
Offset += NumSymbols * sizeof(typename MachOTraits::NList);
|
||||
size_t StringTableSize =
|
||||
StrTab.back().Offset + StrTab.back().S.size() + 1;
|
||||
|
||||
SymTabLC->stroff = Offset;
|
||||
SymTabLC->strsize = StringTableSize;
|
||||
Offset += StringTableSize;
|
||||
}
|
||||
}
|
||||
|
||||
return Offset;
|
||||
}
|
||||
|
||||
void write(MutableArrayRef<char> Buffer) {
|
||||
BufferWriter BW(Buffer);
|
||||
writeHeader(BW);
|
||||
writeSegments(BW);
|
||||
writeLoadCommands(BW);
|
||||
writeSectionContent(BW);
|
||||
writeRelocations(BW);
|
||||
writeSymbols(BW);
|
||||
writeStrings(BW);
|
||||
}
|
||||
|
||||
typename MachOTraits::Header Header;
|
||||
|
||||
private:
|
||||
void makeStringTable() {
|
||||
if (Strings.empty())
|
||||
return;
|
||||
|
||||
StrTab.resize(Strings.size());
|
||||
for (auto &KV : Strings)
|
||||
StrTab[KV.second] = {KV.first, 0};
|
||||
size_t Offset = 0;
|
||||
for (auto &Elem : StrTab) {
|
||||
Elem.Offset = Offset;
|
||||
Offset += Elem.S.size() + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void writeHeader(BufferWriter &BW) {
|
||||
Header.ncmds = Segments.size() + LoadCommands.size();
|
||||
writeMachOStruct(BW, Header);
|
||||
}
|
||||
|
||||
void writeSegments(BufferWriter &BW) {
|
||||
for (auto &Seg : Segments)
|
||||
Seg.write(BW);
|
||||
}
|
||||
|
||||
void writeLoadCommands(BufferWriter &BW) {
|
||||
for (auto &LC : LoadCommands)
|
||||
LC->write(BW);
|
||||
}
|
||||
|
||||
void writeSectionContent(BufferWriter &BW) {
|
||||
for (auto &Seg : Segments) {
|
||||
for (auto &Sec : Seg.Sections) {
|
||||
if (!Sec->Content.Data) {
|
||||
assert(Sec->Relocs.empty() &&
|
||||
"Cant' have relocs for zero-fill segment");
|
||||
continue;
|
||||
}
|
||||
size_t ZeroPad = Sec->offset - BW.tell();
|
||||
while (ZeroPad--)
|
||||
BW.write('\0');
|
||||
BW.write(Sec->Content.Data, Sec->Content.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeRelocations(BufferWriter &BW) {
|
||||
for (auto &Seg : Segments) {
|
||||
for (auto &Sec : Seg.Sections) {
|
||||
if (!Sec->Relocs.empty()) {
|
||||
while (BW.tell() % sizeof(MachO::relocation_info))
|
||||
BW.write('\0');
|
||||
}
|
||||
for (auto &R : Sec->Relocs)
|
||||
writeMachOStruct(BW, R.rawStruct());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeSymbols(BufferWriter &BW) {
|
||||
|
||||
// Count symbols.
|
||||
size_t NumSymbols = SC.Symbols.size();
|
||||
for (auto &Seg : Segments)
|
||||
for (auto &Sec : Seg.Sections)
|
||||
NumSymbols += Sec->SC.Symbols.size();
|
||||
|
||||
// If none then return.
|
||||
if (NumSymbols == 0)
|
||||
return;
|
||||
|
||||
size_t ZeroPad =
|
||||
alignTo(BW.tell(), sizeof(typename MachOTraits::NList)) - BW.tell();
|
||||
while (ZeroPad--)
|
||||
BW.write('\0');
|
||||
|
||||
// Write non-section symbols.
|
||||
for (auto &Sym : SC.Symbols)
|
||||
writeMachOStruct(BW, Sym);
|
||||
|
||||
// Write section symbols.
|
||||
for (auto &Seg : Segments) {
|
||||
for (auto &Sec : Seg.Sections) {
|
||||
for (auto &Sym : Sec->SC.Symbols) {
|
||||
writeMachOStruct(BW, Sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeStrings(BufferWriter &BW) {
|
||||
for (auto &Elem : StrTab) {
|
||||
BW.write(Elem.S.data(), Elem.S.size());
|
||||
BW.write('\0');
|
||||
}
|
||||
}
|
||||
|
||||
size_t PageSize;
|
||||
std::list<Segment> Segments;
|
||||
std::vector<std::unique_ptr<LoadCommandBase>> LoadCommands;
|
||||
SymbolContainer SC;
|
||||
|
||||
// Maps strings to their "id" (addition order).
|
||||
std::map<StringRef, size_t> Strings;
|
||||
StringTable StrTab;
|
||||
};
|
||||
|
||||
struct MachO64LE {
|
||||
using UIntPtr = uint64_t;
|
||||
using Header = MachO::mach_header_64;
|
||||
using Section = MachO::section_64;
|
||||
using NList = MachO::nlist_64;
|
||||
using Relocation = MachO::relocation_info;
|
||||
|
||||
static constexpr support::endianness Endianness = support::little;
|
||||
static constexpr uint32_t Magic = MachO::MH_MAGIC_64;
|
||||
static constexpr MachO::LoadCommandType SegmentCmd = MachO::LC_SEGMENT_64;
|
||||
static constexpr MachO::LoadCommandType SymTabCmd = MachO::LC_SYMTAB;
|
||||
};
|
||||
|
||||
} // namespace orc
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_EXECUTIONENGINE_ORC_MACHOBUILDER_H
|
@ -10,7 +10,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
|
||||
#include "llvm/ExecutionEngine/Orc/MachOBuilder.h"
|
||||
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
@ -27,6 +26,19 @@ static const char *SynthDebugSectionName = "__jitlink_synth_debug_object";
|
||||
|
||||
namespace {
|
||||
|
||||
struct MachO64LE {
|
||||
using UIntPtr = uint64_t;
|
||||
|
||||
using Header = MachO::mach_header_64;
|
||||
using SegmentLC = MachO::segment_command_64;
|
||||
using Section = MachO::section_64;
|
||||
using NList = MachO::nlist_64;
|
||||
|
||||
static constexpr support::endianness Endianness = support::little;
|
||||
static constexpr const uint32_t Magic = MachO::MH_MAGIC_64;
|
||||
static constexpr const uint32_t SegmentCmd = MachO::LC_SEGMENT_64;
|
||||
};
|
||||
|
||||
class MachODebugObjectSynthesizerBase
|
||||
: public GDBJITDebugInfoRegistrationPlugin::DebugSectionSynthesizer {
|
||||
public:
|
||||
@ -72,7 +84,6 @@ public:
|
||||
if (!PreservedBlocks.count(B))
|
||||
G.addAnonymousSymbol(*B, 0, 0, false, true);
|
||||
}
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
@ -83,12 +94,28 @@ protected:
|
||||
|
||||
template <typename MachOTraits>
|
||||
class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
|
||||
public:
|
||||
MachODebugObjectSynthesizer(ExecutionSession &ES, LinkGraph &G,
|
||||
ExecutorAddr RegisterActionAddr)
|
||||
: MachODebugObjectSynthesizerBase(G, RegisterActionAddr),
|
||||
Builder(ES.getPageSize()) {}
|
||||
private:
|
||||
class MachOStructWriter {
|
||||
public:
|
||||
MachOStructWriter(MutableArrayRef<char> Buffer) : Buffer(Buffer) {}
|
||||
|
||||
size_t getOffset() const { return Offset; }
|
||||
|
||||
template <typename MachOStruct> void write(MachOStruct S) {
|
||||
assert(Offset + sizeof(S) <= Buffer.size() &&
|
||||
"Container block overflow while constructing debug MachO");
|
||||
if (MachOTraits::Endianness != support::endian::system_endianness())
|
||||
MachO::swapStruct(S);
|
||||
memcpy(Buffer.data() + Offset, &S, sizeof(S));
|
||||
Offset += sizeof(S);
|
||||
}
|
||||
|
||||
private:
|
||||
MutableArrayRef<char> Buffer;
|
||||
size_t Offset = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase;
|
||||
|
||||
Error startSynthesis() override {
|
||||
@ -96,79 +123,164 @@ public:
|
||||
dbgs() << "Creating " << SynthDebugSectionName << " for " << G.getName()
|
||||
<< "\n";
|
||||
});
|
||||
|
||||
auto &SDOSec = G.createSection(SynthDebugSectionName, MemProt::Read);
|
||||
|
||||
struct DebugSectionInfo {
|
||||
Section *Sec = nullptr;
|
||||
StringRef SegName;
|
||||
StringRef SecName;
|
||||
uint64_t Alignment = 0;
|
||||
orc::ExecutorAddr StartAddr;
|
||||
uint64_t Size = 0;
|
||||
};
|
||||
|
||||
SmallVector<DebugSectionInfo, 12> DebugSecInfos;
|
||||
size_t NumSections = 0;
|
||||
for (auto &Sec : G.sections()) {
|
||||
if (Sec.blocks().empty())
|
||||
continue;
|
||||
|
||||
// Skip sections whose name's don't fit the MachO standard.
|
||||
if (Sec.getName().empty() || Sec.getName().size() > 33 ||
|
||||
Sec.getName().find(',') > 16)
|
||||
continue;
|
||||
++NumSections;
|
||||
if (isDebugSection(Sec)) {
|
||||
size_t SepPos = Sec.getName().find(',');
|
||||
if (SepPos > 16 || (Sec.getName().size() - (SepPos + 1) > 16)) {
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Skipping debug object synthesis for graph "
|
||||
<< G.getName()
|
||||
<< ": encountered non-standard DWARF section name \""
|
||||
<< Sec.getName() << "\"\n";
|
||||
});
|
||||
return Error::success();
|
||||
}
|
||||
DebugSecInfos.push_back({&Sec, Sec.getName().substr(0, SepPos),
|
||||
Sec.getName().substr(SepPos + 1), 0,
|
||||
orc::ExecutorAddr(), 0});
|
||||
} else {
|
||||
NonDebugSections.push_back(&Sec);
|
||||
|
||||
if (isDebugSection(Sec))
|
||||
DebugSections.push_back({&Sec, nullptr});
|
||||
else if (Sec.getMemLifetimePolicy() != MemLifetimePolicy::NoAlloc)
|
||||
NonDebugSections.push_back({&Sec, nullptr});
|
||||
// If the first block in the section has a non-zero alignment offset
|
||||
// then we need to add a padding block, since the section command in
|
||||
// the header doesn't allow for aligment offsets.
|
||||
SectionRange R(Sec);
|
||||
if (!R.empty()) {
|
||||
auto &FB = *R.getFirstBlock();
|
||||
if (FB.getAlignmentOffset() != 0) {
|
||||
auto Padding = G.allocateBuffer(FB.getAlignmentOffset());
|
||||
memset(Padding.data(), 0, Padding.size());
|
||||
G.createContentBlock(Sec, Padding,
|
||||
FB.getAddress() - FB.getAlignmentOffset(),
|
||||
FB.getAlignment(), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create container block.
|
||||
size_t SectionsCmdSize =
|
||||
sizeof(typename MachOTraits::Section) * NumSections;
|
||||
size_t SegmentLCSize =
|
||||
sizeof(typename MachOTraits::SegmentLC) + SectionsCmdSize;
|
||||
size_t ContainerBlockSize =
|
||||
sizeof(typename MachOTraits::Header) + SegmentLCSize;
|
||||
auto ContainerBlockContent = G.allocateBuffer(ContainerBlockSize);
|
||||
MachOContainerBlock = &G.createMutableContentBlock(
|
||||
SDOSec, ContainerBlockContent, orc::ExecutorAddr(), 8, 0);
|
||||
|
||||
// Copy debug section blocks and symbols.
|
||||
orc::ExecutorAddr NextBlockAddr(MachOContainerBlock->getSize());
|
||||
for (auto &SI : DebugSecInfos) {
|
||||
assert(!SI.Sec->blocks().empty() && "Empty debug info section?");
|
||||
|
||||
// Update addresses in debug section.
|
||||
LLVM_DEBUG({
|
||||
dbgs() << " Appending " << SI.Sec->getName() << " ("
|
||||
<< SI.Sec->blocks_size() << " block(s)) at "
|
||||
<< formatv("{0:x8}", NextBlockAddr) << "\n";
|
||||
});
|
||||
for (auto *B : SI.Sec->blocks()) {
|
||||
NextBlockAddr = alignToBlock(NextBlockAddr, *B);
|
||||
B->setAddress(NextBlockAddr);
|
||||
NextBlockAddr += B->getSize();
|
||||
}
|
||||
|
||||
auto &FirstBlock = **SI.Sec->blocks().begin();
|
||||
if (FirstBlock.getAlignmentOffset() != 0)
|
||||
return make_error<StringError>(
|
||||
"First block in " + SI.Sec->getName() +
|
||||
" section has non-zero alignment offset",
|
||||
inconvertibleErrorCode());
|
||||
if (FirstBlock.getAlignment() > std::numeric_limits<uint32_t>::max())
|
||||
return make_error<StringError>("First block in " + SI.Sec->getName() +
|
||||
" has alignment >4Gb",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
SI.Alignment = FirstBlock.getAlignment();
|
||||
SI.StartAddr = FirstBlock.getAddress();
|
||||
SI.Size = NextBlockAddr - SI.StartAddr;
|
||||
G.mergeSections(SDOSec, *SI.Sec);
|
||||
SI.Sec = nullptr;
|
||||
}
|
||||
size_t DebugSectionsSize =
|
||||
NextBlockAddr - orc::ExecutorAddr(MachOContainerBlock->getSize());
|
||||
|
||||
// Write MachO header and debug section load commands.
|
||||
Builder.Header.filetype = MachO::MH_OBJECT;
|
||||
MachOStructWriter Writer(MachOContainerBlock->getAlreadyMutableContent());
|
||||
typename MachOTraits::Header Hdr;
|
||||
memset(&Hdr, 0, sizeof(Hdr));
|
||||
Hdr.magic = MachOTraits::Magic;
|
||||
switch (G.getTargetTriple().getArch()) {
|
||||
case Triple::x86_64:
|
||||
Builder.Header.cputype = MachO::CPU_TYPE_X86_64;
|
||||
Builder.Header.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
|
||||
Hdr.cputype = MachO::CPU_TYPE_X86_64;
|
||||
Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
|
||||
break;
|
||||
case Triple::aarch64:
|
||||
Builder.Header.cputype = MachO::CPU_TYPE_ARM64;
|
||||
Builder.Header.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
|
||||
Hdr.cputype = MachO::CPU_TYPE_ARM64;
|
||||
Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("Unsupported architecture");
|
||||
}
|
||||
Hdr.filetype = MachO::MH_OBJECT;
|
||||
Hdr.ncmds = 1;
|
||||
Hdr.sizeofcmds = SegmentLCSize;
|
||||
Hdr.flags = 0;
|
||||
Writer.write(Hdr);
|
||||
|
||||
Seg = &Builder.addSegment("");
|
||||
typename MachOTraits::SegmentLC SegLC;
|
||||
memset(&SegLC, 0, sizeof(SegLC));
|
||||
SegLC.cmd = MachOTraits::SegmentCmd;
|
||||
SegLC.cmdsize = SegmentLCSize;
|
||||
SegLC.vmaddr = ContainerBlockSize;
|
||||
SegLC.vmsize = DebugSectionsSize;
|
||||
SegLC.fileoff = ContainerBlockSize;
|
||||
SegLC.filesize = DebugSectionsSize;
|
||||
SegLC.maxprot =
|
||||
MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
|
||||
SegLC.initprot =
|
||||
MachO::VM_PROT_READ | MachO::VM_PROT_WRITE | MachO::VM_PROT_EXECUTE;
|
||||
SegLC.nsects = NumSections;
|
||||
SegLC.flags = 0;
|
||||
Writer.write(SegLC);
|
||||
|
||||
for (auto &DSec : DebugSections) {
|
||||
auto [SegName, SecName] = DSec.GraphSec->getName().split(',');
|
||||
DSec.BuilderSec = &Seg->addSection(SecName, SegName);
|
||||
|
||||
SectionRange SR(*DSec.GraphSec);
|
||||
DSec.BuilderSec->Content.Size = SR.getSize();
|
||||
if (!SR.empty())
|
||||
DSec.BuilderSec->align = Log2_64(SR.getFirstBlock()->getAlignment());
|
||||
StringSet<> ExistingLongNames;
|
||||
for (auto &SI : DebugSecInfos) {
|
||||
typename MachOTraits::Section Sec;
|
||||
memset(&Sec, 0, sizeof(Sec));
|
||||
memcpy(Sec.sectname, SI.SecName.data(), SI.SecName.size());
|
||||
memcpy(Sec.segname, SI.SegName.data(), SI.SegName.size());
|
||||
Sec.addr = SI.StartAddr.getValue();
|
||||
Sec.size = SI.Size;
|
||||
Sec.offset = SI.StartAddr.getValue();
|
||||
Sec.align = SI.Alignment;
|
||||
Sec.reloff = 0;
|
||||
Sec.nreloc = 0;
|
||||
Sec.flags = MachO::S_ATTR_DEBUG;
|
||||
Writer.write(Sec);
|
||||
}
|
||||
|
||||
for (auto &NDSP : NonDebugSections) {
|
||||
auto [SegName, SecName] = NDSP.GraphSec->getName().split(',');
|
||||
NDSP.BuilderSec = &Seg->addSection(SecName, SegName);
|
||||
SectionRange SR(*NDSP.GraphSec);
|
||||
if (!SR.empty())
|
||||
NDSP.BuilderSec->align = Log2_64(SR.getFirstBlock()->getAlignment());
|
||||
|
||||
// Add stabs.
|
||||
for (auto *Sym : NDSP.GraphSec->symbols()) {
|
||||
// Skip anonymous symbols.
|
||||
if (!Sym->hasName())
|
||||
continue;
|
||||
|
||||
uint8_t SymType = Sym->isCallable() ? MachO::N_FUN : MachO::N_GSYM;
|
||||
|
||||
Builder.addSymbol("", MachO::N_BNSYM, 1, 0, 0);
|
||||
StabSymbols.push_back(
|
||||
{*Sym, Builder.addSymbol(Sym->getName(), SymType, 1, 0, 0),
|
||||
Builder.addSymbol(Sym->getName(), SymType, 0, 0, 0)});
|
||||
Builder.addSymbol("", MachO::N_ENSYM, 1, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
size_t DebugObjectSize = Builder.layout();
|
||||
|
||||
MachOContainerBlock = &G.createMutableContentBlock(
|
||||
SDOSec, G.allocateBuffer(DebugObjectSize), orc::ExecutorAddr(), 8, 0);
|
||||
|
||||
// Set MachOContainerBlock to indicate success to
|
||||
// completeSynthesisAndRegister.
|
||||
NonDebugSectionsStart = Writer.getOffset();
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
@ -178,45 +290,63 @@ public:
|
||||
dbgs() << "Not writing MachO debug object header for " << G.getName()
|
||||
<< " since createDebugSection failed\n";
|
||||
});
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
ExecutorAddr MaxAddr;
|
||||
for (auto &NDSec : NonDebugSections) {
|
||||
SectionRange SR(*NDSec.GraphSec);
|
||||
NDSec.BuilderSec->addr = SR.getStart().getValue();
|
||||
NDSec.BuilderSec->size = SR.getSize();
|
||||
NDSec.BuilderSec->offset = SR.getStart().getValue();
|
||||
if (SR.getEnd() > MaxAddr)
|
||||
MaxAddr = SR.getEnd();
|
||||
}
|
||||
|
||||
for (auto &DSec : DebugSections) {
|
||||
if (DSec.GraphSec->blocks_size() != 1)
|
||||
return make_error<StringError>(
|
||||
"Unexpected number of blocks in debug info section",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
if (ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size > MaxAddr)
|
||||
MaxAddr = ExecutorAddr(DSec.BuilderSec->addr) + DSec.BuilderSec->size;
|
||||
|
||||
auto &B = **DSec.GraphSec->blocks().begin();
|
||||
DSec.BuilderSec->Content.Data = B.getContent().data();
|
||||
DSec.BuilderSec->Content.Size = B.getContent().size();
|
||||
DSec.BuilderSec->flags |= MachO::S_ATTR_DEBUG;
|
||||
}
|
||||
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Writing MachO debug object header for " << G.getName() << "\n";
|
||||
});
|
||||
|
||||
// Update stab symbol addresses.
|
||||
for (auto &SS : StabSymbols) {
|
||||
SS.StartStab.nlist().n_value = SS.Sym.getAddress().getValue();
|
||||
SS.EndStab.nlist().n_value = SS.Sym.getSize();
|
||||
}
|
||||
MachOStructWriter Writer(
|
||||
MachOContainerBlock->getAlreadyMutableContent().drop_front(
|
||||
NonDebugSectionsStart));
|
||||
|
||||
Builder.write(MachOContainerBlock->getAlreadyMutableContent());
|
||||
unsigned LongSectionNameIdx = 0;
|
||||
for (auto *Sec : NonDebugSections) {
|
||||
size_t SepPos = Sec->getName().find(',');
|
||||
StringRef SegName, SecName;
|
||||
std::string CustomSecName;
|
||||
|
||||
if ((SepPos == StringRef::npos && Sec->getName().size() <= 16)) {
|
||||
// No embedded segment name, short section name.
|
||||
SegName = "__JITLINK_CUSTOM";
|
||||
SecName = Sec->getName();
|
||||
} else if (SepPos < 16 && (Sec->getName().size() - (SepPos + 1) <= 16)) {
|
||||
// Canonical embedded segment and section name.
|
||||
SegName = Sec->getName().substr(0, SepPos);
|
||||
SecName = Sec->getName().substr(SepPos + 1);
|
||||
} else {
|
||||
// Long section name that needs to be truncated.
|
||||
assert(Sec->getName().size() > 16 &&
|
||||
"Short section name should have been handled above");
|
||||
SegName = "__JITLINK_CUSTOM";
|
||||
auto IdxStr = std::to_string(++LongSectionNameIdx);
|
||||
CustomSecName = Sec->getName().substr(0, 15 - IdxStr.size()).str();
|
||||
CustomSecName += ".";
|
||||
CustomSecName += IdxStr;
|
||||
SecName = StringRef(CustomSecName.data(), 16);
|
||||
}
|
||||
|
||||
SectionRange R(*Sec);
|
||||
if (R.getFirstBlock()->getAlignmentOffset() != 0)
|
||||
return make_error<StringError>(
|
||||
"While building MachO debug object for " + G.getName() +
|
||||
" first block has non-zero alignment offset",
|
||||
inconvertibleErrorCode());
|
||||
|
||||
typename MachOTraits::Section SecCmd;
|
||||
memset(&SecCmd, 0, sizeof(SecCmd));
|
||||
memcpy(SecCmd.sectname, SecName.data(), SecName.size());
|
||||
memcpy(SecCmd.segname, SegName.data(), SegName.size());
|
||||
SecCmd.addr = R.getStart().getValue();
|
||||
SecCmd.size = R.getSize();
|
||||
SecCmd.offset = 0;
|
||||
SecCmd.align = R.getFirstBlock()->getAlignment();
|
||||
SecCmd.reloff = 0;
|
||||
SecCmd.nreloc = 0;
|
||||
SecCmd.flags = 0;
|
||||
Writer.write(SecCmd);
|
||||
}
|
||||
|
||||
static constexpr bool AutoRegisterCode = true;
|
||||
SectionRange R(MachOContainerBlock->getSection());
|
||||
@ -225,34 +355,13 @@ public:
|
||||
shared::SPSArgList<shared::SPSExecutorAddrRange, bool>>(
|
||||
RegisterActionAddr, R.getRange(), AutoRegisterCode)),
|
||||
{}});
|
||||
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
private:
|
||||
struct SectionPair {
|
||||
Section *GraphSec = nullptr;
|
||||
typename MachOBuilder<MachOTraits>::Section *BuilderSec = nullptr;
|
||||
};
|
||||
|
||||
struct StabSymbolsEntry {
|
||||
using RelocTarget = typename MachOBuilder<MachOTraits>::RelocTarget;
|
||||
|
||||
StabSymbolsEntry(Symbol &Sym, RelocTarget StartStab, RelocTarget EndStab)
|
||||
: Sym(Sym), StartStab(StartStab), EndStab(EndStab) {}
|
||||
|
||||
Symbol &Sym;
|
||||
RelocTarget StartStab, EndStab;
|
||||
};
|
||||
|
||||
using BuilderType = MachOBuilder<MachOTraits>;
|
||||
|
||||
Block *MachOContainerBlock = nullptr;
|
||||
MachOBuilder<MachOTraits> Builder;
|
||||
typename MachOBuilder<MachOTraits>::Segment *Seg = nullptr;
|
||||
std::vector<StabSymbolsEntry> StabSymbols;
|
||||
SmallVector<SectionPair, 16> DebugSections;
|
||||
SmallVector<SectionPair, 16> NonDebugSections;
|
||||
SmallVector<Section *, 16> NonDebugSections;
|
||||
size_t NonDebugSectionsStart = 0;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
@ -344,12 +453,12 @@ void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
|
||||
});
|
||||
|
||||
auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>(
|
||||
MR.getTargetJITDylib().getExecutionSession(), LG, RegisterActionAddr);
|
||||
LG, RegisterActionAddr);
|
||||
PassConfig.PrePrunePasses.push_back(
|
||||
[=](LinkGraph &G) { return MDOS->preserveDebugSections(); });
|
||||
PassConfig.PostPrunePasses.push_back(
|
||||
[=](LinkGraph &G) { return MDOS->startSynthesis(); });
|
||||
PassConfig.PostFixupPasses.push_back(
|
||||
PassConfig.PreFixupPasses.push_back(
|
||||
[=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); });
|
||||
} else {
|
||||
LLVM_DEBUG({
|
||||
|
Loading…
Reference in New Issue
Block a user