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. 51char* 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 . 58extern "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 70namespace { 71 72// Buffer for an in-memory object file in executable memory 73typedef 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. 80class GDBJITRegistrar { 81 /// A map of in-memory object files that have been registered with the GDB JIT interface. 82 RegisteredObjectBufferMap ObjectBufferMap; 83 84public: 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 102private: 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. 111llvm::sys::Mutex JITDebugLock; 112 113/// Acquire the lock and do the registration. 114void 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 130GDBJITRegistrar* 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 144GDBJITRegistrar::~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 155void 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 186bool 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 197void 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 233void registerObjectWithGDB(const ObjectBuffer* Object, std::size_t Size) { 234 GDBJITRegistrar* Registrar = RegistrarSingleton(); 235 if (Registrar) { 236 Registrar->registerObject(Object, Size); 237 } 238} 239 240void deregisterObjectWithGDB(const ObjectBuffer* Object) { 241 GDBJITRegistrar* Registrar = RegistrarSingleton(); 242 if (Registrar) { 243 Registrar->deregisterObject(Object); 244 } 245} 246