[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