blob: 783508f79f71985d0f9bdada7697111198b7f955 [file] [log] [blame]
//===-- 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 "MICmnConfig.h"
#include "MICmnLLDBDebugger.h"
#include "MICmnResources.h"
#include "MICmnLog.h"
#include "MIDriverBase.h"
#include "MICmnThreadMgrStd.h"
#include "MICmnLLDBDebuggerHandleEvents.h"
#include "MICmnLLDBDebugSessionInfo.h"
#include "MIUtilDebug.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;
}