[llvm] ef23892 - [Orc] Add JITLink debug support plugin for ELF x86-64

Stefan Gränitz via llvm-commits llvm-commits at lists.llvm.org
Tue Mar 2 06:08:19 PST 2021


Author: Stefan Gränitz
Date: 2021-03-02T15:07:35+01:00
New Revision: ef2389235c5dec03be93f8c9585cd9416767ef4c

URL: https://github.com/llvm/llvm-project/commit/ef2389235c5dec03be93f8c9585cd9416767ef4c
DIFF: https://github.com/llvm/llvm-project/commit/ef2389235c5dec03be93f8c9585cd9416767ef4c.diff

LOG: [Orc] Add JITLink debug support plugin for ELF x86-64

Add a new ObjectLinkingLayer plugin `DebugObjectManagerPlugin` and infrastructure to handle creation of `DebugObject`s as well as their registration in OrcTargetProcess. The current implementation only covers ELF on x86-64, but the infrastructure is not limited to that.

The journey starts with a new `LinkGraph` / `JITLinkContext` pair being created for a `MaterializationResponsibility` in ORC's `ObjectLinkingLayer`. It sends a `notifyMaterializing()` notification, which is forwarded to all registered plugins. The `DebugObjectManagerPlugin` aims to create a  `DebugObject` form the provided target triple and object buffer. (Future implementations might create `DebugObject`s from a `LinkGraph` in other ways.) On success it will track it as the pending `DebugObject` for the `MaterializationResponsibility`.

This patch only implements the `ELFDebugObject` for `x86-64` targets. It follows the RuntimeDyld approach for debug object setup: it captures a copy of the input object, parses all section headers and prepares to patch their load-address fields with their final addresses in target memory. It instructs the plugin to report the section load-addresses once they are available. The plugin overrides `modifyPassConfig()` and installs a JITLink post-allocation pass to capture them.

Once JITLink emitted the finalized executable, the plugin emits and registers the `DebugObject`. For emission it requests a new `JITLinkMemoryManager::Allocation` with a single read-only segment, copies the object with patched section load-addresses over to working memory and triggers finalization to target memory. For registration, it notifies the `DebugObjectRegistrar` provided in the constructor and stores the previously pending`DebugObject` as registered for the corresponding MaterializationResponsibility.

The `DebugObjectRegistrar` registers the `DebugObject` with the target process. `llvm-jitlink` uses the `TPCDebugObjectRegistrar`, which calls `llvm_orc_registerJITLoaderGDBWrapper()` in the target process via `TargetProcessControl` to emit a `jit_code_entry` compatible with the GDB JIT interface [1]. So far the implementation only supports registration and no removal. It appears to me that it wouldn't raise any new design questions, so I left this as an addition for the near future.

[1] https://sourceware.org/gdb/current/onlinedocs/gdb/JIT-Interface.html

Reviewed By: lhames

Differential Revision: https://reviews.llvm.org/D97335

Added: 
    llvm/include/llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h
    llvm/include/llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h
    llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h
    llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp
    llvm/lib/ExecutionEngine/Orc/TPCDebugObjectRegistrar.cpp
    llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp

Modified: 
    llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
    llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
    llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
    llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
    llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
    llvm/tools/llvm-jitlink/llvm-jitlink.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h b/llvm/include/llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h
new file mode 100644
index 000000000000..51efd8a6cd5a
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h
@@ -0,0 +1,84 @@
+//===---- DebugObjectManagerPlugin.h - JITLink debug 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
+//
+//===----------------------------------------------------------------------===//
+//
+// ObjectLinkingLayer plugin for emitting debug objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_DEBUGOBJECTMANAGERPLUGIN_H
+#define LLVM_EXECUTIONENGINE_ORC_DEBUGOBJECTMANAGERPLUGIN_H
+
+#include "llvm/ADT/Triple.h"
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Memory.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+#include <functional>
+#include <map>
+#include <memory>
+#include <mutex>
+
+namespace llvm {
+namespace orc {
+
+class DebugObject;
+
+/// Creates and manages DebugObjects for JITLink artifacts.
+///
+/// DebugObjects are created when linking for a MaterializationResponsibility
+/// starts. They are pending as long as materialization is in progress.
+///
+/// There can only be one pending DebugObject per MaterializationResponsibility.
+/// If materialization fails, pending DebugObjects are discarded.
+///
+/// Once executable code for the MaterializationResponsibility is emitted, the
+/// corresponding DebugObject is finalized to target memory and the provided
+/// DebugObjectRegistrar is notified. Ownership of DebugObjects remains with the
+/// plugin.
+///
+class DebugObjectManagerPlugin : public ObjectLinkingLayer::Plugin {
+public:
+  DebugObjectManagerPlugin(ExecutionSession &ES,
+                           std::unique_ptr<DebugObjectRegistrar> Target);
+  ~DebugObjectManagerPlugin();
+
+  void notifyMaterializing(MaterializationResponsibility &MR,
+                           jitlink::LinkGraph &G, jitlink::JITLinkContext &Ctx,
+                           MemoryBufferRef InputObject) override;
+
+  Error notifyEmitted(MaterializationResponsibility &MR) override;
+  Error notifyFailed(MaterializationResponsibility &MR) override;
+  Error notifyRemovingResources(ResourceKey K) override;
+
+  void notifyTransferringResources(ResourceKey DstKey,
+                                   ResourceKey SrcKey) override;
+
+  void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
+                        jitlink::PassConfiguration &PassConfig) override;
+
+private:
+  ExecutionSession &ES;
+
+  using OwnedDebugObject = std::unique_ptr<DebugObject>;
+  std::map<ResourceKey, OwnedDebugObject> PendingObjs;
+  std::map<ResourceKey, std::vector<OwnedDebugObject>> RegisteredObjs;
+
+  std::mutex PendingObjsLock;
+  std::mutex RegisteredObjsLock;
+
+  std::unique_ptr<DebugObjectRegistrar> Target;
+};
+
+} // namespace orc
+} // namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_DEBUGOBJECTMANAGERPLUGIN_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
index 567754cd9862..273870275296 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h
@@ -72,6 +72,13 @@ class ObjectLinkingLayer : public RTTIExtends<ObjectLinkingLayer, ObjectLayer>,
                                   const Triple &TT,
                                   jitlink::PassConfiguration &Config) {}
 
