[llvm] 54397f9 - [llvm-c] Expose debug support for LLJIT in Orc C-API bindings (#73257)

via llvm-commits llvm-commits at lists.llvm.org
Mon Dec 11 11:47:24 PST 2023


Author: Stefan Gränitz
Date: 2023-12-11T20:47:20+01:00
New Revision: 54397f9ac128568838f2ac7bfc8e1f94b3eb264d

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

LOG: [llvm-c] Expose debug support for LLJIT in Orc C-API bindings (#73257)

Allow C-API users to debug their JITed code via the GDB JIT Interface.

This is currently supported on ELF and MachO based platforms. On
other systems `LLVMOrcLLJITEnableDebugSupport()` returns an error.

This patch adds a new C-API header `LLJITUtils.h`, which can host
further advanced JIT features in the future. Using the header requires
linking against LLVMOrcDebugging.

Added: 
    llvm/include/llvm-c/LLJITUtils.h
    llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp

Modified: 
    llvm/include/llvm-c/LLJIT.h
    llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
    llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp
    llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
    llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm-c/LLJIT.h b/llvm/include/llvm-c/LLJIT.h
index a06133aac4fb0..a58c3b8bbef70 100644
--- a/llvm/include/llvm-c/LLJIT.h
+++ b/llvm/include/llvm-c/LLJIT.h
@@ -1,4 +1,4 @@
-/*===----------- llvm-c/LLJIT.h - OrcV2 LLJIT C bindings --------*- C++ -*-===*\
+/*===----------- llvm-c/LLJIT.h - OrcV2 LLJIT C bindings ----------*- C -*-===*\
 |*                                                                            *|
 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM          *|
 |* Exceptions.                                                                *|

diff  --git a/llvm/include/llvm-c/LLJITUtils.h b/llvm/include/llvm-c/LLJITUtils.h
new file mode 100644
index 0000000000000..940097432b78f
--- /dev/null
+++ b/llvm/include/llvm-c/LLJITUtils.h
@@ -0,0 +1,52 @@
+/*===------- llvm-c/LLJITUtils.h - Advanced LLJIT features --------*- 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                    *|
+|*                                                                            *|
+|*===----------------------------------------------------------------------===*|
+|*                                                                            *|
+|* This header declares the C interface for extra utilities to be used with   *|
+|* the LLJIT class from the llvm-c/LLJIT.h header. It requires to following   *|
+|* link libraries in addition to libLLVMOrcJIT.a:                             *|
+|*  - libLLVMOrcDebugging.a                                                   *|
+|*                                                                            *|
+|* Many exotic languages can interoperate with C code but have a harder time  *|
+|* with C++ due to name mangling. So in addition to C, this interface enables *|
+|* tools written in such languages.                                           *|
+|*                                                                            *|
+|* Note: This interface is experimental. It is *NOT* stable, and may be       *|
+|*       changed without warning. Only C API usage documentation is           *|
+|*       provided. See the C++ documentation for all higher level ORC API     *|
+|*       details.                                                             *|
+|*                                                                            *|
+\*===----------------------------------------------------------------------===*/
+
+#ifndef LLVM_C_LLJITUTILS_H
+#define LLVM_C_LLJITUTILS_H
+
+#include "llvm-c/LLJIT.h"
+
+LLVM_C_EXTERN_C_BEGIN
+
+/**
+ * @defgroup LLVMCExecutionEngineLLJITUtils LLJIT Utilities
+ * @ingroup LLVMCExecutionEngineLLJIT
+ *
+ * @{
+ */
+
+/**
+ * Install the plugin that submits debug objects to the executor. Executors must
+ * expose the llvm_orc_registerJITLoaderGDBWrapper symbol.
+ */
+LLVMErrorRef LLVMOrcLLJITEnableDebugSupport(LLVMOrcLLJITRef J);
+
+/**
+ * @}
+ */
+
+LLVM_C_EXTERN_C_END
+
+#endif /* LLVM_C_LLJITUTILS_H */

diff  --git a/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
index 23b4714816185..5bf23a7ec0bc8 100644
--- a/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/CMakeLists.txt
@@ -6,6 +6,7 @@ add_llvm_component_library(LLVMOrcDebugging
   DebugInfoSupport.cpp
   DebuggerSupport.cpp
   DebuggerSupportPlugin.cpp
+  LLJITUtilsCBindings.cpp
   PerfSupportPlugin.cpp
 
   ADDITIONAL_HEADER_DIRS

diff  --git a/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp
index 9ba6dd90f50de..1668473c0eb47 100644
--- a/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/DebuggerSupport.cpp
@@ -39,7 +39,7 @@ Error enableDebuggerSupport(LLJIT &J) {
     if (!Registrar)
       return Registrar.takeError();
     ObjLinkingLayer->addPlugin(std::make_unique<DebugObjectManagerPlugin>(
-        ES, std::move(*Registrar), true, true));
+        ES, std::move(*Registrar), false, true));
     return Error::success();
   }
   case Triple::MachO: {

diff  --git a/llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp b/llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp
new file mode 100644
index 0000000000000..2df5aef733fb3
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/Debugging/LLJITUtilsCBindings.cpp
@@ -0,0 +1,22 @@
+//===--------- LLJITUtilsCBindings.cpp - Advanced LLJIT features ----------===//
+//
+// 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-c/LLJIT.h"
+#include "llvm-c/LLJITUtils.h"
+
+#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+
+DEFINE_SIMPLE_CONVERSION_FUNCTIONS(LLJIT, LLVMOrcLLJITRef)
+
+LLVMErrorRef LLVMOrcLLJITEnableDebugSupport(LLVMOrcLLJITRef J) {
+  return wrap(llvm::orc::enableDebuggerSupport(*unwrap(J)));
+}

diff  --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
index 37768e91fd447..f102ba59e3754 100644
--- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS
   IRReader
   JITLink
   Object
+  OrcDebugging
   OrcJIT
   OrcShared
   OrcTargetProcess

diff  --git a/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp b/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
index cbdd4af47e1d4..65d2f57234d0a 100644
--- a/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/OrcCAPITest.cpp
@@ -9,10 +9,12 @@
 #include "llvm-c/Core.h"
 #include "llvm-c/Error.h"
 #include "llvm-c/LLJIT.h"
+#include "llvm-c/LLJITUtils.h"
 #include "llvm-c/Orc.h"
 #include "gtest/gtest.h"
 
 #include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
 #include "llvm/IR/LLVMContext.h"
 #include "llvm/IR/Module.h"
 #include "llvm/IRReader/IRReader.h"
@@ -211,6 +213,20 @@ constexpr StringRef SumExample =
     }
   )";
 
