| //===-- MICmnLLDBDebuggerHandleEvents.cpp -----------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| // Third party headers: |
| #include "lldb/API/SBAddress.h" |
| #include "lldb/API/SBBreakpoint.h" |
| #include "lldb/API/SBCommandInterpreter.h" |
| #include "lldb/API/SBCommandReturnObject.h" |
| #include "lldb/API/SBEvent.h" |
| #include "lldb/API/SBProcess.h" |
| #include "lldb/API/SBStream.h" |
| #include "lldb/API/SBTarget.h" |
| #include "lldb/API/SBThread.h" |
| #include "lldb/API/SBUnixSignals.h" |
| #include "llvm/Support/Compiler.h" |
| #ifdef _WIN32 |
| #include <io.h> // For the ::_access() |
| #else |
| #include <unistd.h> // For the ::access() |
| #endif // _WIN32 |
| |
| // In-house headers: |
| #include "MICmnLLDBDebugSessionInfo.h" |
| #include "MICmnLLDBDebugger.h" |
| #include "MICmnLLDBDebuggerHandleEvents.h" |
| #include "MICmnLog.h" |
| #include "MICmnMIOutOfBandRecord.h" |
| #include "MICmnMIResultRecord.h" |
| #include "MICmnMIValueConst.h" |
| #include "MICmnMIValueList.h" |
| #include "MICmnResources.h" |
| #include "MICmnStreamStderr.h" |
| #include "MICmnStreamStdout.h" |
| #include "MIDriver.h" |
| #include "MIUtilDebug.h" |
| #include "Platform.h" // for PATH_MAX |
| |
| #include <algorithm> |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: CMICmnLLDBDebuggerHandleEvents constructor. |
| // Type: Method. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMICmnLLDBDebuggerHandleEvents::CMICmnLLDBDebuggerHandleEvents() {} |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: CMICmnLLDBDebuggerHandleEvents destructor. |
| // Type: Overridable. |
| // Args: None. |
| // Return: None. |
| // Throws: None. |
| //-- |
| CMICmnLLDBDebuggerHandleEvents::~CMICmnLLDBDebuggerHandleEvents() { |
| Shutdown(); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Initialize resources for *this broadcaster object. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::Initialize() { |
| m_clientUsageRefCnt++; |
| |
| if (m_bInitialized) |
| return MIstatus::success; |
| |
| m_bInitialized = MIstatus::success; |
| m_bSignalsInitialized = false; |
| m_SIGINT = 0; |
| m_SIGSTOP = 0; |
| m_SIGSEGV = 0; |
| m_SIGTRAP = 0; |
| |
| return m_bInitialized; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Release resources for *this broadcaster object. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::Shutdown() { |
| 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 ascertain 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. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::HandleEvent(const lldb::SBEvent &vEvent, |
| bool &vrbHandledEvent) { |
| bool bOk = MIstatus::success; |
| vrbHandledEvent = false; |
| |
| if (lldb::SBProcess::EventIsProcessEvent(vEvent)) { |
| vrbHandledEvent = true; |
| bOk = HandleEventSBProcess(vEvent); |
| } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(vEvent)) { |
| vrbHandledEvent = true; |
| bOk = HandleEventSBBreakPoint(vEvent); |
| } else if (lldb::SBThread::EventIsThreadEvent(vEvent)) { |
| vrbHandledEvent = true; |
| bOk = HandleEventSBThread(vEvent); |
| } else if (lldb::SBTarget::EventIsTargetEvent(vEvent)) { |
| vrbHandledEvent = true; |
| bOk = HandleEventSBTarget(vEvent); |
| } else if (lldb::SBCommandInterpreter::EventIsCommandInterpreterEvent( |
| vEvent)) { |
| vrbHandledEvent = true; |
| bOk = HandleEventSBCommandInterpreter(vEvent); |
| } |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Handle a LLDB SBProcess event. |
| // Type: Method. |
| // Args: vEvent - (R) An LLDB broadcast event. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBProcess( |
| const lldb::SBEvent &vEvent) { |
| bool bOk = MIstatus::success; |
| |
| const char *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::eBroadcastBitStructuredData: |
| pEventType = "eBroadcastBitStructuredData"; |
| break; |
| case lldb::SBProcess::eBroadcastBitStateChanged: |
| pEventType = "eBroadcastBitStateChanged"; |
| bOk = HandleProcessEventBroadcastBitStateChanged(vEvent); |
| 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 char *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"; |
| bOk = HandleEventSBBreakpointCmn(vEvent); |
| 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; |
| case lldb::eBreakpointEventTypeAutoContinueChanged: |
| pEventType = "eBreakpointEventTypeAutoContinueChanged"; |
| bOk = HandleEventSBBreakpointCmn(vEvent); |
| break; |
| } |
| 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%016" |
| // PRIx64 "\", |
| // 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); |
| bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| |
| 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 char *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%016" |
| // PRIx64 |
| // "\",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); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| } 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%016" |
| // PRIx64 |
| // "\",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); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| } |
| |
| 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 char *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); |
| miOutOfBandRecord.Add(miValueResult2); |
| return MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // 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 SBTarget event. |
| // Type: Method. |
| // Args: vEvent - (R) An LLDB broadcast event. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBTarget( |
| const lldb::SBEvent &vEvent) { |
| if (!ChkForStateChanges()) |
| return MIstatus::failure; |
| |
| bool bOk = MIstatus::success; |
| const char *pEventType = ""; |
| const MIuint nEventType = vEvent.GetType(); |
| switch (nEventType) { |
| case lldb::SBTarget::eBroadcastBitBreakpointChanged: |
| pEventType = "eBroadcastBitBreakpointChanged"; |
| break; |
| case lldb::SBTarget::eBroadcastBitModulesLoaded: |
| pEventType = "eBroadcastBitModulesLoaded"; |
| bOk = HandleTargetEventBroadcastBitModulesLoaded(vEvent); |
| break; |
| case lldb::SBTarget::eBroadcastBitModulesUnloaded: |
| pEventType = "eBroadcastBitModulesUnloaded"; |
| bOk = HandleTargetEventBroadcastBitModulesUnloaded(vEvent); |
| break; |
| case lldb::SBTarget::eBroadcastBitWatchpointChanged: |
| pEventType = "eBroadcastBitWatchpointChanged"; |
| break; |
| case lldb::SBTarget::eBroadcastBitSymbolsLoaded: |
| pEventType = "eBroadcastBitSymbolsLoaded"; |
| break; |
| default: { |
| const CMIUtilString msg( |
| CMIUtilString::Format(MIRSRC(IDS_LLDBOUTOFBAND_ERR_UNKNOWN_EVENT), |
| "SBTarget", (MIuint)nEventType)); |
| SetErrorDescription(msg); |
| return MIstatus::failure; |
| } |
| } |
| m_pLog->WriteLog(CMIUtilString::Format("##### An SBTarget event occurred: %s", |
| pEventType)); |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Print to stdout |
| // "=library-loaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" |
| // PRIx64"\"" |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Function succeeded. |
| // MIstatus::failure - Function failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::HandleTargetEventBroadcastBitModulesLoaded( |
| const lldb::SBEvent &vEvent) { |
| bool bOk = MIstatus::failure; |
| const MIuint nSize = lldb::SBTarget::GetNumModulesFromEvent(vEvent); |
| for (MIuint nIndex = 0; nIndex < nSize; ++nIndex) { |
| const lldb::SBModule sbModule = |
| lldb::SBTarget::GetModuleAtIndexFromEvent(nIndex, vEvent); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleLoaded); |
| const bool bWithExtraFields = true; |
| bOk = MiHelpGetModuleInfo(sbModule, bWithExtraFields, miOutOfBandRecord); |
| bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| if (!bOk) |
| break; |
| } |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Print to stdout |
| // "=library-unloaded,id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" |
| // PRIx64"\"" |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Function succeeded. |
| // MIstatus::failure - Function failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents:: |
| HandleTargetEventBroadcastBitModulesUnloaded(const lldb::SBEvent &vEvent) { |
| bool bOk = MIstatus::failure; |
| const MIuint nSize = lldb::SBTarget::GetNumModulesFromEvent(vEvent); |
| for (MIuint nIndex = 0; nIndex < nSize; ++nIndex) { |
| const lldb::SBModule sbModule = |
| lldb::SBTarget::GetModuleAtIndexFromEvent(nIndex, vEvent); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_TargetModuleUnloaded); |
| const bool bWithExtraFields = false; |
| bOk = MiHelpGetModuleInfo(sbModule, bWithExtraFields, miOutOfBandRecord); |
| bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| if (!bOk) |
| break; |
| } |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Build module information for =library-loaded/=library-unloaded: |
| // "id=\"%s\",target-name=\"%s\",host-name=\"%s\",symbols-loaded="%d"[,symbols-path=\"%s\"],loaded_addr=\"0x%016" |
| // PRIx64"\"" |
| // Type: Method. |
| // Args: vwrMiValueList - (W) MI value list object. |
| // Return: MIstatus::success - Function succeeded. |
| // MIstatus::failure - Function failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::MiHelpGetModuleInfo( |
| const lldb::SBModule &vModule, const bool vbWithExtraFields, |
| CMICmnMIOutOfBandRecord &vwrMiOutOfBandRecord) { |
| bool bOk = MIstatus::success; |
| |
| // First, build standard fields: |
| // Build "id" field |
| std::unique_ptr<char[]> apPath(new char[PATH_MAX]); |
| vModule.GetFileSpec().GetPath(apPath.get(), PATH_MAX); |
| const CMIUtilString strTargetPath(apPath.get()); |
| const CMICmnMIValueConst miValueConst(strTargetPath.AddSlashes()); |
| const CMICmnMIValueResult miValueResult("id", miValueConst); |
| vwrMiOutOfBandRecord.Add(miValueResult); |
| // Build "target-name" field |
| const CMICmnMIValueConst miValueConst2(strTargetPath.AddSlashes()); |
| const CMICmnMIValueResult miValueResult2("target-name", miValueConst2); |
| vwrMiOutOfBandRecord.Add(miValueResult2); |
| // Build "host-name" field |
| vModule.GetPlatformFileSpec().GetPath(apPath.get(), PATH_MAX); |
| const CMIUtilString strHostPath(apPath.get()); |
| const CMICmnMIValueConst miValueConst3(strHostPath.AddSlashes()); |
| const CMICmnMIValueResult miValueResult3("host-name", miValueConst3); |
| vwrMiOutOfBandRecord.Add(miValueResult3); |
| |
| // Then build extra fields if needed: |
| if (vbWithExtraFields) { |
| // Build "symbols-loaded" field |
| vModule.GetSymbolFileSpec().GetPath(apPath.get(), PATH_MAX); |
| const CMIUtilString strSymbolsPath(apPath.get()); |
| const bool bSymbolsLoaded = |
| !CMIUtilString::Compare(strHostPath, strSymbolsPath); |
| const CMICmnMIValueConst miValueConst4( |
| CMIUtilString::Format("%d", bSymbolsLoaded)); |
| const CMICmnMIValueResult miValueResult4("symbols-loaded", miValueConst4); |
| vwrMiOutOfBandRecord.Add(miValueResult4); |
| // Build "symbols-path" field |
| if (bSymbolsLoaded) { |
| const CMICmnMIValueConst miValueConst5(strSymbolsPath.AddSlashes()); |
| const CMICmnMIValueResult miValueResult5("symbols-path", miValueConst5); |
| vwrMiOutOfBandRecord.Add(miValueResult5); |
| } |
| // Build "loaded_addr" field |
| lldb::SBAddress sbAddress(vModule.GetObjectFileHeaderAddress()); |
| CMICmnLLDBDebugSessionInfo &rSessionInfo( |
| CMICmnLLDBDebugSessionInfo::Instance()); |
| const lldb::addr_t nLoadAddress( |
| sbAddress.GetLoadAddress(rSessionInfo.GetTarget())); |
| const CMIUtilString strLoadedAddr( |
| nLoadAddress != LLDB_INVALID_ADDRESS |
| ? CMIUtilString::Format("0x%016" PRIx64, nLoadAddress) |
| : "-"); |
| const CMICmnMIValueConst miValueConst6(strLoadedAddr); |
| const CMICmnMIValueResult miValueResult6("loaded_addr", miValueConst6); |
| vwrMiOutOfBandRecord.Add(miValueResult6); |
| |
| // Build "size" field |
| lldb::SBSection sbSection = sbAddress.GetSection(); |
| const CMIUtilString strSize( |
| CMIUtilString::Format("%" PRIu64, sbSection.GetByteSize())); |
| const CMICmnMIValueConst miValueConst7(strSize); |
| const CMICmnMIValueResult miValueResult7("size", miValueConst7); |
| vwrMiOutOfBandRecord.Add(miValueResult7); |
| } |
| |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // 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 char *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"; |
| const bool bForceExit = true; |
| CMICmnLLDBDebugger::Instance().GetDriver().SetExitApplicationFlag( |
| bForceExit); |
| 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. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventBroadcastBitStateChanged( |
| const lldb::SBEvent &vEvent) { |
| // Make sure the program hasn't been auto-restarted: |
| if (lldb::SBProcess::GetRestartedFromEvent(vEvent)) |
| return MIstatus::success; |
| |
| 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 char *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(vEvent, bShouldBrk); |
| if (bShouldBrk) |
| break; |
| LLVM_FALLTHROUGH; |
| 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: |
| // Don't exit from lldb-mi here. We should be able to re-run target. |
| pEventType = "eStateExited"; |
| 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) { |
| bool bOk = MIstatus::success; |
| lldb::SBDebugger &rDebugger = |
| CMICmnLLDBDebugSessionInfo::Instance().GetDebugger(); |
| lldb::SBProcess sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| lldb::SBTarget target = sbProcess.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( |
| const lldb::SBEvent &vrEvent, bool &vwrbShouldBrk) { |
| if (!UpdateSelectedThread()) |
| return MIstatus::failure; |
| |
| const char *pEventType = ""; |
| bool bOk = MIstatus::success; |
| lldb::SBProcess sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| const lldb::StopReason eStoppedReason = |
| sbProcess.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(vrEvent); |
| break; |
| case lldb::eStopReasonException: |
| pEventType = "eStopReasonException"; |
| bOk = HandleProcessEventStopException(); |
| break; |
| case lldb::eStopReasonExec: |
| pEventType = "eStopReasonExec"; |
| break; |
| case lldb::eStopReasonPlanComplete: |
| pEventType = "eStopReasonPlanComplete"; |
| bOk = HandleProcessEventStopReasonTrace(); |
| break; |
| case lldb::eStopReasonThreadExiting: |
| pEventType = "eStopReasonThreadExiting"; |
| break; |
| case lldb::eStopReasonInstrumentation: |
| pEventType = "eStopReasonInstrumentation"; |
| break; |
| } |
| |
| // 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: vrEvent - (R) An LLDB broadcast event. |
| // Return: MIstatus::success - Functionality succeeded. |
| // MIstatus::failure - Functionality failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopSignal( |
| const lldb::SBEvent &vrEvent) { |
| bool bOk = MIstatus::success; |
| |
| InitializeSignals(); |
| lldb::SBProcess sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| const MIuint64 nStopReason = |
| sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); |
| const bool bInterrupted = lldb::SBProcess::GetInterruptedFromEvent(vrEvent); |
| if (nStopReason == m_SIGINT || (nStopReason == m_SIGSTOP && bInterrupted)) { |
| // MI print |
| // "*stopped,reason=\"signal-received\",signal-name=\"SIGINT\",signal-meaning=\"Interrupt\",frame={%s},thread-id=\"%d\",stopped-threads=\"all\"" |
| 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); |
| miOutOfBandRecord.Add(miValueResult2); |
| const CMICmnMIValueConst miValueConst3("Interrupt"); |
| const CMICmnMIValueResult miValueResult3("signal-meaning", miValueConst3); |
| miOutOfBandRecord.Add(miValueResult3); |
| CMICmnMIValueTuple miValueTuple; |
| bOk = bOk && MiHelpGetCurrentThreadFrame(miValueTuple); |
| const CMICmnMIValueResult miValueResult4("frame", miValueTuple); |
| miOutOfBandRecord.Add(miValueResult4); |
| const CMIUtilString strThreadId(CMIUtilString::Format( |
| "%" PRIu32, sbProcess.GetSelectedThread().GetIndexID())); |
| const CMICmnMIValueConst miValueConst5(strThreadId); |
| const CMICmnMIValueResult miValueResult5("thread-id", miValueConst5); |
| miOutOfBandRecord.Add(miValueResult5); |
| const CMICmnMIValueConst miValueConst6("all"); |
| const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); |
| miOutOfBandRecord.Add(miValueResult6); |
| bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| } else if (nStopReason == m_SIGSTOP) { |
| // MI print |
| // "*stopped,reason=\"signal-received\",signal-name=\"SIGSTOP\",signal-meaning=\"Stop\",frame={%s},thread-id=\"%d\",stopped-threads=\"all\"" |
| const CMICmnMIValueConst miValueConst("signal-received"); |
| const CMICmnMIValueResult miValueResult("reason", miValueConst); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult); |
| const CMICmnMIValueConst miValueConst2("SIGSTOP"); |
| const CMICmnMIValueResult miValueResult2("signal-name", miValueConst2); |
| miOutOfBandRecord.Add(miValueResult2); |
| const CMICmnMIValueConst miValueConst3("Stop"); |
| const CMICmnMIValueResult miValueResult3("signal-meaning", miValueConst3); |
| miOutOfBandRecord.Add(miValueResult3); |
| CMICmnMIValueTuple miValueTuple; |
| bOk = bOk && MiHelpGetCurrentThreadFrame(miValueTuple); |
| const CMICmnMIValueResult miValueResult4("frame", miValueTuple); |
| miOutOfBandRecord.Add(miValueResult4); |
| const CMIUtilString strThreadId(CMIUtilString::Format( |
| "%" PRIu32, sbProcess.GetSelectedThread().GetIndexID())); |
| const CMICmnMIValueConst miValueConst5(strThreadId); |
| const CMICmnMIValueResult miValueResult5("thread-id", miValueConst5); |
| miOutOfBandRecord.Add(miValueResult5); |
| const CMICmnMIValueConst miValueConst6("all"); |
| const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); |
| miOutOfBandRecord.Add(miValueResult6); |
| bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| } else if (nStopReason == m_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); |
| miOutOfBandRecord.Add(miValueResult2); |
| const CMICmnMIValueConst miValueConst3("Segmentation fault"); |
| const CMICmnMIValueResult miValueResult3("signal-meaning", miValueConst3); |
| miOutOfBandRecord.Add(miValueResult3); |
| CMICmnMIValueTuple miValueTuple; |
| bOk = bOk && MiHelpGetCurrentThreadFrame(miValueTuple); |
| const CMICmnMIValueResult miValueResult4("frame", miValueTuple); |
| miOutOfBandRecord.Add(miValueResult4); |
| const CMIUtilString strThreadId(CMIUtilString::Format( |
| "%d", sbProcess.GetSelectedThread().GetIndexID())); |
| const CMICmnMIValueConst miValueConst5(strThreadId); |
| const CMICmnMIValueResult miValueResult5("thread-id", miValueConst5); |
| miOutOfBandRecord.Add(miValueResult5); |
| bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| // Note no "(gdb)" output here |
| } else if (nStopReason == m_SIGTRAP) { |
| lldb::SBThread thread = sbProcess.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 (sbProcess.IsValid()) |
| sbProcess.Continue(); |
| } |
| } |
| } |
| } else { |
| // MI print |
| // "*stopped,reason=\"signal-received\",signal-name=\"%s\",thread-id=\"%d\",stopped-threads=\"all\"" |
| // MI print |
| // "*stopped,reason=\"signal-received\",signal=\"%d\",thread-id=\"%d\",stopped-threads=\"all\"" |
| const CMICmnMIValueConst miValueConst("signal-received"); |
| const CMICmnMIValueResult miValueResult("reason", miValueConst); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult); |
| lldb::SBUnixSignals sbUnixSignals = sbProcess.GetUnixSignals(); |
| const char *pSignal = sbUnixSignals.GetSignalAsCString(nStopReason); |
| if (pSignal) { |
| const CMICmnMIValueConst miValueConst2(pSignal); |
| const CMICmnMIValueResult miValueResult2("signal-name", miValueConst2); |
| miOutOfBandRecord.Add(miValueResult2); |
| } else { |
| const CMIUtilString strSignal( |
| CMIUtilString::Format("%" PRIu64, nStopReason)); |
| const CMICmnMIValueConst miValueConst2(strSignal); |
| const CMICmnMIValueResult miValueResult2("signal", miValueConst2); |
| miOutOfBandRecord.Add(miValueResult2); |
| } |
| const CMIUtilString strThreadId(CMIUtilString::Format( |
| "%d", sbProcess.GetSelectedThread().GetIndexID())); |
| const CMICmnMIValueConst miValueConst3(strThreadId); |
| const CMICmnMIValueResult miValueResult3("thread-id", miValueConst3); |
| miOutOfBandRecord.Add(miValueResult3); |
| const CMICmnMIValueConst miValueConst4("all"); |
| const CMICmnMIValueResult miValueResult4("stopped-threads", miValueConst4); |
| miOutOfBandRecord.Add(miValueResult4); |
| bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| } |
| return bOk; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Asynchronous event handler for LLDB Process stop exception. |
| // Type: Method. |
| // Args: None. |
| // Return: MIstatus::success - Functional succeeded. |
| // MIstatus::failure - Functional failed. |
| // Throws: None. |
| //-- |
| bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopException() { |
| const lldb::SBProcess sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| lldb::SBThread sbThread = sbProcess.GetSelectedThread(); |
| const size_t nStopDescriptionLen = sbThread.GetStopDescription(nullptr, 0); |
| std::unique_ptr<char[]> apStopDescription(new char[nStopDescriptionLen]); |
| sbThread.GetStopDescription(apStopDescription.get(), nStopDescriptionLen); |
| |
| // MI print |
| // "*stopped,reason=\"exception-received\",exception=\"%s\",thread-id=\"%d\",stopped-threads=\"all\"" |
| const CMICmnMIValueConst miValueConst("exception-received"); |
| const CMICmnMIValueResult miValueResult("reason", miValueConst); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResult); |
| const CMIUtilString strReason(apStopDescription.get()); |
| const CMICmnMIValueConst miValueConst2(strReason); |
| const CMICmnMIValueResult miValueResult2("exception", miValueConst2); |
| miOutOfBandRecord.Add(miValueResult2); |
| const CMIUtilString strThreadId( |
| CMIUtilString::Format("%d", sbThread.GetIndexID())); |
| const CMICmnMIValueConst miValueConst3(strThreadId); |
| const CMICmnMIValueResult miValueResult3("thread-id", miValueConst3); |
| miOutOfBandRecord.Add(miValueResult3); |
| const CMICmnMIValueConst miValueConst4("all"); |
| const CMICmnMIValueResult miValueResult4("stopped-threads", miValueConst4); |
| miOutOfBandRecord.Add(miValueResult4); |
| bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| |
| 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 sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| lldb::SBThread thread = sbProcess.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, CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_NoArguments, |
| 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() { |
| // 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 sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| const MIuint64 brkPtId = |
| sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0); |
| lldb::SBBreakpoint brkPt = |
| CMICmnLLDBDebugSessionInfo::Instance().GetTarget().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 sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| lldb::SBThread thread = sbProcess.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); |
| miOutOfBandRecord.Add(miValueResult2); |
| const CMIUtilString strBkp(CMIUtilString::Format("%d", vBrkPtId)); |
| const CMICmnMIValueConst miValueConst3(strBkp); |
| CMICmnMIValueResult miValueResult3("bkptno", miValueConst3); |
| miOutOfBandRecord.Add(miValueResult3); |
| const CMICmnMIValueConst miValueConst4("{}"); |
| const CMICmnMIValueResult miValueResult4("frame", miValueConst4); |
| miOutOfBandRecord.Add(miValueResult4); |
| const CMIUtilString strThreadId( |
| CMIUtilString::Format("%d", vBrkPt.GetThreadIndex())); |
| const CMICmnMIValueConst miValueConst5(strThreadId); |
| const CMICmnMIValueResult miValueResult5("thread-id", miValueConst5); |
| miOutOfBandRecord.Add(miValueResult5); |
| const CMICmnMIValueConst miValueConst6("all"); |
| const CMICmnMIValueResult miValueResult6("stopped-threads", miValueConst6); |
| miOutOfBandRecord.Add(miValueResult6); |
| bOk = bOk && MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| return bOk; |
| } |
| |
| CMICmnLLDBDebugSessionInfo &rSessionInfo( |
| CMICmnLLDBDebugSessionInfo::Instance()); |
| |
| // MI print |
| // "*stopped,reason=\"breakpoint-hit\",disp=\"del\",bkptno=\"%d\",frame={addr=\"0x%016" |
| // PRIx64 |
| // "\",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); |
| miOutOfBandRecord.Add(miValueResultA); |
| const CMIUtilString strBkp(CMIUtilString::Format("%d", vBrkPtId)); |
| const CMICmnMIValueConst miValueConstB(strBkp); |
| CMICmnMIValueResult miValueResultB("bkptno", miValueConstB); |
| miOutOfBandRecord.Add(miValueResultB); |
| |
| // frame={addr=\"0x%016" PRIx64 |
| // "\",func=\"%s\",args=[],file=\"%s\",fullname=\"%s\",line=\"%d\"} |
| if (bOk) { |
| CMICmnMIValueTuple miValueTuple; |
| bOk = bOk && |
| rSessionInfo.MIResponseFormFrameInfo( |
| thread, 0, |
| CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_AllArguments, |
| miValueTuple); |
| const CMICmnMIValueResult miValueResult8("frame", miValueTuple); |
| 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); |
| miOutOfBandRecord.Add(miValueResult8); |
| } |
| if (bOk) { |
| const CMICmnMIValueConst miValueConst9("all"); |
| const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); |
| miOutOfBandRecord.Add(miValueResult9); |
| bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| } |
| |
| 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() { |
| bool bOk = true; |
| lldb::SBProcess sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| lldb::SBThread thread = sbProcess.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); |
| miOutOfBandRecord.Add(miValueResult2); |
| bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| return bOk; |
| } |
| |
| CMICmnLLDBDebugSessionInfo &rSessionInfo( |
| CMICmnLLDBDebugSessionInfo::Instance()); |
| |
| // MI print |
| // "*stopped,reason=\"end-stepping-range\",frame={addr=\"0x%016" PRIx64 |
| // "\",func=\"%s\",args=[\"%s\"],file=\"%s\",fullname=\"%s\",line=\"%d\"},thread-id=\"%d\",stopped-threads=\"all\"" |
| |
| // Function args |
| CMICmnMIValueTuple miValueTuple; |
| if (!rSessionInfo.MIResponseFormFrameInfo( |
| thread, 0, CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_AllArguments, |
| 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); |
| miOutOfBandRecord.Add(miValueResult2); |
| |
| // Add to MI thread-id=\"%d\",stopped-threads=\"all\" |
| const CMIUtilString strThreadId( |
| CMIUtilString::Format("%d", thread.GetIndexID())); |
| const CMICmnMIValueConst miValueConst8(strThreadId); |
| const CMICmnMIValueResult miValueResult8("thread-id", miValueConst8); |
| miOutOfBandRecord.Add(miValueResult8); |
| |
| const CMICmnMIValueConst miValueConst9("all"); |
| const CMICmnMIValueResult miValueResult9("stopped-threads", miValueConst9); |
| miOutOfBandRecord.Add(miValueResult9); |
| bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| |
| 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() { |
| lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance() |
| .GetDebugger() |
| .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() { |
| CMICmnMIValueConst miValueConst("all"); |
| CMICmnMIValueResult miValueResult("thread-id", miValueConst); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_Running, miValueResult); |
| bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| bOk = bOk && CMICmnStreamStdout::WritePrompt(); |
| |
| 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() { |
| 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); |
| miOutOfBandRecord.Add(miValueResult2); |
| bool 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); |
| 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 && CMICmnStreamStdout::WritePrompt(); |
| |
| 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() { |
| CMIUtilString text; |
| std::unique_ptr<char[]> apStdoutBuffer(new char[1024]); |
| lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance() |
| .GetDebugger() |
| .GetSelectedTarget() |
| .GetProcess(); |
| while (1) { |
| const size_t nBytes = process.GetSTDOUT(apStdoutBuffer.get(), 1024); |
| text.append(apStdoutBuffer.get(), nBytes); |
| |
| while (1) { |
| const size_t nNewLine = text.find('\n'); |
| if (nNewLine == std::string::npos) |
| break; |
| |
| const CMIUtilString line(text.substr(0, nNewLine + 1)); |
| text.erase(0, nNewLine + 1); |
| const bool bEscapeQuotes(true); |
| CMICmnMIValueConst miValueConst(line.Escape(bEscapeQuotes)); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, miValueConst); |
| const bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| if (!bOk) |
| return MIstatus::failure; |
| } |
| |
| if (nBytes == 0) { |
| if (!text.empty()) { |
| const bool bEscapeQuotes(true); |
| CMICmnMIValueConst miValueConst(text.Escape(bEscapeQuotes)); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, |
| miValueConst); |
| return MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| } |
| break; |
| } |
| } |
| |
| return MIstatus::success; |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // 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() { |
| CMIUtilString text; |
| std::unique_ptr<char[]> apStderrBuffer(new char[1024]); |
| lldb::SBProcess process = CMICmnLLDBDebugSessionInfo::Instance() |
| .GetDebugger() |
| .GetSelectedTarget() |
| .GetProcess(); |
| while (1) { |
| const size_t nBytes = process.GetSTDERR(apStderrBuffer.get(), 1024); |
| text.append(apStderrBuffer.get(), nBytes); |
| |
| while (1) { |
| const size_t nNewLine = text.find('\n'); |
| if (nNewLine == std::string::npos) |
| break; |
| |
| const CMIUtilString line(text.substr(0, nNewLine + 1)); |
| const bool bEscapeQuotes(true); |
| CMICmnMIValueConst miValueConst(line.Escape(bEscapeQuotes)); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, miValueConst); |
| const bool bOk = MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| if (!bOk) |
| return MIstatus::failure; |
| } |
| |
| if (nBytes == 0) { |
| if (!text.empty()) { |
| const bool bEscapeQuotes(true); |
| CMICmnMIValueConst miValueConst(text.Escape(bEscapeQuotes)); |
| CMICmnMIOutOfBandRecord miOutOfBandRecord( |
| CMICmnMIOutOfBandRecord::eOutOfBand_TargetStreamOutput, |
| miValueConst); |
| return MiOutOfBandRecordToStdout(miOutOfBandRecord); |
| } |
| 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() { |
| CMICmnLLDBDebugSessionInfo &rSessionInfo( |
| CMICmnLLDBDebugSessionInfo::Instance()); |
| lldb::SBProcess sbProcess = rSessionInfo.GetProcess(); |
| if (!sbProcess.IsValid()) |
| return MIstatus::success; |
| |
| // Check for created threads |
| const MIuint nThread = sbProcess.GetNumThreads(); |
| for (MIuint i = 0; i < nThread; i++) { |
| // GetThreadAtIndex() uses a base 0 index |
| // GetThreadByIndexID() uses a base 1 index |
| lldb::SBThread thread = sbProcess.GetThreadAtIndex(i); |
| if (!thread.IsValid()) |
| continue; |
| |
| const MIuint threadIndexID = thread.GetIndexID(); |
| const bool bFound = |
| std::find(rSessionInfo.m_vecActiveThreadId.cbegin(), |
| rSessionInfo.m_vecActiveThreadId.cend(), |
| threadIndexID) != rSessionInfo.m_vecActiveThreadId.end(); |
| if (!bFound) { |
| rSessionInfo.m_vecActiveThreadId.push_back(threadIndexID); |
| |
| // Form MI "=thread-created,id=\"%d\",group-id=\"i1\"" |
| const CMIUtilString strValue(CMIUtilString::Format("%d", threadIndexID)); |
| 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); |
| miOutOfBand.Add(miValueResult2); |
| bool bOk = MiOutOfBandRecordToStdout(miOutOfBand); |
| if (!bOk) |
| return MIstatus::failure; |
| } |
| } |
| |
| lldb::SBThread currentThread = sbProcess.GetSelectedThread(); |
| if (currentThread.IsValid()) { |
| const MIuint currentThreadIndexID = currentThread.GetIndexID(); |
| if (rSessionInfo.m_currentSelectedThread != currentThreadIndexID) { |
| rSessionInfo.m_currentSelectedThread = currentThreadIndexID; |
| |
| // Form MI "=thread-selected,id=\"%d\"" |
| const CMIUtilString strValue( |
| CMIUtilString::Format("%d", currentThreadIndexID)); |
| 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::iterator it = |
| rSessionInfo.m_vecActiveThreadId.begin(); |
| while (it != rSessionInfo.m_vecActiveThreadId.end()) { |
| const MIuint threadIndexID = *it; |
| lldb::SBThread thread = sbProcess.GetThreadByIndexID(threadIndexID); |
| if (!thread.IsValid()) { |
| // Form MI "=thread-exited,id=\"%ld\",group-id=\"i1\"" |
| const CMIUtilString strValue(CMIUtilString::Format("%ld", threadIndexID)); |
| 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); |
| miOutOfBand.Add(miValueResult2); |
| bool bOk = MiOutOfBandRecordToStdout(miOutOfBand); |
| if (!bOk) |
| return MIstatus::failure; |
| |
| // Remove current thread from cache and get next |
| it = rSessionInfo.m_vecActiveThreadId.erase(it); |
| } else |
| // Next |
| ++it; |
| } |
| |
| return CMICmnStreamStdout::WritePrompt(); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // 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); |
| } |
| |
| //++ |
| //------------------------------------------------------------------------------------ |
| // Details: Initialize the member variables with the signal values in this |
| // process |
| // file. |
| // Type: Method. |
| // Args: None |
| // Return: Noen |
| // Throws: None. |
| //-- |
| void CMICmnLLDBDebuggerHandleEvents::InitializeSignals() { |
| if (!m_bSignalsInitialized) { |
| lldb::SBProcess sbProcess = |
| CMICmnLLDBDebugSessionInfo::Instance().GetProcess(); |
| if (sbProcess.IsValid()) { |
| lldb::SBUnixSignals unix_signals = sbProcess.GetUnixSignals(); |
| m_SIGINT = unix_signals.GetSignalNumberFromName("SIGINT"); |
| m_SIGSTOP = unix_signals.GetSignalNumberFromName("SIGSTOP"); |
| m_SIGSEGV = unix_signals.GetSignalNumberFromName("SIGSEGV"); |
| m_SIGTRAP = unix_signals.GetSignalNumberFromName("SIGTRAP"); |
| m_bSignalsInitialized = true; |
| } |
| } |
| } |