1277323Sdim//===----- GDBRegistrationListener.cpp - Registers objects with GDB -------===//
2277323Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6277323Sdim//
7277323Sdim//===----------------------------------------------------------------------===//
8277323Sdim
9341825Sdim#include "llvm-c/ExecutionEngine.h"
10277323Sdim#include "llvm/ADT/DenseMap.h"
11277323Sdim#include "llvm/ExecutionEngine/JITEventListener.h"
12277323Sdim#include "llvm/Object/ObjectFile.h"
13277323Sdim#include "llvm/Support/Compiler.h"
14277323Sdim#include "llvm/Support/ErrorHandling.h"
15277323Sdim#include "llvm/Support/ManagedStatic.h"
16277323Sdim#include "llvm/Support/Mutex.h"
17360784Sdim#include <mutex>
18277323Sdim
19277323Sdimusing namespace llvm;
20277323Sdimusing namespace llvm::object;
21277323Sdim
22277323Sdim// This must be kept in sync with gdb/gdb/jit.h .
23277323Sdimextern "C" {
24277323Sdim
25277323Sdim  typedef enum {
26277323Sdim    JIT_NOACTION = 0,
27277323Sdim    JIT_REGISTER_FN,
28277323Sdim    JIT_UNREGISTER_FN
29277323Sdim  } jit_actions_t;
30277323Sdim
31277323Sdim  struct jit_code_entry {
32277323Sdim    struct jit_code_entry *next_entry;
33277323Sdim    struct jit_code_entry *prev_entry;
34277323Sdim    const char *symfile_addr;
35277323Sdim    uint64_t symfile_size;
36277323Sdim  };
37277323Sdim
38277323Sdim  struct jit_descriptor {
39277323Sdim    uint32_t version;
40277323Sdim    // This should be jit_actions_t, but we want to be specific about the
41277323Sdim    // bit-width.
42277323Sdim    uint32_t action_flag;
43277323Sdim    struct jit_code_entry *relevant_entry;
44277323Sdim    struct jit_code_entry *first_entry;
45277323Sdim  };
46277323Sdim
47277323Sdim  // We put information about the JITed function in this global, which the
48277323Sdim  // debugger reads.  Make sure to specify the version statically, because the
49277323Sdim  // debugger checks the version before we can set it during runtime.
50277323Sdim  struct jit_descriptor __jit_debug_descriptor = { 1, 0, nullptr, nullptr };
51277323Sdim
52277323Sdim  // Debuggers puts a breakpoint in this function.
53277323Sdim  LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
54277323Sdim    // The noinline and the asm prevent calls to this function from being
55277323Sdim    // optimized out.
56277323Sdim#if !defined(_MSC_VER)
57277323Sdim    asm volatile("":::"memory");
58277323Sdim#endif
59277323Sdim  }
60277323Sdim
61277323Sdim}
62277323Sdim
63277323Sdimnamespace {
64277323Sdim
65277323Sdimstruct RegisteredObjectInfo {
66277323Sdim  RegisteredObjectInfo() {}
67277323Sdim
68277323Sdim  RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry,
69277323Sdim                       OwningBinary<ObjectFile> Obj)
70277323Sdim    : Size(Size), Entry(Entry), Obj(std::move(Obj)) {}
71277323Sdim
72277323Sdim  std::size_t Size;
73277323Sdim  jit_code_entry *Entry;
74277323Sdim  OwningBinary<ObjectFile> Obj;
75277323Sdim};
76277323Sdim
77277323Sdim// Buffer for an in-memory object file in executable memory
78344779Sdimtypedef llvm::DenseMap<JITEventListener::ObjectKey, RegisteredObjectInfo>
79344779Sdim    RegisteredObjectBufferMap;
80277323Sdim
81277323Sdim/// Global access point for the JIT debugging interface designed for use with a
82277323Sdim/// singleton toolbox. Handles thread-safe registration and deregistration of
83277323Sdim/// object files that are in executable memory managed by the client of this
84277323Sdim/// class.
85277323Sdimclass GDBJITRegistrationListener : public JITEventListener {
86277323Sdim  /// A map of in-memory object files that have been registered with the
87277323Sdim  /// JIT interface.
88277323Sdim  RegisteredObjectBufferMap ObjectBufferMap;
89277323Sdim
90277323Sdimpublic:
91277323Sdim  /// Instantiates the JIT service.
92277323Sdim  GDBJITRegistrationListener() : ObjectBufferMap() {}
93277323Sdim
94277323Sdim  /// Unregisters each object that was previously registered and releases all
95277323Sdim  /// internal resources.
96288943Sdim  ~GDBJITRegistrationListener() override;
97277323Sdim
98277323Sdim  /// Creates an entry in the JIT registry for the buffer @p Object,
99277323Sdim  /// which must contain an object file in executable memory with any
100277323Sdim  /// debug information for the debugger.
101344779Sdim  void notifyObjectLoaded(ObjectKey K, const ObjectFile &Obj,
102344779Sdim                          const RuntimeDyld::LoadedObjectInfo &L) override;
103277323Sdim
104277323Sdim  /// Removes the internal registration of @p Object, and
105277323Sdim  /// frees associated resources.
106277323Sdim  /// Returns true if @p Object was found in ObjectBufferMap.
107344779Sdim  void notifyFreeingObject(ObjectKey K) override;
108277323Sdim
109277323Sdimprivate:
110277323Sdim  /// Deregister the debug info for the given object file from the debugger
111277323Sdim  /// and delete any temporary copies.  This private method does not remove
112277323Sdim  /// the function from Map so that it can be called while iterating over Map.
113277323Sdim  void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I);
114277323Sdim};
115277323Sdim
116277323Sdim/// Lock used to serialize all jit registration events, since they
117277323Sdim/// modify global variables.
118277323SdimManagedStatic<sys::Mutex> JITDebugLock;
119277323Sdim
120277323Sdim/// Do the registration.
121277323Sdimvoid NotifyDebugger(jit_code_entry* JITCodeEntry) {
122277323Sdim  __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
123277323Sdim
124277323Sdim  // Insert this entry at the head of the list.
125277323Sdim  JITCodeEntry->prev_entry = nullptr;
126277323Sdim  jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry;
127277323Sdim  JITCodeEntry->next_entry = NextEntry;
128277323Sdim  if (NextEntry) {
129277323Sdim    NextEntry->prev_entry = JITCodeEntry;
130277323Sdim  }
131277323Sdim  __jit_debug_descriptor.first_entry = JITCodeEntry;
132277323Sdim  __jit_debug_descriptor.relevant_entry = JITCodeEntry;
133277323Sdim  __jit_debug_register_code();
134277323Sdim}
135277323Sdim
136277323SdimGDBJITRegistrationListener::~GDBJITRegistrationListener() {
137277323Sdim  // Free all registered object files.
138360784Sdim  std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock);
139277323Sdim  for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(),
140277323Sdim                                           E = ObjectBufferMap.end();
141277323Sdim       I != E; ++I) {
142277323Sdim    // Call the private method that doesn't update the map so our iterator
143277323Sdim    // doesn't break.
144277323Sdim    deregisterObjectInternal(I);
145277323Sdim  }
146277323Sdim  ObjectBufferMap.clear();
147277323Sdim}
148277323Sdim
149344779Sdimvoid GDBJITRegistrationListener::notifyObjectLoaded(
150344779Sdim    ObjectKey K, const ObjectFile &Obj,
151344779Sdim    const RuntimeDyld::LoadedObjectInfo &L) {
152277323Sdim
153344779Sdim  OwningBinary<ObjectFile> DebugObj = L.getObjectForDebug(Obj);
154277323Sdim
155277323Sdim  // Bail out if debug objects aren't supported.
156277323Sdim  if (!DebugObj.getBinary())
157277323Sdim    return;
158277323Sdim
159277323Sdim  const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart();
160277323Sdim  size_t      Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize();
161277323Sdim
162360784Sdim  std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock);
163344779Sdim  assert(ObjectBufferMap.find(K) == ObjectBufferMap.end() &&
164277323Sdim         "Second attempt to perform debug registration.");
165277323Sdim  jit_code_entry* JITCodeEntry = new jit_code_entry();
166277323Sdim
167277323Sdim  if (!JITCodeEntry) {
168277323Sdim    llvm::report_fatal_error(
169277323Sdim      "Allocation failed when registering a JIT entry!\n");
170277323Sdim  } else {
171277323Sdim    JITCodeEntry->symfile_addr = Buffer;
172277323Sdim    JITCodeEntry->symfile_size = Size;
173277323Sdim
174344779Sdim    ObjectBufferMap[K] =
175344779Sdim        RegisteredObjectInfo(Size, JITCodeEntry, std::move(DebugObj));
176277323Sdim    NotifyDebugger(JITCodeEntry);
177277323Sdim  }
178277323Sdim}
179277323Sdim
180344779Sdimvoid GDBJITRegistrationListener::notifyFreeingObject(ObjectKey K) {
181360784Sdim  std::lock_guard<llvm::sys::Mutex> locked(*JITDebugLock);
182344779Sdim  RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(K);
183277323Sdim
184277323Sdim  if (I != ObjectBufferMap.end()) {
185277323Sdim    deregisterObjectInternal(I);
186277323Sdim    ObjectBufferMap.erase(I);
187277323Sdim  }
188277323Sdim}
189277323Sdim
190277323Sdimvoid GDBJITRegistrationListener::deregisterObjectInternal(
191277323Sdim    RegisteredObjectBufferMap::iterator I) {
192277323Sdim
193277323Sdim  jit_code_entry*& JITCodeEntry = I->second.Entry;
194277323Sdim
195277323Sdim  // Do the unregistration.
196277323Sdim  {
197277323Sdim    __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
198277323Sdim
199277323Sdim    // Remove the jit_code_entry from the linked list.
200277323Sdim    jit_code_entry* PrevEntry = JITCodeEntry->prev_entry;
201277323Sdim    jit_code_entry* NextEntry = JITCodeEntry->next_entry;
202277323Sdim
203277323Sdim    if (NextEntry) {
204277323Sdim      NextEntry->prev_entry = PrevEntry;
205277323Sdim    }
206277323Sdim    if (PrevEntry) {
207277323Sdim      PrevEntry->next_entry = NextEntry;
208277323Sdim    }
209277323Sdim    else {
210277323Sdim      assert(__jit_debug_descriptor.first_entry == JITCodeEntry);
211277323Sdim      __jit_debug_descriptor.first_entry = NextEntry;
212277323Sdim    }
213277323Sdim
214277323Sdim    // Tell the debugger which entry we removed, and unregister the code.
215277323Sdim    __jit_debug_descriptor.relevant_entry = JITCodeEntry;
216277323Sdim    __jit_debug_register_code();
217277323Sdim  }
218277323Sdim
219277323Sdim  delete JITCodeEntry;
220277323Sdim  JITCodeEntry = nullptr;
221277323Sdim}
222277323Sdim
223277323Sdimllvm::ManagedStatic<GDBJITRegistrationListener> GDBRegListener;
224277323Sdim
225277323Sdim} // end namespace
226277323Sdim
227277323Sdimnamespace llvm {
228277323Sdim
229277323SdimJITEventListener* JITEventListener::createGDBRegistrationListener() {
230277323Sdim  return &*GDBRegListener;
231277323Sdim}
232277323Sdim
233277323Sdim} // namespace llvm
234341825Sdim
235341825SdimLLVMJITEventListenerRef LLVMCreateGDBRegistrationListener(void)
236341825Sdim{
237341825Sdim  return wrap(JITEventListener::createGDBRegistrationListener());
238341825Sdim}
239