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