• 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 "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