• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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