From: Lang Hames Date: Thu, 27 Nov 2014 01:41:16 +0000 (+0000) Subject: [MCJIT] Replace JITEventListener::anchor (temporarily removed in r222861), and X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=7032f3cbe4e6a27cffa91fcbc3e3a77cdf94bc0f;p=oota-llvm.git [MCJIT] Replace JITEventListener::anchor (temporarily removed in r222861), and move GDBRegistrationListener into ExecutionEngine to avoid layering violation. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@222864 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/ExecutionEngine/JITEventListener.h b/include/llvm/ExecutionEngine/JITEventListener.h index dd52dfbdaf9..c3edec86878 100644 --- a/include/llvm/ExecutionEngine/JITEventListener.h +++ b/include/llvm/ExecutionEngine/JITEventListener.h @@ -113,6 +113,8 @@ public: return nullptr; } #endif // USE_OPROFILE +private: + virtual void anchor(); }; } // end namespace llvm. diff --git a/lib/ExecutionEngine/CMakeLists.txt b/lib/ExecutionEngine/CMakeLists.txt index 208495c8847..dc2fe9bf97f 100644 --- a/lib/ExecutionEngine/CMakeLists.txt +++ b/lib/ExecutionEngine/CMakeLists.txt @@ -3,6 +3,7 @@ add_llvm_library(LLVMExecutionEngine ExecutionEngine.cpp ExecutionEngineBindings.cpp + GDBRegistrationListener.cpp RTDyldMemoryManager.cpp TargetSelect.cpp ) diff --git a/lib/ExecutionEngine/ExecutionEngine.cpp b/lib/ExecutionEngine/ExecutionEngine.cpp index 20d1631a0ce..9ca0330d792 100644 --- a/lib/ExecutionEngine/ExecutionEngine.cpp +++ b/lib/ExecutionEngine/ExecutionEngine.cpp @@ -48,6 +48,8 @@ ExecutionEngine *(*ExecutionEngine::MCJITCtor)( ExecutionEngine *(*ExecutionEngine::InterpCtor)(std::unique_ptr M, std::string *ErrorStr) =nullptr; +void JITEventListener::anchor() {} + ExecutionEngine::ExecutionEngine(std::unique_ptr M) : EEState(*this), LazyFunctionCreator(nullptr) { diff --git a/lib/ExecutionEngine/GDBRegistrationListener.cpp b/lib/ExecutionEngine/GDBRegistrationListener.cpp new file mode 100644 index 00000000000..5439a77e1a5 --- /dev/null +++ b/lib/ExecutionEngine/GDBRegistrationListener.cpp @@ -0,0 +1,247 @@ +//===----- GDBRegistrationListener.cpp - Registers objects with GDB -------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ExecutionEngine/JITEventListener.h" +#include "llvm/Object/ObjectFile.h" +#include "llvm/Support/Compiler.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Mutex.h" +#include "llvm/Support/MutexGuard.h" +#include "llvm/Support/ManagedStatic.h" + +using namespace llvm; +using namespace llvm::object; + +// This must be kept in sync with gdb/gdb/jit.h . +extern "C" { + + typedef enum { + JIT_NOACTION = 0, + JIT_REGISTER_FN, + JIT_UNREGISTER_FN + } jit_actions_t; + + struct jit_code_entry { + struct jit_code_entry *next_entry; + struct jit_code_entry *prev_entry; + const char *symfile_addr; + uint64_t symfile_size; + }; + + struct jit_descriptor { + uint32_t version; + // This should be jit_actions_t, but we want to be specific about the + // bit-width. + uint32_t action_flag; + struct jit_code_entry *relevant_entry; + struct jit_code_entry *first_entry; + }; + + // We put information about the JITed function in this global, which the + // debugger reads. Make sure to specify the version statically, because the + // debugger checks the version before we can set it during runtime. + struct jit_descriptor __jit_debug_descriptor = { 1, 0, nullptr, nullptr }; + + // Debuggers puts a breakpoint in this function. + LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { + // The noinline and the asm prevent calls to this function from being + // optimized out. +#if !defined(_MSC_VER) + asm volatile("":::"memory"); +#endif + } + +} + +namespace { + +struct RegisteredObjectInfo { + RegisteredObjectInfo() {} + + RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry, + OwningBinary Obj) + : Size(Size), Entry(Entry), Obj(std::move(Obj)) {} + + RegisteredObjectInfo(RegisteredObjectInfo &&Other) + : Size(Other.Size), Entry(Other.Entry), Obj(std::move(Other.Obj)) {} + + RegisteredObjectInfo& operator=(RegisteredObjectInfo &&Other) { + Size = Other.Size; + Entry = Other.Entry; + Obj = std::move(Other.Obj); + return *this; + } + + std::size_t Size; + jit_code_entry *Entry; + OwningBinary Obj; +}; + +// Buffer for an in-memory object file in executable memory +typedef llvm::DenseMap< const char*, RegisteredObjectInfo> + RegisteredObjectBufferMap; + +/// Global access point for the JIT debugging interface designed for use with a +/// singleton toolbox. Handles thread-safe registration and deregistration of +/// object files that are in executable memory managed by the client of this +/// class. +class GDBJITRegistrationListener : public JITEventListener { + /// A map of in-memory object files that have been registered with the + /// JIT interface. + RegisteredObjectBufferMap ObjectBufferMap; + +public: + /// Instantiates the JIT service. + GDBJITRegistrationListener() : ObjectBufferMap() {} + + /// Unregisters each object that was previously registered and releases all + /// internal resources. + virtual ~GDBJITRegistrationListener(); + + /// Creates an entry in the JIT registry for the buffer @p Object, + /// which must contain an object file in executable memory with any + /// debug information for the debugger. + void NotifyObjectEmitted(const ObjectFile &Object, + const RuntimeDyld::LoadedObjectInfo &L) override; + + /// Removes the internal registration of @p Object, and + /// frees associated resources. + /// Returns true if @p Object was found in ObjectBufferMap. + void NotifyFreeingObject(const ObjectFile &Object) override; + +private: + /// Deregister the debug info for the given object file from the debugger + /// and delete any temporary copies. This private method does not remove + /// the function from Map so that it can be called while iterating over Map. + void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I); +}; + +/// Lock used to serialize all jit registration events, since they +/// modify global variables. +ManagedStatic JITDebugLock; + +/// Do the registration. +void NotifyDebugger(jit_code_entry* JITCodeEntry) { + __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; + + // Insert this entry at the head of the list. + JITCodeEntry->prev_entry = nullptr; + jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry; + JITCodeEntry->next_entry = NextEntry; + if (NextEntry) { + NextEntry->prev_entry = JITCodeEntry; + } + __jit_debug_descriptor.first_entry = JITCodeEntry; + __jit_debug_descriptor.relevant_entry = JITCodeEntry; + __jit_debug_register_code(); +} + +GDBJITRegistrationListener::~GDBJITRegistrationListener() { + // Free all registered object files. + llvm::MutexGuard locked(*JITDebugLock); + for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), + E = ObjectBufferMap.end(); + I != E; ++I) { + // Call the private method that doesn't update the map so our iterator + // doesn't break. + deregisterObjectInternal(I); + } + ObjectBufferMap.clear(); +} + +void GDBJITRegistrationListener::NotifyObjectEmitted( + const ObjectFile &Object, + const RuntimeDyld::LoadedObjectInfo &L) { + + OwningBinary DebugObj = L.getObjectForDebug(Object); + + // Bail out if debug objects aren't supported. + if (!DebugObj.getBinary()) + return; + + const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart(); + size_t Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize(); + + const char *Key = Object.getMemoryBufferRef().getBufferStart(); + + assert(Key && "Attempt to register a null object with a debugger."); + llvm::MutexGuard locked(*JITDebugLock); + assert(ObjectBufferMap.find(Key) == ObjectBufferMap.end() && + "Second attempt to perform debug registration."); + jit_code_entry* JITCodeEntry = new jit_code_entry(); + + if (!JITCodeEntry) { + llvm::report_fatal_error( + "Allocation failed when registering a JIT entry!\n"); + } else { + JITCodeEntry->symfile_addr = Buffer; + JITCodeEntry->symfile_size = Size; + + ObjectBufferMap[Key] = RegisteredObjectInfo(Size, JITCodeEntry, + std::move(DebugObj)); + NotifyDebugger(JITCodeEntry); + } +} + +void GDBJITRegistrationListener::NotifyFreeingObject(const ObjectFile& Object) { + const char *Key = Object.getMemoryBufferRef().getBufferStart(); + llvm::MutexGuard locked(*JITDebugLock); + RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Key); + + if (I != ObjectBufferMap.end()) { + deregisterObjectInternal(I); + ObjectBufferMap.erase(I); + } +} + +void GDBJITRegistrationListener::deregisterObjectInternal( + RegisteredObjectBufferMap::iterator I) { + + jit_code_entry*& JITCodeEntry = I->second.Entry; + + // Do the unregistration. + { + __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; + + // Remove the jit_code_entry from the linked list. + jit_code_entry* PrevEntry = JITCodeEntry->prev_entry; + jit_code_entry* NextEntry = JITCodeEntry->next_entry; + + if (NextEntry) { + NextEntry->prev_entry = PrevEntry; + } + if (PrevEntry) { + PrevEntry->next_entry = NextEntry; + } + else { + assert(__jit_debug_descriptor.first_entry == JITCodeEntry); + __jit_debug_descriptor.first_entry = NextEntry; + } + + // Tell the debugger which entry we removed, and unregister the code. + __jit_debug_descriptor.relevant_entry = JITCodeEntry; + __jit_debug_register_code(); + } + + delete JITCodeEntry; + JITCodeEntry = nullptr; +} + +llvm::ManagedStatic GDBRegListener; + +} // end namespace + +namespace llvm { + +JITEventListener* JITEventListener::createGDBRegistrationListener() { + return &*GDBRegListener; +} + +} // namespace llvm diff --git a/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt b/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt index 583d7a0aa41..5790eee9c82 100644 --- a/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt +++ b/lib/ExecutionEngine/RuntimeDyld/CMakeLists.txt @@ -1,5 +1,4 @@ add_llvm_library(LLVMRuntimeDyld - GDBRegistrationListener.cpp RuntimeDyld.cpp RuntimeDyldChecker.cpp RuntimeDyldELF.cpp diff --git a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrationListener.cpp b/lib/ExecutionEngine/RuntimeDyld/GDBRegistrationListener.cpp deleted file mode 100644 index 5439a77e1a5..00000000000 --- a/lib/ExecutionEngine/RuntimeDyld/GDBRegistrationListener.cpp +++ /dev/null @@ -1,247 +0,0 @@ -//===----- GDBRegistrationListener.cpp - Registers objects with GDB -------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ExecutionEngine/JITEventListener.h" -#include "llvm/Object/ObjectFile.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Mutex.h" -#include "llvm/Support/MutexGuard.h" -#include "llvm/Support/ManagedStatic.h" - -using namespace llvm; -using namespace llvm::object; - -// This must be kept in sync with gdb/gdb/jit.h . -extern "C" { - - typedef enum { - JIT_NOACTION = 0, - JIT_REGISTER_FN, - JIT_UNREGISTER_FN - } jit_actions_t; - - struct jit_code_entry { - struct jit_code_entry *next_entry; - struct jit_code_entry *prev_entry; - const char *symfile_addr; - uint64_t symfile_size; - }; - - struct jit_descriptor { - uint32_t version; - // This should be jit_actions_t, but we want to be specific about the - // bit-width. - uint32_t action_flag; - struct jit_code_entry *relevant_entry; - struct jit_code_entry *first_entry; - }; - - // We put information about the JITed function in this global, which the - // debugger reads. Make sure to specify the version statically, because the - // debugger checks the version before we can set it during runtime. - struct jit_descriptor __jit_debug_descriptor = { 1, 0, nullptr, nullptr }; - - // Debuggers puts a breakpoint in this function. - LLVM_ATTRIBUTE_NOINLINE void __jit_debug_register_code() { - // The noinline and the asm prevent calls to this function from being - // optimized out. -#if !defined(_MSC_VER) - asm volatile("":::"memory"); -#endif - } - -} - -namespace { - -struct RegisteredObjectInfo { - RegisteredObjectInfo() {} - - RegisteredObjectInfo(std::size_t Size, jit_code_entry *Entry, - OwningBinary Obj) - : Size(Size), Entry(Entry), Obj(std::move(Obj)) {} - - RegisteredObjectInfo(RegisteredObjectInfo &&Other) - : Size(Other.Size), Entry(Other.Entry), Obj(std::move(Other.Obj)) {} - - RegisteredObjectInfo& operator=(RegisteredObjectInfo &&Other) { - Size = Other.Size; - Entry = Other.Entry; - Obj = std::move(Other.Obj); - return *this; - } - - std::size_t Size; - jit_code_entry *Entry; - OwningBinary Obj; -}; - -// Buffer for an in-memory object file in executable memory -typedef llvm::DenseMap< const char*, RegisteredObjectInfo> - RegisteredObjectBufferMap; - -/// Global access point for the JIT debugging interface designed for use with a -/// singleton toolbox. Handles thread-safe registration and deregistration of -/// object files that are in executable memory managed by the client of this -/// class. -class GDBJITRegistrationListener : public JITEventListener { - /// A map of in-memory object files that have been registered with the - /// JIT interface. - RegisteredObjectBufferMap ObjectBufferMap; - -public: - /// Instantiates the JIT service. - GDBJITRegistrationListener() : ObjectBufferMap() {} - - /// Unregisters each object that was previously registered and releases all - /// internal resources. - virtual ~GDBJITRegistrationListener(); - - /// Creates an entry in the JIT registry for the buffer @p Object, - /// which must contain an object file in executable memory with any - /// debug information for the debugger. - void NotifyObjectEmitted(const ObjectFile &Object, - const RuntimeDyld::LoadedObjectInfo &L) override; - - /// Removes the internal registration of @p Object, and - /// frees associated resources. - /// Returns true if @p Object was found in ObjectBufferMap. - void NotifyFreeingObject(const ObjectFile &Object) override; - -private: - /// Deregister the debug info for the given object file from the debugger - /// and delete any temporary copies. This private method does not remove - /// the function from Map so that it can be called while iterating over Map. - void deregisterObjectInternal(RegisteredObjectBufferMap::iterator I); -}; - -/// Lock used to serialize all jit registration events, since they -/// modify global variables. -ManagedStatic JITDebugLock; - -/// Do the registration. -void NotifyDebugger(jit_code_entry* JITCodeEntry) { - __jit_debug_descriptor.action_flag = JIT_REGISTER_FN; - - // Insert this entry at the head of the list. - JITCodeEntry->prev_entry = nullptr; - jit_code_entry* NextEntry = __jit_debug_descriptor.first_entry; - JITCodeEntry->next_entry = NextEntry; - if (NextEntry) { - NextEntry->prev_entry = JITCodeEntry; - } - __jit_debug_descriptor.first_entry = JITCodeEntry; - __jit_debug_descriptor.relevant_entry = JITCodeEntry; - __jit_debug_register_code(); -} - -GDBJITRegistrationListener::~GDBJITRegistrationListener() { - // Free all registered object files. - llvm::MutexGuard locked(*JITDebugLock); - for (RegisteredObjectBufferMap::iterator I = ObjectBufferMap.begin(), - E = ObjectBufferMap.end(); - I != E; ++I) { - // Call the private method that doesn't update the map so our iterator - // doesn't break. - deregisterObjectInternal(I); - } - ObjectBufferMap.clear(); -} - -void GDBJITRegistrationListener::NotifyObjectEmitted( - const ObjectFile &Object, - const RuntimeDyld::LoadedObjectInfo &L) { - - OwningBinary DebugObj = L.getObjectForDebug(Object); - - // Bail out if debug objects aren't supported. - if (!DebugObj.getBinary()) - return; - - const char *Buffer = DebugObj.getBinary()->getMemoryBufferRef().getBufferStart(); - size_t Size = DebugObj.getBinary()->getMemoryBufferRef().getBufferSize(); - - const char *Key = Object.getMemoryBufferRef().getBufferStart(); - - assert(Key && "Attempt to register a null object with a debugger."); - llvm::MutexGuard locked(*JITDebugLock); - assert(ObjectBufferMap.find(Key) == ObjectBufferMap.end() && - "Second attempt to perform debug registration."); - jit_code_entry* JITCodeEntry = new jit_code_entry(); - - if (!JITCodeEntry) { - llvm::report_fatal_error( - "Allocation failed when registering a JIT entry!\n"); - } else { - JITCodeEntry->symfile_addr = Buffer; - JITCodeEntry->symfile_size = Size; - - ObjectBufferMap[Key] = RegisteredObjectInfo(Size, JITCodeEntry, - std::move(DebugObj)); - NotifyDebugger(JITCodeEntry); - } -} - -void GDBJITRegistrationListener::NotifyFreeingObject(const ObjectFile& Object) { - const char *Key = Object.getMemoryBufferRef().getBufferStart(); - llvm::MutexGuard locked(*JITDebugLock); - RegisteredObjectBufferMap::iterator I = ObjectBufferMap.find(Key); - - if (I != ObjectBufferMap.end()) { - deregisterObjectInternal(I); - ObjectBufferMap.erase(I); - } -} - -void GDBJITRegistrationListener::deregisterObjectInternal( - RegisteredObjectBufferMap::iterator I) { - - jit_code_entry*& JITCodeEntry = I->second.Entry; - - // Do the unregistration. - { - __jit_debug_descriptor.action_flag = JIT_UNREGISTER_FN; - - // Remove the jit_code_entry from the linked list. - jit_code_entry* PrevEntry = JITCodeEntry->prev_entry; - jit_code_entry* NextEntry = JITCodeEntry->next_entry; - - if (NextEntry) { - NextEntry->prev_entry = PrevEntry; - } - if (PrevEntry) { - PrevEntry->next_entry = NextEntry; - } - else { - assert(__jit_debug_descriptor.first_entry == JITCodeEntry); - __jit_debug_descriptor.first_entry = NextEntry; - } - - // Tell the debugger which entry we removed, and unregister the code. - __jit_debug_descriptor.relevant_entry = JITCodeEntry; - __jit_debug_register_code(); - } - - delete JITCodeEntry; - JITCodeEntry = nullptr; -} - -llvm::ManagedStatic GDBRegListener; - -} // end namespace - -namespace llvm { - -JITEventListener* JITEventListener::createGDBRegistrationListener() { - return &*GDBRegListener; -} - -} // namespace llvm