+constexpr StringRef SumDebugExample =
+    R"(
+    define i32 @sum(i32 %x, i32 %y) {
+    entry:
+      %r = add nsw i32 %x, %y
+      ret i32 %r
+    }
+    !llvm.module.flags = !{!0}
+    !llvm.dbg.cu = !{!1}
+    !0 = !{i32 2, !"Debug Info Version", i32 3}
+    !1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, emissionKind: FullDebug)
+    !2 = !DIFile(filename: "sum.c", directory: "/tmp")
+  )";
+
 } // end anonymous namespace.
 
 // Consumes the given error ref and returns the string error message.
@@ -494,6 +510,75 @@ 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 struct jit_descriptor __jit_debug_descriptor;
+
+static void *findLastDebugDescriptorEntryPtr() {
+  struct jit_code_entry *Last = __jit_debug_descriptor.first_entry;
+  while (Last && Last->next_entry)
+    Last = Last->next_entry;
+  return Last;
+}
+}
+
+#if defined(_AIX) or not(defined(__ELF__) or defined(__MACH__))
+TEST_F(OrcCAPITestBase, DISABLED_EnableDebugSupport) {
+#else
+static LLVM_ATTRIBUTE_USED void linkComponents() {
+  errs() << "Linking in runtime functions\n"
+         << (void *)&llvm_orc_registerJITLoaderGDBWrapper << '\n'
+         << (void *)&llvm_orc_registerJITLoaderGDBAllocAction << '\n';
+}
+TEST_F(OrcCAPITestBase, EnableDebugSupport) {
+#endif
+  if (LLVMErrorRef E = LLVMOrcLLJITEnableDebugSupport(Jit))
+    FAIL() << "Error testing LLJIT debug support (triple = " << TargetTriple
+           << "): " << toString(E);
+
+  void *Before = findLastDebugDescriptorEntryPtr();
+  LLVMMemoryBufferRef ObjBuffer = createTestObject(SumDebugExample, "sum.ll");
+  LLVMOrcObjectLayerRef ObjLayer = LLVMOrcLLJITGetObjLinkingLayer(Jit);
+  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);
+
+  void *After = findLastDebugDescriptorEntryPtr();
+  ASSERT_NE(Before, After);
+}
+
 #if defined(_AIX)
 TEST_F(OrcCAPITestBase, DISABLED_ExecutionTest) {
 #else


        


More information about the llvm-commits mailing list