1ef238923SStefan Gränitz //===- JITLoaderGDB.h - Register objects via GDB JIT interface -*- C++ -*-===//
2ef238923SStefan Gränitz //
3ef238923SStefan Gränitz // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ef238923SStefan Gränitz // See https://llvm.org/LICENSE.txt for license information.
5ef238923SStefan Gränitz // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ef238923SStefan Gränitz //
7ef238923SStefan Gränitz //===----------------------------------------------------------------------===//
8ef238923SStefan Gränitz
9ef238923SStefan Gränitz #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
10ef238923SStefan Gränitz
11ef238923SStefan Gränitz #include "llvm/ExecutionEngine/JITSymbol.h"
12ef238923SStefan Gränitz #include "llvm/Support/BinaryStreamReader.h"
1369be352aSLang Hames #include "llvm/Support/FormatVariadic.h"
14ef238923SStefan Gränitz
15ef238923SStefan Gränitz #include <cstdint>
16ef238923SStefan Gränitz #include <mutex>
17ef238923SStefan Gränitz #include <utility>
18ef238923SStefan Gränitz
19ef238923SStefan Gränitz #define DEBUG_TYPE "orc"
20ef238923SStefan Gränitz
21ef238923SStefan Gränitz // First version as landed in August 2009
22ef238923SStefan Gränitz static constexpr uint32_t JitDescriptorVersion = 1;
23ef238923SStefan Gränitz
24ef238923SStefan Gränitz // Keep in sync with gdb/gdb/jit.h
25ef238923SStefan Gränitz extern "C" {
26ef238923SStefan Gränitz
27ef238923SStefan Gränitz typedef enum {
28ef238923SStefan Gränitz JIT_NOACTION = 0,
29ef238923SStefan Gränitz JIT_REGISTER_FN,
30ef238923SStefan Gränitz JIT_UNREGISTER_FN
31ef238923SStefan Gränitz } jit_actions_t;
32ef238923SStefan Gränitz
33ef238923SStefan Gränitz struct jit_code_entry {
34ef238923SStefan Gränitz struct jit_code_entry *next_entry;
35ef238923SStefan Gränitz struct jit_code_entry *prev_entry;
36ef238923SStefan Gränitz const char *symfile_addr;
37ef238923SStefan Gränitz uint64_t symfile_size;
38ef238923SStefan Gränitz };
39ef238923SStefan Gränitz
40ef238923SStefan Gränitz struct jit_descriptor {
41ef238923SStefan Gränitz uint32_t version;
42ef238923SStefan Gränitz // This should be jit_actions_t, but we want to be specific about the
43ef238923SStefan Gränitz // bit-width.
44ef238923SStefan Gränitz uint32_t action_flag;
45ef238923SStefan Gränitz struct jit_code_entry *relevant_entry;
46ef238923SStefan Gränitz struct jit_code_entry *first_entry;
47ef238923SStefan Gränitz };
48ef238923SStefan Gränitz
49ef238923SStefan Gränitz // We put information about the JITed function in this global, which the
50ef238923SStefan Gränitz // debugger reads. Make sure to specify the version statically, because the
51ef238923SStefan Gränitz // debugger checks the version before we can set it during runtime.
52ef238923SStefan Gränitz struct jit_descriptor __jit_debug_descriptor = {JitDescriptorVersion, 0,
53ef238923SStefan Gränitz nullptr, nullptr};
54ef238923SStefan Gränitz
55ef238923SStefan Gränitz // Debuggers that implement the GDB JIT interface put a special breakpoint in
56ef238923SStefan Gränitz // this function.
__jit_debug_register_code()57ef238923SStefan Gränitz LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
58ef238923SStefan Gränitz // The noinline and the asm prevent calls to this function from being
59ef238923SStefan Gränitz // optimized out.
60ef238923SStefan Gränitz #if !defined(_MSC_VER)
61ef238923SStefan Gränitz asm volatile("" ::: "memory");
62ef238923SStefan Gränitz #endif
63ef238923SStefan Gränitz }
64ef238923SStefan Gränitz }
65ef238923SStefan Gränitz
66ef238923SStefan Gränitz using namespace llvm;
67962a2479SLang Hames using namespace llvm::orc;
68ef238923SStefan Gränitz
694eb9fe2eSLang Hames // Register debug object, return error message or null for success.
registerJITLoaderGDBImpl(const char * ObjAddr,size_t Size)7069be352aSLang Hames static void registerJITLoaderGDBImpl(const char *ObjAddr, size_t Size) {
7169be352aSLang Hames LLVM_DEBUG({
7269be352aSLang Hames dbgs() << "Registering debug object with GDB JIT interface "
7369be352aSLang Hames << formatv("([{0:x16} -- {1:x16}])",
7469be352aSLang Hames reinterpret_cast<uintptr_t>(ObjAddr),
7569be352aSLang Hames reinterpret_cast<uintptr_t>(ObjAddr + Size))
7669be352aSLang Hames << "\n";
7769be352aSLang Hames });
7869be352aSLang Hames
79ef238923SStefan Gränitz jit_code_entry *E = new jit_code_entry;
8069be352aSLang Hames E->symfile_addr = ObjAddr;
8169be352aSLang Hames E->symfile_size = Size;
82ef238923SStefan Gränitz E->prev_entry = nullptr;
83ef238923SStefan Gränitz
84*60cbf3faSNicolai Hähnle // Serialize rendezvous with the debugger as well as access to shared data.
85*60cbf3faSNicolai Hähnle static std::mutex JITDebugLock;
86*60cbf3faSNicolai Hähnle std::lock_guard<std::mutex> Lock(JITDebugLock);
87ef238923SStefan Gränitz
88ef238923SStefan Gränitz // Insert this entry at the head of the list.
89ef238923SStefan Gränitz jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
90ef238923SStefan Gränitz E->next_entry = NextEntry;
91ef238923SStefan Gränitz if (NextEntry) {
92ef238923SStefan Gränitz NextEntry->prev_entry = E;
93ef238923SStefan Gränitz }
94ef238923SStefan Gränitz
95ef238923SStefan Gränitz __jit_debug_descriptor.first_entry = E;
96ef238923SStefan Gränitz __jit_debug_descriptor.relevant_entry = E;
97ef238923SStefan Gränitz
98ef238923SStefan Gränitz // Run into the rendezvous breakpoint.
99ef238923SStefan Gränitz __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
100ef238923SStefan Gränitz __jit_debug_register_code();
1014eb9fe2eSLang Hames }
102ef238923SStefan Gränitz
103213666f8SLang Hames extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerJITLoaderGDBAllocAction(const char * Data,size_t Size)10469be352aSLang Hames llvm_orc_registerJITLoaderGDBAllocAction(const char *Data, size_t Size) {
10569be352aSLang Hames using namespace orc::shared;
106089acf25SLang Hames return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
107089acf25SLang Hames Data, Size,
108089acf25SLang Hames [](ExecutorAddrRange R) {
109089acf25SLang Hames registerJITLoaderGDBImpl(R.Start.toPtr<const char *>(),
110089acf25SLang Hames R.size());
11169be352aSLang Hames return Error::success();
11269be352aSLang Hames })
11369be352aSLang Hames .release();
11469be352aSLang Hames }
11569be352aSLang Hames
11669be352aSLang Hames extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerJITLoaderGDBWrapper(const char * Data,uint64_t Size)1174eb9fe2eSLang Hames llvm_orc_registerJITLoaderGDBWrapper(const char *Data, uint64_t Size) {
1184eb9fe2eSLang Hames using namespace orc::shared;
119089acf25SLang Hames return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
12069be352aSLang Hames Data, Size,
12169be352aSLang Hames [](ExecutorAddrRange R) {
122089acf25SLang Hames registerJITLoaderGDBImpl(R.Start.toPtr<const char *>(),
123089acf25SLang Hames R.size());
124089acf25SLang Hames return Error::success();
12569be352aSLang Hames })
1264eb9fe2eSLang Hames .release();
127ef238923SStefan Gränitz }
128