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