xref: /freebsd-src/contrib/llvm-project/llvm/lib/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
13349cc55cSDimitry Andric #include "llvm/Support/FormatVariadic.h"
14fe6060f1SDimitry Andric 
15fe6060f1SDimitry Andric #include <cstdint>
16fe6060f1SDimitry Andric #include <mutex>
17fe6060f1SDimitry Andric #include <utility>
18fe6060f1SDimitry Andric 
19fe6060f1SDimitry Andric #define DEBUG_TYPE "orc"
20fe6060f1SDimitry Andric 
21fe6060f1SDimitry Andric // First version as landed in August 2009
22fe6060f1SDimitry Andric static constexpr uint32_t JitDescriptorVersion = 1;
23fe6060f1SDimitry Andric 
24fe6060f1SDimitry Andric extern "C" {
25fe6060f1SDimitry Andric 
26fe6060f1SDimitry Andric // We put information about the JITed function in this global, which the
27fe6060f1SDimitry Andric // debugger reads.  Make sure to specify the version statically, because the
28fe6060f1SDimitry Andric // debugger checks the version before we can set it during runtime.
29*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
30fe6060f1SDimitry Andric struct jit_descriptor __jit_debug_descriptor = {JitDescriptorVersion, 0,
31fe6060f1SDimitry Andric                                                 nullptr, nullptr};
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric // Debuggers that implement the GDB JIT interface put a special breakpoint in
34fe6060f1SDimitry Andric // this function.
35*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_VISIBILITY_DEFAULT
36fe6060f1SDimitry Andric LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
37fe6060f1SDimitry Andric   // The noinline and the asm prevent calls to this function from being
38fe6060f1SDimitry Andric   // optimized out.
39fe6060f1SDimitry Andric #if !defined(_MSC_VER)
40fe6060f1SDimitry Andric   asm volatile("" ::: "memory");
41fe6060f1SDimitry Andric #endif
42fe6060f1SDimitry Andric }
43fe6060f1SDimitry Andric }
44fe6060f1SDimitry Andric 
45fe6060f1SDimitry Andric using namespace llvm;
46349cc55cSDimitry Andric using namespace llvm::orc;
47fe6060f1SDimitry Andric 
48fe6060f1SDimitry Andric // Register debug object, return error message or null for success.
4906c3fb27SDimitry Andric static void appendJITDebugDescriptor(const char *ObjAddr, size_t Size) {
50349cc55cSDimitry Andric   LLVM_DEBUG({
5106c3fb27SDimitry Andric     dbgs() << "Adding debug object to GDB JIT interface "
52349cc55cSDimitry Andric            << formatv("([{0:x16} -- {1:x16}])",
53349cc55cSDimitry Andric                       reinterpret_cast<uintptr_t>(ObjAddr),
54349cc55cSDimitry Andric                       reinterpret_cast<uintptr_t>(ObjAddr + Size))
55349cc55cSDimitry Andric            << "\n";
56349cc55cSDimitry Andric   });
57349cc55cSDimitry Andric 
58fe6060f1SDimitry Andric   jit_code_entry *E = new jit_code_entry;
59349cc55cSDimitry Andric   E->symfile_addr = ObjAddr;
60fe6060f1SDimitry Andric   E->symfile_size = Size;
61fe6060f1SDimitry Andric   E->prev_entry = nullptr;
62fe6060f1SDimitry Andric 
63753f127fSDimitry Andric   // Serialize rendezvous with the debugger as well as access to shared data.
64753f127fSDimitry Andric   static std::mutex JITDebugLock;
65753f127fSDimitry Andric   std::lock_guard<std::mutex> Lock(JITDebugLock);
66fe6060f1SDimitry Andric 
67fe6060f1SDimitry Andric   // Insert this entry at the head of the list.
68fe6060f1SDimitry Andric   jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
69fe6060f1SDimitry Andric   E->next_entry = NextEntry;
70fe6060f1SDimitry Andric   if (NextEntry) {
71fe6060f1SDimitry Andric     NextEntry->prev_entry = E;
72fe6060f1SDimitry Andric   }
73fe6060f1SDimitry Andric 
74fe6060f1SDimitry Andric   __jit_debug_descriptor.first_entry = E;
75fe6060f1SDimitry Andric   __jit_debug_descriptor.relevant_entry = E;
76fe6060f1SDimitry Andric   __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
77fe6060f1SDimitry Andric }
78fe6060f1SDimitry Andric 
79349cc55cSDimitry Andric extern "C" orc::shared::CWrapperFunctionResult
80349cc55cSDimitry Andric llvm_orc_registerJITLoaderGDBAllocAction(const char *Data, size_t Size) {
81349cc55cSDimitry Andric   using namespace orc::shared;
8206c3fb27SDimitry Andric   return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle(
8304eeddc0SDimitry Andric              Data, Size,
8406c3fb27SDimitry Andric              [](ExecutorAddrRange R, bool AutoRegisterCode) {
8506c3fb27SDimitry Andric                appendJITDebugDescriptor(R.Start.toPtr<const char *>(),
8604eeddc0SDimitry Andric                                         R.size());
8706c3fb27SDimitry Andric                // Run into the rendezvous breakpoint.
8806c3fb27SDimitry Andric                if (AutoRegisterCode)
8906c3fb27SDimitry Andric                  __jit_debug_register_code();
90349cc55cSDimitry Andric                return Error::success();
91349cc55cSDimitry Andric              })
92349cc55cSDimitry Andric       .release();
93349cc55cSDimitry Andric }
94349cc55cSDimitry Andric 
95349cc55cSDimitry Andric extern "C" orc::shared::CWrapperFunctionResult
96fe6060f1SDimitry Andric llvm_orc_registerJITLoaderGDBWrapper(const char *Data, uint64_t Size) {
97fe6060f1SDimitry Andric   using namespace orc::shared;
9806c3fb27SDimitry Andric   return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle(
99349cc55cSDimitry Andric              Data, Size,
10006c3fb27SDimitry Andric              [](ExecutorAddrRange R, bool AutoRegisterCode) {
10106c3fb27SDimitry Andric                appendJITDebugDescriptor(R.Start.toPtr<const char *>(),
10204eeddc0SDimitry Andric                                         R.size());
10306c3fb27SDimitry Andric                // Run into the rendezvous breakpoint.
10406c3fb27SDimitry Andric                if (AutoRegisterCode)
10506c3fb27SDimitry Andric                  __jit_debug_register_code();
10604eeddc0SDimitry Andric                return Error::success();
107349cc55cSDimitry Andric              })
108fe6060f1SDimitry Andric       .release();
109fe6060f1SDimitry Andric }
110