[llvm] 5293109 - Re-apply 75c487602a "[ORC] Add a MachOBuilder utility, use it to..." with fixes.
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 11 10:57:02 PDT 2023
Author: Lang Hames
Date: 2023-09-11T10:56:54-07:00
New Revision: 5293109774def143a7afe96e5705ffc7d74ed177
URL: https://github.com/llvm/llvm-project/commit/5293109774def143a7afe96e5705ffc7d74ed177
DIFF: https://github.com/llvm/llvm-project/commit/5293109774def143a7afe96e5705ffc7d74ed177.diff
LOG: Re-apply 75c487602a "[ORC] Add a MachOBuilder utility, use it to..." with fixes.
This re-applies 75c487602a8 ([ORC] Add a MachOBuilder utility, use it to build
MachO debug objects), which was reverted in 99e70cc3a5 due to build
failures. The MachoBuilder class has been refactored to fix the errors.
Added:
llvm/include/llvm/ExecutionEngine/Orc/MachOBuilder.h
Modified:
llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/MachOBuilder.h b/llvm/include/llvm/ExecutionEngine/Orc/MachOBuilder.h
new file mode 100644
index 000000000000000..239889be91138e7
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/MachOBuilder.h
@@ -0,0 +1,519 @@
+//===------------ 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 {
+
+template <typename MachOStruct>
+size_t writeMachOStruct(MutableArrayRef<char> Buf, size_t Offset, MachOStruct S,
+ bool SwapStruct) {
+ if (SwapStruct)
+ MachO::swapStruct(S);
+ assert(Offset + sizeof(MachOStruct) <= Buf.size() && "Buffer overflow");
+ memcpy(&Buf[Offset], reinterpret_cast<const char *>(&S), sizeof(MachOStruct));
+ return Offset + sizeof(MachOStruct);
+}
+
+/// Base type for MachOBuilder load command wrappers.
+struct MachOBuilderLoadCommandBase {
+ virtual ~MachOBuilderLoadCommandBase() {}
+ virtual size_t size() const = 0;
+ virtual size_t write(MutableArrayRef<char> Buf, size_t Offset,
+ bool SwapStruct) = 0;
+};
+
+/// MachOBuilder load command wrapper type.
+template <MachO::LoadCommandType LCType> struct MachOBuilderLoadCommand;
+
+#define HANDLE_LOAD_COMMAND(Name, Value, LCStruct) \
+ template <> \
+ struct MachOBuilderLoadCommand<MachO::Name> \
+ : public MachO::LCStruct, public MachOBuilderLoadCommandBase { \
+ using CmdStruct = LCStruct; \
+ MachOBuilderLoadCommand() { \
+ memset(&rawStruct(), 0, sizeof(CmdStruct)); \
+ cmd = Value; \
+ cmdsize = sizeof(CmdStruct); \
+ } \
+ template <typename... ArgTs> \
+ MachOBuilderLoadCommand(ArgTs &&...Args) \
+ : CmdStruct{Value, sizeof(CmdStruct), std::forward<ArgTs>(Args)...} {} \
+ CmdStruct &rawStruct() { return static_cast<CmdStruct &>(*this); } \
+ size_t size() const override { return cmdsize; } \
+ size_t write(MutableArrayRef<char> Buf, size_t Offset, \
+ bool SwapStruct) override { \
+ return writeMachOStruct(Buf, Offset, rawStruct(), SwapStruct); \
+ } \
+ };
+
+#include "llvm/BinaryFormat/MachO.def"
+
+#undef HANDLE_LOAD_COMMAND
+
+// Builds MachO objects.
+template <typename MachOTraits> class MachOBuilder {
+private:
+ struct SymbolContainer {
+ size_t SymbolIndexBase = 0;
+ std::vector<typename MachOTraits::NList> Symbols;
+ };
+
+ struct StringTableEntry {
+ StringRef S;
+ size_t Offset;
+ };
+
+ using StringTable = std::vector<StringTableEntry>;
+
+ static bool swapStruct() {
+ return MachOTraits::Endianness != support::endian::system_endianness();
+ }
+
+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 MachOBuilderLoadCommand<MachOTraits::SegmentCmd> {
+ MachOBuilder &Builder;
+ std::vector<std::unique_ptr<Section>> Sections;
+
+ Segment(MachOBuilder &Builder, StringRef SegName)
+ : MachOBuilderLoadCommand<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();
+ }
+
+ size_t write(MutableArrayRef<char> Buf, size_t Offset,
+ bool SwapStruct) override {
+ Offset = MachOBuilderLoadCommand<MachOTraits::SegmentCmd>::write(
+ Buf, Offset, SwapStruct);
+ for (auto &Sec : Sections)
+ Offset = writeMachOStruct(Buf, Offset, Sec->rawStruct(), SwapStruct);
+ return Offset;
+ }
+ };
+
+ MachOBuilder(size_t PageSize) : PageSize(PageSize) {
+ memset((char *)&Header, 0, sizeof(Header));
+ Header.magic = MachOTraits::Magic;
+ }
+
+ template <MachO::LoadCommandType LCType, typename... ArgTs>
+ MachOBuilderLoadCommand<LCType> &addLoadCommand(ArgTs &&...Args) {
+ static_assert(LCType != MachOTraits::SegmentCmd,
+ "Use addSegment to add segment load command");
+ auto LC = std::make_unique<MachOBuilderLoadCommand<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();
+ MachOBuilderLoadCommand<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) {
+ size_t Offset = 0;
+ Offset = writeHeader(Buffer, Offset);
+ Offset = writeSegments(Buffer, Offset);
+ Offset = writeLoadCommands(Buffer, Offset);
+ Offset = writeSectionContent(Buffer, Offset);
+ Offset = writeRelocations(Buffer, Offset);
+ Offset = writeSymbols(Buffer, Offset);
+ Offset = writeStrings(Buffer, Offset);
+ }
+
+ 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;
+ }
+ }
+
+ size_t writeHeader(MutableArrayRef<char> Buf, size_t Offset) {
+ Header.ncmds = Segments.size() + LoadCommands.size();
+ return writeMachOStruct(Buf, Offset, Header, swapStruct());
+ }
+
+ size_t writeSegments(MutableArrayRef<char> Buf, size_t Offset) {
+ for (auto &Seg : Segments)
+ Offset = Seg.write(Buf, Offset, swapStruct());
+ return Offset;
+ }
+
+ size_t writeLoadCommands(MutableArrayRef<char> Buf, size_t Offset) {
+ for (auto &LC : LoadCommands)
+ Offset = LC->write(Buf, Offset, swapStruct());
+ return Offset;
+ }
+
+ size_t writeSectionContent(MutableArrayRef<char> Buf, size_t Offset) {
+ 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;
+ }
+ while (Offset != Sec->offset)
+ Buf[Offset++] = '\0';
+
+ assert(Offset + Sec->Content.Size <= Buf.size() && "Buffer overflow");
+ memcpy(&Buf[Offset], Sec->Content.Data, Sec->Content.Size);
+ Offset += Sec->Content.Size;
+ }
+ }
+ return Offset;
+ }
+
+ size_t writeRelocations(MutableArrayRef<char> Buf, size_t Offset) {
+ for (auto &Seg : Segments) {
+ for (auto &Sec : Seg.Sections) {
+ if (!Sec->Relocs.empty()) {
+ while (Offset % sizeof(MachO::relocation_info))
+ Buf[Offset++] = '\0';
+ }
+ for (auto &R : Sec->Relocs) {
+ assert(Offset + sizeof(MachO::relocation_info) <= Buf.size() &&
+ "Buffer overflow");
+ memcpy(&Buf[Offset], reinterpret_cast<const char *>(&R.rawStruct()),
+ sizeof(MachO::relocation_info));
+ Offset += sizeof(MachO::relocation_info);
+ }
+ }
+ }
+ return Offset;
+ }
+
+ size_t writeSymbols(MutableArrayRef<char> Buf, size_t Offset) {
+
+ // 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 Offset;
+
+ // Align to nlist entry size.
+ while (Offset % sizeof(typename MachOTraits::NList))
+ Buf[Offset++] = '\0';
+
+ // Write non-section symbols.
+ for (auto &Sym : SC.Symbols)
+ Offset = writeMachOStruct(Buf, Offset, Sym, swapStruct());
+
+ // Write section symbols.
+ for (auto &Seg : Segments) {
+ for (auto &Sec : Seg.Sections) {
+ for (auto &Sym : Sec->SC.Symbols) {
+ Offset = writeMachOStruct(Buf, Offset, Sym, swapStruct());
+ }
+ }
+ }
+ return Offset;
+ }
+
+ size_t writeStrings(MutableArrayRef<char> Buf, size_t Offset) {
+ for (auto &Elem : StrTab) {
+ assert(Offset + Elem.S.size() + 1 <= Buf.size() && "Buffer overflow");
+ memcpy(&Buf[Offset], Elem.S.data(), Elem.S.size());
+ Offset += Elem.S.size();
+ Buf[Offset++] = '\0';
+ }
+ return Offset;
+ }
+
+ size_t PageSize;
+ std::list<Segment> Segments;
+ std::vector<std::unique_ptr<MachOBuilderLoadCommandBase>> 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
diff --git a/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp
index 830582bb3649115..63c188676d197b4 100644
--- a/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/DebuggerSupportPlugin.cpp
@@ -10,6 +10,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/DebuggerSupportPlugin.h"
+#include "llvm/ExecutionEngine/Orc/MachOBuilder.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
@@ -26,19 +27,6 @@ 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:
@@ -84,6 +72,7 @@ class MachODebugObjectSynthesizerBase
if (!PreservedBlocks.count(B))
G.addAnonymousSymbol(*B, 0, 0, false, true);
}
+
return Error::success();
}
@@ -94,28 +83,12 @@ class MachODebugObjectSynthesizerBase
template <typename MachOTraits>
class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
-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:
+ MachODebugObjectSynthesizer(ExecutionSession &ES, LinkGraph &G,
+ ExecutorAddr RegisterActionAddr)
+ : MachODebugObjectSynthesizerBase(G, RegisterActionAddr),
+ Builder(ES.getPageSize()) {}
+
using MachODebugObjectSynthesizerBase::MachODebugObjectSynthesizerBase;
Error startSynthesis() override {
@@ -123,164 +96,79 @@ class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
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;
- ++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 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();
- }
+ // Skip sections whose name's don't fit the MachO standard.
+ if (Sec.getName().empty() || Sec.getName().size() > 33 ||
+ Sec.getName().find(',') > 16)
+ continue;
- 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;
+ if (isDebugSection(Sec))
+ DebugSections.push_back({&Sec, nullptr});
+ else if (Sec.getMemLifetimePolicy() != MemLifetimePolicy::NoAlloc)
+ NonDebugSections.push_back({&Sec, nullptr});
}
- size_t DebugSectionsSize =
- NextBlockAddr - orc::ExecutorAddr(MachOContainerBlock->getSize());
// Write MachO header and debug section load commands.
- MachOStructWriter Writer(MachOContainerBlock->getAlreadyMutableContent());
- typename MachOTraits::Header Hdr;
- memset(&Hdr, 0, sizeof(Hdr));
- Hdr.magic = MachOTraits::Magic;
+ Builder.Header.filetype = MachO::MH_OBJECT;
switch (G.getTargetTriple().getArch()) {
case Triple::x86_64:
- Hdr.cputype = MachO::CPU_TYPE_X86_64;
- Hdr.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
+ Builder.Header.cputype = MachO::CPU_TYPE_X86_64;
+ Builder.Header.cpusubtype = MachO::CPU_SUBTYPE_X86_64_ALL;
break;
case Triple::aarch64:
- Hdr.cputype = MachO::CPU_TYPE_ARM64;
- Hdr.cpusubtype = MachO::CPU_SUBTYPE_ARM64_ALL;
+ Builder.Header.cputype = MachO::CPU_TYPE_ARM64;
+ Builder.Header.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);
-
- 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);
-
- 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);
+
+ Seg = &Builder.addSegment("");
+
+ 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());
}
- // Set MachOContainerBlock to indicate success to
- // completeSynthesisAndRegister.
- NonDebugSectionsStart = Writer.getOffset();
+ 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);
+
return Error::success();
}
@@ -290,64 +178,46 @@ class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
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";
});
- MachOStructWriter Writer(
- MachOContainerBlock->getAlreadyMutableContent().drop_front(
- NonDebugSectionsStart));
-
- 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);
+ // 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();
}
+ Builder.write(MachOContainerBlock->getAlreadyMutableContent());
+
static constexpr bool AutoRegisterCode = true;
SectionRange R(MachOContainerBlock->getSection());
G.allocActions().push_back(
@@ -355,13 +225,34 @@ class MachODebugObjectSynthesizer : public MachODebugObjectSynthesizerBase {
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;
- SmallVector<Section *, 16> NonDebugSections;
- size_t NonDebugSectionsStart = 0;
+ MachOBuilder<MachOTraits> Builder;
+ typename MachOBuilder<MachOTraits>::Segment *Seg = nullptr;
+ std::vector<StabSymbolsEntry> StabSymbols;
+ SmallVector<SectionPair, 16> DebugSections;
+ SmallVector<SectionPair, 16> NonDebugSections;
};
} // end anonymous namespace
@@ -453,12 +344,12 @@ void GDBJITDebugInfoRegistrationPlugin::modifyPassConfigForMachO(
});
auto MDOS = std::make_shared<MachODebugObjectSynthesizer<MachO64LE>>(
- LG, RegisterActionAddr);
+ MR.getTargetJITDylib().getExecutionSession(), LG, RegisterActionAddr);
PassConfig.PrePrunePasses.push_back(
[=](LinkGraph &G) { return MDOS->preserveDebugSections(); });
PassConfig.PostPrunePasses.push_back(
[=](LinkGraph &G) { return MDOS->startSynthesis(); });
- PassConfig.PreFixupPasses.push_back(
+ PassConfig.PostFixupPasses.push_back(
[=](LinkGraph &G) { return MDOS->completeSynthesisAndRegister(); });
} else {
LLVM_DEBUG({
More information about the llvm-commits
mailing list