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 LLVM_ATTRIBUTE_VISIBILITY_DEFAULT 30 struct jit_descriptor __jit_debug_descriptor = {JitDescriptorVersion, 0, 31 nullptr, nullptr}; 32 33 // Debuggers that implement the GDB JIT interface put a special breakpoint in 34 // this function. 35 LLVM_ATTRIBUTE_VISIBILITY_DEFAULT 36 LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { 37 // The noinline and the asm prevent calls to this function from being 38 // optimized out. 39 #if !defined(_MSC_VER) 40 asm volatile("" ::: "memory"); 41 #endif 42 } 43 } 44 45 using namespace llvm; 46 using namespace llvm::orc; 47 48 // Register debug object, return error message or null for success. 49 static void appendJITDebugDescriptor(const char *ObjAddr, size_t Size) { 50 LLVM_DEBUG({ 51 dbgs() << "Adding debug object to GDB JIT interface " 52 << formatv("([{0:x16} -- {1:x16}])", 53 reinterpret_cast<uintptr_t>(ObjAddr), 54 reinterpret_cast<uintptr_t>(ObjAddr + Size)) 55 << "\n"; 56 }); 57 58 jit_code_entry *E = new jit_code_entry; 59 E->symfile_addr = ObjAddr; 60 E->symfile_size = Size; 61 E->prev_entry = nullptr; 62 63 // Serialize rendezvous with the debugger as well as access to shared data. 64 static std::mutex JITDebugLock; 65 std::lock_guard<std::mutex> Lock(JITDebugLock); 66 67 // Insert this entry at the head of the list. 68 jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry; 69 E->next_entry = NextEntry; 70 if (NextEntry) { 71 NextEntry->prev_entry = E; 72 } 73 74 __jit_debug_descriptor.first_entry = E; 75 __jit_debug_descriptor.relevant_entry = E; 76 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 77 } 78 79 extern "C" orc::shared::CWrapperFunctionResult 80 llvm_orc_registerJITLoaderGDBAllocAction(const char *Data, size_t Size) { 81 using namespace orc::shared; 82 return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle( 83 Data, Size, 84 [](ExecutorAddrRange R, bool AutoRegisterCode) { 85 appendJITDebugDescriptor(R.Start.toPtr<const char *>(), 86 R.size()); 87 // Run into the rendezvous breakpoint. 88 if (AutoRegisterCode) 89 __jit_debug_register_code(); 90 return Error::success(); 91 }) 92 .release(); 93 } 94 95 extern "C" orc::shared::CWrapperFunctionResult 96 llvm_orc_registerJITLoaderGDBWrapper(const char *Data, uint64_t Size) { 97 using namespace orc::shared; 98 return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle( 99 Data, Size, 100 [](ExecutorAddrRange R, bool AutoRegisterCode) { 101 appendJITDebugDescriptor(R.Start.toPtr<const char *>(), 102 R.size()); 103 // Run into the rendezvous breakpoint. 104 if (AutoRegisterCode) 105 __jit_debug_register_code(); 106 return Error::success(); 107 }) 108 .release(); 109 } 110