+    // Deprecated. Don't use this in new code. There will be a proper mechanism
+    // for capturing object buffers.
+    virtual void notifyMaterializing(MaterializationResponsibility &MR,
+                                     jitlink::LinkGraph &G,
+                                     jitlink::JITLinkContext &Ctx,
+                                     MemoryBufferRef InputObject) {}
+
     virtual void notifyLoaded(MaterializationResponsibility &MR) {}
     virtual Error notifyEmitted(MaterializationResponsibility &MR) {
       return Error::success();

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h b/llvm/include/llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h
new file mode 100644
index 000000000000..9ec233a0d38c
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h
@@ -0,0 +1,67 @@
+//===- TPCDebugObjectRegistrar.h - TPC-based debug registration -*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// TargetProcessControl based registration of debug objects.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TPCDEBUGOBJECTREGISTRAR_H
+#define LLVM_EXECUTIONENGINE_ORC_TPCDEBUGOBJECTREGISTRAR_H
+
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Memory.h"
+
+#include <cstdint>
+#include <memory>
+#include <vector>
+
+namespace llvm {
+namespace orc {
+
+/// Abstract interface for registering debug objects in the target process.
+class DebugObjectRegistrar {
+public:
+  virtual Error registerDebugObject(sys::MemoryBlock) = 0;
+  virtual ~DebugObjectRegistrar() {}
+};
+
+/// Use TargetProcessControl to register debug objects locally or in a remote
+/// target process.
+class TPCDebugObjectRegistrar : public DebugObjectRegistrar {
+public:
+  using SerializeBlockInfoFn =
+      std::vector<uint8_t> (*)(sys::MemoryBlock TargetMemBlock);
+
+  TPCDebugObjectRegistrar(TargetProcessControl &TPC,
+                          JITTargetAddress RegisterFn,
+                          SerializeBlockInfoFn SerializeBlockInfo)
+      : TPC(TPC), RegisterFn(RegisterFn),
+        SerializeBlockInfo(SerializeBlockInfo) {}
+
+  Error registerDebugObject(sys::MemoryBlock TargetMem) override {
+    return TPC.runWrapper(RegisterFn, SerializeBlockInfo(TargetMem))
+        .takeError();
+  }
+
+private:
+  TargetProcessControl &TPC;
+  JITTargetAddress RegisterFn;
+  SerializeBlockInfoFn SerializeBlockInfo;
+};
+
+/// Create a TargetProcessControl-based DebugObjectRegistrar that emits debug
+/// objects to the GDB JIT interface.
+Expected<std::unique_ptr<TPCDebugObjectRegistrar>>
+createJITLoaderGDBRegistrar(TargetProcessControl &TPC);
+
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TDEBUGOBJECTREGISTRAR_H

diff  --git a/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h
new file mode 100644
index 000000000000..4188cea2b711
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h
@@ -0,0 +1,22 @@
+//===- JITLoaderGDB.h - Register objects via GDB JIT interface -*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Register objects for access by debuggers via the GDB JIT interface.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERGDB_H
+#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERGDB_H
+
+#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
+#include <cstdint>
+
+extern "C" llvm::orc::tpctypes::CWrapperFunctionResult
+llvm_orc_registerJITLoaderGDBWrapper(uint8_t *Data, uint64_t Size);
+
+#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERGDB_H

diff  --git a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
index 791b037323f2..edcdfb2b1c41 100644
--- a/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/CMakeLists.txt
@@ -2,6 +2,7 @@ add_llvm_component_library(LLVMOrcJIT
   CompileOnDemandLayer.cpp
   CompileUtils.cpp
   Core.cpp
+  DebugObjectManagerPlugin.cpp
   DebugUtils.cpp
   ExecutionUtils.cpp
   IndirectionUtils.cpp
@@ -22,6 +23,7 @@ add_llvm_component_library(LLVMOrcJIT
   SpeculateAnalyses.cpp
   TargetProcessControl.cpp
   ThreadSafeModule.cpp
+  TPCDebugObjectRegistrar.cpp
   TPCDynamicLibrarySearchGenerator.cpp
   TPCEHFrameRegistrar.cpp
   TPCIndirectionUtils.cpp

diff  --git a/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp b/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp
new file mode 100644
index 000000000000..dc1778d4534c
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/DebugObjectManagerPlugin.cpp
@@ -0,0 +1,482 @@
+//===---- DebugObjectManagerPlugin.h - JITLink debug 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/ExecutionEngine/JITLink/JITLinkDylib.h"
+#include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <set>
+
+#define DEBUG_TYPE "orc"
+
+using namespace llvm::jitlink;
+using namespace llvm::object;
+
+namespace llvm {
+namespace orc {
+
+class DebugObjectSection {
+public:
+  virtual void setTargetMemoryRange(SectionRange Range) = 0;
+  virtual void dump(raw_ostream &OS, StringRef Name) {}
+  virtual ~DebugObjectSection() {}
+};
+
+template <typename ELFT>
+class ELFDebugObjectSection : public DebugObjectSection {
+public:
+  // BinaryFormat ELF is not meant as a mutable format. We can only make changes
+  // that don't invalidate the file structure.
+  ELFDebugObjectSection(const typename ELFT::Shdr *Header)
+      : Header(const_cast<typename ELFT::Shdr *>(Header)) {}
+
+  void setTargetMemoryRange(SectionRange Range) override;
+  void dump(raw_ostream &OS, StringRef Name) override;
+
+private:
+  typename ELFT::Shdr *Header;
+
+  bool isTextOrDataSection() const;
+};
+
+template <typename ELFT>
+void ELFDebugObjectSection<ELFT>::setTargetMemoryRange(SectionRange Range) {
+  // Only patch load-addresses for executable and data sections.
+  if (isTextOrDataSection()) {
+    Header->sh_addr = static_cast<typename ELFT::uint>(Range.getStart());
+  }
+}
+
+template <typename ELFT>
+void ELFDebugObjectSection<ELFT>::dump(raw_ostream &OS, StringRef Name) {
+  if (auto Addr = static_cast<JITTargetAddress>(Header->sh_addr)) {
+    OS << formatv("  {0:x16} {1}\n", Addr, Name);
+  } else {
+    OS << formatv("                     {0}\n", Name);
+  }
+}
+
+template <typename ELFT>
+bool ELFDebugObjectSection<ELFT>::isTextOrDataSection() const {
+  switch (Header->sh_type) {
+  case ELF::SHT_PROGBITS:
+  case ELF::SHT_X86_64_UNWIND:
+    return Header->sh_flags & (ELF::SHF_EXECINSTR | ELF::SHF_ALLOC);
+  }
+  return false;
+}
+
+static constexpr sys::Memory::ProtectionFlags ReadOnly =
+    static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ);
+
+enum class Requirement {
+  // Request final target memory load-addresses for all sections.
+  ReportFinalSectionLoadAddresses,
+};
+
+/// The plugin creates a debug object from JITLinkContext when JITLink starts
+/// processing the corresponding LinkGraph. It provides access to the pass
+/// configuration of the LinkGraph and calls the finalization function, once
+/// the resulting link artifact was emitted.
+///
+class DebugObject {
+public:
+  DebugObject(JITLinkContext &Ctx) : Ctx(Ctx) {}
+
+  void set(Requirement Req) { Reqs.insert(Req); }
+  bool has(Requirement Req) const { return Reqs.count(Req) > 0; }
+
+  using FinalizeContinuation = std::function<void(Expected<sys::MemoryBlock>)>;
+  void finalizeAsync(FinalizeContinuation OnFinalize);
+
+  virtual void reportSectionTargetMemoryRange(StringRef Name,
+                                              SectionRange TargetMem) {}
+  virtual ~DebugObject() {}
+
+protected:
+  using Allocation = JITLinkMemoryManager::Allocation;
+
+  virtual Expected<std::unique_ptr<Allocation>>
+  finalizeWorkingMemory(JITLinkContext &Ctx) = 0;
+
+private:
+  JITLinkContext &Ctx;
+  std::set<Requirement> Reqs;
+  std::unique_ptr<Allocation> Alloc{nullptr};
+};
+
+// Finalize working memory and take ownership of the resulting allocation. Start
+// copying memory over to the target and pass on the result once we're done.
+// Ownership of the allocation remains with us for the rest of our lifetime.
+void DebugObject::finalizeAsync(FinalizeContinuation OnFinalize) {
+  assert(Alloc == nullptr && "Cannot finalize more than once");
+
+  auto AllocOrErr = finalizeWorkingMemory(Ctx);
+  if (!AllocOrErr)
+    OnFinalize(AllocOrErr.takeError());
+  Alloc = std::move(*AllocOrErr);
+
+  Alloc->finalizeAsync([this, OnFinalize](Error Err) {
+    if (Err)
+      OnFinalize(std::move(Err));
+    else
+      OnFinalize(sys::MemoryBlock(
+          jitTargetAddressToPointer<void *>(Alloc->getTargetMemory(ReadOnly)),
+          Alloc->getWorkingMemory(ReadOnly).size()));
+  });
+}
+
+/// The current implementation of ELFDebugObject replicates the approach used in
+/// RuntimeDyld: It patches executable and data section headers in the given
+/// object buffer with load-addresses of their corresponding sections in target
+/// memory.
+///
+class ELFDebugObject : public DebugObject {
+public:
+  static Expected<std::unique_ptr<DebugObject>> Create(MemoryBufferRef Buffer,
+                                                       JITLinkContext &Ctx);
+
+  void reportSectionTargetMemoryRange(StringRef Name,
+                                      SectionRange TargetMem) override;
+
+protected:
+  Expected<std::unique_ptr<Allocation>>
+  finalizeWorkingMemory(JITLinkContext &Ctx) override;
+
+  Error recordSection(StringRef Name,
+                      std::unique_ptr<DebugObjectSection> Section);
+  DebugObjectSection *getSection(StringRef Name);
+
+private:
+  template <typename ELFT>
+  static Expected<std::unique_ptr<ELFDebugObject>>
+  CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx);
+
+  static Expected<std::unique_ptr<WritableMemoryBuffer>>
+  CopyBuffer(MemoryBufferRef Buffer);
+
+  ELFDebugObject(std::unique_ptr<WritableMemoryBuffer> Buffer,
+                 JITLinkContext &Ctx)
+      : DebugObject(Ctx), Buffer(std::move(Buffer)) {
+    set(Requirement::ReportFinalSectionLoadAddresses);
+  }
+
+  std::unique_ptr<WritableMemoryBuffer> Buffer;
+  StringMap<std::unique_ptr<DebugObjectSection>> Sections;
+};
+
+static const std::set<StringRef> DwarfSectionNames = {
+#define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
+  ELF_NAME,
+#include "llvm/BinaryFormat/Dwarf.def"
+#undef HANDLE_DWARF_SECTION
+};
+
+static bool isDwarfSection(StringRef SectionName) {
+  return DwarfSectionNames.count(SectionName) == 1;
+}
+
+Expected<std::unique_ptr<WritableMemoryBuffer>>
+ELFDebugObject::CopyBuffer(MemoryBufferRef Buffer) {
+  size_t Size = Buffer.getBufferSize();
+  StringRef Name = Buffer.getBufferIdentifier();
+  auto Copy = WritableMemoryBuffer::getNewUninitMemBuffer(Size, Name);
+  if (!Copy)
+    return errorCodeToError(make_error_code(errc::not_enough_memory));
+
+  memcpy(Copy->getBufferStart(), Buffer.getBufferStart(), Size);
+  return std::move(Copy);
+}
+
+template <typename ELFT>
+Expected<std::unique_ptr<ELFDebugObject>>
+ELFDebugObject::CreateArchType(MemoryBufferRef Buffer, JITLinkContext &Ctx) {
+  using SectionHeader = typename ELFT::Shdr;
+
+  Expected<ELFFile<ELFT>> ObjRef = ELFFile<ELFT>::create(Buffer.getBuffer());
+  if (!ObjRef)
+    return ObjRef.takeError();
+
+  // TODO: Add support for other architectures.
+  uint16_t TargetMachineArch = ObjRef->getHeader().e_machine;
+  if (TargetMachineArch != ELF::EM_X86_64)
+    return nullptr;
+
+  Expected<ArrayRef<SectionHeader>> Sections = ObjRef->sections();
+  if (!Sections)
+    return Sections.takeError();
+
+  Expected<std::unique_ptr<WritableMemoryBuffer>> Copy = CopyBuffer(Buffer);
+  if (!Copy)
+    return Copy.takeError();
+
+  std::unique_ptr<ELFDebugObject> DebugObj(
+      new ELFDebugObject(std::move(*Copy), Ctx));
+
+  bool HasDwarfSection = false;
+  for (const SectionHeader &Header : *Sections) {
+    Expected<StringRef> Name = ObjRef->getSectionName(Header);
+    if (!Name)
+      return Name.takeError();
+    if (Name->empty())
+      continue;
+    HasDwarfSection |= isDwarfSection(*Name);
+
+    auto Wrapped = std::make_unique<ELFDebugObjectSection<ELFT>>(&Header);
+    if (Error Err = DebugObj->recordSection(*Name, std::move(Wrapped)))
+      return std::move(Err);
+  }
+
+  if (!HasDwarfSection) {
+    LLVM_DEBUG(dbgs() << "Aborting debug registration for LinkGraph \""
+                      << DebugObj->Buffer->getBufferIdentifier()
+                      << "\": input object contains no debug info\n");
+    return nullptr;
+  }
+
+  return std::move(DebugObj);
+}
+
+Expected<std::unique_ptr<DebugObject>>
+ELFDebugObject::Create(MemoryBufferRef Buffer, JITLinkContext &Ctx) {
+  unsigned char Class, Endian;
+  std::tie(Class, Endian) = getElfArchType(Buffer.getBuffer());
+
+  if (Class == ELF::ELFCLASS32) {
+    if (Endian == ELF::ELFDATA2LSB)
+      return CreateArchType<ELF32LE>(Buffer, Ctx);
+    if (Endian == ELF::ELFDATA2MSB)
+      return CreateArchType<ELF32BE>(Buffer, Ctx);
+    return nullptr;
+  }
+  if (Class == ELF::ELFCLASS64) {
+    if (Endian == ELF::ELFDATA2LSB)
+      return CreateArchType<ELF64LE>(Buffer, Ctx);
+    if (Endian == ELF::ELFDATA2MSB)
+      return CreateArchType<ELF64BE>(Buffer, Ctx);
+    return nullptr;
+  }
+  return nullptr;
+}
+
+Expected<std::unique_ptr<DebugObject::Allocation>>
+ELFDebugObject::finalizeWorkingMemory(JITLinkContext &Ctx) {
+  LLVM_DEBUG({
+    dbgs() << "Section load-addresses in debug object for \""
+           << Buffer->getBufferIdentifier() << "\":\n";
+    for (const auto &KV : Sections)
+      KV.second->dump(dbgs(), KV.first());
+  });
+
+  // TODO: This works, but what actual alignment requirements do we have?
+  unsigned Alignment = sys::Process::getPageSizeEstimate();
+  JITLinkMemoryManager &MemMgr = Ctx.getMemoryManager();
+  const JITLinkDylib *JD = Ctx.getJITLinkDylib();
+  size_t Size = Buffer->getBufferSize();
+
+  // Allocate working memory for debug object in read-only segment.
+  auto AllocOrErr = MemMgr.allocate(JD, {{ReadOnly, {Alignment, Size, 0}}});
+  if (!AllocOrErr)
+    return AllocOrErr.takeError();
+
+  // Initialize working memory with a copy of our object buffer.
+  // TODO: Use our buffer as working memory directly.
+  std::unique_ptr<Allocation> Alloc = std::move(*AllocOrErr);
+  MutableArrayRef<char> WorkingMem = Alloc->getWorkingMemory(ReadOnly);
+  memcpy(WorkingMem.data(), Buffer->getBufferStart(), Size);
+  Buffer.reset();
+
+  return std::move(Alloc);
+}
+
+void ELFDebugObject::reportSectionTargetMemoryRange(StringRef Name,
+                                                    SectionRange TargetMem) {
+  if (auto *DebugObjSection = getSection(Name))
+    DebugObjSection->setTargetMemoryRange(TargetMem);
+}
+
+Error ELFDebugObject::recordSection(
+    StringRef Name, std::unique_ptr<DebugObjectSection> Section) {
+  auto ItInserted = Sections.try_emplace(Name, std::move(Section));
+  if (!ItInserted.second)
+    return make_error<StringError>("Duplicate section",
+                                   inconvertibleErrorCode());
+  return Error::success();
+}
+
+DebugObjectSection *ELFDebugObject::getSection(StringRef Name) {
+  auto It = Sections.find(Name);
+  return It == Sections.end() ? nullptr : It->second.get();
+}
+
+static ResourceKey getResourceKey(MaterializationResponsibility &MR) {
+  ResourceKey Key;
+  if (auto Err = MR.withResourceKeyDo([&](ResourceKey K) { Key = K; })) {
+    MR.getExecutionSession().reportError(std::move(Err));
+    return ResourceKey{};
+  }
+  assert(Key && "Invalid key");
+  return Key;
+}
+
+/// Creates a debug object based on the input object file from
+/// ObjectLinkingLayerJITLinkContext.
+///
+static Expected<std::unique_ptr<DebugObject>>
+createDebugObjectFromBuffer(LinkGraph &G, JITLinkContext &Ctx,
+                            MemoryBufferRef ObjBuffer) {
+  switch (G.getTargetTriple().getObjectFormat()) {
+  case Triple::ELF:
+    return ELFDebugObject::Create(ObjBuffer, Ctx);
+
+  default:
+    // TODO: Once we add support for other formats, we might want to split this
+    // into multiple files.
+    return nullptr;
+  }
+}
+
+DebugObjectManagerPlugin::DebugObjectManagerPlugin(
+    ExecutionSession &ES, std::unique_ptr<DebugObjectRegistrar> Target)
+    : ES(ES), Target(std::move(Target)) {}
+
+DebugObjectManagerPlugin::~DebugObjectManagerPlugin() {}
+
+void DebugObjectManagerPlugin::notifyMaterializing(
+    MaterializationResponsibility &MR, LinkGraph &G, JITLinkContext &Ctx,
+    MemoryBufferRef ObjBuffer) {
+  assert(PendingObjs.count(getResourceKey(MR)) == 0 &&
+         "Cannot have more than one pending debug object per "
+         "MaterializationResponsibility");
+
+  std::lock_guard<std::mutex> Lock(PendingObjsLock);
+  if (auto DebugObj = createDebugObjectFromBuffer(G, Ctx, ObjBuffer)) {
+    // Not all link artifacts allow debugging.
+    if (*DebugObj != nullptr) {
+      ResourceKey Key = getResourceKey(MR);
+      PendingObjs[Key] = std::move(*DebugObj);
+    }
+  } else {
+    ES.reportError(DebugObj.takeError());
+  }
+}
+
+void DebugObjectManagerPlugin::modifyPassConfig(
+    MaterializationResponsibility &MR, const Triple &TT,
+    PassConfiguration &PassConfig) {
+  // Not all link artifacts have associated debug objects.
+  std::lock_guard<std::mutex> Lock(PendingObjsLock);
+  auto It = PendingObjs.find(getResourceKey(MR));
+  if (It == PendingObjs.end())
+    return;
+
+  DebugObject &DebugObj = *It->second;
+  if (DebugObj.has(Requirement::ReportFinalSectionLoadAddresses)) {
+    PassConfig.PostAllocationPasses.push_back(
+        [&DebugObj](LinkGraph &Graph) -> Error {
+          for (const Section &GraphSection : Graph.sections())
+            DebugObj.reportSectionTargetMemoryRange(GraphSection.getName(),
+                                                    SectionRange(GraphSection));
+          return Error::success();
+        });
+  }
+}
+
+Error DebugObjectManagerPlugin::notifyEmitted(
+    MaterializationResponsibility &MR) {
+  ResourceKey Key = getResourceKey(MR);
+
+  std::lock_guard<std::mutex> Lock(PendingObjsLock);
+  auto It = PendingObjs.find(Key);
+  if (It == PendingObjs.end())
+    return Error::success();
+
+  DebugObject *UnownedDebugObj = It->second.release();
+  PendingObjs.erase(It);
+
+  // FIXME: We released ownership of the DebugObject, so we can easily capture
+  // the raw pointer in the continuation function, which re-owns it immediately.
+  if (UnownedDebugObj)
+    UnownedDebugObj->finalizeAsync(
+        [this, Key, UnownedDebugObj](Expected<sys::MemoryBlock> TargetMem) {
+          std::unique_ptr<DebugObject> ReownedDebugObj(UnownedDebugObj);
+          if (!TargetMem) {
+            ES.reportError(TargetMem.takeError());
+            return;
+          }
+          if (Error Err = Target->registerDebugObject(*TargetMem)) {
+            ES.reportError(std::move(Err));
+            return;
+          }
+
+          std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
+          RegisteredObjs[Key].push_back(std::move(ReownedDebugObj));
+        });
+
+  return Error::success();
+}
+
+Error DebugObjectManagerPlugin::notifyFailed(
+    MaterializationResponsibility &MR) {
+  std::lock_guard<std::mutex> Lock(PendingObjsLock);
+  PendingObjs.erase(getResourceKey(MR));
+  return Error::success();
+}
+
+void DebugObjectManagerPlugin::notifyTransferringResources(ResourceKey DstKey,
+                                                           ResourceKey SrcKey) {
+  {
+    std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
+    auto SrcIt = RegisteredObjs.find(SrcKey);
+    if (SrcIt != RegisteredObjs.end()) {
+      // Resources from distinct MaterializationResponsibilitys can get merged
+      // after emission, so we can have multiple debug objects per resource key.
+      for (std::unique_ptr<DebugObject> &DebugObj : SrcIt->second)
+        RegisteredObjs[DstKey].push_back(std::move(DebugObj));
+      RegisteredObjs.erase(SrcIt);
+    }
+  }
+  {
+    std::lock_guard<std::mutex> Lock(PendingObjsLock);
+    auto SrcIt = PendingObjs.find(SrcKey);
+    if (SrcIt != PendingObjs.end()) {
+      assert(PendingObjs.count(DstKey) == 0 &&
+             "Cannot have more than one pending debug object per "
+             "MaterializationResponsibility");
+      PendingObjs[DstKey] = std::move(SrcIt->second);
+      PendingObjs.erase(SrcIt);
+    }
+  }
+}
+
+Error DebugObjectManagerPlugin::notifyRemovingResources(ResourceKey K) {
+  {
+    std::lock_guard<std::mutex> Lock(RegisteredObjsLock);
+    RegisteredObjs.erase(K);
+    // TODO: Implement unregister notifications.
+  }
+  std::lock_guard<std::mutex> Lock(PendingObjsLock);
+  PendingObjs.erase(K);
+
+  return Error::success();
+}
+
+} // namespace orc
+} // namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
index 6de62f80a96c..24db73e4cf51 100644
--- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp
@@ -10,6 +10,8 @@
 
 #include "llvm/ADT/Optional.h"
 #include "llvm/ExecutionEngine/JITLink/EHFrameSupport.h"
+#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
+#include "llvm/Support/MemoryBuffer.h"
 
 #include <vector>
 
@@ -40,6 +42,11 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext {
 
   JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
 
+  void notifyMaterializing(LinkGraph &G) {
+    for (auto &P : Layer.Plugins)
+      P->notifyMaterializing(*MR, G, *this, ObjBuffer->getMemBufferRef());
+  }
+
   void notifyFailed(Error Err) override {
     for (auto &P : Layer.Plugins)
       Err = joinErrors(std::move(Err), P->notifyFailed(*MR));
@@ -483,19 +490,24 @@ ObjectLinkingLayer::~ObjectLinkingLayer() {
 void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
                               std::unique_ptr<MemoryBuffer> O) {
   assert(O && "Object must not be null");
-  auto ObjBuffer = O->getMemBufferRef();
+  MemoryBufferRef ObjBuffer = O->getMemBufferRef();
+
   auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
       *this, std::move(R), std::move(O));
-  if (auto G = createLinkGraphFromObject(ObjBuffer))
+  if (auto G = createLinkGraphFromObject(ObjBuffer)) {
+    Ctx->notifyMaterializing(**G);
     link(std::move(*G), std::move(Ctx));
-  else
+  } else {
     Ctx->notifyFailed(G.takeError());
+  }
 }
 
 void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
                               std::unique_ptr<LinkGraph> G) {
-  link(std::move(G), std::make_unique<ObjectLinkingLayerJITLinkContext>(
-                         *this, std::move(R), nullptr));
+  auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
+      *this, std::move(R), nullptr);
+  Ctx->notifyMaterializing(*G);
+  link(std::move(G), std::move(Ctx));
 }
 
 void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,

diff  --git a/llvm/lib/ExecutionEngine/Orc/TPCDebugObjectRegistrar.cpp b/llvm/lib/ExecutionEngine/Orc/TPCDebugObjectRegistrar.cpp
new file mode 100644
index 000000000000..5c5533828656
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TPCDebugObjectRegistrar.cpp
@@ -0,0 +1,62 @@
+//===----- TPCDebugObjectRegistrar.cpp - TPC-based debug registration -----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h"
+
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+namespace llvm {
+namespace orc {
+
+// Counterpart for readDebugObjectInfo() in TargetProcess/JITLoaderGDB.cpp
+static std::vector<uint8_t>
+writeDebugObjectInfo(sys::MemoryBlock TargetMemBlock) {
+  auto DebugObjAddr = pointerToJITTargetAddress(TargetMemBlock.base());
+  uint64_t DebugObjSize = TargetMemBlock.allocatedSize();
+
+  std::vector<uint8_t> ArgBuffer;
+  ArgBuffer.resize(sizeof(decltype(DebugObjAddr)) +
+                   sizeof(decltype(DebugObjSize)));
+
+  BinaryStreamWriter ArgWriter(ArgBuffer, support::endianness::big);
+  cantFail(ArgWriter.writeInteger(DebugObjAddr));
+  cantFail(ArgWriter.writeInteger(DebugObjSize));
+
+  return ArgBuffer;
+}
+
+Expected<std::unique_ptr<TPCDebugObjectRegistrar>>
+createJITLoaderGDBRegistrar(TargetProcessControl &TPC) {
+  auto ProcessHandle = TPC.loadDylib(nullptr);
+  if (!ProcessHandle)
+    return ProcessHandle.takeError();
+
+  SymbolStringPtr RegisterFn =
+      TPC.getTargetTriple().isOSBinFormatMachO()
+          ? TPC.intern("_llvm_orc_registerJITLoaderGDBWrapper")
+          : TPC.intern("llvm_orc_registerJITLoaderGDBWrapper");
+
+  SymbolLookupSet RegistrationSymbols;
+  RegistrationSymbols.add(RegisterFn);
+
+  auto Result = TPC.lookupSymbols({{*ProcessHandle, RegistrationSymbols}});
+  if (!Result)
+    return Result.takeError();
+
+  assert(Result->size() == 1 && "Unexpected number of dylibs in result");
+  assert((*Result)[0].size() == 1 &&
+         "Unexpected number of addresses in result");
+
+  return std::make_unique<TPCDebugObjectRegistrar>(TPC, (*Result)[0][0],
+                                                   &writeDebugObjectInfo);
+}
+
+} // namespace orc
+} // namespace llvm

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
index 4eb05300bce9..b04c09c50244 100644
--- a/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_llvm_component_library(LLVMOrcTargetProcess
+  JITLoaderGDB.cpp
   RegisterEHFrames.cpp
   TargetExecutionUtils.cpp
 

diff  --git a/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp b/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp
new file mode 100644
index 000000000000..30f833ec29bb
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp
@@ -0,0 +1,110 @@
+//===- JITLoaderGDB.h - Register objects via GDB JIT interface -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
+
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/ManagedStatic.h"
+
+#include <cstdint>
+#include <mutex>
+#include <utility>
+
+#define DEBUG_TYPE "orc"
+
+// First version as landed in August 2009
+static constexpr uint32_t JitDescriptorVersion = 1;
+
+// Keep in sync with gdb/gdb/jit.h
+extern "C" {
+
+typedef enum {
+  JIT_NOACTION = 0,
+  JIT_REGISTER_FN,
+  JIT_UNREGISTER_FN
+} jit_actions_t;
+
+struct jit_code_entry {
+  struct jit_code_entry *next_entry;
+  struct jit_code_entry *prev_entry;
+  const char *symfile_addr;
+  uint64_t symfile_size;
+};
+
+struct jit_descriptor {
+  uint32_t version;
+  // This should be jit_actions_t, but we want to be specific about the
+  // bit-width.
+  uint32_t action_flag;
+  struct jit_code_entry *relevant_entry;
+  struct jit_code_entry *first_entry;
+};
+
+// We put information about the JITed function in this global, which the
+// debugger reads.  Make sure to specify the version statically, because the
+// debugger checks the version before we can set it during runtime.
+struct jit_descriptor __jit_debug_descriptor = {JitDescriptorVersion, 0,
+                                                nullptr, nullptr};
+
+// Debuggers that implement the GDB JIT interface put a special breakpoint in
+// this function.
+LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
+  // The noinline and the asm prevent calls to this function from being
+  // optimized out.
+#if !defined(_MSC_VER)
+  asm volatile("" ::: "memory");
+#endif
+}
+}
+
+using namespace llvm;
+
+// Serialize rendezvous with the debugger as well as access to shared data.
+ManagedStatic<std::mutex> JITDebugLock;
+
+static std::pair<const char *, uint64_t> readDebugObjectInfo(uint8_t *ArgData,
+                                                             uint64_t ArgSize) {
+  BinaryStreamReader ArgReader(ArrayRef<uint8_t>(ArgData, ArgSize),
+                               support::endianness::big);
+  uint64_t Addr, Size;
+  cantFail(ArgReader.readInteger(Addr));
+  cantFail(ArgReader.readInteger(Size));
+
+  return std::make_pair(jitTargetAddressToPointer<const char *>(Addr), Size);
+}
+
+extern "C" orc::tpctypes::CWrapperFunctionResult
+llvm_orc_registerJITLoaderGDBWrapper(uint8_t *Data, uint64_t Size) {
+  if (Size != sizeof(uint64_t) + sizeof(uint64_t))
+    return orc::tpctypes::WrapperFunctionResult::from(
+               "Invalid arguments to llvm_orc_registerJITLoaderGDBWrapper")
+        .release();
+
+  jit_code_entry *E = new jit_code_entry;
+  std::tie(E->symfile_addr, E->symfile_size) = readDebugObjectInfo(Data, Size);
+  E->prev_entry = nullptr;
+
+  std::lock_guard<std::mutex> Lock(*JITDebugLock);
+
+  // Insert this entry at the head of the list.
+  jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
+  E->next_entry = NextEntry;
+  if (NextEntry) {
+    NextEntry->prev_entry = E;
+  }
+
+  __jit_debug_descriptor.first_entry = E;
+  __jit_debug_descriptor.relevant_entry = E;
+
+  // Run into the rendezvous breakpoint.
+  __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
+  __jit_debug_register_code();
+
+  return orc::tpctypes::WrapperFunctionResult().release();
+}

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
index fd7e30ffea87..f693b0268cd8 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
@@ -12,6 +12,7 @@
 
 #include "llvm/ADT/StringRef.h"
 #include "llvm/ExecutionEngine/Orc/Shared/FDRawByteChannel.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcess/OrcRPCTPCServer.h"
 #include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
 #include "llvm/Support/DynamicLibrary.h"
@@ -33,7 +34,8 @@ ExitOnError ExitOnErr;
 
 LLVM_ATTRIBUTE_USED void linkComponents() {
   errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
-         << (void *)&llvm_orc_deregisterEHFrameSectionWrapper;
+         << (void *)&llvm_orc_deregisterEHFrameSectionWrapper
+         << (void *)&llvm_orc_registerJITLoaderGDBWrapper;
 }
 
 void printErrorAndExit(Twine ErrMsg) {

diff  --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index 108dd61d0404..fd5331ab97af 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -15,9 +15,13 @@
 #include "llvm-jitlink.h"
 
 #include "llvm/BinaryFormat/Magic.h"
+#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
 #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h"
 #include "llvm/ExecutionEngine/Orc/TPCDynamicLibrarySearchGenerator.h"
 #include "llvm/ExecutionEngine/Orc/TPCEHFrameRegistrar.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/RegisterEHFrames.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCDisassembler/MCDisassembler.h"
@@ -155,6 +159,12 @@ static cl::opt<std::string> OutOfProcessExecutorConnect(
 
 ExitOnError ExitOnErr;
 
+LLVM_ATTRIBUTE_USED void linkComponents() {
+  errs() << (void *)&llvm_orc_registerEHFrameSectionWrapper
+         << (void *)&llvm_orc_deregisterEHFrameSectionWrapper
+         << (void *)&llvm_orc_registerJITLoaderGDBWrapper;
+}
+
 namespace llvm {
 
 static raw_ostream &
@@ -842,6 +852,9 @@ Session::Session(std::unique_ptr<TargetProcessControl> TPC, Error &Err)
     ObjLayer.addPlugin(std::make_unique<EHFrameRegistrationPlugin>(
         ES, ExitOnErr(TPCEHFrameRegistrar::Create(*this->TPC))));
 
+  ObjLayer.addPlugin(std::make_unique<DebugObjectManagerPlugin>(
+      ES, ExitOnErr(createJITLoaderGDBRegistrar(*this->TPC))));
+
   ObjLayer.addPlugin(std::make_unique<JITLinkSessionPlugin>(*this));
 
   // Process any harness files.


        


More information about the llvm-commits mailing list