1 //===----- GDBRegistrationListener.cpp - Registers objects with GDB -------===// 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-c/ExecutionEngine.h" 10 #include "llvm/ADT/DenseMap.h" 11 #include "llvm/ExecutionEngine/JITEventListener.h" 12 #include "llvm/Object/ObjectFile.h" 13 #include "llvm/Support/Compiler.h" 14 #include "llvm/Support/ErrorHandling.h" 15 #include "llvm/Support/ManagedStatic.h" 16 #include "llvm/Support/MemoryBuffer.h" 17 #include "llvm/Support/Mutex.h" 18 #include <mutex> 19 20 using namespace llvm; 21 using namespace llvm::object; 22 23 // This must be kept in sync with gdb/gdb/jit.h . 24 extern "C" { 25 26 typedef enum { 27 JIT_NOACTION = 0, 28 JIT_REGISTER_FN, 29 JIT_UNREGISTER_FN 30 } jit_actions_t; 31 32 struct jit_code_entry { 33 struct jit_code_entry *next_entry; 34 struct jit_code_entry *prev_entry; 35 const char *symfile_addr; 36 uint64_t symfile_size; 37 }; 38 39 struct jit_descriptor { 40 uint32_t version; 41 // This should be jit_actions_t, but we want to be specific about the 42 // bit-width. 43 uint32_t action_flag; 44 struct jit_code_entry *relevant_entry; 45 struct jit_code_entry *first_entry; 46 }; 47 48 // We put information about the JITed function in this global, which the 49 // debugger reads. Make sure to specify the version statically, because the 50 // debugger checks the version before we can set it during runtime. 51 extern struct jit_descriptor __jit_debug_descriptor; 52 53 // Debuggers puts a breakpoint in this function. 54 extern "C" void __jit_debug_register_code(); 55 } 56 57 namespace { 58 59 // FIXME: lli aims to provide both, RuntimeDyld and JITLink, as the dynamic 60 // loaders for it's JIT implementations. And they both offer debugging via the 61 // GDB JIT interface, which builds on the two well-known symbol names below. 62 // As these symbols must be unique accross the linked executable, we can only 63 // define them in one of the libraries and make the other depend on it. 64 // OrcTargetProcess is a minimal stub for embedding a JIT client in remote 65 // executors. For the moment it seems reasonable to have the definition there 66 // and let ExecutionEngine depend on it, until we find a better solution. 67 // 68 LLVM_ATTRIBUTE_USED void requiredSymbolDefinitionsFromOrcTargetProcess() { 69 errs() << (void *)&__jit_debug_register_code 70 << (void *)&__jit_debug_descriptor; 71 } 72 73 struct RegisteredObjectInfo { 74 RegisteredObjectInfo() = default; 75 76 RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry, 77 OwningBinary<ObjectFile> Obj) 78 : Size(Size), Entry(Entry), Obj(std::move(Obj)) {} 79 80 std::size_t Size; 81 jit_code_entry *Entry; 82 OwningBinary<ObjectFile> Obj; 83 }; 84 85 // Buffer for an in-memory object file in executable memory 86 typedef llvm::DenseMap<JITEventListener::ObjectKey, RegisteredObjectInfo> 87 RegisteredObjectBufferMap; 88 89 /// Global access point for the JIT debugging interface designed for use with a 90 /// singleton toolbox. Handles thread-safe registration and deregistration of 91 /// object files that are in executable memory managed by the client of this 92 /// class. 93 class GDBJITRegistrationListener : public JITEventListener { 94 /// A map of in-memory object files that have been registered with the 95 /// JIT interface. 96 RegisteredObjectBufferMap ObjectBufferMap; 97 98 public: 99 /// Instantiates the JIT service. 100 GDBJITRegistrationListener() = default; 101 102 /// Unregisters each object that was previously registered and releases all 103 /// internal resources. 104 ~GDBJITRegistrationListener() override; 105 106 /// Creates an entry in the JIT registry for the buffer @p Object, 107 /// which must contain an object file in executable memory with any 108 /// debug information for the debugger. 109 void notifyObjectLoaded(ObjectKey K, const ObjectFile &Obj, 110 const RuntimeDyld::LoadedObjectInfo &L) override; 111 112 /// Removes the internal registration of @p Object, and 113 /// frees associated resources. 114 /// Returns true if @p Object was found in ObjectBufferMap. 115 void notifyFreeingObject(ObjectKey K) override; 116 117 private: 118 /// Deregister the debug info for the given object file from the debugger 119 /// and delete any temporary copies. This private method does not remove 120 /// the function from Map so that it can be called while iterating over Map. 121 void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I); 122 }; 123 124 /// Lock used to serialize all jit registration events, since they 125 /// modify global variables. 126 ManagedStatic<sys::Mutex> JITDebugLock; 127 128 /// Do the registration. 129 void NotifyDebugger(jit_code_entry* JITCodeEntry) { 130 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 131 132 // Insert this entry at the head of the list. 133 JITCodeEntry->prev_entry = nullptr; 134 jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry; 135 JITCodeEntry->next_entry = NextEntry; 136 if (NextEntry) { 137 NextEntry->prev_entry = JITCodeEntry; 138 } 139 __jit_debug_descriptor.first_entry = JITCodeEntry; 140 __jit_debug_descriptor.relevant_entry = JITCodeEntry; 141 __jit_debug_register_code(); 142 } 143 144 GDBJITRegistrationListener::~GDBJITRegistrationListener() { 145 // Free all registered object files. 146 std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); 147 for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), 148 E = ObjectBufferMap.end(); 149 I != E; ++I) { 150 // Call the private method that doesn't update the map so our iterator 151 // doesn't break. 152 deregisterObjectInternal(I); 153 } 154 ObjectBufferMap.clear(); 155 } 156 157 void GDBJITRegistrationListener::notifyObjectLoaded( 158 ObjectKey K, const ObjectFile &Obj, 159 const RuntimeDyld::LoadedObjectInfo &L) { 160 161 OwningBinary<ObjectFile> DebugObj = L.getObjectForDebug(Obj); 162 163 // Bail out if debug objects aren't supported. 164 if (!DebugObj.getBinary()) 165 return; 166 167 const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart(); 168 size_t Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize(); 169 170 std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); 171 assert(ObjectBufferMap.find(K) == ObjectBufferMap.end() && 172 "Second attempt to perform debug registration."); 173 jit_code_entry* JITCodeEntry = new jit_code_entry(); 174 175 if (!JITCodeEntry) { 176 llvm::report_fatal_error( 177 "Allocation failed when registering a JIT entry!\n"); 178 } else { 179 JITCodeEntry->symfile_addr = Buffer; 180 JITCodeEntry->symfile_size = Size; 181 182 ObjectBufferMap[K] = 183 RegisteredObjectInfo(Size, JITCodeEntry, std::move(DebugObj)); 184 NotifyDebugger(JITCodeEntry); 185 } 186 } 187 188 void GDBJITRegistrationListener::notifyFreeingObject(ObjectKey K) { 189 std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock); 190 RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(K); 191 192 if (I != ObjectBufferMap.end()) { 193 deregisterObjectInternal(I); 194 ObjectBufferMap.erase(I); 195 } 196 } 197 198 void GDBJITRegistrationListener::deregisterObjectInternal( 199 RegisteredObjectBufferMap::iterator I) { 200 201 jit_code_entry*& JITCodeEntry = I->second.Entry; 202 203 // Do the unregistration. 204 { 205 __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; 206 207 // Remove the jit_code_entry from the linked list. 208 jit_code_entry* PrevEntry = JITCodeEntry->prev_entry; 209 jit_code_entry* NextEntry = JITCodeEntry->next_entry; 210 211 if (NextEntry) { 212 NextEntry->prev_entry = PrevEntry; 213 } 214 if (PrevEntry) { 215 PrevEntry->next_entry = NextEntry; 216 } 217 else { 218 assert(__jit_debug_descriptor.first_entry == JITCodeEntry); 219 __jit_debug_descriptor.first_entry = NextEntry; 220 } 221 222 // Tell the debugger which entry we removed, and unregister the code. 223 __jit_debug_descriptor.relevant_entry = JITCodeEntry; 224 __jit_debug_register_code(); 225 } 226 227 delete JITCodeEntry; 228 JITCodeEntry = nullptr; 229 } 230 231 llvm::ManagedStatic<GDBJITRegistrationListener> GDBRegListener; 232 233 } // end namespace 234 235 namespace llvm { 236 237 JITEventListener* JITEventListener::createGDBRegistrationListener() { 238 return &*GDBRegListener; 239 } 240 241 } // namespace llvm 242 243 LLVMJITEventListenerRef LLVMCreateGDBRegistrationListener(void) 244 { 245 return wrap(JITEventListener::createGDBRegistrationListener()); 246 } 247