Skip to content

Commit ef23892

Browse files
[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
1 parent 171849c commit ef23892

File tree

12 files changed

+870
-6
lines changed

12 files changed

+870
-6
lines changed
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===---- DebugObjectManagerPlugin.h - JITLink debug objects ---*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// ObjectLinkingLayer plugin for emitting debug objects.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_DEBUGOBJECTMANAGERPLUGIN_H
14+
#define LLVM_EXECUTIONENGINE_ORC_DEBUGOBJECTMANAGERPLUGIN_H
15+
16+
#include "llvm/ADT/Triple.h"
17+
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
18+
#include "llvm/ExecutionEngine/Orc/Core.h"
19+
#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
20+
#include "llvm/ExecutionEngine/Orc/TPCDebugObjectRegistrar.h"
21+
#include "llvm/Support/Error.h"
22+
#include "llvm/Support/Memory.h"
23+
#include "llvm/Support/MemoryBuffer.h"
24+
25+
#include <functional>
26+
#include <map>
27+
#include <memory>
28+
#include <mutex>
29+
30+
namespace llvm {
31+
namespace orc {
32+
33+
class DebugObject;
34+
35+
/// Creates and manages DebugObjects for JITLink artifacts.
36+
///
37+
/// DebugObjects are created when linking for a MaterializationResponsibility
38+
/// starts. They are pending as long as materialization is in progress.
39+
///
40+
/// There can only be one pending DebugObject per MaterializationResponsibility.
41+
/// If materialization fails, pending DebugObjects are discarded.
42+
///
43+
/// Once executable code for the MaterializationResponsibility is emitted, the
44+
/// corresponding DebugObject is finalized to target memory and the provided
45+
/// DebugObjectRegistrar is notified. Ownership of DebugObjects remains with the
46+
/// plugin.
47+
///
48+
class DebugObjectManagerPlugin : public ObjectLinkingLayer::Plugin {
49+
public:
50+
DebugObjectManagerPlugin(ExecutionSession &ES,
51+
std::unique_ptr<DebugObjectRegistrar> Target);
52+
~DebugObjectManagerPlugin();
53+
54+
void notifyMaterializing(MaterializationResponsibility &MR,
55+
jitlink::LinkGraph &G, jitlink::JITLinkContext &Ctx,
56+
MemoryBufferRef InputObject) override;
57+
58+
Error notifyEmitted(MaterializationResponsibility &MR) override;
59+
Error notifyFailed(MaterializationResponsibility &MR) override;
60+
Error notifyRemovingResources(ResourceKey K) override;
61+
62+
void notifyTransferringResources(ResourceKey DstKey,
63+
ResourceKey SrcKey) override;
64+
65+
void modifyPassConfig(MaterializationResponsibility &MR, const Triple &TT,
66+
jitlink::PassConfiguration &PassConfig) override;
67+
68+
private:
69+
ExecutionSession &ES;
70+
71+
using OwnedDebugObject = std::unique_ptr<DebugObject>;
72+
std::map<ResourceKey, OwnedDebugObject> PendingObjs;
73+
std::map<ResourceKey, std::vector<OwnedDebugObject>> RegisteredObjs;
74+
75+
std::mutex PendingObjsLock;
76+
std::mutex RegisteredObjsLock;
77+
78+
std::unique_ptr<DebugObjectRegistrar> Target;
79+
};
80+
81+
} // namespace orc
82+
} // namespace llvm
83+
84+
#endif // LLVM_EXECUTIONENGINE_ORC_DEBUGOBJECTMANAGERPLUGIN_H

llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ class ObjectLinkingLayer : public RTTIExtends<ObjectLinkingLayer, ObjectLayer>,
7272
const Triple &TT,
7373
jitlink::PassConfiguration &Config) {}
7474

