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
__jit_debug_register_code()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.
appendJITDebugDescriptor(const char * ObjAddr,size_t Size)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
llvm_orc_registerJITLoaderGDBAllocAction(const char * Data,size_t Size)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
llvm_orc_registerJITLoaderGDBWrapper(const char * Data,uint64_t Size)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