LCOV - code coverage report
Current view: top level - lib/ExecutionEngine - GDBRegistrationListener.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 62 63 98.4 %
Date: 2017-09-14 15:23:50 Functions: 6 7 85.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===----- GDBRegistrationListener.cpp - Registers objects with GDB -------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is distributed under the University of Illinois Open Source
       6             : // License. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : 
      10             : #include "llvm/ADT/DenseMap.h"
      11             : #include "llvm/ExecutionEngine/JITEventListener.h"
      12             : #include "llvm/Object/ObjectFile.h"
      13             : #include "llvm/Support/Compiler.h"
      14             : #include "llvm/Support/ErrorHandling.h"
      15             : #include "llvm/Support/ManagedStatic.h"
      16             : #include "llvm/Support/Mutex.h"
      17             : #include "llvm/Support/MutexGuard.h"
      18             : 
      19             : using namespace llvm;
      20             : using namespace llvm::object;
      21             : 
      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             :   struct jit_descriptor __jit_debug_descriptor = { 1, 0, nullptr, nullptr };
      51             : 
      52             :   // Debuggers puts a breakpoint in this function.
      53         296 :   LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() {
      54             :     // The noinline and the asm prevent calls to this function from being
      55             :     // optimized out.
      56             : #if !defined(_MSC_VER)
      57         296 :     asm volatile("":::"memory");
      58             : #endif
      59         296 :   }
      60             : 
      61             : }
      62             : 
      63             : namespace {
      64             : 
      65         444 : struct RegisteredObjectInfo {
      66         296 :   RegisteredObjectInfo() {}
      67             : 
      68             :   RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry,
      69             :                        OwningBinary<ObjectFile> Obj)
      70         296 :     : Size(Size), Entry(Entry), Obj(std::move(Obj)) {}
      71             : 
      72             :   std::size_t Size;
      73             :   jit_code_entry *Entry;
      74             :   OwningBinary<ObjectFile> Obj;
      75             : };
      76             : 
      77             : // Buffer for an in-memory object file in executable memory
      78             : typedef llvm::DenseMap< const char*, RegisteredObjectInfo>
      79             :   RegisteredObjectBufferMap;
      80             : 
      81             : /// Global access point for the JIT debugging interface designed for use with a
      82             : /// singleton toolbox. Handles thread-safe registration and deregistration of
      83             : /// object files that are in executable memory managed by the client of this
      84             : /// class.
      85             : class GDBJITRegistrationListener : public JITEventListener {
      86             :   /// A map of in-memory object files that have been registered with the
      87             :   /// JIT interface.
      88             :   RegisteredObjectBufferMap ObjectBufferMap;
      89             : 
      90             : public:
      91             :   /// Instantiates the JIT service.
      92         238 :   GDBJITRegistrationListener() : ObjectBufferMap() {}
      93             : 
      94             :   /// Unregisters each object that was previously registered and releases all
      95             :   /// internal resources.
      96             :   ~GDBJITRegistrationListener() override;
      97             : 
      98             :   /// Creates an entry in the JIT registry for the buffer @p Object,
      99             :   /// which must contain an object file in executable memory with any
     100             :   /// debug information for the debugger.
     101             :   void NotifyObjectEmitted(const ObjectFile &Object,
     102             :                            const RuntimeDyld::LoadedObjectInfo &L) override;
     103             : 
     104             :   /// Removes the internal registration of @p Object, and
     105             :   /// frees associated resources.
     106             :   /// Returns true if @p Object was found in ObjectBufferMap.
     107             :   void NotifyFreeingObject(const ObjectFile &Object) override;
     108             : 
     109             : private:
     110             :   /// Deregister the debug info for the given object file from the debugger
     111             :   /// and delete any temporary copies.  This private method does not remove
     112             :   /// the function from Map so that it can be called while iterating over Map.
     113             :   void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I);
     114             : };
     115             : 
     116             : /// Lock used to serialize all jit registration events, since they
     117             : /// modify global variables.
     118             : ManagedStatic<sys::Mutex> JITDebugLock;
     119             : 
     120             : /// Do the registration.
     121             : void NotifyDebugger(jit_code_entry* JITCodeEntry) {
     122         148 :   __jit_debug_descriptor.action_flag = JIT_REGISTER_FN;
     123             : 
     124             :   // Insert this entry at the head of the list.
     125         148 :   JITCodeEntry->prev_entry = nullptr;
     126         148 :   jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry;
     127         148 :   JITCodeEntry->next_entry = NextEntry;
     128         148 :   if (NextEntry) {
     129          31 :     NextEntry->prev_entry = JITCodeEntry;
     130             :   }
     131         148 :   __jit_debug_descriptor.first_entry = JITCodeEntry;
     132         148 :   __jit_debug_descriptor.relevant_entry = JITCodeEntry;
     133         148 :   __jit_debug_register_code();
     134             : }
     135             : 
     136         255 : GDBJITRegistrationListener::~GDBJITRegistrationListener() {
     137             :   // Free all registered object files.
     138         255 :   llvm::MutexGuard locked(*JITDebugLock);
     139          85 :   for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(),
     140         170 :                                            E = ObjectBufferMap.end();
     141         170 :        I != E; ++I) {
     142             :     // Call the private method that doesn't update the map so our iterator
     143             :     // doesn't break.
     144          85 :     deregisterObjectInternal(I);
     145             :   }
     146          85 :   ObjectBufferMap.clear();
     147         170 : }
     148             : 
     149         148 : void GDBJITRegistrationListener::NotifyObjectEmitted(
     150             :                                        const ObjectFile &Object,
     151             :                                        const RuntimeDyld::LoadedObjectInfo &L) {
     152             : 
     153         296 :   OwningBinary<ObjectFile> DebugObj = L.getObjectForDebug(Object);
     154             : 
     155             :   // Bail out if debug objects aren't supported.
     156         148 :   if (!DebugObj.getBinary())
     157           0 :     return;
     158             : 
     159         296 :   const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart();
     160         296 :   size_t      Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize();
     161             : 
     162         296 :   const char *Key = Object.getMemoryBufferRef().getBufferStart();
     163             : 
     164             :   assert(Key && "Attempt to register a null object with a debugger.");
     165         444 :   llvm::MutexGuard locked(*JITDebugLock);
     166             :   assert(ObjectBufferMap.find(Key) == ObjectBufferMap.end() &&
     167             :          "Second attempt to perform debug registration.");
     168         148 :   jit_code_entry* JITCodeEntry = new jit_code_entry();
     169             : 
     170             :   if (!JITCodeEntry) {
     171             :     llvm::report_fatal_error(
     172             :       "Allocation failed when registering a JIT entry!\n");
     173             :   } else {
     174         148 :     JITCodeEntry->symfile_addr = Buffer;
     175         148 :     JITCodeEntry->symfile_size = Size;
     176             : 
     177         740 :     ObjectBufferMap[Key] = RegisteredObjectInfo(Size, JITCodeEntry,
     178         148 :                                                 std::move(DebugObj));
     179         148 :     NotifyDebugger(JITCodeEntry);
     180             :   }
     181             : }
     182             : 
     183          63 : void GDBJITRegistrationListener::NotifyFreeingObject(const ObjectFile& Object) {
     184         126 :   const char *Key = Object.getMemoryBufferRef().getBufferStart();
     185         189 :   llvm::MutexGuard locked(*JITDebugLock);
     186          63 :   RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Key);
     187             : 
     188         189 :   if (I != ObjectBufferMap.end()) {
     189          63 :     deregisterObjectInternal(I);
     190          63 :     ObjectBufferMap.erase(I);
     191             :   }
     192          63 : }
     193             : 
     194         148 : void GDBJITRegistrationListener::deregisterObjectInternal(
     195             :     RegisteredObjectBufferMap::iterator I) {
     196             : 
     197         148 :   jit_code_entry*& JITCodeEntry = I->second.Entry;
     198             : 
     199             :   // Do the unregistration.
     200             :   {
     201         148 :     __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN;
     202             : 
     203             :     // Remove the jit_code_entry from the linked list.
     204         148 :     jit_code_entry* PrevEntry = JITCodeEntry->prev_entry;
     205         148 :     jit_code_entry* NextEntry = JITCodeEntry->next_entry;
     206             : 
     207         148 :     if (NextEntry) {
     208           9 :       NextEntry->prev_entry = PrevEntry;
     209             :     }
     210         148 :     if (PrevEntry) {
     211          24 :       PrevEntry->next_entry = NextEntry;
     212             :     }
     213             :     else {
     214             :       assert(__jit_debug_descriptor.first_entry == JITCodeEntry);
     215         124 :       __jit_debug_descriptor.first_entry = NextEntry;
     216             :     }
     217             : 
     218             :     // Tell the debugger which entry we removed, and unregister the code.
     219         148 :     __jit_debug_descriptor.relevant_entry = JITCodeEntry;
     220         148 :     __jit_debug_register_code();
     221             :   }
     222             : 
     223         148 :   delete JITCodeEntry;
     224         148 :   JITCodeEntry = nullptr;
     225         148 : }
     226             : 
     227             : llvm::ManagedStatic<GDBJITRegistrationListener> GDBRegListener;
     228             : 
     229             : } // end namespace
     230             : 
     231             : namespace llvm {
     232             : 
     233         121 : JITEventListener* JITEventListener::createGDBRegistrationListener() {
     234         121 :   return &*GDBRegListener;
     235             : }
     236             : 
     237             : } // namespace llvm

Generated by: LCOV version 1.13