75+
// Deprecated. Don't use this in new code. There will be a proper mechanism
76+
// for capturing object buffers.
77+
virtual void notifyMaterializing(MaterializationResponsibility &MR,
78+
jitlink::LinkGraph &G,
79+
jitlink::JITLinkContext &Ctx,
80+
MemoryBufferRef InputObject) {}
81+
7582
virtual void notifyLoaded(MaterializationResponsibility &MR) {}
7683
virtual Error notifyEmitted(MaterializationResponsibility &MR) {
7784
return Error::success();
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
//===- TPCDebugObjectRegistrar.h - TPC-based debug registration -*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// TargetProcessControl based registration of debug objects.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_TPCDEBUGOBJECTREGISTRAR_H
14+
#define LLVM_EXECUTIONENGINE_ORC_TPCDEBUGOBJECTREGISTRAR_H
15+
16+
#include "llvm/ExecutionEngine/JITSymbol.h"
17+
#include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
18+
#include "llvm/Support/Error.h"
19+
#include "llvm/Support/Memory.h"
20+
21+
#include <cstdint>
22+
#include <memory>
23+
#include <vector>
24+
25+
namespace llvm {
26+
namespace orc {
27+
28+
/// Abstract interface for registering debug objects in the target process.
29+
class DebugObjectRegistrar {
30+
public:
31+
virtual Error registerDebugObject(sys::MemoryBlock) = 0;
32+
virtual ~DebugObjectRegistrar() {}
33+
};
34+
35+
/// Use TargetProcessControl to register debug objects locally or in a remote
36+
/// target process.
37+
class TPCDebugObjectRegistrar : public DebugObjectRegistrar {
38+
public:
39+
using SerializeBlockInfoFn =
40+
std::vector<uint8_t> (*)(sys::MemoryBlock TargetMemBlock);
41+
42+
TPCDebugObjectRegistrar(TargetProcessControl &TPC,
43+
JITTargetAddress RegisterFn,
44+
SerializeBlockInfoFn SerializeBlockInfo)
45+
: TPC(TPC), RegisterFn(RegisterFn),
46+
SerializeBlockInfo(SerializeBlockInfo) {}
47+
48+
Error registerDebugObject(sys::MemoryBlock TargetMem) override {
49+
return TPC.runWrapper(RegisterFn, SerializeBlockInfo(TargetMem))
50+
.takeError();
51+
}
52+
53+
private:
54+
TargetProcessControl &TPC;
55+
JITTargetAddress RegisterFn;
56+
SerializeBlockInfoFn SerializeBlockInfo;
57+
};
58+
59+
/// Create a TargetProcessControl-based DebugObjectRegistrar that emits debug
60+
/// objects to the GDB JIT interface.
61+
Expected<std::unique_ptr<TPCDebugObjectRegistrar>>
62+
createJITLoaderGDBRegistrar(TargetProcessControl &TPC);
63+
64+
} // end namespace orc
65+
} // end namespace llvm
66+
67+
#endif // LLVM_EXECUTIONENGINE_ORC_TDEBUGOBJECTREGISTRAR_H
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//===- JITLoaderGDB.h - Register objects via GDB JIT interface -*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Register objects for access by debuggers via the GDB JIT interface.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERGDB_H
14+
#define LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERGDB_H
15+
16+
#include "llvm/ExecutionEngine/Orc/Shared/TargetProcessControlTypes.h"
17+
#include <cstdint>
18+
19+
extern "C" llvm::orc::tpctypes::CWrapperFunctionResult
20+
llvm_orc_registerJITLoaderGDBWrapper(uint8_t *Data, uint64_t Size);
21+
22+
#endif // LLVM_EXECUTIONENGINE_ORC_TARGETPROCESS_JITLOADERGDB_H

llvm/lib/ExecutionEngine/Orc/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ add_llvm_component_library(LLVMOrcJIT
22
CompileOnDemandLayer.cpp
33
CompileUtils.cpp
44
Core.cpp
5+
DebugObjectManagerPlugin.cpp
56
DebugUtils.cpp
67
ExecutionUtils.cpp
78
IndirectionUtils.cpp
@@ -22,6 +23,7 @@ add_llvm_component_library(LLVMOrcJIT
2223
SpeculateAnalyses.cpp
2324
TargetProcessControl.cpp
2425
ThreadSafeModule.cpp
26+
TPCDebugObjectRegistrar.cpp
2527
TPCDynamicLibrarySearchGenerator.cpp
2628
TPCEHFrameRegistrar.cpp
2729
TPCIndirectionUtils.cpp

0 commit comments

Comments
 (0)