Skip to content

Commit

Permalink
Handle watchpoints-related stop reasons
Browse files Browse the repository at this point in the history
This commit allows LLDB-MI to send `[read/access-]watchpoint-trigger`
out of band records. `value={...}` part of the record is not printed due
to inability to get the old value.
  • Loading branch information
ilya-nozhkin authored and tkrasnukha committed Jan 13, 2021
1 parent a6cabcc commit 65ec0a8
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 8 deletions.
112 changes: 108 additions & 4 deletions src/MICmnLLDBDebuggerHandleEvents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ bool CMICmnLLDBDebuggerHandleEvents::HandleEventSBBreakpointLocationsAdded(
// MIstatus::failure - Functionality failed.
// Throws: None.
//--
template <class T>
template <class T, class>
bool CMICmnLLDBDebuggerHandleEvents::HandleEventStoppointCmn(T &vrStopPt) {
if (!vrStopPt.IsValid())
return MIstatus::success;
Expand Down Expand Up @@ -486,7 +486,7 @@ void FillInPointTypeDependentInfo(
// MIstatus::failure - Functionality failed.
// Throws: None.
//--
template <class T>
template <class T, class>
bool CMICmnLLDBDebuggerHandleEvents::HandleEventStoppointAdded(T &vrStopPt) {
if (!vrStopPt.IsValid())
return MIstatus::failure;
Expand Down Expand Up @@ -596,7 +596,7 @@ CMICmnLLDBDebuggerHandleEvents::HandleEventStoppointAdded(lldb::SBBreakpoint &);
template bool
CMICmnLLDBDebuggerHandleEvents::HandleEventStoppointAdded(lldb::SBWatchpoint &);

template <class T>
template <class T, class>
bool CMICmnLLDBDebuggerHandleEvents::RemoveStoppointInfo(T &vrStopPt) {
auto eType = std::is_same<std::remove_cv_t<T>, lldb::SBBreakpoint>::value
? CMICmnLLDBDebugSessionInfo::eStoppointType_Breakpoint
Expand Down Expand Up @@ -1140,6 +1140,7 @@ bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStateStopped(
break;
case lldb::eStopReasonWatchpoint:
pEventType = "eStopReasonWatchpoint";
bOk = HandleProcessEventStopReasonWatchpoint();
break;
case lldb::eStopReasonSignal:
pEventType = "eStopReasonSignal";
Expand Down Expand Up @@ -1433,12 +1434,41 @@ bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonBreakpoint() {
const MIuint64 brkPtId =
sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0);
lldb::SBBreakpoint brkPt =
CMICmnLLDBDebugSessionInfo::Instance().GetTarget().GetBreakpointAtIndex(
CMICmnLLDBDebugSessionInfo::Instance().GetTarget().FindBreakpointByID(
(MIuint)brkPtId);

return MiStoppedAtBreakPoint(brkPtId, brkPt);
}

//++
// Details: Asynchronous event handler for LLDB Process stop reason watchpoint.
// Type: Method.
// Args: None.
// Return: MIstatus::success - Functionality succeeded.
// MIstatus::failure - Functionality failed.
// Throws: None.
//--
bool CMICmnLLDBDebuggerHandleEvents::HandleProcessEventStopReasonWatchpoint() {
// 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),
__func__, rErrMsg.c_str()));
return MIstatus::failure;
}

lldb::SBProcess sbProcess =
CMICmnLLDBDebugSessionInfo::Instance().GetProcess();
const auto watchPtId = static_cast<uint32_t>(
sbProcess.GetSelectedThread().GetStopReasonDataAtIndex(0U));
lldb::SBWatchpoint watchPt =
CMICmnLLDBDebugSessionInfo::Instance().GetTarget().FindWatchpointByID(
watchPtId);

return MiStoppedAtWatchpoint(watchPt);
}

//++
// Details: Form the MI Out-of-band response for stopped reason on hitting a
// break point.
Expand Down Expand Up @@ -1537,6 +1567,80 @@ bool CMICmnLLDBDebuggerHandleEvents::MiStoppedAtBreakPoint(
return MIstatus::success;
}

//++
// Details: Form the MI Out-of-band response for stopped reason on hitting a
// watch point.
// Type: Method.
// Args: vrWatchPtId - (R) The LLDB watch point.
// Return: MIstatus::success - Functionality succeeded.
// MIstatus::failure - Functionality failed.
// Throws: None.
//--
bool CMICmnLLDBDebuggerHandleEvents::MiStoppedAtWatchpoint(
lldb::SBWatchpoint &vrWatchPt) {
CMICmnLLDBDebugSessionInfo &rSessionInfo(
CMICmnLLDBDebugSessionInfo::Instance());

auto nGdbBrkPtId = rSessionInfo.GetOrCreateMiStopPtId(
vrWatchPt.GetID(), CMICmnLLDBDebugSessionInfo::eStoppointType_Watchpoint);

CMICmnLLDBDebugSessionInfo::SStopPtInfo sStopPtInfo;
if (!rSessionInfo.RecordStopPtInfoGet(nGdbBrkPtId, sStopPtInfo))
return MIstatus::failure;

const char *reason = sStopPtInfo.m_watchPtRead
? sStopPtInfo.m_watchPtWrite
? "access-watchpoint-trigger"
: "read-watchpoint-trigger"
: "watchpoint-trigger";

const CMICmnMIValueConst miValueConstReason(reason);
const CMICmnMIValueResult miValueResultReason("reason", miValueConstReason);
CMICmnMIOutOfBandRecord miOutOfBandRecord(
CMICmnMIOutOfBandRecord::eOutOfBand_Stopped, miValueResultReason);

// value={...} is not supported yet because it is not obvious how to get the
// old value.

// wpt={...}
CMICmnMIValueResult miValueResultWpt;
rSessionInfo.MIResponseFormWatchPtInfo(sStopPtInfo, miValueResultWpt);
miOutOfBandRecord.Add(miValueResultWpt);

// frame={...}
lldb::SBThread thread = rSessionInfo.GetProcess().GetSelectedThread();
if (thread.GetNumFrames() > 0) {
CMICmnMIValueTuple miValueTupleFrame;
if (!rSessionInfo.MIResponseFormFrameInfo(
thread, 0,
CMICmnLLDBDebugSessionInfo::eFrameInfoFormat_AllArguments,
miValueTupleFrame))
return MIstatus::failure;

const CMICmnMIValueResult miValueResultFrame("frame", miValueTupleFrame);
miOutOfBandRecord.Add(miValueResultFrame);
}

// thread-id=...
const CMIUtilString strThreadId(
CMIUtilString::Format("%d", thread.GetIndexID()));
const CMICmnMIValueConst miValueConstThread(strThreadId);
const CMICmnMIValueResult miValueResultThread("thread-id",
miValueConstThread);
miOutOfBandRecord.Add(miValueResultThread);

// stopped-threads=...
const CMICmnMIValueConst miValueConstStopped("all");
const CMICmnMIValueResult miValueResultStopped("stopped-threads",
miValueConstStopped);
miOutOfBandRecord.Add(miValueResultStopped);

if (!MiOutOfBandRecordToStdout(miOutOfBandRecord))
return MIstatus::failure;

return CMICmnStreamStdout::WritePrompt();
}

//++
// Details: Asynchronous event handler for LLDB Process stop reason trace.
// Type: Method.
Expand Down
20 changes: 17 additions & 3 deletions src/MICmnLLDBDebuggerHandleEvents.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#pragma once

// Third party headers:
#include <type_traits>

// In-house headers:
#include "MICmnBase.h"
#include "MICmnMIValueList.h"
Expand Down Expand Up @@ -53,9 +56,18 @@ class CMICmnLLDBDebuggerHandleEvents
bool HandleEventSBBreakPoint(const lldb::SBEvent &vEvent);
bool HandleEventSBWatchpoint(const lldb::SBEvent &vEvent);
bool HandleEventSBBreakpointLocationsAdded(const lldb::SBEvent &vEvent);
template <class T> bool HandleEventStoppointCmn(T &vrStopPt);
template <class T> bool HandleEventStoppointAdded(T &vrStopPt);
template <class T> bool RemoveStoppointInfo(T &vrStopPt);
template <class T, class = std::enable_if_t<
std::is_same<T, lldb::SBBreakpoint>::value ||
std::is_same<T, lldb::SBWatchpoint>::value>>
bool HandleEventStoppointCmn(T &vrStopPt);
template <class T, class = std::enable_if_t<
std::is_same<T, lldb::SBBreakpoint>::value ||
std::is_same<T, lldb::SBWatchpoint>::value>>
bool HandleEventStoppointAdded(T &vrStopPt);
template <class T, class = std::enable_if_t<
std::is_same<T, lldb::SBBreakpoint>::value ||
std::is_same<T, lldb::SBWatchpoint>::value>>
bool RemoveStoppointInfo(T &vrStopPt);
bool HandleEventSBProcess(const lldb::SBEvent &vEvent);
bool HandleEventSBTarget(const lldb::SBEvent &vEvent);
bool HandleEventSBThread(const lldb::SBEvent &vEvent);
Expand All @@ -69,6 +81,7 @@ class CMICmnLLDBDebuggerHandleEvents
bool &vwrbShouldBrk);
bool HandleProcessEventStopReasonTrace();
bool HandleProcessEventStopReasonBreakpoint();
bool HandleProcessEventStopReasonWatchpoint();
bool HandleProcessEventStopSignal(const lldb::SBEvent &vrEvent);
bool HandleProcessEventStopException();
bool HandleProcessEventStateSuspended(const lldb::SBEvent &vEvent);
Expand All @@ -84,6 +97,7 @@ class CMICmnLLDBDebuggerHandleEvents
MiOutOfBandRecordToStdout(const CMICmnMIOutOfBandRecord &vrMiResultRecord);
bool MiStoppedAtBreakPoint(const MIuint64 vBrkPtId,
const lldb::SBBreakpoint &vBrkPt);
bool MiStoppedAtWatchpoint(lldb::SBWatchpoint &vrWatchPt);
bool TextToStdout(const CMIUtilString &vrTxt);
bool TextToStderr(const CMIUtilString &vrTxt);
bool UpdateSelectedThread();
Expand Down
2 changes: 1 addition & 1 deletion src/MICmnResources.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ const CMICmnResources::SRsrcTextData
{IDS_LLDBOUTOFBAND_ERR_FRAME_INFO_GET,
"LLDB Out-of-band. %s(). Failed to retrieve frame information"},
{IDS_LLDBOUTOFBAND_ERR_SETNEWDRIVERSTATE,
"LLDB Out-of-band. %s. Event handler tried to set new MI Driver "
"LLDB Out-of-band. %s(). Event handler tried to set new MI Driver "
"running state and failed. %s"},
{IDS_LLDBOUTOFBAND_ERR_STOPPT_CNT_EXCEEDED,
"LLDB Out-of-band. '%s'. Number of valid stoppoint exceeded %" PRIu64
Expand Down

0 comments on commit 65ec0a8

Please sign in to comment.