diff options
Diffstat (limited to 'tools/lldb-mi/MICmnLLDBDebugger.cpp')
-rw-r--r-- | tools/lldb-mi/MICmnLLDBDebugger.cpp | 707 |
1 files changed, 707 insertions, 0 deletions
diff --git a/tools/lldb-mi/MICmnLLDBDebugger.cpp b/tools/lldb-mi/MICmnLLDBDebugger.cpp new file mode 100644 index 000000000000..f68f5083054b --- /dev/null +++ b/tools/lldb-mi/MICmnLLDBDebugger.cpp @@ -0,0 +1,707 @@ +//===-- MICmnLLDBDebugger.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +//++ +// File: MICmnLLDBDebugger.cpp +// +// Overview: CMICmnLLDBDebugger implementation. +// +// Environment: Compilers: Visual C++ 12. +// gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 +// Libraries: See MIReadmetxt. +// +// Copyright: None. +//-- + +// Third party headers: +#include <lldb/API/SBTarget.h> +#include <lldb/API/SBThread.h> +#include <lldb/API/SBProcess.h> +#include <lldb/API/SBCommandInterpreter.h> + +// In-house headers: +#include "MICmnLLDBDebugger.h" +#include "MICmnResources.h" +#include "MICmnLog.h" +#include "MIDriverBase.h" +#include "MICmnThreadMgrStd.h" +#include "MICmnLLDBDebuggerHandleEvents.h" +#include "MICmnLLDBDebugSessionInfo.h" +#include "MIUtilSingletonHelper.h" + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmnLLDBDebugger constructor. +// Type: Method. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmnLLDBDebugger::CMICmnLLDBDebugger( void ) +: m_constStrThisThreadId( "MI debugger event" ) +{ +} + +//++ ------------------------------------------------------------------------------------ +// Details: CMICmnLLDBDebugger destructor. +// Type: Overridable. +// Args: None. +// Return: None. +// Throws: None. +//-- +CMICmnLLDBDebugger::~CMICmnLLDBDebugger( void ) +{ + Shutdown(); +} + +//++ ------------------------------------------------------------------------------------ +// Details: Initialize resources for *this debugger object. +// Type: Method. +// Args: None. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::Initialize( void ) +{ + m_clientUsageRefCnt++; + + if( m_bInitialized ) + return MIstatus::success; + + bool bOk = MIstatus::success; + CMIUtilString errMsg; + ClrErrorDescription(); + + if( m_pClientDriver == nullptr ) + { + bOk = false; + errMsg = MIRSRC( IDS_LLDBDEBUGGER_ERR_CLIENTDRIVER ); + } + + // Note initialization order is important here as some resources depend on previous + MI::ModuleInit< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg ); + MI::ModuleInit< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg ); + MI::ModuleInit< CMICmnThreadMgrStd > ( IDS_MI_INIT_ERR_THREADMGR , bOk, errMsg ); + MI::ModuleInit< CMICmnLLDBDebuggerHandleEvents >( IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg ); + MI::ModuleInit< CMICmnLLDBDebugSessionInfo > ( IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg ); + + // Note order is important here! + if( bOk ) + lldb::SBDebugger::Initialize(); + if( bOk && !InitSBDebugger() ) + { + bOk = false; + if( !errMsg.empty() ) errMsg += ", "; + errMsg += GetErrorDescription().c_str(); + } + if( bOk && !InitSBListener() ) + { + bOk = false; + if( !errMsg.empty() ) errMsg += ", "; + errMsg += GetErrorDescription().c_str(); + } + bOk = bOk && InitStdStreams(); + + m_bInitialized = bOk; + + if( !bOk && !HaveErrorDescription() ) + { + CMIUtilString strInitError( CMIUtilString::Format( MIRSRC( IDS_MI_INIT_ERR_LLDBDEBUGGER ), errMsg.c_str() ) ); + SetErrorDescription( strInitError ); + } + + return bOk; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Release resources for *this debugger object. +// Type: Method. +// Args: None. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::Shutdown( void ) +{ + if( --m_clientUsageRefCnt > 0 ) + return MIstatus::success; + + if( !m_bInitialized ) + return MIstatus::success; + + m_bInitialized = false; + + ClrErrorDescription(); + + bool bOk = MIstatus::success; + CMIUtilString errMsg; + + // Explicitly delete the remote target in case MI needs to exit prematurely otherwise + // LLDB debugger may hang in its Destroy() fn waiting on events + m_lldbDebugger.DeleteTarget( CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget ); + + // Debug: May need this but does seem to work without it so commented out the fudge 19/06/2014 + // It appears we need to wait as hang does not occur when hitting a debug breakpoint here + //const std::chrono::milliseconds time( 1000 ); + //std::this_thread::sleep_for( time ); + + lldb::SBDebugger::Destroy( m_lldbDebugger ); + lldb::SBDebugger::Terminate(); + m_pClientDriver = nullptr; + m_mapBroadcastClassNameToEventMask.clear(); + m_mapIdToEventMask.clear(); + + // Note shutdown order is important here + MI::ModuleShutdown< CMICmnLLDBDebugSessionInfo > ( IDS_MI_INIT_ERR_DEBUGSESSIONINFO, bOk, errMsg ); + MI::ModuleShutdown< CMICmnLLDBDebuggerHandleEvents >( IDS_MI_INIT_ERR_OUTOFBANDHANDLER, bOk, errMsg ); + MI::ModuleShutdown< CMICmnThreadMgrStd > ( IDS_MI_INIT_ERR_THREADMGR , bOk, errMsg ); + MI::ModuleShutdown< CMICmnResources > ( IDS_MI_INIT_ERR_RESOURCES , bOk, errMsg ); + MI::ModuleShutdown< CMICmnLog > ( IDS_MI_INIT_ERR_LOG , bOk, errMsg ); + + if( !bOk ) + { + SetErrorDescriptionn( MIRSRC( IDS_MI_SHTDWN_ERR_LLDBDEBUGGER ), errMsg.c_str() ); + } + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Return the LLDB debugger instance created for this debug session. +// Type: Method. +// Args: None. +// Return: lldb::SBDebugger & - LLDB debugger object reference. +// Throws: None. +//-- +lldb::SBDebugger & CMICmnLLDBDebugger::GetTheDebugger( void ) +{ + return m_lldbDebugger; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Return the LLDB listener instance created for this debug session. +// Type: Method. +// Args: None. +// Return: lldb::SBListener & - LLDB listener object reference. +// Throws: None. +//-- +lldb::SBListener & CMICmnLLDBDebugger::GetTheListener( void ) +{ + return m_lldbListener; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Set the client driver that wants to use *this LLDB debugger. Call this function +// prior to Initialize(). +// Type: Method. +// Args: vClientDriver - (R) A driver. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::SetDriver( const CMIDriverBase & vClientDriver ) +{ + m_pClientDriver = const_cast< CMIDriverBase * >( &vClientDriver ); + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Get the client driver that is use *this LLDB debugger. +// Type: Method. +// Args: vClientDriver - (R) A driver. +// Return: CMIDriverBase & - A driver instance. +// Throws: None. +//-- +CMIDriverBase & CMICmnLLDBDebugger::GetDriver( void ) const +{ + return *m_pClientDriver; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Initialize the LLDB Debugger object. +// Type: Method. +// Args: None. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::InitSBDebugger( void ) +{ + m_lldbDebugger = lldb::SBDebugger::Create( false ); + if( m_lldbDebugger.IsValid() ) + return MIstatus::success; + + SetErrorDescription( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDDEBUGGER ) ); + return MIstatus::failure; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Set the LLDB Debugger's std in, err and out streams. (Not implemented left +// here for reference. Was called in the CMICmnLLDBDebugger::Initialize() ) +// Type: Method. +// Args: None. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::InitStdStreams( void ) +{ + // This is not required when operating the MI driver's code as it has its own + // streams. Setting the Stdin for the lldbDebugger especially on LINUX will cause + // another thread to run and partially consume stdin data meant for MI stdin handler + //m_lldbDebugger.SetErrorFileHandle( m_pClientDriver->GetStderr(), false ); + //m_lldbDebugger.SetOutputFileHandle( m_pClientDriver->GetStdout(), false ); + //m_lldbDebugger.SetInputFileHandle( m_pClientDriver->GetStdin(), false ); + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Set up the events from the SBDebugger's we would to listent to. +// Type: Method. +// Args: None. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::InitSBListener( void ) +{ + m_lldbListener = m_lldbDebugger.GetListener(); + if( !m_lldbListener.IsValid() ) + { + SetErrorDescription( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDLISTENER ) ); + return MIstatus::failure; + } + + const CMIUtilString strDbgId( "CMICmnLLDBDebugger1" ); + MIuint eventMask = lldb::SBTarget::eBroadcastBitBreakpointChanged; + bool bOk = RegisterForEvent( strDbgId, CMIUtilString( lldb::SBTarget::GetBroadcasterClassName() ), eventMask ); + + eventMask = lldb::SBThread::eBroadcastBitStackChanged; + bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBThread::GetBroadcasterClassName() ), eventMask ); + + eventMask = lldb::SBProcess::eBroadcastBitStateChanged | + lldb::SBProcess::eBroadcastBitInterrupt | + lldb::SBProcess::eBroadcastBitSTDOUT | + lldb::SBProcess::eBroadcastBitSTDERR | + lldb::SBProcess::eBroadcastBitProfileData; + bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBProcess::GetBroadcasterClassName() ), eventMask ); + + eventMask = lldb::SBCommandInterpreter::eBroadcastBitQuitCommandReceived | + lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit | + lldb::SBCommandInterpreter::eBroadcastBitAsynchronousOutputData | + lldb::SBCommandInterpreter::eBroadcastBitAsynchronousErrorData; + bOk = bOk && RegisterForEvent( strDbgId, CMIUtilString( lldb::SBCommandInterpreter::GetBroadcasterClass() ), eventMask ); + + return bOk; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Register with the debugger, the SBListener, the type of events you are interested +// in. Others, like commands, may have already set the mask. +// Type: Method. +// Args: vClientName - (R) ID of the client who wants these events set. +// vBroadcasterClass - (R) The SBBroadcaster's class name. +// vEventMask - (R) The mask of events to listen for. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::RegisterForEvent( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask ) +{ + MIuint existingMask = 0; + if( !BroadcasterGetMask( vBroadcasterClass, existingMask ) ) + return MIstatus::failure; + + if( !ClientSaveMask( vClientName, vBroadcasterClass, vEventMask ) ) + return MIstatus::failure; + + const MIchar * pBroadCasterName = vBroadcasterClass.c_str(); + MIuint eventMask = vEventMask; + eventMask += existingMask; + const MIuint result = m_lldbListener.StartListeningForEventClass( m_lldbDebugger, pBroadCasterName, eventMask ); + if( result == 0 ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STARTLISTENER ), pBroadCasterName ) ); + return MIstatus::failure; + } + + return BroadcasterSaveMask( vBroadcasterClass, eventMask ); +} + +//++ ------------------------------------------------------------------------------------ +// Details: Register with the debugger, the SBListener, the type of events you are interested +// in. Others, like commands, may have already set the mask. +// Type: Method. +// Args: vClientName - (R) ID of the client who wants these events set. +// vBroadcaster - (R) An SBBroadcaster's derived class. +// vEventMask - (R) The mask of events to listen for. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::RegisterForEvent( const CMIUtilString & vClientName, const lldb::SBBroadcaster & vBroadcaster, const MIuint vEventMask ) +{ + const MIchar * pBroadcasterName = vBroadcaster.GetName(); + if( pBroadcasterName == nullptr ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME ), MIRSRC( IDS_WORD_INVALIDNULLPTR ) ) ); + return MIstatus::failure; + } + CMIUtilString broadcasterName( pBroadcasterName ); + if( broadcasterName.length() == 0 ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_BROARDCASTER_NAME ), MIRSRC( IDS_WORD_INVALIDEMPTY ) ) ); + return MIstatus::failure; + } + + MIuint existingMask = 0; + if( !BroadcasterGetMask( broadcasterName, existingMask ) ) + return MIstatus::failure; + + if( !ClientSaveMask( vClientName, broadcasterName, vEventMask ) ) + return MIstatus::failure; + + MIuint eventMask = vEventMask; + eventMask += existingMask; + const MIuint result = m_lldbListener.StartListeningForEvents( vBroadcaster, eventMask ); + if( result == 0 ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STARTLISTENER ), pBroadcasterName ) ); + return MIstatus::failure; + } + + return BroadcasterSaveMask( broadcasterName, eventMask ); +} + +//++ ------------------------------------------------------------------------------------ +// Details: Unregister with the debugger, the SBListener, the type of events you are no +// longer interested in. Others, like commands, may still remain interested so +// an event may not necessarily be stopped. +// Type: Method. +// Args: vClientName - (R) ID of the client who no longer requires these events. +// vBroadcasterClass - (R) The SBBroadcaster's class name. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::UnregisterForEvent( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass ) +{ + MIuint clientsEventMask = 0; + if( !ClientGetTheirMask( vClientName, vBroadcasterClass, clientsEventMask ) ) + return MIstatus::failure; + if( !ClientRemoveTheirMask( vClientName, vBroadcasterClass ) ) + return MIstatus::failure; + + const MIuint otherClientsEventMask = ClientGetMaskForAllClients( vBroadcasterClass ); + MIuint newEventMask = 0; + for( MIuint i = 0; i < 32; i++ ) + { + const MIuint bit = 1 << i; + const MIuint clientBit = bit & clientsEventMask; + const MIuint othersBit = bit & otherClientsEventMask; + if( (clientBit != 0) && (othersBit == 0) ) + { + newEventMask += clientBit; + } + } + + const MIchar * pBroadCasterName = vBroadcasterClass.c_str(); + if( !m_lldbListener.StopListeningForEventClass( m_lldbDebugger, pBroadCasterName, newEventMask ) ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STOPLISTENER ), vClientName.c_str(), pBroadCasterName ) ); + return MIstatus::failure; + } + + return BroadcasterSaveMask( vBroadcasterClass, otherClientsEventMask ); +} + +//++ ------------------------------------------------------------------------------------ +// Details: Given the SBBroadcaster class name retrieve it's current event mask. +// Type: Method. +// Args: vBroadcasterClass - (R) The SBBroadcaster's class name. +// vEventMask - (W) The mask of events to listen for. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::BroadcasterGetMask( const CMIUtilString & vBroadcasterClass, MIuint & vwEventMask ) const +{ + vwEventMask = 0; + + if( vBroadcasterClass.empty() ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ), vBroadcasterClass.c_str() ) ); + return MIstatus::failure; + } + + const MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find( vBroadcasterClass ); + if( it != m_mapBroadcastClassNameToEventMask.end() ) + { + vwEventMask = (*it).second; + } + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Remove the event mask for the specified SBBroadcaster class name. +// Type: Method. +// Args: vBroadcasterClass - (R) The SBBroadcaster's class name. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::BroadcasterRemoveMask( const CMIUtilString & vBroadcasterClass ) +{ + MapBroadcastClassNameToEventMask_t::const_iterator it = m_mapBroadcastClassNameToEventMask.find( vBroadcasterClass ); + if( it != m_mapBroadcastClassNameToEventMask.end() ) + { + m_mapBroadcastClassNameToEventMask.erase( it ); + } + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Given the SBBroadcaster class name save it's current event mask. +// Type: Method. +// Args: vBroadcasterClass - (R) The SBBroadcaster's class name. +// vEventMask - (R) The mask of events to listen for. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::BroadcasterSaveMask( const CMIUtilString & vBroadcasterClass, const MIuint vEventMask ) +{ + if( vBroadcasterClass.empty() ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDBROADCASTER ), vBroadcasterClass.c_str() ) ); + return MIstatus::failure; + } + + BroadcasterRemoveMask( vBroadcasterClass ); + MapPairBroadcastClassNameToEventMask_t pr( vBroadcasterClass, vEventMask ); + m_mapBroadcastClassNameToEventMask.insert( pr ); + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Iterate all the clients who have registered event masks against particular +// SBBroadcasters and build up the mask that is for all of them. +// Type: Method. +// Args: vBroadcasterClass - (R) The broadcaster to retrieve the mask for. +// Return: MIuint - Event mask. +// Throws: None. +//-- +MIuint CMICmnLLDBDebugger::ClientGetMaskForAllClients( const CMIUtilString & vBroadcasterClass ) const +{ + MIuint mask = 0; + MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.begin(); + while( it != m_mapIdToEventMask.end() ) + { + const CMIUtilString & rId( (*it).first ); + if( rId.find( vBroadcasterClass.c_str() ) != std::string::npos ) + { + const MIuint clientsMask = (*it).second; + mask |= clientsMask; + } + + // Next + ++it; + } + + return mask; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Given the client save its particular event requirements. +// Type: Method. +// Args: vClientName - (R) The Client's unique ID. +// vBroadcasterClass - (R) The SBBroadcaster's class name targeted for the events. +// vEventMask - (R) The mask of events to listen for. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::ClientSaveMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, const MIuint vEventMask ) +{ + if( vClientName.empty() ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) ); + return MIstatus::failure; + } + + CMIUtilString strId( vBroadcasterClass ); + strId += vClientName; + + ClientRemoveTheirMask( vClientName, vBroadcasterClass ); + MapPairIdToEventMask_t pr( strId, vEventMask ); + m_mapIdToEventMask.insert( pr ); + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Given the client remove it's particular event requirements. +// Type: Method. +// Args: vClientName - (R) The Client's unique ID. +// vBroadcasterClass - (R) The SBBroadcaster's class name. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::ClientRemoveTheirMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass ) +{ + if( vClientName.empty() ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) ); + return MIstatus::failure; + } + + CMIUtilString strId( vBroadcasterClass ); + strId += vClientName; + + const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find( strId ); + if( it != m_mapIdToEventMask.end() ) + { + m_mapIdToEventMask.erase( it ); + } + + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Retrieve the client's event mask used for on a particular SBBroadcaster. +// Type: Method. +// Args: vClientName - (R) The Client's unique ID. +// vBroadcasterClass - (R) The SBBroadcaster's class name. +// vwEventMask - (W) The client's mask. +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::ClientGetTheirMask( const CMIUtilString & vClientName, const CMIUtilString & vBroadcasterClass, MIuint & vwEventMask ) +{ + vwEventMask = 0; + + if( vClientName.empty() ) + { + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_INVALIDCLIENTNAME ), vClientName.c_str() ) ); + return MIstatus::failure; + } + + CMIUtilString strId( vBroadcasterClass.c_str() ); + strId += vClientName; + + const MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.find( strId ); + if( it != m_mapIdToEventMask.end() ) + { + vwEventMask = (*it).second; + } + + SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_CLIENTNOTREGISTERD ), vClientName.c_str() ) ); + + return MIstatus::failure; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Momentarily wait for an events being broadcast and inspect those that do +// come this way. Check if the target should exit event if so start shutting +// down this thread and the application. Any other events pass on to the +// Out-of-band handler to futher determine what kind of event arrived. +// This function runs in the thread "MI debugger event". +// Type: Method. +// Args: vrbIsAlive - (W) False = yes exit event monitoring thread, true = continue. +// Return: MIstatus::success - Functional succeeded. +// MIstatus::failure - Functional failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::MonitorSBListenerEvents( bool & vrbIsAlive ) +{ + vrbIsAlive = true; + + lldb::SBEvent event; + const bool bGotEvent = m_lldbListener.GetNextEvent( event ); + if ( !bGotEvent || !event.IsValid() ) + { + const std::chrono::milliseconds time( 1 ); + std::this_thread::sleep_for( time ); + return MIstatus::success; + } + if( !event.GetBroadcaster().IsValid() ) + return MIstatus::success; + + // Debugging + m_pLog->WriteLog( CMIUtilString::Format( "##### An event occurred: %s", event.GetBroadcasterClass() ) ); + + bool bHandledEvent = false; + bool bExitAppEvent = false; + const bool bOk = CMICmnLLDBDebuggerHandleEvents::Instance().HandleEvent( event, bHandledEvent, bExitAppEvent ); + if( !bHandledEvent ) + { + const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_WRN_UNKNOWN_EVENT ), event.GetBroadcasterClass() ) ); + m_pLog->WriteLog( msg ); + } + if( !bOk ) + { + m_pLog->WriteLog( CMICmnLLDBDebuggerHandleEvents::Instance().GetErrorDescription() ); + } + + if( bExitAppEvent ) + { + // Set the application to shutdown + m_pClientDriver->SetExitApplicationFlag( true ); + + // Kill *this thread + vrbIsAlive = false; + } + + return bOk; +} + +//++ ------------------------------------------------------------------------------------ +// Details: The main worker method for this thread. +// Type: Method. +// Args: vrbIsAlive = (W) True = *this thread is working, false = thread has exited. +// Return: MIstatus::success - Functional succeeded. +// MIstatus::failure - Functional failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::ThreadRun( bool & vrbIsAlive ) +{ + return MonitorSBListenerEvents( vrbIsAlive ); +} + +//++ ------------------------------------------------------------------------------------ +// Details: Let this thread clean up after itself. +// Type: Method. +// Args: +// Return: MIstatus::success - Functionality succeeded. +// MIstatus::failure - Functionality failed. +// Throws: None. +//-- +bool CMICmnLLDBDebugger::ThreadFinish( void ) +{ + return MIstatus::success; +} + +//++ ------------------------------------------------------------------------------------ +// Details: Retrieve *this thread object's name. +// Type: Overridden. +// Args: None. +// Return: CMIUtilString & - Text. +// Throws: None. +//-- +const CMIUtilString & CMICmnLLDBDebugger::ThreadGetName( void ) const +{ + return m_constStrThisThreadId; +} |