[llvm] [llvm-c] Expose debug object registration in Orc C-API bindings (PR #73257)
Stefan Gränitz via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 23 10:23:20 PST 2023
https://github.com/weliveindetail created https://github.com/llvm/llvm-project/pull/73257
Allow C-API users to debug their JITed code. The new API function `LLVMOrcObjectLayerRegisterPluginJITLoaderGDB()` adds the required plugin to provide GDB JIT Interface support. This initial patch covers the ELF use-case by installing the DebugObjectManagerPlugin. It should be easy to add support for other object formats later on.
>From 47801ac3e05f6b437e26459bdd7bb7dbe702e649 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Thu, 23 Nov 2023 09:41:30 +0100
Subject: [PATCH 1/2] [llvm-c] Expose debug object registration in Orc bindings
---
llvm/include/llvm-c/Orc.h | 19 +++++++++++++
.../ExecutionEngine/Orc/OrcV2CBindings.cpp | 28 +++++++++++++++++++
2 files changed, 47 insertions(+)
diff --git a/llvm/include/llvm-c/Orc.h b/llvm/include/llvm-c/Orc.h
index a40b17b712fb3f2..6f869177b8e728d 100644
--- a/llvm/include/llvm-c/Orc.h
+++ b/llvm/include/llvm-c/Orc.h
@@ -1206,6 +1206,25 @@ void LLVMOrcObjectLayerEmit(LLVMOrcObjectLayerRef ObjLayer,
LLVMOrcMaterializationResponsibilityRef R,
LLVMMemoryBufferRef ObjBuffer);
+/**
+ * Install the plugin that submits debug objects to the executor. Out-of-process
+ * executors must provide the llvm_orc_registerJITLoaderGDBWrapper symbol.
+ *
+ * RequireDebugSectionsFlag lets the plugin pass debug objects only if they
+ * contain actual debug info. Turning this off may allow minimal debugging based
+ * on raw symbol names. It may cause significant memory and transport overhead
+ * for objects built with a release configuration.
+ *
+ * AutoRegisterCodeFlag lets the executor notify the debugger for each new debug
+ * object. This is a good default mode, but it may cause significant overhead
+ * when adding many modules in sequence. When turned off, the user has to issue
+ * the call to __jit_debug_register_code() on the executor side manually.
+ */
+LLVMErrorRef
+LLVMOrcObjectLayerRegisterPluginJITLoaderGDB(LLVMOrcObjectLayerRef ObjLayer,
+ LLVMBool RequireDebugSectionsFlag,
+ LLVMBool AutoRegisterCodeFlag);
+
/**
* Dispose of an ObjectLayer.
*/
diff --git a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
index a73aec6d98c64c9..871a9b44306ac49 100644
--- a/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/OrcV2CBindings.cpp
@@ -11,10 +11,13 @@
#include "llvm-c/OrcEE.h"
#include "llvm-c/TargetMachine.h"
+#include "llvm/ExecutionEngine/Orc/DebugObjectManagerPlugin.h"
+#include "llvm/ExecutionEngine/Orc/EPCDebugObjectRegistrar.h"
#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/ExecutionEngine/Orc/ObjectTransformLayer.h"
#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
using namespace llvm;
@@ -863,6 +866,31 @@ void LLVMOrcObjectLayerEmit(LLVMOrcObjectLayerRef ObjLayer,
std::unique_ptr<MemoryBuffer>(unwrap(ObjBuffer)));
}
+LLVMErrorRef
+LLVMOrcObjectLayerRegisterPluginJITLoaderGDB(LLVMOrcObjectLayerRef ObjLayer,
+ LLVMBool RequireDebugSectionsFlag,
+ LLVMBool AutoRegisterCodeFlag) {
+ ExecutionSession &ES = unwrap(ObjLayer)->getExecutionSession();
+ auto Registrar = createJITLoaderGDBRegistrar(ES);
+ if (!Registrar)
+ return wrap(Registrar.takeError());
+
+ auto *ObjLinkingLayer = cast<ObjectLinkingLayer>(unwrap(ObjLayer));
+ if (!ObjLinkingLayer)
+ return wrap(
+ createStringError(inconvertibleErrorCode(),
+ "No debug support for given object layer type"));
+
+ ObjLinkingLayer->addPlugin(std::make_unique<DebugObjectManagerPlugin>(
+ ES, std::move(*Registrar), RequireDebugSectionsFlag,
+ AutoRegisterCodeFlag));
+
+ auto TargetProcessFn = &llvm_orc_registerJITLoaderGDBWrapper;
+ (void)TargetProcessFn;
+
+ return LLVMErrorSuccess;
+}
+
void LLVMOrcDisposeObjectLayer(LLVMOrcObjectLayerRef ObjLayer) {
delete unwrap(ObjLayer);
}
>From 83cebca8367efacb1995d5dbe9eaaac3c6d99e75 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Stefan=20Gr=C3=A4nitz?= <stefan.graenitz at gmail.com>
Date: Thu, 23 Nov 2023 18:03:00 +0100
Subject: [PATCH 2/2] [llvm-c] Add unit test for Orc debug object registration
---
.../ExecutionEngine/Orc/OrcCAPITest.cpp | 66 +++++++++++++++++++
1 file changed, 66 insertions(+)
diff --git a/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
index cbdd4af47e1d47d..6f72d5ddc5dca91 100644
--- a/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
@@ -13,6 +13,7 @@
#include "gtest/gtest.h"
#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IRReader/IRReader.h"
@@ -27,6 +28,7 @@ using namespace llvm;
using namespace llvm::orc;
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ThreadSafeModule, LLVMOrcThreadSafeModuleRef)
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ObjectLayer, LLVMOrcObjectLayerRef)
// OrcCAPITestBase contains several helper methods and pointers for unit tests
// written for the LLVM-C API. It provides the following helpers:
@@ -494,6 +496,70 @@ TEST_F(OrcCAPITestBase, AddObjectBuffer) {
ASSERT_TRUE(!!SumAddr);
}
+// This must be kept 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.
+extern "C" struct jit_descriptor __jit_debug_descriptor;
+}
+
+#if defined(_AIX)
+TEST_F(OrcCAPITestBase, DISABLED_RegisterJITLoaderGDB) {
+#else
+TEST_F(OrcCAPITestBase, RegisterJITLoaderGDB) {
+#endif
+ LLVMOrcObjectLayerRef ObjLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit);
+ auto *ObjLinkingLayer = cast<orc::ObjectLinkingLayer>(unwrap(ObjLayer));
+ ASSERT_TRUE(ObjLinkingLayer);
+
+ constexpr bool RequireDebugSectionsFlag = false;
+ constexpr bool AutoRegisterCodeFlag = true;
+ LLVMErrorRef E = LLVMOrcObjectLayerRegisterPluginJITLoaderGDB(
+ ObjLayer, RequireDebugSectionsFlag, AutoRegisterCodeFlag);
+ if (E)
+ FAIL() << "Failed to register plugin to ObjLinkingLayer (triple = "
+ << TargetTriple << "): " << toString(E);
+
+ ASSERT_EQ(__jit_debug_descriptor.first_entry, nullptr);
+
+ LLVMMemoryBufferRef ObjBuffer = createTestObject(SumExample, "sum.ll");
+ if (LLVMErrorRef E =
+ LLVMOrcObjectLayerAddObjectFile(ObjLayer, MainDylib, ObjBuffer))
+ FAIL() << "Failed to add object file to ObjLinkingLayer (triple = "
+ << TargetTriple << "): " << toString(E);
+
+ LLVMOrcJITTargetAddress SumAddr;
+ if (LLVMErrorRef E = LLVMOrcLLJITLookup(Jit, &SumAddr, "sum"))
+ FAIL() << "Symbol \"sum\" was not added into JIT (triple = " << TargetTriple
+ << "): " << toString(E);
+
+ ASSERT_NE(__jit_debug_descriptor.first_entry, nullptr);
+}
+
#if defined(_AIX)
TEST_F(OrcCAPITestBase, DISABLED_ExecutionTest) {
#else
More information about the llvm-commits
mailing list