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