1 /* 2 * Copyright 2012, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // This file contains portions derived from LLVM, with the original copyright 18 // header below: 19 //==----- GDBJITRegistrar.cpp - Notify GDB about in-memory object files ---==// 20 // 21 // The LLVM Compiler Infrastructure 22 // 23 // This file is distributed under the University of Illinois Open Source 24 // License. See LICENSE.TXT for details. 25 // 26 //===----------------------------------------------------------------------===// 27 // 28 // This file defines the GDBJITRegistrar object which is used by JIT engines to 29 // register in-memory object files with GDB for debugging. 30 // 31 //===----------------------------------------------------------------------===// 32 33 #include "bcc/ExecutionEngine/GDBJITRegistrar.h" 34 35 #include <llvm/ADT/DenseMap.h> 36 #include <llvm/Support/ErrorHandling.h> 37 #include <llvm/Support/Memory.h> 38 #include <llvm/Support/Mutex.h> 39 #include <llvm/Support/MutexGuard.h> 40 41 #include "bcc/ExecutionEngine/GDBJIT.h" 42 43 #include <fstream> 44 45 #ifdef ANDROID_ENGINEERING_BUILD 46 // Path to write dump output. 47 // It is expected that a debugger (plugin) sets this 48 // string to a writeable directory where files (such as JITted object files, 49 // IR dumps) are to be written. If this variable is 0, no debug dumps 50 // are generated. 51 char* gDebugDumpDirectory = 0; 52 #endif // ANDROID_ENGINEERING_BUILD 53 54 //************************************************************************ 55 // COPIED/ADAPTED FROM llvm/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp 56 //************************************************************************ 57 // This must be kept in sync with gdb/gdb/jit.h . 58 extern "C" { 59 60 // We put information about the JITed function in this global, which the 61 // debugger reads. Make sure to specify the version statically, because the 62 // debugger checks the version before we can set it during runtime. 63 static struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 }; 64 65 } 66 //**************************************************************************** 67 // END COPIED/ADAPTED FROM llvm/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp 68 //**************************************************************************** 69 70 namespace { 71 72 // Buffer for an in-memory object file in executable memory 73 typedef llvm::DenseMap< const ObjectBuffer*, std::pair<std::size_t, jit_code_entry*> > 74 RegisteredObjectBufferMap; 75 76 /// Global access point for the GDB JIT interface designed for use with a 77 /// singleton toolbox. Handles thread-safe registration and deregistration of 78 /// object files that are in executable memory managed by the client of this 79 /// class. 80 class GDBJITRegistrar { 81 /// A map of in-memory object files that have been registered with the GDB JIT interface. 82 RegisteredObjectBufferMap ObjectBufferMap; 83 84 public: 85 /// Instantiates the GDB JIT service. 86 GDBJITRegistrar() : ObjectBufferMap() {} 87 88 /// Unregisters each object that was previously registered with GDB, and 89 /// releases all internal resources. 90 ~GDBJITRegistrar(); 91 92 /// Creates an entry in the GDB JIT registry for the buffer @p Object, 93 /// which must contain an object file in executable memory with any 94 /// debug information for GDB. 95 void registerObject(const ObjectBuffer* Object, std::size_t Size); 96 97 /// Removes the internal registration of @p Object, and 98 /// frees associated resources. 99 /// Returns true if @p Object was found in ObjectBufferMap. 100 bool deregisterObject(const ObjectBuffer* Object); 101 102 private: 103 /// Deregister the debug info for the given object file from the debugger 104 /// and delete any temporary copies. This private method does not remove 105 /// the function from Map so that it can be called while iterating over Map. 106 void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I); 107 }; 108 109 /// Lock used to serialize all gdb-jit registration events, since they 110 /// modify global variables. 111 llvm::sys::Mutex JITDebugLock; 112 113 /// Acquire the lock and do the registration. 114 void NotifyGDB(jit_code_entry* JITCodeEntry) { 115 llvm::MutexGuard locked(JITDebugLock); 116 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; 117 118 // Insert this entry at the head of the list. 119 JITCodeEntry->prev_entry = NULL; 120 jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry; 121 JITCodeEntry->next_entry = NextEntry; 122 if (NextEntry != NULL) { 123 NextEntry->prev_entry = JITCodeEntry; 124 } 125 __jit_debug_descriptor.first_entry = JITCodeEntry; 126 __jit_debug_descriptor.relevant_entry = JITCodeEntry; 127 __jit_debug_register_code(); 128 } 129 130 GDBJITRegistrar* RegistrarSingleton() { 131 static GDBJITRegistrar* sRegistrar = NULL; 132 if (sRegistrar == NULL) { 133 // The mutex is here so that it won't slow down access once the registrar 134 // is instantiated 135 llvm::MutexGuard locked(JITDebugLock); 136 // Check again to be sure another thread didn't create this while we waited 137 if (sRegistrar == NULL) { 138 sRegistrar = new GDBJITRegistrar; 139 } 140 } 141 return sRegistrar; 142 } 143 144 GDBJITRegistrar::~GDBJITRegistrar() { 145 // Free all registered object files. 146 for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end(); 147 I != E; ++I) { 148 // Call the private method that doesn't update the map so our iterator 149 // doesn't break. 150 deregisterObjectInternal(I); 151 } 152 ObjectBufferMap.clear(); 153 } 154 155 void GDBJITRegistrar::registerObject(const ObjectBuffer* Object, std::size_t Size) { 156 157 assert(Object && "Attempt to register a null object with a debugger."); 158 assert(ObjectBufferMap.find(Object) == ObjectBufferMap.end() 159 && "Second attempt to perform debug registration."); 160 161 jit_code_entry* JITCodeEntry = new jit_code_entry(); 162 163 if (JITCodeEntry == 0) { 164 llvm::report_fatal_error("Allocation failed when registering a GDB-JIT entry!\n"); 165 } 166 else { 167 JITCodeEntry->symfile_addr = Object; 168 JITCodeEntry->symfile_size = Size; 169 170 ObjectBufferMap[Object] = std::make_pair(Size, JITCodeEntry); 171 NotifyGDB(JITCodeEntry); 172 173 #ifdef ANDROID_ENGINEERING_BUILD 174 if (0 != gDebugDumpDirectory) { 175 std::string Filename(gDebugDumpDirectory); 176 Filename += "/jit_registered.o"; 177 178 std::ofstream outfile(Filename.c_str(), std::ofstream::binary); 179 outfile.write((char*)JITCodeEntry->symfile_addr, JITCodeEntry->symfile_size); 180 outfile.close(); 181 } 182 #endif 183 } 184 } 185 186 bool GDBJITRegistrar::deregisterObject(const ObjectBuffer *Object) { 187 RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Object); 188 189 if (I != ObjectBufferMap.end()) { 190 deregisterObjectInternal(I); 191 ObjectBufferMap.erase(I); 192 return true; 193 } 194 return false; 195 } 196 197 void GDBJITRegistrar::deregisterObjectInternal( 198 RegisteredObjectBufferMap::iterator I) { 199 200 jit_code_entry*& JITCodeEntry = I->second.second; 201 202 // Acquire the lock and do the unregistration. 203 { 204 llvm::MutexGuard locked(JITDebugLock); 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 GDB 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 = NULL; 229 } 230 231 } // end namespace 232 233 void registerObjectWithGDB(const ObjectBuffer* Object, std::size_t Size) { 234 GDBJITRegistrar* Registrar = RegistrarSingleton(); 235 if (Registrar) { 236 Registrar->registerObject(Object, Size); 237 } 238 } 239 240 void deregisterObjectWithGDB(const ObjectBuffer* Object) { 241 GDBJITRegistrar* Registrar = RegistrarSingleton(); 242 if (Registrar) { 243 Registrar->deregisterObject(Object); 244 } 245 } 246