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