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