xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
1*fe6060f1SDimitry Andric //===- JITLoaderGDB.h - Register objects via GDB JIT interface -*- C++ -*-===//
2*fe6060f1SDimitry Andric //
3*fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*fe6060f1SDimitry Andric //
7*fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
8*fe6060f1SDimitry Andric 
9*fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
10*fe6060f1SDimitry Andric 
11*fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITSymbol.h"
12*fe6060f1SDimitry Andric #include "llvm/Support/BinaryStreamReader.h"
13*fe6060f1SDimitry Andric #include "llvm/Support/ManagedStatic.h"
14*fe6060f1SDimitry Andric 
15*fe6060f1SDimitry Andric #include <cstdint>
16*fe6060f1SDimitry Andric #include <mutex>
17*fe6060f1SDimitry Andric #include <utility>
18*fe6060f1SDimitry Andric 
19*fe6060f1SDimitry Andric #define DEBUG_TYPE "orc"
20*fe6060f1SDimitry Andric 
21*fe6060f1SDimitry Andric // First version as landed in August 2009
22*fe6060f1SDimitry Andric static constexpr uint32_t JitDescriptorVersion = 1;
23*fe6060f1SDimitry Andric 
24*fe6060f1SDimitry Andric // Keep in sync with gdb/gdb/jit.h
25*fe6060f1SDimitry Andric extern "C" {
26*fe6060f1SDimitry Andric 
27*fe6060f1SDimitry Andric typedef enum {
28*fe6060f1SDimitry Andric   JIT_NOACTION = 0,
29*fe6060f1SDimitry Andric   JIT_REGISTER_FN,
30*fe6060f1SDimitry Andric   JIT_UNREGISTER_FN
31*fe6060f1SDimitry Andric } jit_actions_t;
32*fe6060f1SDimitry Andric 
33*fe6060f1SDimitry Andric struct jit_code_entry {
34*fe6060f1SDimitry Andric   struct jit_code_entry *next_entry;
35*fe6060f1SDimitry Andric   struct jit_code_entry *prev_entry;
36*fe6060f1SDimitry Andric   const char *symfile_addr;
37*fe6060f1SDimitry Andric   uint64_t symfile_size;
38*fe6060f1SDimitry Andric };
39*fe6060f1SDimitry Andric 
40*fe6060f1SDimitry Andric struct jit_descriptor {
41*fe6060f1SDimitry Andric   uint32_t version;
42*fe6060f1SDimitry Andric   // This should be jit_actions_t, but we want to be specific about the
43*fe6060f1SDimitry Andric   // bit-width.
44*fe6060f1SDimitry Andric   uint32_t action_flag;
45*fe6060f1SDimitry Andric   struct jit_code_entry *relevant_entry;
46*fe6060f1SDimitry Andric   struct jit_code_entry *first_entry;
47*fe6060f1SDimitry Andric };
48*fe6060f1SDimitry Andric 
49*fe6060f1SDimitry Andric // We put information about the JITed function in this global, which the
50*fe6060f1SDimitry Andric // debugger reads.  Make sure to specify the version statically, because the
51*fe6060f1SDimitry Andric // debugger checks the version before we can set it during runtime.
52*fe6060f1SDimitry Andric struct jit_descriptor __jit_debug_descriptor = {JitDescriptorVersion, 0,
53*fe6060f1SDimitry Andric                                                 nullptr, nullptr};
54*fe6060f1SDimitry Andric 
55*fe6060f1SDimitry Andric // Debuggers that implement the GDB JIT interface put a special breakpoint in
56*fe6060f1SDimitry Andric // this function.
57*fe6060f1SDimitry Andric LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
58*fe6060f1SDimitry Andric   // The noinline and the asm prevent calls to this function from being
59*fe6060f1SDimitry Andric   // optimized out.
60*fe6060f1SDimitry Andric #if !defined(_MSC_VER)
61*fe6060f1SDimitry Andric   asm volatile("" ::: "memory");
62*fe6060f1SDimitry Andric #endif
63*fe6060f1SDimitry Andric }
64*fe6060f1SDimitry Andric }
65*fe6060f1SDimitry Andric 
66*fe6060f1SDimitry Andric using namespace llvm;
67*fe6060f1SDimitry Andric 
68*fe6060f1SDimitry Andric // Serialize rendezvous with the debugger as well as access to shared data.
69*fe6060f1SDimitry Andric ManagedStatic<std::mutex> JITDebugLock;
70*fe6060f1SDimitry Andric 
71*fe6060f1SDimitry Andric // Register debug object, return error message or null for success.
72*fe6060f1SDimitry Andric static void registerJITLoaderGDBImpl(JITTargetAddress Addr, uint64_t Size) {
73*fe6060f1SDimitry Andric   jit_code_entry *E = new jit_code_entry;
74*fe6060f1SDimitry Andric   E->symfile_addr = jitTargetAddressToPointer<const char *>(Addr);
75*fe6060f1SDimitry Andric   E->symfile_size = Size;
76*fe6060f1SDimitry Andric   E->prev_entry = nullptr;
77*fe6060f1SDimitry Andric 
78*fe6060f1SDimitry Andric   std::lock_guard<std::mutex> Lock(*JITDebugLock);
79*fe6060f1SDimitry Andric 
80*fe6060f1SDimitry Andric   // Insert this entry at the head of the list.
81*fe6060f1SDimitry Andric   jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
82*fe6060f1SDimitry Andric   E->next_entry = NextEntry;
83*fe6060f1SDimitry Andric   if (NextEntry) {
84*fe6060f1SDimitry Andric     NextEntry->prev_entry = E;
85*fe6060f1SDimitry Andric   }
86*fe6060f1SDimitry Andric 
87*fe6060f1SDimitry Andric   __jit_debug_descriptor.first_entry = E;
88*fe6060f1SDimitry Andric   __jit_debug_descriptor.relevant_entry = E;
89*fe6060f1SDimitry Andric 
90*fe6060f1SDimitry Andric   // Run into the rendezvous breakpoint.
91*fe6060f1SDimitry Andric   __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
92*fe6060f1SDimitry Andric   __jit_debug_register_code();
93*fe6060f1SDimitry Andric }
94*fe6060f1SDimitry Andric 
95*fe6060f1SDimitry Andric extern "C" orc::shared::detail::CWrapperFunctionResult
96*fe6060f1SDimitry Andric llvm_orc_registerJITLoaderGDBWrapper(const char *Data, uint64_t Size) {
97*fe6060f1SDimitry Andric   using namespace orc::shared;
98*fe6060f1SDimitry Andric   return WrapperFunction<void(SPSExecutorAddress, uint64_t)>::handle(
99*fe6060f1SDimitry Andric              Data, Size, registerJITLoaderGDBImpl)
100*fe6060f1SDimitry Andric       .release();
101*fe6060f1SDimitry Andric }
102