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_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_ALWAYS_EXPORT LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
33 // The noinline and the asm prevent calls to this function from being
34 // optimized out.
35#if !defined(_MSC_VER)
36 asm volatile("" ::: "memory");
37#endif
38}
39}
40
41using namespace llvm;
42using namespace llvm::orc;
43
44// Register debug object, return error message or null for success.
45static void appendJITDebugDescriptor(const char *ObjAddr, size_t Size) {
46 LLVM_DEBUG({
47 dbgs() << "Adding debug object to GDB JIT interface "
48 << formatv("([{0:x16} -- {1:x16}])",
49 reinterpret_cast<uintptr_t>(ObjAddr),
50 reinterpret_cast<uintptr_t>(ObjAddr + Size))
51 << "\n";
52 });
53
54 jit_code_entry *E = new jit_code_entry;
55 E->symfile_addr = ObjAddr;
56 E->symfile_size = Size;
57 E->prev_entry = nullptr;
58
59 // Serialize rendezvous with the debugger as well as access to shared data.
60 static std::mutex JITDebugLock;
61 std::lock_guard<std::mutex> Lock(JITDebugLock);
62
63 // Insert this entry at the head of the list.
64 jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
65 E->next_entry = NextEntry;
66 if (NextEntry) {
67 NextEntry->prev_entry = E;
68 }
69
70 __jit_debug_descriptor.first_entry = E;
71 __jit_debug_descriptor.relevant_entry = E;
72 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
73}
74
75extern "C" orc::shared::CWrapperFunctionBuffer
76llvm_orc_registerJITLoaderGDBAllocAction(const char *ArgData, size_t ArgSize) {
77 using namespace orc::shared;
78 return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle(
79 ArgData, ArgSize,
80 Handler: [](ExecutorAddrRange R, bool AutoRegisterCode) {
81 appendJITDebugDescriptor(ObjAddr: R.Start.toPtr<const char *>(),
82 Size: R.size());
83 // Run into the rendezvous breakpoint.
84 if (AutoRegisterCode)
85 __jit_debug_register_code();
86 return Error::success();
87 })
88 .release();
89}
90