1fe6060f1SDimitry Andric //===- JITLoaderGDB.h - Register objects via GDB JIT interface -*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric 9fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h" 10fe6060f1SDimitry Andric 11fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITSymbol.h" 12fe6060f1SDimitry Andric #include "llvm/Support/BinaryStreamReader.h" 13349cc55cSDimitry Andric #include "llvm/Support/FormatVariadic.h" 14fe6060f1SDimitry Andric 15fe6060f1SDimitry Andric #include <cstdint> 16fe6060f1SDimitry Andric #include <mutex> 17fe6060f1SDimitry Andric #include <utility> 18fe6060f1SDimitry Andric 19fe6060f1SDimitry Andric #define DEBUG_TYPE "orc" 20fe6060f1SDimitry Andric 21fe6060f1SDimitry Andric // First version as landed in August 2009 22fe6060f1SDimitry Andric static constexpr uint32_t JitDescriptorVersion = 1; 23fe6060f1SDimitry Andric 24fe6060f1SDimitry Andric extern "C" { 25fe6060f1SDimitry Andric 26fe6060f1SDimitry Andric // We put information about the JITed function in this global, which the 27fe6060f1SDimitry Andric // debugger reads. Make sure to specify the version statically, because the 28fe6060f1SDimitry Andric // debugger checks the version before we can set it during runtime. 29*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_VISIBILITY_DEFAULT 30fe6060f1SDimitry Andric struct jit_descriptor __jit_debug_descriptor = {JitDescriptorVersion, 0, 31fe6060f1SDimitry Andric nullptr, nullptr}; 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric // Debuggers that implement the GDB JIT interface put a special breakpoint in 34fe6060f1SDimitry Andric // this function. 35*0fca6ea1SDimitry Andric LLVM_ATTRIBUTE_VISIBILITY_DEFAULT 36fe6060f1SDimitry Andric LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { 37fe6060f1SDimitry Andric // The noinline and the asm prevent calls to this function from being 38fe6060f1SDimitry Andric // optimized out. 39fe6060f1SDimitry Andric #if !defined(_MSC_VER) 40fe6060f1SDimitry Andric asm volatile("" ::: "memory"); 41fe6060f1SDimitry Andric #endif 42fe6060f1SDimitry Andric } 43fe6060f1SDimitry Andric } 44fe6060f1SDimitry Andric 45fe6060f1SDimitry Andric using namespace llvm; 46349cc55cSDimitry Andric using namespace llvm::orc; 47fe6060f1SDimitry Andric 48fe6060f1SDimitry Andric // Register debug object, return error message or null for success. 4906c3fb27SDimitry Andric static void appendJITDebugDescriptor(const char *ObjAddr, size_t Size) { 50349cc55cSDimitry Andric LLVM_DEBUG({ 5106c3fb27SDimitry Andric dbgs() << "Adding debug object to GDB JIT interface " 52349cc55cSDimitry Andric << formatv("([{0:x16} -- {1:x16}])", 53349cc55cSDimitry Andric reinterpret_cast<uintptr_t>(ObjAddr), 54349cc55cSDimitry Andric reinterpret_cast<uintptr_t>(ObjAddr + Size)) 55349cc55cSDimitry Andric << "\n"; 56349cc55cSDimitry Andric }); 57349cc55cSDimitry Andric 58fe6060f1SDimitry Andric jit_code_entry *E = new jit_code_entry; 59349cc55cSDimitry Andric E->symfile_addr = ObjAddr; 60fe6060f1SDimitry Andric E->symfile_size = Size; 61fe6060f1SDimitry Andric E->prev_entry = nullptr; 62fe6060f1SDimitry Andric 63753f127fSDimitry Andric // Serialize rendezvous with the debugger as well as access to shared data. 64753f127fSDimitry Andric static std::mutex JITDebugLock; 65753f127fSDimitry Andric std::lock_guard<std::mutex> Lock(JITDebugLock); 66fe6060f1SDimitry Andric 67fe6060f1SDimitry Andric // Insert this entry at the head of the list. 68fe6060f1SDimitry Andric jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry; 69fe6060f1SDimitry Andric E->next_entry = NextEntry; 70fe6060f1SDimitry Andric if (NextEntry) { 71fe6060f1SDimitry Andric NextEntry->prev_entry = E; 72fe6060f1SDimitry Andric } 73fe6060f1SDimitry Andric 74fe6060f1SDimitry Andric __jit_debug_descriptor.first_entry = E; 75fe6060f1SDimitry Andric __jit_debug_descriptor.relevant_entry = E; 76fe6060f1SDimitry Andric __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 77fe6060f1SDimitry Andric } 78fe6060f1SDimitry Andric 79349cc55cSDimitry Andric extern "C" orc::shared::CWrapperFunctionResult 80349cc55cSDimitry Andric llvm_orc_registerJITLoaderGDBAllocAction(const char *Data, size_t Size) { 81349cc55cSDimitry Andric using namespace orc::shared; 8206c3fb27SDimitry Andric return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle( 8304eeddc0SDimitry Andric Data, Size, 8406c3fb27SDimitry Andric [](ExecutorAddrRange R, bool AutoRegisterCode) { 8506c3fb27SDimitry Andric appendJITDebugDescriptor(R.Start.toPtr<const char *>(), 8604eeddc0SDimitry Andric R.size()); 8706c3fb27SDimitry Andric // Run into the rendezvous breakpoint. 8806c3fb27SDimitry Andric if (AutoRegisterCode) 8906c3fb27SDimitry Andric __jit_debug_register_code(); 90349cc55cSDimitry Andric return Error::success(); 91349cc55cSDimitry Andric }) 92349cc55cSDimitry Andric .release(); 93349cc55cSDimitry Andric } 94349cc55cSDimitry Andric 95349cc55cSDimitry Andric extern "C" orc::shared::CWrapperFunctionResult 96fe6060f1SDimitry Andric llvm_orc_registerJITLoaderGDBWrapper(const char *Data, uint64_t Size) { 97fe6060f1SDimitry Andric using namespace orc::shared; 9806c3fb27SDimitry Andric return WrapperFunction<SPSError(SPSExecutorAddrRange, bool)>::handle( 99349cc55cSDimitry Andric Data, Size, 10006c3fb27SDimitry Andric [](ExecutorAddrRange R, bool AutoRegisterCode) { 10106c3fb27SDimitry Andric appendJITDebugDescriptor(R.Start.toPtr<const char *>(), 10204eeddc0SDimitry Andric R.size()); 10306c3fb27SDimitry Andric // Run into the rendezvous breakpoint. 10406c3fb27SDimitry Andric if (AutoRegisterCode) 10506c3fb27SDimitry Andric __jit_debug_register_code(); 10604eeddc0SDimitry Andric return Error::success(); 107349cc55cSDimitry Andric }) 108fe6060f1SDimitry Andric .release(); 109fe6060f1SDimitry Andric } 110