1 //===----- GDBRegistrationListener.cpp - Registers objects with GDB -------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 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/Mutex.h" 17 #include "llvm/Support/MutexGuard.h" 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 struct jit_descriptor __jit_debug_descriptor = { 1, 0, nullptr, nullptr }; 51 52 // Debuggers puts a breakpoint in this function. 53 LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { 54 // The noinline and the asm prevent calls to this function from being 55 // optimized out. 56 #if !defined(_MSC_VER) 57 asm volatile("":::"memory"); 58 #endif 59 } 60 61 } 62 63 namespace { 64 65 struct RegisteredObjectInfo { 66 RegisteredObjectInfo() {} 67 68 RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry, 69 OwningBinary<ObjectFile> Obj) 70 : Size(Size), Entry(Entry), Obj(std::move(Obj)) {} 71 72 RegisteredObjectInfo(RegisteredObjectInfo &&Other) 73 : Size(Other.Size), Entry(Other.Entry), Obj(std::move(Other.Obj)) {} 74 75 RegisteredObjectInfo& operator=(RegisteredObjectInfo &&Other) { 76 Size = Other.Size; 77 Entry = Other.Entry; 78 Obj = std::move(Other.Obj); 79 return *this; 80 } 81 82 std::size_t Size; 83 jit_code_entry *Entry; 84 OwningBinary<ObjectFile> Obj; 85 }; 86 87 // Buffer for an in-memory object file in executable memory 88 typedef llvm::DenseMap< const char*, RegisteredObjectInfo> 89 RegisteredObjectBufferMap; 90 91 /// Global access point for the JIT debugging interface designed for use with a 92 /// singleton toolbox. Handles thread-safe registration and deregistration of 93 /// object files that are in executable memory managed by the client of this 94 /// class. 95 class GDBJITRegistrationListener : public JITEventListener { 96 /// A map of in-memory object files that have been registered with the 97 /// JIT interface. 98 RegisteredObjectBufferMap ObjectBufferMap; 99 100 public: 101 /// Instantiates the JIT service. 102 GDBJITRegistrationListener() : ObjectBufferMap() {} 103 104 /// Unregisters each object that was previously registered and releases all 105 /// internal resources. 106 ~GDBJITRegistrationListener() override; 107 108 /// Creates an entry in the JIT registry for the buffer @p Object, 109 /// which must contain an object file in executable memory with any 110 /// debug information for the debugger. 111 void NotifyObjectEmitted(const ObjectFile &Object, 112 const RuntimeDyld::LoadedObjectInfo &L) override; 113 114 /// Removes the internal registration of @p Object, and 115 /// frees associated resources. 116 /// Returns true if @p Object was found in ObjectBufferMap. 117 void NotifyFreeingObject(const ObjectFile &Object) override; 118 119 private: 120 /// Deregister the debug info for the given object file from the debugger 121 /// and delete any temporary copies. This private method does not remove 122 /// the function from Map so that it can be called while iterating over Map. 123 void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I); 124 }; 125 126 /// Lock used to serialize all jit registration events, since they 127 /// modify global variables. 128 ManagedStatic<sys::Mutex> JITDebugLock; 129 130 /// Do the registration. 131 void NotifyDebugger(jit_code_entry* JITCodeEntry) { 132 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 133 134 // Insert this entry at the head of the list. 135 JITCodeEntry->prev_entry = nullptr; 136 jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry; 137 JITCodeEntry->next_entry = NextEntry; 138 if (NextEntry) { 139 NextEntry->prev_entry = JITCodeEntry; 140 } 141 __jit_debug_descriptor.first_entry = JITCodeEntry; 142 __jit_debug_descriptor.relevant_entry = JITCodeEntry; 143 __jit_debug_register_code(); 144 } 145 146 GDBJITRegistrationListener::~GDBJITRegistrationListener() { 147 // Free all registered object files. 148 llvm::MutexGuard locked(*JITDebugLock); 149 for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), 150 E = ObjectBufferMap.end(); 151 I != E; ++I) { 152 // Call the private method that doesn't update the map so our iterator 153 // doesn't break. 154 deregisterObjectInternal(I); 155 } 156 ObjectBufferMap.clear(); 157 } 158 159 void GDBJITRegistrationListener::NotifyObjectEmitted( 160 const ObjectFile &Object, 161 const RuntimeDyld::LoadedObjectInfo &L) { 162 163 OwningBinary<ObjectFile> DebugObj = L.getObjectForDebug(Object); 164 165 // Bail out if debug objects aren't supported. 166 if (!DebugObj.getBinary()) 167 return; 168 169 const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart(); 170 size_t Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize(); 171 172 const char *Key = Object.getMemoryBufferRef().getBufferStart(); 173 174 assert(Key && "Attempt to register a null object with a debugger."); 175 llvm::MutexGuard locked(*JITDebugLock); 176 assert(ObjectBufferMap.find(Key) == ObjectBufferMap.end() && 177 "Second attempt to perform debug registration."); 178 jit_code_entry* JITCodeEntry = new jit_code_entry(); 179 180 if (!JITCodeEntry) { 181 llvm::report_fatal_error( 182 "Allocation failed when registering a JIT entry!\n"); 183 } else { 184 JITCodeEntry->symfile_addr = Buffer; 185 JITCodeEntry->symfile_size = Size; 186 187 ObjectBufferMap[Key] = RegisteredObjectInfo(Size, JITCodeEntry, 188 std::move(DebugObj)); 189 NotifyDebugger(JITCodeEntry); 190 } 191 } 192 193 void GDBJITRegistrationListener::NotifyFreeingObject(const ObjectFile& Object) { 194 const char *Key = Object.getMemoryBufferRef().getBufferStart(); 195 llvm::MutexGuard locked(*JITDebugLock); 196 RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Key); 197 198 if (I != ObjectBufferMap.end()) { 199 deregisterObjectInternal(I); 200 ObjectBufferMap.erase(I); 201 } 202 } 203 204 void GDBJITRegistrationListener::deregisterObjectInternal( 205 RegisteredObjectBufferMap::iterator I) { 206 207 jit_code_entry*& JITCodeEntry = I->second.Entry; 208 209 // Do the unregistration. 210 { 211 __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; 212 213 // Remove the jit_code_entry from the linked list. 214 jit_code_entry* PrevEntry = JITCodeEntry->prev_entry; 215 jit_code_entry* NextEntry = JITCodeEntry->next_entry; 216 217 if (NextEntry) { 218 NextEntry->prev_entry = PrevEntry; 219 } 220 if (PrevEntry) { 221 PrevEntry->next_entry = NextEntry; 222 } 223 else { 224 assert(__jit_debug_descriptor.first_entry == JITCodeEntry); 225 __jit_debug_descriptor.first_entry = NextEntry; 226 } 227 228 // Tell the debugger which entry we removed, and unregister the code. 229 __jit_debug_descriptor.relevant_entry = JITCodeEntry; 230 __jit_debug_register_code(); 231 } 232 233 delete JITCodeEntry; 234 JITCodeEntry = nullptr; 235 } 236 237 llvm::ManagedStatic<GDBJITRegistrationListener> GDBRegListener; 238 239 } // end namespace 240 241 namespace llvm { 242 243 JITEventListener* JITEventListener::createGDBRegistrationListener() { 244 return &*GDBRegListener; 245 } 246 247 } // namespace llvm 248