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