//===-- 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/SBEvent.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" #include "lldb/API/SBCommandInterpreter.h" #include "lldb/API/SBCommandReturnObject.h" #include "lldb/API/SBUnixSignals.h" #ifdef _WIN32 #include // For the ::_access() #else #include // For the ::access() #endif // _WIN32 // In-house headers: #include "MICmnLLDBDebuggerHandleEvents.h" #include "MICmnResources.h" #include "MICmnLog.h" #include "MICmnLLDBDebugger.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" #include "Platform.h" // for PATH_MAX //++ ------------------------------------------------------------------------------------ // 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::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; } 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 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; 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 : ("); 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 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 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 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; } } }