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