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.
GDBJITRegistrar()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.
NotifyGDB(jit_code_entry * JITCodeEntry)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
RegistrarSingleton()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
~GDBJITRegistrar()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
registerObject(const ObjectBuffer * Object,std::size_t Size)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
deregisterObject(const ObjectBuffer * Object)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
deregisterObjectInternal(RegisteredObjectBufferMap::iterator I)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
registerObjectWithGDB(const ObjectBuffer * Object,std::size_t Size)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
deregisterObjectWithGDB(const ObjectBuffer * Object)240 void deregisterObjectWithGDB(const ObjectBuffer* Object) {
241 GDBJITRegistrar* Registrar = RegistrarSingleton();
242 if (Registrar) {
243 Registrar->deregisterObject(Object);
244 }
245 }
246