//===-- MICmnLLDBDebuggerHandleEvents.cpp --------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //++ // File: MICmnLLDBDebuggerHandleEvents.cpp // // Overview: CMICmnLLDBDebuggerHandleEvents 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 #include #include #include #ifdef _WIN32 #include // For the ::_access() #else #include // For the ::access() #endif // _WIN32 #include // In-house headers: #include "MICmnLLDBDebuggerHandleEvents.h" #include "MICmnResources.h" #include "MICmnLog.h" #include "MICmnLLDBDebugSessionInfo.h" #include "MICmnMIResultRecord.h" #include "MICmnMIValueConst.h" #include "MICmnMIValueList.h" #include "MICmnMIOutOfBandRecord.h" #include "MICmnStreamStdout.h" #include "MICmnStreamStderr.h" #include "MIUtilDebug.h" #include "MIDriver.h" //++ ------------------------------------------------------------------------------------ // Details: CMICmnLLDBDebuggerHandleEvents constructor. // Type: Method. // Args: None. // Return: None. // Throws: None. //-- CMICmnLLDBDebuggerHandleEvents::CMICmnLLDBDebuggerHandleEvents( void ) { } //++ ------------------------------------------------------------------------------------ // Details: CMICmnLLDBDebuggerHandleEvents destructor. // Type: Overridable. // Args: None. // Return: None. // Throws: None. //-- CMICmnLLDBDebuggerHandleEvents::~CMICmnLLDBDebuggerHandleEvents( void ) { Shutdown(); } //++ ------------------------------------------------------------------------------------ // Details: Initialize resources for *this broardcaster object. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::Initialize( void ) { m_clientUsageRefCnt++; if( m_bInitialized ) return MIstatus::success; m_bInitialized = MIstatus::success; return m_bInitialized; } //++ ------------------------------------------------------------------------------------ // Details: Release resources for *this broardcaster object. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::Shutdown( void ) { if( --m_clientUsageRefCnt > 0 ) return MIstatus::success; if( !m_bInitialized ) return MIstatus::success; m_bInitialized = false; return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Interpret the event object to asscertain the action to take or information to // to form and put in a MI Out-of-band record object which is given to stdout. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // vrbHandledEvent - (W) True - event handled, false = not handled. // vrbExitAppEvent - (W) True - Received LLDB exit app event, false = did not. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEvent( const lldb::SBEvent & vEvent, bool & vrbHandledEvent, bool & vrbExitAppEvent ) { bool bOk = MIstatus::success; vrbHandledEvent = false; vrbExitAppEvent = false; if( lldb::SBProcess::EventIsProcessEvent( vEvent ) ) { vrbHandledEvent = true; bOk = HandleEventSBProcess( vEvent, vrbExitAppEvent ); } else if( lldb::SBBreakpoint::EventIsBreakpointEvent( vEvent ) ) { vrbHandledEvent = true; bOk = HandleEventSBBreakPoint( vEvent ); } else if( lldb::SBThread::EventIsThreadEvent( vEvent ) ) { vrbHandledEvent = true; bOk = HandleEventSBThread( vEvent ); } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBProcess event. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // vrbExitAppEvent - (W) True - Received LLDB exit app event, false = did not. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBProcess( const lldb::SBEvent & vEvent, bool & vrbExitAppEvent ) { bool bOk = MIstatus::success; const MIchar * pEventType = ""; const MIuint nEventType = vEvent.GetType(); switch( nEventType ) { case lldb::SBProcess::eBroadcastBitInterrupt: pEventType = "eBroadcastBitInterrupt"; break; case lldb::SBProcess::eBroadcastBitProfileData: pEventType = "eBroadcastBitProfileData"; break; case lldb::SBProcess::eBroadcastBitStateChanged: pEventType = "eBroadcastBitStateChanged"; bOk = HandleProcessEventBroadcastBitStateChanged( vEvent, vrbExitAppEvent ); break; case lldb::SBProcess::eBroadcastBitSTDERR: pEventType = "eBroadcastBitSTDERR"; bOk = GetProcessStderr(); break; case lldb::SBProcess::eBroadcastBitSTDOUT: pEventType = "eBroadcastBitSTDOUT"; bOk = GetProcessStdout(); break; default: { const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBProcess", (MIuint) nEventType ) ); SetErrorDescription( msg ); return MIstatus::failure; } } m_pLog->WriteLog( CMIUtilString::Format( "##### An SB Process event occurred: %s", pEventType ) ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBBreakpoint event. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakPoint( const lldb::SBEvent & vEvent ) { bool bOk = MIstatus::success; const MIchar * pEventType =""; const lldb::BreakpointEventType eEvent = lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent( vEvent ); switch( eEvent ) { case lldb::eBreakpointEventTypeThreadChanged: pEventType = "eBreakpointEventTypeThreadChanged"; break; case lldb::eBreakpointEventTypeLocationsRemoved: pEventType = "eBreakpointEventTypeLocationsRemoved"; break; case lldb::eBreakpointEventTypeInvalidType: pEventType = "eBreakpointEventTypeInvalidType"; break; case lldb::eBreakpointEventTypeLocationsAdded: pEventType = "eBreakpointEventTypeLocationsAdded"; bOk = HandleEventSBBreakpointLocationsAdded( vEvent ); break; case lldb::eBreakpointEventTypeAdded: pEventType = "eBreakpointEventTypeAdded"; bOk = HandleEventSBBreakpointAdded( vEvent ); break; case lldb::eBreakpointEventTypeRemoved: pEventType = "eBreakpointEventTypeRemoved"; bOk = HandleEventSBBreakpointCmn( vEvent ); break; case lldb::eBreakpointEventTypeLocationsResolved: pEventType = "eBreakpointEventTypeLocationsResolved"; break; case lldb::eBreakpointEventTypeEnabled: pEventType ="eBreakpointEventTypeEnabled"; bOk = HandleEventSBBreakpointCmn( vEvent ); break; case lldb::eBreakpointEventTypeDisabled: pEventType = "eBreakpointEventTypeDisabled"; bOk = HandleEventSBBreakpointCmn( vEvent ); break; case lldb::eBreakpointEventTypeCommandChanged: pEventType = "eBreakpointEventTypeCommandChanged"; bOk = HandleEventSBBreakpointCmn( vEvent ); break; case lldb::eBreakpointEventTypeConditionChanged: pEventType ="eBreakpointEventTypeConditionChanged"; bOk = HandleEventSBBreakpointCmn( vEvent ); break; case lldb::eBreakpointEventTypeIgnoreChanged: pEventType = "eBreakpointEventTypeIgnoreChanged"; bOk = HandleEventSBBreakpointCmn( vEvent ); break; default: { const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBBreakPoint", (MIuint) eEvent ) ); SetErrorDescription( msg ); return MIstatus::failure; } } m_pLog->WriteLog( CMIUtilString::Format( "##### An SB Breakpoint event occurred: %s", pEventType ) ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBBreakpoint event. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointLocationsAdded( const lldb::SBEvent & vEvent ) { const MIuint nLoc = lldb::SBBreakpoint::GetNumBreakpointLocationsFromEvent( vEvent ); if( nLoc == 0 ) return MIstatus::success; lldb::SBBreakpoint brkPt = lldb::SBBreakpoint::GetBreakpointFromEvent( vEvent ); const CMIUtilString plural( (nLoc == 1) ? "" : "s" ); const CMIUtilString msg( CMIUtilString::Format( "%d location%s added to breakpoint %d", nLoc, plural.c_str(), brkPt.GetID() ) ); return TextToStdout( msg ); } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBBreakpoint event. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointCmn( const lldb::SBEvent & vEvent ) { lldb::SBBreakpoint brkPt = lldb::SBBreakpoint::GetBreakpointFromEvent( vEvent ); if( !brkPt.IsValid() ) return MIstatus::success; CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo; if( !rSessionInfo.GetBrkPtInfo( brkPt, sBrkPtInfo ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_GET ), "HandleEventSBBreakpointCmn()", brkPt.GetID() ) ); return MIstatus::failure; } // CODETAG_LLDB_BREAKPOINT_CREATION // This is in a worker thread // Add more breakpoint information or overwrite existing information CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfoRec; if( !rSessionInfo.RecordBrkPtInfoGet( brkPt.GetID(), sBrkPtInfoRec ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_BRKPT_NOTFOUND ), "HandleEventSBBreakpointCmn()", brkPt.GetID() ) ); return MIstatus::failure; } sBrkPtInfo.m_bDisp = sBrkPtInfoRec.m_bDisp; sBrkPtInfo.m_bEnabled = brkPt.IsEnabled(); sBrkPtInfo.m_bHaveArgOptionThreadGrp = false; sBrkPtInfo.m_strOptThrdGrp = ""; sBrkPtInfo.m_nTimes = brkPt.GetHitCount(); sBrkPtInfo.m_strOrigLoc = sBrkPtInfoRec.m_strOrigLoc; sBrkPtInfo.m_nIgnore = sBrkPtInfoRec.m_nIgnore; sBrkPtInfo.m_bPending = sBrkPtInfoRec.m_bPending; sBrkPtInfo.m_bCondition = sBrkPtInfoRec.m_bCondition; sBrkPtInfo.m_strCondition = sBrkPtInfoRec.m_strCondition; sBrkPtInfo.m_bBrkPtThreadId = sBrkPtInfoRec.m_bBrkPtThreadId; sBrkPtInfo.m_nBrkPtThreadId = sBrkPtInfoRec.m_nBrkPtThreadId; // MI print "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\", func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}" CMICmnMIValueTuple miValueTuple; if( !rSessionInfo.MIResponseFormBrkPtInfo( sBrkPtInfo, miValueTuple ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE ), "HandleEventSBBreakpointCmn()" ) ); return MIstatus::failure; } const CMICmnMIValueResult miValueResultC( "bkpt", miValueTuple ); const CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointModified, miValueResultC ); const bool bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBBreakpoint added event. // Add more breakpoint information or overwrite existing information. // Normally a break point session info objects exists by now when an MI command // was issued to insert a break so the retrieval would normally always succeed // however should a user type "b main" into a console then LLDB will create a // breakpoint directly, hence no MI command, hence no previous record of the // breakpoint so RecordBrkPtInfoGet() will fail. We still get the event though // so need to create a breakpoint info object here and send appropriate MI // response. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointAdded( const lldb::SBEvent & vEvent ) { lldb::SBBreakpoint brkPt = lldb::SBBreakpoint::GetBreakpointFromEvent( vEvent ); if( !brkPt.IsValid() ) return MIstatus::success; CMICmnLLDBDebugSessionInfo & rSessionInfo( CMICmnLLDBDebugSessionInfo::Instance() ); CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfo; if( !rSessionInfo.GetBrkPtInfo( brkPt, sBrkPtInfo ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_GET ), "HandleEventSBBreakpointAdded()", brkPt.GetID() ) ); return MIstatus::failure; } // CODETAG_LLDB_BREAKPOINT_CREATION // This is in a worker thread CMICmnLLDBDebugSessionInfo::SBrkPtInfo sBrkPtInfoRec; const bool bBrkPtExistAlready = rSessionInfo.RecordBrkPtInfoGet( brkPt.GetID(), sBrkPtInfoRec ); if( bBrkPtExistAlready ) { // Update breakpoint information object sBrkPtInfo.m_bDisp = sBrkPtInfoRec.m_bDisp; sBrkPtInfo.m_bEnabled = brkPt.IsEnabled(); sBrkPtInfo.m_bHaveArgOptionThreadGrp = false; sBrkPtInfo.m_strOptThrdGrp.clear(); sBrkPtInfo.m_nTimes = brkPt.GetHitCount(); sBrkPtInfo.m_strOrigLoc = sBrkPtInfoRec.m_strOrigLoc; sBrkPtInfo.m_nIgnore = sBrkPtInfoRec.m_nIgnore; sBrkPtInfo.m_bPending = sBrkPtInfoRec.m_bPending; sBrkPtInfo.m_bCondition = sBrkPtInfoRec.m_bCondition; sBrkPtInfo.m_strCondition = sBrkPtInfoRec.m_strCondition; sBrkPtInfo.m_bBrkPtThreadId = sBrkPtInfoRec.m_bBrkPtThreadId; sBrkPtInfo.m_nBrkPtThreadId = sBrkPtInfoRec.m_nBrkPtThreadId; } else { // Create a breakpoint information object sBrkPtInfo.m_bDisp = brkPt.IsOneShot(); sBrkPtInfo.m_bEnabled = brkPt.IsEnabled(); sBrkPtInfo.m_bHaveArgOptionThreadGrp = false; sBrkPtInfo.m_strOptThrdGrp.clear(); sBrkPtInfo.m_strOrigLoc = CMIUtilString::Format( "%s:%d", sBrkPtInfo.m_fileName.c_str(), sBrkPtInfo.m_nLine ); sBrkPtInfo.m_nIgnore = brkPt.GetIgnoreCount(); sBrkPtInfo.m_bPending = false; const MIchar * pStrCondition = brkPt.GetCondition(); sBrkPtInfo.m_bCondition = (pStrCondition != nullptr) ? true : false; sBrkPtInfo.m_strCondition = (pStrCondition != nullptr) ? pStrCondition : "??"; sBrkPtInfo.m_bBrkPtThreadId = (brkPt.GetThreadID() != 0) ? true : false; sBrkPtInfo.m_nBrkPtThreadId = brkPt.GetThreadID(); } CMICmnMIValueTuple miValueTuple; if( !rSessionInfo.MIResponseFormBrkPtInfo( sBrkPtInfo, miValueTuple ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE ), "HandleEventSBBreakpointAdded()" ) ); return MIstatus::failure; } bool bOk = MIstatus::success; if( bBrkPtExistAlready ) { // MI print "=breakpoint-modified,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\",func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}" const CMICmnMIValueResult miValueResult( "bkpt", miValueTuple ); const CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointModified, miValueResult ); bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord ); } else { // CODETAG_LLDB_BRKPT_ID_MAX if( brkPt.GetID() > (lldb::break_id_t) rSessionInfo.m_nBrkPointCntMax ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_CMD_ERR_BRKPT_CNT_EXCEEDED ), "HandleEventSBBreakpointAdded()", rSessionInfo.m_nBrkPointCntMax, sBrkPtInfo.m_id ) ); return MIstatus::failure; } if( !rSessionInfo.RecordBrkPtInfo( brkPt.GetID(), sBrkPtInfo ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_BRKPT_INFO_SET ), "HandleEventSBBreakpointAdded()", sBrkPtInfo.m_id ) ); return MIstatus::failure; } // MI print "=breakpoint-created,bkpt={number=\"%d\",type=\"breakpoint\",disp=\"%s\",enabled=\"%c\",addr=\"0x%08x\",func=\"%s\",file=\"%s\",fullname=\"%s/%s\",line=\"%d\",times=\"%d\",original-location=\"%s\"}" const CMICmnMIValueResult miValueResult( "bkpt", miValueTuple ); const CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_BreakPointCreated, miValueResult ); bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord ); } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBThread event. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBThread( const lldb::SBEvent & vEvent ) { if( !ChkForStateChanges() ) return MIstatus::failure; bool bOk = MIstatus::success; const MIchar * pEventType = ""; const MIuint nEventType = vEvent.GetType(); switch( nEventType ) { case lldb::SBThread::eBroadcastBitStackChanged: pEventType = "eBroadcastBitStackChanged"; bOk = HandleEventSBThreadBitStackChanged( vEvent ); break; case lldb::SBThread::eBroadcastBitThreadSuspended: pEventType = "eBroadcastBitThreadSuspended"; bOk = HandleEventSBThreadSuspended( vEvent ); break; case lldb::SBThread::eBroadcastBitThreadResumed: pEventType = "eBroadcastBitThreadResumed"; break; case lldb::SBThread::eBroadcastBitSelectedFrameChanged: pEventType = "eBroadcastBitSelectedFrameChanged"; break; case lldb::SBThread::eBroadcastBitThreadSelected: pEventType = "eBroadcastBitThreadSelected"; break; default: { const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBThread", (MIuint) nEventType ) ); SetErrorDescription( msg ); return MIstatus::failure; } } m_pLog->WriteLog( CMIUtilString::Format( "##### An SBThread event occurred: %s", pEventType ) ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBThread event. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBThreadSuspended( const lldb::SBEvent & vEvent ) { lldb::SBThread thread = lldb::SBThread::GetThreadFromEvent( vEvent ); if( !thread.IsValid() ) return MIstatus::success; const lldb::StopReason eStopReason = thread.GetStopReason(); if( eStopReason != lldb::eStopReasonSignal ) return MIstatus::success; // MI print "@thread=%d,signal=%lld" const MIuint64 nId = thread.GetStopReasonDataAtIndex( 0 ); const CMIUtilString strThread( CMIUtilString::Format( "%d", thread.GetThreadID() ) ); const CMICmnMIValueConst miValueConst( strThread ); const CMICmnMIValueResult miValueResult( "thread", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Thread, miValueResult ); const CMIUtilString strSignal( CMIUtilString::Format( "%lld", nId ) ); const CMICmnMIValueConst miValueConst2( strSignal ); const CMICmnMIValueResult miValueResult2( "signal", miValueConst2 ); bool bOk = miOutOfBandRecord.Add( miValueResult2 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBThread event. // Type: Method. // Args: vEvent - (R) An LLDB broadcast event. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBThreadBitStackChanged( const lldb::SBEvent & vEvent ) { lldb::SBThread thread = lldb::SBThread::GetThreadFromEvent( vEvent ); if( !thread.IsValid() ) return MIstatus::success; lldb::SBStream streamOut; const bool bOk = thread.GetStatus( streamOut ); return bOk && TextToStdout( streamOut.GetData() ); } //++ ------------------------------------------------------------------------------------ // Details: Handle a LLDB SBCommandInterpreter event. // Type: Method. // Args: vEvent - (R) An LLDB command interpreter event. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBCommandInterpreter( const lldb::SBEvent & vEvent ) { // This function is not used // *** This function is under development const MIchar * pEventType = ""; const MIuint nEventType = vEvent.GetType(); switch( nEventType ) { case lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit: pEventType ="eBroadcastBitThreadShouldExit"; // ToDo: IOR: Reminder to maybe handle this here //const MIuint nEventType = event.GetType(); //if( nEventType & lldb::SBCommandInterpreter::eBroadcastBitThreadShouldExit ) //{ // m_pClientDriver->SetExitApplicationFlag(); // vrbYesExit = true; // return MIstatus::success; //} break; case lldb::SBCommandInterpreter::eBroadcastBitResetPrompt: pEventType = "eBroadcastBitResetPrompt"; break; case lldb::SBCommandInterpreter::eBroadcastBitQuitCommandReceived: pEventType = "eBroadcastBitQuitCommandReceived"; break; case lldb::SBCommandInterpreter::eBroadcastBitAsynchronousOutputData: pEventType = "eBroadcastBitAsynchronousOutputData"; break; case lldb::SBCommandInterpreter::eBroadcastBitAsynchronousErrorData: pEventType = "eBroadcastBitAsynchronousErrorData"; break; default: { const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBCommandInterpreter", (MIuint) nEventType ) ); SetErrorDescription( msg ); return MIstatus::failure; } } m_pLog->WriteLog( CMIUtilString::Format( "##### An SBCommandInterpreter event occurred: %s", pEventType ) ); return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Handle SBProcess event eBroadcastBitStateChanged. // Type: Method. // Args: vEvent - (R) An LLDB event object. // vrbExitAppEvent - (W) True - Received LLDB exit app event, false = did not. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged( const lldb::SBEvent & vEvent, bool & vrbExitAppEvent ) { bool bOk = ChkForStateChanges(); bOk = bOk && GetProcessStdout(); bOk = bOk && GetProcessStderr(); if( !bOk ) return MIstatus::failure; // Something changed in the process; get the event and report the process's current // status and location const lldb::StateType eEventState = lldb::SBProcess::GetStateFromEvent( vEvent ); if( eEventState == lldb::eStateInvalid ) return MIstatus::success; lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent( vEvent ); if( !process.IsValid() ) { const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_PROCESS_INVALID ), "SBProcess", "HandleProcessEventBroadcastBitStateChanged()" ) ); SetErrorDescription( msg ); return MIstatus::failure; } bool bShouldBrk = true; const MIchar * pEventType = ""; switch( eEventState ) { case lldb::eStateUnloaded: pEventType = "eStateUnloaded"; break; case lldb::eStateConnected: pEventType = "eStateConnected"; break; case lldb::eStateAttaching: pEventType = "eStateAttaching"; break; case lldb::eStateLaunching: pEventType ="eStateLaunching"; break; case lldb::eStateStopped: pEventType = "eStateStopped"; bOk = HandleProcessEventStateStopped( bShouldBrk ); if( bShouldBrk ) break; case lldb::eStateCrashed: case lldb::eStateSuspended: pEventType = "eStateSuspended"; bOk = HandleProcessEventStateSuspended( vEvent ); break; case lldb::eStateRunning: pEventType = "eStateRunning"; bOk = HandleProcessEventStateRunning(); break; case lldb::eStateStepping: pEventType = "eStateStepping"; break; case lldb::eStateDetached: pEventType = "eStateDetached"; break; case lldb::eStateExited: pEventType = "eStateExited"; vrbExitAppEvent = true; bOk = HandleProcessEventStateExited(); break; default: { const CMIUtilString msg( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT ), "SBProcess BroadcastBitStateChanged", (MIuint) eEventState ) ); SetErrorDescription( msg ); return MIstatus::failure; } } // ToDo: Remove when finished coding application m_pLog->WriteLog( CMIUtilString::Format( "##### An SB Process event BroadcastBitStateChanged occurred: %s", pEventType ) ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Asynchronous event handler for LLDB Process state suspended. // Type: Method. // Args: vEvent - (R) An LLDB event object. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateSuspended( const lldb::SBEvent & vEvent ) { // Make sure the program hasn't been auto-restarted: if( lldb::SBProcess::GetRestartedFromEvent( vEvent ) ) return MIstatus::success; bool bOk = MIstatus::success; lldb::SBDebugger & rDebugger = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger; lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; lldb::SBTarget target = rProcess.GetTarget(); if( rDebugger.GetSelectedTarget() == target ) { if( !UpdateSelectedThread() ) return MIstatus::failure; lldb::SBCommandReturnObject result; const lldb::ReturnStatus status = rDebugger.GetCommandInterpreter().HandleCommand( "process status", result, false ); MIunused( status ); bOk = TextToStderr( result.GetError() ); bOk = bOk && TextToStdout( result.GetOutput() ); } else { lldb::SBStream streamOut; const MIuint nTargetIndex = rDebugger.GetIndexOfTarget( target ); if( nTargetIndex != UINT_MAX ) streamOut.Printf( "Target %d: (", nTargetIndex ); else streamOut.Printf( "Target : (" ); target.GetDescription( streamOut, lldb::eDescriptionLevelBrief ); streamOut.Printf( ") stopped.\n" ); bOk = TextToStdout( streamOut.GetData() ); } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Print to stdout MI formatted text to indicate process stopped. // Type: Method. // Args: vwrbShouldBrk - (W) True = Yes break, false = do not. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateStopped( bool & vwrbShouldBrk ) { if( !UpdateSelectedThread() ) return MIstatus::failure; const MIchar * pEventType = ""; bool bOk = MIstatus::success; lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; const lldb::StopReason eStoppedReason = rProcess.GetSelectedThread().GetStopReason(); switch( eStoppedReason ) { case lldb::eStopReasonInvalid: pEventType = "eStopReasonInvalid"; vwrbShouldBrk = false; break; case lldb::eStopReasonNone: pEventType = "eStopReasonNone"; break; case lldb::eStopReasonTrace: pEventType = "eStopReasonTrace"; bOk = HandleProcessEventStopReasonTrace(); break; case lldb::eStopReasonBreakpoint: pEventType = "eStopReasonBreakpoint"; bOk = HandleProcessEventStopReasonBreakpoint(); break; case lldb::eStopReasonWatchpoint: pEventType = "eStopReasonWatchpoint"; break; case lldb::eStopReasonSignal: pEventType = "eStopReasonSignal"; bOk = HandleProcessEventStopSignal( vwrbShouldBrk ); break; case lldb::eStopReasonException: pEventType ="eStopReasonException"; break; case lldb::eStopReasonExec: pEventType = "eStopReasonExec"; break; case lldb::eStopReasonPlanComplete: pEventType = "eStopReasonPlanComplete"; bOk = HandleProcessEventStopReasonTrace(); break; case lldb::eStopReasonThreadExiting: pEventType = "eStopReasonThreadExiting"; break; default: { vwrbShouldBrk = false; // MI print "*stopped,reason=\"%d\",stopped-threads=\"all\",from-thread=\"%u\"" const CMIUtilString strReason( CMIUtilString::Format( "%d", eStoppedReason ) ); const CMICmnMIValueConst miValueConst( strReason ); const CMICmnMIValueResult miValueResult( "reason", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult ); const CMICmnMIValueConst miValueConst2( "all" ); const CMICmnMIValueResult miValueResult2( "stopped-threads", miValueConst2 ); bOk = miOutOfBandRecord.Add( miValueResult2 ); const CMIUtilString strFromThread( CMIUtilString::Format( "%u", rProcess.GetSelectedThread().GetIndexID() ) ); const CMICmnMIValueConst miValueConst3( strFromThread ); const CMICmnMIValueResult miValueResult3( "from-thread", miValueConst3 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult3 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord ); bOk = bOk && TextToStdout( "(gdb)" ); } } // ToDo: Remove when finished coding application m_pLog->WriteLog( CMIUtilString::Format( "##### An SB Process event stop state occurred: %s", pEventType ) ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Asynchronous event handler for LLDB Process stop signal. // Type: Method. // Args: vwrbShouldBrk - (W) True = Yes break, false = do not. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopSignal( bool & vwrbShouldBrk ) { bool bOk = MIstatus::success; lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; const MIuint64 nStopReason = rProcess.GetSelectedThread().GetStopReasonDataAtIndex( 0 ); switch( nStopReason ) { case 2: // Terminal interrupt signal. SIGINT { // MI print "*stopped,reason=\"signal-received\",signal-name=\"SIGNINT\",signal-meaning=\"Interrupt\",frame={%s}" const CMICmnMIValueConst miValueConst( "signal-received" ); const CMICmnMIValueResult miValueResult( "reason", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult ); const CMICmnMIValueConst miValueConst2( "SIGINT" ); const CMICmnMIValueResult miValueResult2( "signal-name", miValueConst2 ); bOk = miOutOfBandRecord.Add( miValueResult2 ); const CMICmnMIValueConst miValueConst3( "Interrupt" ); const CMICmnMIValueResult miValueResult3( "signal-meaning", miValueConst3 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult3 ); CMICmnMIValueTuple miValueTuple; bOk = bOk && MiHelpGetCurrentThreadFrame( miValueTuple ); const CMICmnMIValueResult miValueResult5( "frame", miValueTuple ); bOk = bOk && miOutOfBandRecord.Add( miValueResult5 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord ); bOk = bOk && TextToStdout( "(gdb)" ); } break; case 11: // Invalid memory reference. SIGSEGV { // MI print "*stopped,reason=\"signal-received\",signal-name=\"SIGSEGV\",signal-meaning=\"Segmentation fault\",thread-id=\"%d\",frame={%s}" const CMICmnMIValueConst miValueConst( "signal-received" ); const CMICmnMIValueResult miValueResult( "reason", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult ); const CMICmnMIValueConst miValueConst2( "SIGSEGV" ); const CMICmnMIValueResult miValueResult2( "signal-name", miValueConst2 ); bOk = miOutOfBandRecord.Add( miValueResult2 ); const CMICmnMIValueConst miValueConst3( "Segmentation fault" ); const CMICmnMIValueResult miValueResult3( "signal-meaning", miValueConst3 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult3 ); const CMIUtilString strThreadId( CMIUtilString::Format( "%d", rProcess.GetSelectedThread().GetIndexID() ) ); const CMICmnMIValueConst miValueConst4( strThreadId ); const CMICmnMIValueResult miValueResult4( "thread-id", miValueConst4 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult4 ); CMICmnMIValueTuple miValueTuple; bOk = bOk && MiHelpGetCurrentThreadFrame( miValueTuple ); const CMICmnMIValueResult miValueResult5( "frame", miValueTuple ); bOk = bOk && miOutOfBandRecord.Add( miValueResult5 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord ); // Note no "(gdb)" output here } break; case 19: if( rProcess.IsValid() ) rProcess.Continue(); break; case 5: // Trace/breakpoint trap. SIGTRAP { lldb::SBThread thread = rProcess.GetSelectedThread(); const MIuint nFrames = thread.GetNumFrames(); if( nFrames > 0 ) { lldb::SBFrame frame = thread.GetFrameAtIndex( 0 ); const char * pFnName = frame.GetFunctionName(); if( pFnName != nullptr ) { const CMIUtilString fnName = CMIUtilString( pFnName ); static const CMIUtilString threadCloneFn = CMIUtilString( "__pthread_clone" ); if( CMIUtilString::Compare( threadCloneFn, fnName ) ) { if( rProcess.IsValid() ) { rProcess.Continue(); vwrbShouldBrk = true; break; } } } } } default: { // MI print "*stopped,reason=\"signal-received\",signal=\"%lld\",stopped-threads=\"all\"" const CMICmnMIValueConst miValueConst( "signal-received" ); const CMICmnMIValueResult miValueResult( "reason", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult ); const CMIUtilString strReason( CMIUtilString::Format( "%lld", nStopReason ) ); const CMICmnMIValueConst miValueConst2( strReason ); const CMICmnMIValueResult miValueResult2( "signal", miValueConst2 ); bOk = miOutOfBandRecord.Add( miValueResult2 ); const CMICmnMIValueConst miValueConst3( "all" ); const CMICmnMIValueResult miValueResult3( "stopped-threads", miValueConst3 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult3 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord ); bOk = bOk && TextToStdout( "(gdb)" ); } } // switch( nStopReason ) return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Form partial MI response in a MI value tuple object. // Type: Method. // Args: vwrMiValueTuple - (W) MI value tuple object. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::MiHelpGetCurrentThreadFrame( CMICmnMIValueTuple & vwrMiValueTuple ) { CMIUtilString strThreadFrame; lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; lldb::SBThread thread = rProcess.GetSelectedThread(); const MIuint nFrame = thread.GetNumFrames(); if( nFrame == 0 ) { // MI print "addr=\"??\",func=\"??\",file=\"??\",fullname=\"??\",line=\"??\"" const CMICmnMIValueConst miValueConst( "??" ); const CMICmnMIValueResult miValueResult( "addr", miValueConst ); CMICmnMIValueTuple miValueTuple( miValueResult ); const CMICmnMIValueResult miValueResult2( "func", miValueConst ); miValueTuple.Add( miValueResult2 ); const CMICmnMIValueResult miValueResult4( "file", miValueConst ); miValueTuple.Add( miValueResult4 ); const CMICmnMIValueResult miValueResult5( "fullname", miValueConst ); miValueTuple.Add( miValueResult5 ); const CMICmnMIValueResult miValueResult6( "line", miValueConst ); miValueTuple.Add( miValueResult6 ); vwrMiValueTuple = miValueTuple; return MIstatus::success; } CMICmnMIValueTuple miValueTuple; if( !CMICmnLLDBDebugSessionInfo::Instance().MIResponseFormFrameInfo( thread, 0, miValueTuple ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FORM_MI_RESPONSE ), "MiHelpGetCurrentThreadFrame()" ) ); return MIstatus::failure; } vwrMiValueTuple = miValueTuple; return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Asynchronous event handler for LLDB Process stop reason breakpoint. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonBreakpoint( void ) { // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM if( !CMIDriver::Instance().SetDriverStateRunningNotDebugging() ) { const CMIUtilString & rErrMsg( CMIDriver::Instance().GetErrorDescription() ); SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_SETNEWDRIVERSTATE ), "HandleProcessEventStopReasonBreakpoint()", rErrMsg.c_str() ) ); return MIstatus::failure; } lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; const MIuint64 brkPtId = rProcess.GetSelectedThread().GetStopReasonDataAtIndex( 0 ); lldb::SBBreakpoint brkPt = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget.GetBreakpointAtIndex( (MIuint) brkPtId ); return MiStoppedAtBreakPoint( brkPtId, brkPt ); } //++ ------------------------------------------------------------------------------------ // Details: Form the MI Out-of-band response for stopped reason on hitting a break point. // Type: Method. // Args: vBrkPtId - (R) The LLDB break point's ID // vBrkPt - (R) THe LLDB break point object. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::MiStoppedAtBreakPoint( const MIuint64 vBrkPtId, const lldb::SBBreakpoint & vBrkPt ) { bool bOk = MIstatus::success; lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; lldb::SBThread thread = rProcess.GetSelectedThread(); const MIuint nFrame = thread.GetNumFrames(); if( nFrame == 0 ) { // MI print "*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"%d\",frame={},thread-id=\"%d\",stopped-threads=\"all\"" const CMICmnMIValueConst miValueConst( "breakpoint-hit" ); const CMICmnMIValueResult miValueResult( "reason", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult ); const CMICmnMIValueConst miValueConst2( "del" ); const CMICmnMIValueResult miValueResult2( "disp", miValueConst2 ); bOk = miOutOfBandRecord.Add( miValueResult2 ); const CMIUtilString strBkp( CMIUtilString::Format( "%d", vBrkPtId ) ); const CMICmnMIValueConst miValueConst3( strBkp ); CMICmnMIValueResult miValueResult3( "bkptno", miValueConst3 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult3 ); const CMICmnMIValueConst miValueConst4( "{}" ); const CMICmnMIValueResult miValueResult4( "frame", miValueConst4 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult4 ); const CMIUtilString strThreadId( CMIUtilString::Format( "%d", vBrkPt.GetThreadIndex() ) ); const CMICmnMIValueConst miValueConst5( strThreadId ); const CMICmnMIValueResult miValueResult5( "thread-id", miValueConst5 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult5 ); const CMICmnMIValueConst miValueConst6( "all" ); const CMICmnMIValueResult miValueResult6( "stopped-threads", miValueConst6 ); bOk = bOk && miOutOfBandRecord.Add( miValueResult6 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord ); bOk = bOk && TextToStdout( "(gdb)" ); return bOk; } CMICmnLLDBDebugSessionInfo & rSession = CMICmnLLDBDebugSessionInfo::Instance(); lldb::SBFrame frame = thread.GetFrameAtIndex( 0 ); lldb::addr_t pc = 0; CMIUtilString fnName; CMIUtilString fileName; CMIUtilString path; MIuint nLine = 0; if( !rSession.GetFrameInfo( frame, pc, fnName, fileName, path, nLine ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FRAME_INFO_GET ), "MiStoppedAtBreakPoint()" ) ); return MIstatus::failure; } // MI print "*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"%d\",frame={addr=\"0x%08x\",func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"},thread-id=\"%d\",stopped-threads=\"all\"" const CMICmnMIValueConst miValueConst( "breakpoint-hit" ); const CMICmnMIValueResult miValueResult( "reason", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult ); const CMICmnMIValueConst miValueConstA( "del" ); const CMICmnMIValueResult miValueResultA( "disp", miValueConstA ); bOk = miOutOfBandRecord.Add( miValueResultA ); const CMIUtilString strBkp( CMIUtilString::Format( "%d", vBrkPtId ) ); const CMICmnMIValueConst miValueConstB( strBkp ); CMICmnMIValueResult miValueResultB( "bkptno", miValueConstB ); bOk = bOk && miOutOfBandRecord.Add( miValueResultB ); // frame={addr=\"0x%08x\",func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"} if( bOk ) { CMICmnMIValueList miValueList( true ); const MIuint maskVarTypes = 0x1000; bOk = rSession.MIResponseFormVariableInfo2( frame, maskVarTypes, miValueList ); CMICmnMIValueTuple miValueTuple; bOk = bOk && rSession.MIResponseFormFrameInfo2( pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple ); const CMICmnMIValueResult miValueResult8( "frame", miValueTuple ); bOk = bOk && miOutOfBandRecord.Add( miValueResult8 ); } // Add to MI thread-id=\"%d\",stopped-threads=\"all\" if( bOk ) { const CMIUtilString strThreadId( CMIUtilString::Format( "%d", thread.GetIndexID() ) ); const CMICmnMIValueConst miValueConst8( strThreadId ); const CMICmnMIValueResult miValueResult8( "thread-id", miValueConst8 ); bOk = miOutOfBandRecord.Add( miValueResult8 ); } if( bOk ) { const CMICmnMIValueConst miValueConst9( "all" ); const CMICmnMIValueResult miValueResult9( "stopped-threads", miValueConst9 ); bOk = miOutOfBandRecord.Add( miValueResult9 ); bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord ); bOk = bOk && TextToStdout( "(gdb)" ); } return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Asynchronous event handler for LLDB Process stop reason trace. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonTrace( void ) { bool bOk = true; lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; lldb::SBThread thread = rProcess.GetSelectedThread(); const MIuint nFrame = thread.GetNumFrames(); if( nFrame == 0 ) { // MI print "*stopped,reason=\"trace\",stopped-threads=\"all\"" const CMICmnMIValueConst miValueConst( "trace" ); const CMICmnMIValueResult miValueResult( "reason", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult ); const CMICmnMIValueConst miValueConst2( "all" ); const CMICmnMIValueResult miValueResult2( "stopped-threads", miValueConst2 ); bOk = miOutOfBandRecord.Add( miValueResult2 ); bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord ); bOk = bOk && TextToStdout( "(gdb)" ); return bOk; } CMICmnLLDBDebugSessionInfo & rSession = CMICmnLLDBDebugSessionInfo::Instance(); // MI print "*stopped,reason=\"end-stepping-range\",frame={addr=\"0x%08x\",func=\"%s\",args=[\"%s\"],file=\"%s\",fullname=\"%s\",line=\"%d\"},thread-id=\"%d\",stopped-threads=\"all\"" lldb::SBFrame frame = thread.GetFrameAtIndex( 0 ); lldb::addr_t pc = 0; CMIUtilString fnName; CMIUtilString fileName; CMIUtilString path; MIuint nLine = 0; if( !rSession.GetFrameInfo( frame, pc, fnName, fileName, path, nLine ) ) { SetErrorDescription( CMIUtilString::Format( MIRSRC( IDS_LLDBOUTOFBAND_ERR_FRAME_INFO_GET ), "HandleProcessEventStopReasonTrace()" ) ); return MIstatus::failure; } // Function args CMICmnMIValueList miValueList( true ); const MIuint maskVarTypes = 0x1000; if( !rSession.MIResponseFormVariableInfo2( frame, maskVarTypes, miValueList ) ) return MIstatus::failure; CMICmnMIValueTuple miValueTuple; if( !rSession.MIResponseFormFrameInfo2( pc, miValueList.GetString(), fnName, fileName, path, nLine, miValueTuple ) ) return MIstatus::failure; const CMICmnMIValueConst miValueConst( "end-stepping-range" ); const CMICmnMIValueResult miValueResult( "reason", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult ); const CMICmnMIValueResult miValueResult2( "frame", miValueTuple ); bOk = miOutOfBandRecord.Add( miValueResult2 ); // Add to MI thread-id=\"%d\",stopped-threads=\"all\" if( bOk ) { const CMIUtilString strThreadId( CMIUtilString::Format( "%d", thread.GetIndexID() ) ); const CMICmnMIValueConst miValueConst8( strThreadId ); const CMICmnMIValueResult miValueResult8( "thread-id", miValueConst8 ); bOk = miOutOfBandRecord.Add( miValueResult8 ); } if( bOk ) { const CMICmnMIValueConst miValueConst9( "all" ); const CMICmnMIValueResult miValueResult9( "stopped-threads", miValueConst9 ); bOk = miOutOfBandRecord.Add( miValueResult9 ); bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord ); bOk = bOk && TextToStdout( "(gdb)" ); } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Asynchronous function update selected thread. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::UpdateSelectedThread( void ) { lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); if( !process.IsValid() ) return MIstatus::success; lldb::SBThread currentThread = process.GetSelectedThread(); lldb::SBThread thread; const lldb::StopReason eCurrentThreadStoppedReason = currentThread.GetStopReason(); if( !currentThread.IsValid() || (eCurrentThreadStoppedReason == lldb::eStopReasonInvalid) || (eCurrentThreadStoppedReason == lldb::eStopReasonNone) ) { // Prefer a thread that has just completed its plan over another thread as current thread lldb::SBThread planThread; lldb::SBThread otherThread; const size_t nThread = process.GetNumThreads(); for( MIuint i = 0; i < nThread; i++ ) { // GetThreadAtIndex() uses a base 0 index // GetThreadByIndexID() uses a base 1 index thread = process.GetThreadAtIndex( i ); const lldb::StopReason eThreadStopReason = thread.GetStopReason(); switch( eThreadStopReason ) { case lldb::eStopReasonTrace: case lldb::eStopReasonBreakpoint: case lldb::eStopReasonWatchpoint: case lldb::eStopReasonSignal: case lldb::eStopReasonException: if( !otherThread.IsValid() ) otherThread = thread; break; case lldb::eStopReasonPlanComplete: if( !planThread.IsValid() ) planThread = thread; break; case lldb::eStopReasonInvalid: case lldb::eStopReasonNone: default: break; } } if( planThread.IsValid() ) process.SetSelectedThread( planThread ); else if( otherThread.IsValid() ) process.SetSelectedThread( otherThread ); else { if( currentThread.IsValid() ) thread = currentThread; else thread = process.GetThreadAtIndex( 0 ); if( thread.IsValid() ) process.SetSelectedThread( thread ); } } // if( !currentThread.IsValid() || (eCurrentThreadStoppedReason == lldb::eStopReasonInvalid) || (eCurrentThreadStoppedReason == lldb::eStopReasonNone) ) return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Print to stdout "*running,thread-id=\"all\"", "(gdb)". // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateRunning( void ) { CMICmnMIValueConst miValueConst( "all" ); CMICmnMIValueResult miValueResult( "thread-id", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult ); bool bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord ); bOk = bOk && TextToStdout( "(gdb)" ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Print to stdout "=thread-exited,id=\"%ld\",group-id=\"i1\"", // "=thread-group-exited,id=\"i1\",exit-code=\"0\""), // "*stopped,reason=\"exited-normally\"", // "(gdb)" // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateExited( void ) { const CMIUtilString strId( CMIUtilString::Format( "%ld", 1 ) ); CMICmnMIValueConst miValueConst( strId ); CMICmnMIValueResult miValueResult( "id", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBandRecord( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, miValueResult ); CMICmnMIValueConst miValueConst2( "i1" ); CMICmnMIValueResult miValueResult2( "group-id", miValueConst2 ); bool bOk = miOutOfBandRecord.Add( miValueResult2 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord ); if( bOk ) { CMICmnMIValueConst miValueConst3( "i1" ); CMICmnMIValueResult miValueResult3( "id", miValueConst3 ); CMICmnMIOutOfBandRecord miOutOfBandRecord2( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadGroupExited, miValueResult3 ); CMICmnMIValueConst miValueConst2( "0" ); CMICmnMIValueResult miValueResult2( "exit-code", miValueConst2 ); bOk = miOutOfBandRecord2.Add( miValueResult2 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBandRecord2 ); } if( bOk ) { CMICmnMIValueConst miValueConst4( "exited-normally" ); CMICmnMIValueResult miValueResult4( "reason", miValueConst4 ); CMICmnMIOutOfBandRecord miOutOfBandRecord3( CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult4 ); bOk = MiOutOfBandRecordToStdout( miOutOfBandRecord3 ); } bOk = bOk && TextToStdout( "(gdb)" ); return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Drain all stdout so we don't see any output come after we print our prompts. // The process has stuff waiting for stdout; get it and write it out to the // appropriate place. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::GetProcessStdout( void ) { bool bOk = MIstatus::success; char c; size_t nBytes = 0; CMIUtilString text; lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); while( process.GetSTDOUT( &c, 1 ) > 0 ) { CMIUtilString str; if( ConvertPrintfCtrlCodeToString( c, str ) ) text += str; nBytes++; } if( nBytes > 0 ) { const CMIUtilString t( CMIUtilString::Format( "~\"%s\"", text.c_str() ) ); bOk = TextToStdout( t ); } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Drain all stderr so we don't see any output come after we print our prompts. // The process has stuff waiting for stderr; get it and write it out to the // appropriate place. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::GetProcessStderr( void ) { bool bOk = MIstatus::success; char c; size_t nBytes = 0; CMIUtilString text; lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance().m_rLldbDebugger.GetSelectedTarget().GetProcess(); while( process.GetSTDERR( &c, 1 ) > 0 ) { CMIUtilString str; if( ConvertPrintfCtrlCodeToString( c, str ) ) text += str; nBytes++; } if( nBytes > 0 ) { const CMIUtilString t( CMIUtilString::Format( "~\"%s\"", text.c_str() ) ); bOk = TextToStdout( t ); } return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Convert text stream control codes to text equivalent. // Type: Method. // Args: vCtrl - (R) The control code. // vwrStrEquivalent - (W) The text equivalent. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::ConvertPrintfCtrlCodeToString( const MIchar vCtrl, CMIUtilString & vwrStrEquivalent ) { switch( vCtrl ) { case '\033': vwrStrEquivalent = "\\e"; break; case '\a': vwrStrEquivalent = "\\a"; break; case '\b': vwrStrEquivalent = "\\b"; break; case '\f': vwrStrEquivalent = "\\f"; break; case '\n': vwrStrEquivalent = "\\n"; break; case '\r': vwrStrEquivalent = "\\r"; break; case '\t': vwrStrEquivalent = "\\t"; break; case '\v': vwrStrEquivalent = "\\v"; break; default: vwrStrEquivalent = CMIUtilString::Format( "%c", vCtrl ); break; } return MIstatus::success; } //++ ------------------------------------------------------------------------------------ // Details: Asynchronous event function check for state changes. // Type: Method. // Args: None. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::ChkForStateChanges( void ) { lldb::SBProcess & rProcess = CMICmnLLDBDebugSessionInfo::Instance().m_lldbProcess; if( !rProcess.IsValid() ) return MIstatus::success; lldb::SBTarget & rTarget = CMICmnLLDBDebugSessionInfo::Instance().m_lldbTarget; if( !rTarget.IsValid() ) return MIstatus::success; bool bOk = MIstatus::success; // Check for created threads const MIuint nThread = rProcess.GetNumThreads(); for( MIuint i = 0; i < nThread; i++ ) { // GetThreadAtIndex() uses a base 0 index // GetThreadByIndexID() uses a base 1 index lldb::SBThread thread = rProcess.GetThreadAtIndex( i ); if( !thread.IsValid() ) continue; CMICmnLLDBDebugSessionInfo::VecActiveThreadId_t::const_iterator it = CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.begin(); bool bFound = false; while( it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end() ) { const MIuint nThreadId = *it; if( nThreadId == i ) { bFound = true; break; } // Next ++it; } if( !bFound ) { CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.push_back( i ); // Form MI "=thread-created,id=\"%d\",group-id=\"i1\"" const CMIUtilString strValue( CMIUtilString::Format( "%d", thread.GetIndexID() ) ); const CMICmnMIValueConst miValueConst( strValue ); const CMICmnMIValueResult miValueResult( "id", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadCreated, miValueResult ); const CMICmnMIValueConst miValueConst2( "i1" ); const CMICmnMIValueResult miValueResult2( "group-id", miValueConst2 ); bOk = miOutOfBand.Add( miValueResult2 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBand ); if( !bOk ) return MIstatus::failure; } } lldb::SBThread currentThread = rProcess.GetSelectedThread(); if( currentThread.IsValid() ) { const MIuint threadId = currentThread.GetIndexID(); if( CMICmnLLDBDebugSessionInfo::Instance().m_currentSelectedThread != threadId ) { CMICmnLLDBDebugSessionInfo::Instance().m_currentSelectedThread = threadId; // Form MI "=thread-selected,id=\"%d\"" const CMIUtilString strValue( CMIUtilString::Format( "%d", currentThread.GetIndexID() ) ); const CMICmnMIValueConst miValueConst( strValue ); const CMICmnMIValueResult miValueResult( "id", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadSelected, miValueResult ); if( !MiOutOfBandRecordToStdout( miOutOfBand ) ) return MIstatus::failure; } } // Check for invalid (removed) threads CMICmnLLDBDebugSessionInfo::VecActiveThreadId_t::const_iterator it = CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.begin(); while( it != CMICmnLLDBDebugSessionInfo::Instance().m_vecActiveThreadId.end() ) { const MIuint nThreadId = *it; lldb::SBThread thread = rProcess.GetThreadAtIndex( nThreadId ); if( !thread.IsValid() ) { // Form MI "=thread-exited,id=\"%ld\",group-id=\"i1\"" const CMIUtilString strValue( CMIUtilString::Format( "%ld", thread.GetIndexID() ) ); const CMICmnMIValueConst miValueConst( strValue ); const CMICmnMIValueResult miValueResult( "id", miValueConst ); CMICmnMIOutOfBandRecord miOutOfBand( CMICmnMIOutOfBandRecord::eOutOfBand_ThreadExited, miValueResult ); const CMICmnMIValueConst miValueConst2( "i1" ); const CMICmnMIValueResult miValueResult2( "group-id", miValueConst2 ); bOk = miOutOfBand.Add( miValueResult2 ); bOk = bOk && MiOutOfBandRecordToStdout( miOutOfBand ); if( !bOk ) return MIstatus::failure; } // Next ++it; } return TextToStdout( "(gdb)" ); } //++ ------------------------------------------------------------------------------------ // Details: Take a fully formed MI result record and send to the stdout stream. // Also output to the MI Log file. // Type: Method. // Args: vrMiResultRecord - (R) MI result record object. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::MiResultRecordToStdout( const CMICmnMIResultRecord & vrMiResultRecord ) { return TextToStdout( vrMiResultRecord.GetString() ); } //++ ------------------------------------------------------------------------------------ // Details: Take a fully formed MI Out-of-band record and send to the stdout stream. // Also output to the MI Log file. // Type: Method. // Args: vrMiOutOfBandRecord - (R) MI Out-of-band record object. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::MiOutOfBandRecordToStdout( const CMICmnMIOutOfBandRecord & vrMiOutOfBandRecord ) { return TextToStdout( vrMiOutOfBandRecord.GetString() ); } //++ ------------------------------------------------------------------------------------ // Details: Take a text data and send to the stdout stream. Also output to the MI Log // file. // Type: Method. // Args: vrTxt - (R) Text. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::TextToStdout( const CMIUtilString & vrTxt ) { return CMICmnStreamStdout::TextToStdout( vrTxt ); } //++ ------------------------------------------------------------------------------------ // Details: Take a text data and send to the stderr stream. Also output to the MI Log // file. // Type: Method. // Args: vrTxt - (R) Text. // Return: MIstatus::success - Functionality succeeded. // MIstatus::failure - Functionality failed. // Throws: None. //-- bool CMICmnLLDBDebuggerHandleEvents::TextToStderr( const CMIUtilString & vrTxt ) { return CMICmnStreamStderr::TextToStderr( vrTxt ); }