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 "GDBJITRegistrar.h"
34 #include "llvm/ADT/DenseMap.h"
35 #include "GDBJIT.h"
36 #include "llvm/Support/Memory.h"
37 #include "llvm/Support/MutexGuard.h"
38 #include "llvm/Support/Mutex.h"
39 #include "llvm/Support/ErrorHandling.h"
40
41 #include <fstream>
42
43 #ifdef ANDROID_ENGINEERING_BUILD
44 // Path to write dump output.
45 // It is expected that a debugger (plugin) sets this
46 // string to a writeable directory where files (such as JITted object files,
47 // IR dumps) are to be written. If this variable is 0, no debug dumps
48 // are generated.
49 char* gDebugDumpDirectory = 0;
50 #endif // ANDROID_ENGINEERING_BUILD
51
52 //************************************************************************
53 // COPIED/ADAPTED FROM llvm/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp
54 //************************************************************************
55 // This must be kept in sync with gdb/gdb/jit.h .
56 extern "C" {
57
58 // We put information about the JITed function in this global, which the
59 // debugger reads. Make sure to specify the version statically, because the
60 // debugger checks the version before we can set it during runtime.
61 static struct jit_descriptor __jit_debug_descriptor = { 1, 0, 0, 0 };
62
63 }
64 //****************************************************************************
65 // END COPIED/ADAPTED FROM llvm/lib/ExecutionEngine/JIT/JITDebugRegisterer.cpp
66 //****************************************************************************
67
68 namespace {
69
70 // Buffer for an in-memory object file in executable memory
71 typedef llvm::DenseMap< const ObjectBuffer*, std::pair<std::size_t, jit_code_entry*> >
72 RegisteredObjectBufferMap;
73
74 /// Global access point for the GDB JIT interface designed for use with a
75 /// singleton toolbox. Handles thread-safe registration and deregistration of
76 /// object files that are in executable memory managed by the client of this
77 /// class.
78 class GDBJITRegistrar {
79 /// A map of in-memory object files that have been registered with the GDB JIT interface.
80 RegisteredObjectBufferMap ObjectBufferMap;
81
82 public:
83 /// Instantiates the GDB JIT service.
GDBJITRegistrar()84 GDBJITRegistrar() : ObjectBufferMap() {}
85
86 /// Unregisters each object that was previously registered with GDB, and
87 /// releases all internal resources.
88 ~GDBJITRegistrar();
89
90 /// Creates an entry in the GDB JIT registry for the buffer @p Object,
91 /// which must contain an object file in executable memory with any
92 /// debug information for GDB.
93 void registerObject(const ObjectBuffer* Object, std::size_t Size);
94
95 /// Removes the internal registration of @p Object, and
96 /// frees associated resources.
97 /// Returns true if @p Object was found in ObjectBufferMap.
98 bool deregisterObject(const ObjectBuffer* Object);
99
100 private:
101 /// Deregister the debug info for the given object file from the debugger
102 /// and delete any temporary copies. This private method does not remove
103 /// the function from Map so that it can be called while iterating over Map.
104 void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I);
105 };
106
107 /// Lock used to serialize all gdb-jit registration events, since they
108 /// modify global variables.
109 llvm::sys::Mutex JITDebugLock;
110
111 /// Acquire the lock and do the registration.
NotifyGDB(jit_code_entry * JITCodeEntry)112 void NotifyGDB(jit_code_entry* JITCodeEntry) {
113 llvm::MutexGuard locked(JITDebugLock);
114 __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
115
116 // Insert this entry at the head of the list.
117 JITCodeEntry->prev_entry = NULL;
118 jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry;
119 JITCodeEntry->next_entry = NextEntry;
120 if (NextEntry != NULL) {
121 NextEntry->prev_entry = JITCodeEntry;
122 }
123 __jit_debug_descriptor.first_entry = JITCodeEntry;
124 __jit_debug_descriptor.relevant_entry = JITCodeEntry;
125 __jit_debug_register_code();
126 }
127
RegistrarSingleton()128 GDBJITRegistrar* RegistrarSingleton() {
129 static GDBJITRegistrar* sRegistrar = NULL;
130 if (sRegistrar == NULL) {
131 // The mutex is here so that it won't slow down access once the registrar
132 // is instantiated
133 llvm::MutexGuard locked(JITDebugLock);
134 // Check again to be sure another thread didn't create this while we waited
135 if (sRegistrar == NULL) {
136 sRegistrar = new GDBJITRegistrar;
137 }
138 }
139 return sRegistrar;
140 }
141
~GDBJITRegistrar()142 GDBJITRegistrar::~GDBJITRegistrar() {
143 // Free all registered object files.
144 for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), E = ObjectBufferMap.end();
145 I != E; ++I) {
146 // Call the private method that doesn't update the map so our iterator
147 // doesn't break.
148 deregisterObjectInternal(I);
149 }
150 ObjectBufferMap.clear();
151 }
152
registerObject(const ObjectBuffer * Object,std::size_t Size)153 void GDBJITRegistrar::registerObject(const ObjectBuffer* Object, std::size_t Size) {
154
155 assert(Object && "Attempt to register a null object with a debugger.");
156 assert(ObjectBufferMap.find(Object) == ObjectBufferMap.end()
157 && "Second attempt to perform debug registration.");
158
159 jit_code_entry* JITCodeEntry = new jit_code_entry();
160
161 if (JITCodeEntry == 0) {
162 llvm::report_fatal_error("Allocation failed when registering a GDB-JIT entry!\n");
163 }
164 else {
165 JITCodeEntry->symfile_addr = Object;
166 JITCodeEntry->symfile_size = Size;
167
168 ObjectBufferMap[Object] = std::make_pair(Size, JITCodeEntry);
169 NotifyGDB(JITCodeEntry);
170
171 #ifdef ANDROID_ENGINEERING_BUILD
172 if (0 != gDebugDumpDirectory) {
173 std::string Filename(gDebugDumpDirectory);
174 Filename += "/jit_registered.o";
175
176 std::ofstream outfile(Filename.c_str(), std::ofstream::binary);
177 outfile.write((char*)JITCodeEntry->symfile_addr, JITCodeEntry->symfile_size);
178 outfile.close();
179 }
180 #endif
181 }
182 }
183
deregisterObject(const ObjectBuffer * Object)184 bool GDBJITRegistrar::deregisterObject(const ObjectBuffer *Object) {
185 RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Object);
186
187 if (I != ObjectBufferMap.end()) {
188 deregisterObjectInternal(I);
189 ObjectBufferMap.erase(I);
190 return true;
191 }
192 return false;
193 }
194
deregisterObjectInternal(RegisteredObjectBufferMap::iterator I)195 void GDBJITRegistrar::deregisterObjectInternal(
196 RegisteredObjectBufferMap::iterator I) {
197
198 jit_code_entry*& JITCodeEntry = I->second.second;
199
200 // Acquire the lock and do the unregistration.
201 {
202 llvm::MutexGuard locked(JITDebugLock);
203 __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
204
205 // Remove the jit_code_entry from the linked list.
206 jit_code_entry* PrevEntry = JITCodeEntry->prev_entry;
207 jit_code_entry* NextEntry = JITCodeEntry->next_entry;
208
209 if (NextEntry) {
210 NextEntry->prev_entry = PrevEntry;
211 }
212 if (PrevEntry) {
213 PrevEntry->next_entry = NextEntry;
214 }
215 else {
216 assert(__jit_debug_descriptor.first_entry == JITCodeEntry);
217 __jit_debug_descriptor.first_entry = NextEntry;
218 }
219
220 // Tell GDB which entry we removed, and unregister the code.
221 __jit_debug_descriptor.relevant_entry = JITCodeEntry;
222 __jit_debug_register_code();
223 }
224
225 delete JITCodeEntry;
226 JITCodeEntry = NULL;
227 }
228
229 } // end namespace
230
registerObjectWithGDB(const ObjectBuffer * Object,std::size_t Size)231 void registerObjectWithGDB(const ObjectBuffer* Object, std::size_t Size) {
232 GDBJITRegistrar* Registrar = RegistrarSingleton();
233 if (Registrar) {
234 Registrar->registerObject(Object, Size);
235 }
236 }
237
deregisterObjectWithGDB(const ObjectBuffer * Object)238 void deregisterObjectWithGDB(const ObjectBuffer* Object) {
239 GDBJITRegistrar* Registrar = RegistrarSingleton();
240 if (Registrar) {
241 Registrar->deregisterObject(Object);
242 }
243 }
244