1919using namespace llvm ;
2020using namespace llvm ::object;
2121
22- // This must be kept in sync with gdb/gdb/jit.h .
23- extern " C" {
24-
25- typedef enum {
26- JIT_NOACTION = 0 ,
27- JIT_REGISTER_FN,
28- JIT_UNREGISTER_FN
29- } jit_actions_t ;
30-
31- struct jit_code_entry {
32- struct jit_code_entry *next_entry;
33- struct jit_code_entry *prev_entry;
34- const char *symfile_addr;
35- uint64_t symfile_size;
36- };
37-
38- struct jit_descriptor {
39- uint32_t version;
40- // This should be jit_actions_t, but we want to be specific about the
41- // bit-width.
42- uint32_t action_flag;
43- struct jit_code_entry *relevant_entry;
44- struct jit_code_entry *first_entry;
45- };
46-
47- // We put information about the JITed function in this global, which the
48- // debugger reads. Make sure to specify the version statically, because the
49- // debugger checks the version before we can set it during runtime.
50- extern struct jit_descriptor __jit_debug_descriptor;
51-
52- // Debuggers puts a breakpoint in this function.
53- extern " C" void __jit_debug_register_code ();
54- }
55-
5622namespace {
5723
58- // FIXME: lli aims to provide both, RuntimeDyld and JITLink, as the dynamic
59- // loaders for it's JIT implementations. And they both offer debugging via the
60- // GDB JIT interface, which builds on the two well-known symbol names below.
61- // As these symbols must be unique accross the linked executable, we can only
62- // define them in one of the libraries and make the other depend on it.
63- // OrcTargetProcess is a minimal stub for embedding a JIT client in remote
64- // executors. For the moment it seems reasonable to have the definition there
65- // and let ExecutionEngine depend on it, until we find a better solution.
66- //
67- LLVM_ATTRIBUTE_USED void requiredSymbolDefinitionsFromOrcTargetProcess () {
68- errs () << (void *)&__jit_debug_register_code
69- << (void *)&__jit_debug_descriptor;
70- }
71-
72- struct RegisteredObjectInfo {
73- RegisteredObjectInfo () {}
74-
75- RegisteredObjectInfo (std::size_t Size, jit_code_entry *Entry,
76- OwningBinary<ObjectFile> Obj)
77- : Size(Size), Entry(Entry), Obj(std::move(Obj)) {}
78-
79- std::size_t Size;
80- jit_code_entry *Entry;
81- OwningBinary<ObjectFile> Obj;
82- };
83-
84- // Buffer for an in-memory object file in executable memory
85- typedef llvm::DenseMap<JITEventListener::ObjectKey, RegisteredObjectInfo>
86- RegisteredObjectBufferMap;
87-
8824// / Global access point for the JIT debugging interface designed for use with a
8925// / singleton toolbox. Handles thread-safe registration and deregistration of
9026// / object files that are in executable memory managed by the client of this
9127// / class.
9228class GDBJITRegistrationListener : public JITEventListener {
93- // / A map of in-memory object files that have been registered with the
94- // / JIT interface.
95- RegisteredObjectBufferMap ObjectBufferMap;
96-
9729public:
9830 // / Instantiates the JIT service.
99- GDBJITRegistrationListener () : ObjectBufferMap() {}
31+ GDBJITRegistrationListener () {}
10032
10133 // / Unregisters each object that was previously registered and releases all
10234 // / internal resources.
@@ -112,119 +44,17 @@ class GDBJITRegistrationListener : public JITEventListener {
11244 // / frees associated resources.
11345 // / Returns true if @p Object was found in ObjectBufferMap.
11446 void notifyFreeingObject (ObjectKey K) override ;
115-
116- private:
117- // / Deregister the debug info for the given object file from the debugger
118- // / and delete any temporary copies. This private method does not remove
119- // / the function from Map so that it can be called while iterating over Map.
120- void deregisterObjectInternal (RegisteredObjectBufferMap::iterator I);
12147};
12248
123- // / Lock used to serialize all jit registration events, since they
124- // / modify global variables.
125- ManagedStatic<sys::Mutex> JITDebugLock;
126-
127- // / Do the registration.
128- void NotifyDebugger (jit_code_entry* JITCodeEntry) {
129- __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
130-
131- // Insert this entry at the head of the list.
132- JITCodeEntry->prev_entry = nullptr ;
133- jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry ;
134- JITCodeEntry->next_entry = NextEntry;
135- if (NextEntry) {
136- NextEntry->prev_entry = JITCodeEntry;
137- }
138- __jit_debug_descriptor.first_entry = JITCodeEntry;
139- __jit_debug_descriptor.relevant_entry = JITCodeEntry;
140- __jit_debug_register_code ();
141- }
142-
14349GDBJITRegistrationListener::~GDBJITRegistrationListener () {
144- // Free all registered object files.
145- std::lock_guard<llvm::sys::Mutex> locked (*JITDebugLock);
146- for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin (),
147- E = ObjectBufferMap.end ();
148- I != E; ++I) {
149- // Call the private method that doesn't update the map so our iterator
150- // doesn't break.
151- deregisterObjectInternal (I);
152- }
153- ObjectBufferMap.clear ();
15450}
15551
15652void GDBJITRegistrationListener::notifyObjectLoaded (
15753 ObjectKey K, const ObjectFile &Obj,
15854 const RuntimeDyld::LoadedObjectInfo &L) {
159-
160- OwningBinary<ObjectFile> DebugObj = L.getObjectForDebug (Obj);
161-
162- // Bail out if debug objects aren't supported.
163- if (!DebugObj.getBinary ())
164- return ;
165-
166- const char *Buffer = DebugObj.getBinary ()->getMemoryBufferRef ().getBufferStart ();
167- size_t Size = DebugObj.getBinary ()->getMemoryBufferRef ().getBufferSize ();
168-
169- std::lock_guard<llvm::sys::Mutex> locked (*JITDebugLock);
170- assert (ObjectBufferMap.find (K) == ObjectBufferMap.end () &&
171- " Second attempt to perform debug registration." );
172- jit_code_entry* JITCodeEntry = new jit_code_entry ();
173-
174- if (!JITCodeEntry) {
175- llvm::report_fatal_error (
176- " Allocation failed when registering a JIT entry!\n " );
177- } else {
178- JITCodeEntry->symfile_addr = Buffer;
179- JITCodeEntry->symfile_size = Size;
180-
181- ObjectBufferMap[K] =
182- RegisteredObjectInfo (Size, JITCodeEntry, std::move (DebugObj));
183- NotifyDebugger (JITCodeEntry);
184- }
18555}
18656
18757void GDBJITRegistrationListener::notifyFreeingObject (ObjectKey K) {
188- std::lock_guard<llvm::sys::Mutex> locked (*JITDebugLock);
189- RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find (K);
190-
191- if (I != ObjectBufferMap.end ()) {
192- deregisterObjectInternal (I);
193- ObjectBufferMap.erase (I);
194- }
195- }
196-
197- void GDBJITRegistrationListener::deregisterObjectInternal (
198- RegisteredObjectBufferMap::iterator I) {
199-
200- jit_code_entry*& JITCodeEntry = I->second .Entry ;
201-
202- // Do the unregistration.
203- {
204- __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
205-
206- // Remove the jit_code_entry from the linked list.
207- jit_code_entry* PrevEntry = JITCodeEntry->prev_entry ;
208- jit_code_entry* NextEntry = JITCodeEntry->next_entry ;
209-
210- if (NextEntry) {
211- NextEntry->prev_entry = PrevEntry;
212- }
213- if (PrevEntry) {
214- PrevEntry->next_entry = NextEntry;
215- }
216- else {
217- assert (__jit_debug_descriptor.first_entry == JITCodeEntry);
218- __jit_debug_descriptor.first_entry = NextEntry;
219- }
220-
221- // Tell the debugger which entry we removed, and unregister the code.
222- __jit_debug_descriptor.relevant_entry = JITCodeEntry;
223- __jit_debug_register_code ();
224- }
225-
226- delete JITCodeEntry;
227- JITCodeEntry = nullptr ;
22858}
22959
23060llvm::ManagedStatic<GDBJITRegistrationListener> GDBRegListener;
0 commit comments