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#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
10
11#include "llvm/Support/Compiler.h"
12#include "llvm/Support/FormatVariadic.h"
13
14#include <cstdint>
15#include <mutex>
16
17#define DEBUG_TYPE "orc"
18
19// First version as landed in August 2009
20static constexpr uint32_t JitDescriptorVersion = 1;
21
22extern "C" {
23
24// We put information about the JITed function in this global, which the
25// debugger reads. Make sure to specify the version statically, because the
26// debugger checks the version before we can set it during runtime.
27LLVM_ABI LLVM_ALWAYS_EXPORT struct jit_descriptor __jit_debug_descriptor = {
28 .version: JitDescriptorVersion, .action_flag: 0, .relevant_entry: nullptr, .first_entry: nullptr};
29
30// Debuggers that implement the GDB JIT interface put a special breakpoint in
31// this function.
32LLVM_ABI LLVM_ALWAYS_EXPORT LLVM_ATTRIBUTE_NOINLINE void
33__jit_debug_register_code() {
34 // The noinline and the asm prevent calls to this function from being
35 // optimized out.
36#if !defined(_MSC_VER)
37 asm volatile("" ::: "memory");
38#endif
39}
40}
41
42using namespace llvm;
43using namespace llvm::orc;
44
45// Register debug object, return error message or null for success.
46static void appendJITDebugDescriptor(const char *ObjAddr, size_t Size) {
47 LLVM_DEBUG({
48 dbgs() << "Adding debug object to GDB JIT interface "
49 << formatv("([{0:x16} -- {1:x16}])",
50 reinterpret_cast<uintptr_t>(ObjAddr),
51 reinterpret_cast<uintptr_t>(ObjAddr + Size))
52 << "\n";
53 });
54
55 jit_code_entry *E = new jit_code_entry;
56 E->symfile_addr = ObjAddr;
57 E->symfile_size = Size;
58 E->prev_entry = nullptr;
59
60 // Serialize rendezvous with the debugger as well as access to shared data.
61 static std::mutex JITDebugLock;
62 std::lock_guard<std::mutex> Lock(JITDebugLock);
63
64 // Insert this entry at the head of the list.
65 jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
66 E->next_entry = NextEntry;
67 if (NextEntry) {
68 NextEntry->prev_entry = E;
69 }
70
71 __jit_debug_descriptor.first_entry = E;
72 __jit_debug_descriptor.relevant_entry = E;
73 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
74}
75
76extern "C" orc::shared::CWrapperFunctionResult
77llvm_orc_registerJITLoaderGDBAllocAction(const char *ArgData, size_t ArgSize) {
78 using namespace orc::shared;
79 return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle(
80 ArgData, ArgSize,
81 Handler: [](ExecutorAddrRange R, bool AutoRegisterCode) {
82 appendJITDebugDescriptor(ObjAddr: R.Start.toPtr<const char *>(),
83 Size: R.size());
84 // Run into the rendezvous breakpoint.
85 if (AutoRegisterCode)
86 __jit_debug_register_code();
87 return Error::success();
88 })
89 .release();
90}
91
92extern "C" orc::shared::CWrapperFunctionResult
93llvm_orc_registerJITLoaderGDBWrapper(const char *ArgData, size_t ArgSize) {
94 using namespace orc::shared;
95 return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle(
96 ArgData, ArgSize,
97 Handler: [](ExecutorAddrRange R, bool AutoRegisterCode) {
98 appendJITDebugDescriptor(ObjAddr: R.Start.toPtr<const char *>(),
99 Size: R.size());
100 // Run into the rendezvous breakpoint.
101 if (AutoRegisterCode)
102 __jit_debug_register_code();
103 return Error::success();
104 })
105 .release();
106}
107