//===-- 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 #include #include #include // 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; }