forked from OSchip/llvm-project
766 lines
26 KiB
C++
766 lines
26 KiB
C++
|
//===-- 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 );
|
||
|
|
||
|
// ToDo: Avaluate if we still need this
|
||
|
// 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 char * 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 char * 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 char * 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: 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.
|
||
|
// vBroadcaster - (R) An SBBroadcaster's derived class.
|
||
|
// Return: MIstatus::success - Functionality succeeded.
|
||
|
// MIstatus::failure - Functionality failed.
|
||
|
// Throws: None.
|
||
|
//--
|
||
|
bool CMICmnLLDBDebugger::UnregisterForEvent( const CMIUtilString & vClientName, const lldb::SBBroadcaster & vBroadcaster )
|
||
|
{
|
||
|
const char * 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 clientsEventMask = 0;
|
||
|
if( !ClientGetTheirMask( vClientName, broadcasterName, clientsEventMask ) )
|
||
|
return MIstatus::failure;
|
||
|
if( !ClientRemoveTheirMask( vClientName, broadcasterName ) )
|
||
|
return MIstatus::failure;
|
||
|
|
||
|
const MIuint otherClientsEventMask = ClientGetMaskForAllClients( broadcasterName );
|
||
|
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;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( !m_lldbListener.StopListeningForEvents( vBroadcaster, newEventMask ) )
|
||
|
{
|
||
|
SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBDEBUGGER_ERR_STOPLISTENER ), vClientName.c_str(), pBroadcasterName ) );
|
||
|
return MIstatus::failure;
|
||
|
}
|
||
|
|
||
|
return BroadcasterSaveMask( broadcasterName, otherClientsEventMask );
|
||
|
}
|
||
|
|
||
|
//++ ------------------------------------------------------------------------------------
|
||
|
// Details: Given the SBBroadcaster class name retrieve 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::BroadcasterGetMask( const CMIUtilString & vBroadcasterClass, MIuint & vEventMask ) const
|
||
|
{
|
||
|
vEventMask = 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() )
|
||
|
{
|
||
|
vEventMask = 0;
|
||
|
return MIstatus::success;
|
||
|
}
|
||
|
|
||
|
vEventMask = (*it).second;
|
||
|
|
||
|
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;
|
||
|
}
|
||
|
|
||
|
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.c_str() );
|
||
|
strId += vClientName;
|
||
|
|
||
|
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.c_str() );
|
||
|
strId += vClientName;
|
||
|
|
||
|
bool bFound = false;
|
||
|
MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.begin();
|
||
|
while( it != m_mapIdToEventMask.end() )
|
||
|
{
|
||
|
const CMIUtilString & rId( (*it).first );
|
||
|
if( rId == strId )
|
||
|
{
|
||
|
bFound = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Next
|
||
|
++it;
|
||
|
}
|
||
|
|
||
|
if( bFound )
|
||
|
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 - (RW) 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;
|
||
|
|
||
|
bool bFound = false;
|
||
|
MapIdToEventMask_t::const_iterator it = m_mapIdToEventMask.begin();
|
||
|
while( it != m_mapIdToEventMask.end() )
|
||
|
{
|
||
|
const CMIUtilString & rId( (*it).first );
|
||
|
if( rId == strId )
|
||
|
{
|
||
|
vwEventMask = (*it).second;
|
||
|
return MIstatus::success;
|
||
|
}
|
||
|
|
||
|
// Next
|
||
|
++it;
|
||
|
}
|
||
|
|
||
|
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();
|
||
|
|
||
|
// 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;
|
||
|
}
|