173471bf0Spatrick //===- JITLoaderGDB.h - Register objects via GDB JIT interface -*- C++ -*-===//
273471bf0Spatrick //
373471bf0Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
473471bf0Spatrick // See https://llvm.org/LICENSE.txt for license information.
573471bf0Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
673471bf0Spatrick //
773471bf0Spatrick //===----------------------------------------------------------------------===//
873471bf0Spatrick
973471bf0Spatrick #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
1073471bf0Spatrick
1173471bf0Spatrick #include "llvm/ExecutionEngine/JITSymbol.h"
1273471bf0Spatrick #include "llvm/Support/BinaryStreamReader.h"
13*d415bd75Srobert #include "llvm/Support/FormatVariadic.h"
1473471bf0Spatrick
1573471bf0Spatrick #include <cstdint>
1673471bf0Spatrick #include <mutex>
1773471bf0Spatrick #include <utility>
1873471bf0Spatrick
1973471bf0Spatrick #define DEBUG_TYPE "orc"
2073471bf0Spatrick
2173471bf0Spatrick // First version as landed in August 2009
2273471bf0Spatrick static constexpr uint32_t JitDescriptorVersion = 1;
2373471bf0Spatrick
2473471bf0Spatrick // Keep in sync with gdb/gdb/jit.h
2573471bf0Spatrick extern "C" {
2673471bf0Spatrick
2773471bf0Spatrick typedef enum {
2873471bf0Spatrick JIT_NOACTION = 0,
2973471bf0Spatrick JIT_REGISTER_FN,
3073471bf0Spatrick JIT_UNREGISTER_FN
3173471bf0Spatrick } jit_actions_t;
3273471bf0Spatrick
3373471bf0Spatrick struct jit_code_entry {
3473471bf0Spatrick struct jit_code_entry *next_entry;
3573471bf0Spatrick struct jit_code_entry *prev_entry;
3673471bf0Spatrick const char *symfile_addr;
3773471bf0Spatrick uint64_t symfile_size;
3873471bf0Spatrick };
3973471bf0Spatrick
4073471bf0Spatrick struct jit_descriptor {
4173471bf0Spatrick uint32_t version;
4273471bf0Spatrick // This should be jit_actions_t, but we want to be specific about the
4373471bf0Spatrick // bit-width.
4473471bf0Spatrick uint32_t action_flag;
4573471bf0Spatrick struct jit_code_entry *relevant_entry;
4673471bf0Spatrick struct jit_code_entry *first_entry;
4773471bf0Spatrick };
4873471bf0Spatrick
4973471bf0Spatrick // We put information about the JITed function in this global, which the
5073471bf0Spatrick // debugger reads. Make sure to specify the version statically, because the
5173471bf0Spatrick // debugger checks the version before we can set it during runtime.
5273471bf0Spatrick struct jit_descriptor __jit_debug_descriptor = {JitDescriptorVersion, 0,
5373471bf0Spatrick nullptr, nullptr};
5473471bf0Spatrick
5573471bf0Spatrick // Debuggers that implement the GDB JIT interface put a special breakpoint in
5673471bf0Spatrick // this function.
__jit_debug_register_code()5773471bf0Spatrick LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
5873471bf0Spatrick // The noinline and the asm prevent calls to this function from being
5973471bf0Spatrick // optimized out.
6073471bf0Spatrick #if !defined(_MSC_VER)
6173471bf0Spatrick asm volatile("" ::: "memory");
6273471bf0Spatrick #endif
6373471bf0Spatrick }
6473471bf0Spatrick }
6573471bf0Spatrick
6673471bf0Spatrick using namespace llvm;
67*d415bd75Srobert using namespace llvm::orc;
6873471bf0Spatrick
6973471bf0Spatrick // Register debug object, return error message or null for success.
registerJITLoaderGDBImpl(const char * ObjAddr,size_t Size)70*d415bd75Srobert static void registerJITLoaderGDBImpl(const char *ObjAddr, size_t Size) {
71*d415bd75Srobert LLVM_DEBUG({
72*d415bd75Srobert dbgs() << "Registering debug object with GDB JIT interface "
73*d415bd75Srobert << formatv("([{0:x16} -- {1:x16}])",
74*d415bd75Srobert reinterpret_cast<uintptr_t>(ObjAddr),
75*d415bd75Srobert reinterpret_cast<uintptr_t>(ObjAddr + Size))
76*d415bd75Srobert << "\n";
77*d415bd75Srobert });
78*d415bd75Srobert
7973471bf0Spatrick jit_code_entry *E = new jit_code_entry;
80*d415bd75Srobert E->symfile_addr = ObjAddr;
8173471bf0Spatrick E->symfile_size = Size;
8273471bf0Spatrick E->prev_entry = nullptr;
8373471bf0Spatrick
84*d415bd75Srobert // Serialize rendezvous with the debugger as well as access to shared data.
85*d415bd75Srobert static std::mutex JITDebugLock;
86*d415bd75Srobert std::lock_guard<std::mutex> Lock(JITDebugLock);
8773471bf0Spatrick
8873471bf0Spatrick // Insert this entry at the head of the list.
8973471bf0Spatrick jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
9073471bf0Spatrick E->next_entry = NextEntry;
9173471bf0Spatrick if (NextEntry) {
9273471bf0Spatrick NextEntry->prev_entry = E;
9373471bf0Spatrick }
9473471bf0Spatrick
9573471bf0Spatrick __jit_debug_descriptor.first_entry = E;
9673471bf0Spatrick __jit_debug_descriptor.relevant_entry = E;
9773471bf0Spatrick
9873471bf0Spatrick // Run into the rendezvous breakpoint.
9973471bf0Spatrick __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
10073471bf0Spatrick __jit_debug_register_code();
10173471bf0Spatrick }
10273471bf0Spatrick
103*d415bd75Srobert extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerJITLoaderGDBAllocAction(const char * Data,size_t Size)104*d415bd75Srobert llvm_orc_registerJITLoaderGDBAllocAction(const char *Data, size_t Size) {
105*d415bd75Srobert using namespace orc::shared;
106*d415bd75Srobert return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
107*d415bd75Srobert Data, Size,
108*d415bd75Srobert [](ExecutorAddrRange R) {
109*d415bd75Srobert registerJITLoaderGDBImpl(R.Start.toPtr<const char *>(),
110*d415bd75Srobert R.size());
111*d415bd75Srobert return Error::success();
112*d415bd75Srobert })
113*d415bd75Srobert .release();
114*d415bd75Srobert }
115*d415bd75Srobert
116*d415bd75Srobert extern "C" orc::shared::CWrapperFunctionResult
llvm_orc_registerJITLoaderGDBWrapper(const char * Data,uint64_t Size)11773471bf0Spatrick llvm_orc_registerJITLoaderGDBWrapper(const char *Data, uint64_t Size) {
11873471bf0Spatrick using namespace orc::shared;
119*d415bd75Srobert return WrapperFunction<SPSError(SPSExecutorAddrRange)>::handle(
120*d415bd75Srobert Data, Size,
121*d415bd75Srobert [](ExecutorAddrRange R) {
122*d415bd75Srobert registerJITLoaderGDBImpl(R.Start.toPtr<const char *>(),
123*d415bd75Srobert R.size());
124*d415bd75Srobert return Error::success();
125*d415bd75Srobert })
12673471bf0Spatrick .release();
12773471bf0Spatrick }
128