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:
Lang Hames 2023-09-07 10:40:07 -07:00
parent 4427407a29
commit 99e70cc3a5
2 changed files with 223 additions and 639 deletions

View File

@ -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

View File

@ -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({