Home | History | Annotate | Line # | Download | only in TargetProcess
      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/ManagedStatic.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 // Keep in sync with gdb/gdb/jit.h
     25 extern "C" {
     26 
     27 typedef enum {
     28   JIT_NOACTION = 0,
     29   JIT_REGISTER_FN,
     30   JIT_UNREGISTER_FN
     31 } jit_actions_t;
     32 
     33 struct jit_code_entry {
     34   struct jit_code_entry *next_entry;
     35   struct jit_code_entry *prev_entry;
     36   const char *symfile_addr;
     37   uint64_t symfile_size;
     38 };
     39 
     40 struct jit_descriptor {
     41   uint32_t version;
     42   // This should be jit_actions_t, but we want to be specific about the
     43   // bit-width.
     44   uint32_t action_flag;
     45   struct jit_code_entry *relevant_entry;
     46   struct jit_code_entry *first_entry;
     47 };
     48 
     49 // We put information about the JITed function in this global, which the
     50 // debugger reads.  Make sure to specify the version statically, because the
     51 // debugger checks the version before we can set it during runtime.
     52 struct jit_descriptor __jit_debug_descriptor = {JitDescriptorVersion, 0,
     53                                                 nullptr, nullptr};
     54 
     55 // Debuggers that implement the GDB JIT interface put a special breakpoint in
     56 // this function.
     57 LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
     58   // The noinline and the asm prevent calls to this function from being
     59   // optimized out.
     60 #if !defined(_MSC_VER)
     61   asm volatile("" ::: "memory");
     62 #endif
     63 }
     64 }
     65 
     66 using namespace llvm;
     67 
     68 // Serialize rendezvous with the debugger as well as access to shared data.
     69 ManagedStatic<std::mutex> JITDebugLock;
     70 
     71 static std::pair<const char *, uint64_t> readDebugObjectInfo(uint8_t *ArgData,
     72                                                              uint64_t ArgSize) {
     73   BinaryStreamReader ArgReader(ArrayRef<uint8_t>(ArgData, ArgSize),
     74                                support::endianness::big);
     75   uint64_t Addr, Size;
     76   cantFail(ArgReader.readInteger(Addr));
     77   cantFail(ArgReader.readInteger(Size));
     78 
     79   return std::make_pair(jitTargetAddressToPointer<const char *>(Addr), Size);
     80 }
     81 
     82 extern "C" orc::tpctypes::CWrapperFunctionResult
     83 llvm_orc_registerJITLoaderGDBWrapper(uint8_t *Data, uint64_t Size) {
     84   if (Size != sizeof(uint64_t) + sizeof(uint64_t))
     85     return orc::tpctypes::WrapperFunctionResult::from(
     86                "Invalid arguments to llvm_orc_registerJITLoaderGDBWrapper")
     87         .release();
     88 
     89   jit_code_entry *E = new jit_code_entry;
     90   std::tie(E->symfile_addr, E->symfile_size) = readDebugObjectInfo(Data, Size);
     91   E->prev_entry = nullptr;
     92 
     93   std::lock_guard<std::mutex> Lock(*JITDebugLock);
     94 
     95   // Insert this entry at the head of the list.
     96   jit_code_entry *NextEntry = __jit_debug_descriptor.first_entry;
     97   E->next_entry = NextEntry;
     98   if (NextEntry) {
     99     NextEntry->prev_entry = E;
    100   }
    101 
    102   __jit_debug_descriptor.first_entry = E;
    103   __jit_debug_descriptor.relevant_entry = E;
    104 
    105   // Run into the rendezvous breakpoint.
    106   __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
    107   __jit_debug_register_code();
    108 
    109   return orc::tpctypes::WrapperFunctionResult().release();
    110 }
    111