| //===-- 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 <lldb/API/SBEvent.h> |
| #include <lldb/API/SBProcess.h> |
| #include <lldb/API/SBBreakpoint.h> |
| #include <lldb/API/SBStream.h> |
| #include <lldb/API/SBThread.h> |
| #include <lldb/API/SBCommandInterpreter.h> |
| #include <lldb/API/SBCommandReturnObject.h> |
| #ifdef _WIN32 |
| #include <io.h> // For the ::_access() |
| #else |
| #include <unistd.h> // For the ::access() |
| #endif // _WIN32 |
| #include <limits.h> |
| |
| // 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 = HandleEventSBBreakpointCmn( 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 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 <unknown index>: (" ); |
| 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=\"??\",args=[],file=\"??\",fullname=\"??\",line=\"??\"" |
| const CMICmnMIValueConst miValueConst( "??" ); |
| const CMICmnMIValueResult miValueResult( "addr", miValueConst ); |
| CMICmnMIValueTuple miValueTuple( miValueResult ); |
| const CMICmnMIValueResult miValueResult2( "func", miValueConst ); |
| miValueTuple.Add( miValueResult2 ); |
| const CMICmnMIValueConst miValueConst2( "[]", true ); |
| const CMICmnMIValueResult miValueResult3( "args", miValueConst2 ); |
| miValueTuple.Add( miValueResult3 ); |
| 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 vMaskVarTypes = 0x1000; |
| bOk = rSession.MIResponseFormVariableInfo( frame, vMaskVarTypes, miValueList ); |
| CMICmnMIValueTuple miValueTuple; |
| bOk = bOk && rSession.MIResponseFormFrameInfo( pc, fnName, miValueList.GetString(), 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=[],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; |
| } |
| |
| // frame={addr=\"0x%08x\",func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"} |
| CMICmnMIValueTuple miValueTuple; |
| if( !rSession.MIResponseFormFrameInfo( pc, 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 ); |
| bOk = miOutOfBandRecord.Add( miValueTuple ); |
| |
| // 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 ); |
| } |