Skip to content

Commit be55209

Browse files
committed
Make breakpoint stop reason more accurate
1 parent e949d2e commit be55209

File tree

5 files changed

+108
-64
lines changed

5 files changed

+108
-64
lines changed

lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py

+32
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,35 @@ def test_functionality(self):
171171
self.continue_to_next_stop()
172172
x_val = self.dap_server.get_local_variable_value("x")
173173
self.assertEqual(x_val, "10")
174+
175+
@skipIfWindows
176+
def test_breakpoint_reason(self):
177+
"""Tests setting data breakpoints on variable. Verify that the breakpoint has the correct reason and description in the stopped event."""
178+
program = self.getBuildArtifact("a.out")
179+
self.build_and_launch(program)
180+
source = "main.cpp"
181+
first_loop_break_line = line_number(source, "// first loop breakpoint")
182+
self.set_source_breakpoints(source, [first_loop_break_line])
183+
self.continue_to_next_stop()
184+
self.dap_server.get_local_variables()
185+
# Test write watchpoints on x, arr[2]
186+
response_x = self.dap_server.request_dataBreakpointInfo(1, "x")
187+
# Test response from dataBreakpointInfo request.
188+
self.assertEqual(response_x["body"]["dataId"].split("/")[1], "4")
189+
self.assertEqual(response_x["body"]["accessTypes"], self.accessTypes)
190+
dataBreakpoints = [
191+
{"dataId": response_x["body"]["dataId"], "accessType": "write"},
192+
]
193+
set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints)
194+
self.assertEqual(
195+
set_response["body"]["breakpoints"],
196+
[{"verified": True}],
197+
)
198+
199+
stopped_events = self.continue_to_next_stop()
200+
self.assertEqual(len(stopped_events), 1)
201+
stopped_event = stopped_events[0]
202+
self.assertEqual(stopped_event["body"]["reason"], "data breakpoint")
203+
self.assertEqual(stopped_event["body"]["description"], "data breakpoint 1.1")
204+
x_val = self.dap_server.get_local_variable_value("x")
205+
self.assertEqual(x_val, "2")

lldb/tools/lldb-dap/DAP.cpp

-58
Original file line numberDiff line numberDiff line change
@@ -183,17 +183,6 @@ ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const std::string &filter) {
183183
return nullptr;
184184
}
185185

186-
ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) {
187-
// See comment in the other GetExceptionBreakpoint().
188-
PopulateExceptionBreakpoints();
189-
190-
for (auto &bp : *exception_breakpoints) {
191-
if (bp.bp.GetID() == bp_id)
192-
return &bp;
193-
}
194-
return nullptr;
195-
}
196-
197186
llvm::Error DAP::ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr) {
198187
in = lldb::SBFile(std::fopen(DEV_NULL, "r"), /*transfer_ownership=*/true);
199188

@@ -444,27 +433,6 @@ DAP::SendFormattedOutput(OutputType o, const char *format, ...) {
444433
o, llvm::StringRef(buffer, std::min<int>(actual_length, sizeof(buffer))));
445434
}
446435

447-
ExceptionBreakpoint *DAP::GetExceptionBPFromStopReason(lldb::SBThread &thread) {
448-
const auto num = thread.GetStopReasonDataCount();
449-
// Check to see if have hit an exception breakpoint and change the
450-
// reason to "exception", but only do so if all breakpoints that were
451-
// hit are exception breakpoints.
452-
ExceptionBreakpoint *exc_bp = nullptr;
453-
for (size_t i = 0; i < num; i += 2) {
454-
// thread.GetStopReasonDataAtIndex(i) will return the bp ID and
455-
// thread.GetStopReasonDataAtIndex(i+1) will return the location
456-
// within that breakpoint. We only care about the bp ID so we can
457-
// see if this is an exception breakpoint that is getting hit.
458-
lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i);
459-
exc_bp = GetExceptionBreakpoint(bp_id);
460-
// If any breakpoint is not an exception breakpoint, then stop and
461-
// report this as a normal breakpoint
462-
if (exc_bp == nullptr)
463-
return nullptr;
464-
}
465-
return exc_bp;
466-
}
467-
468436
lldb::SBThread DAP::GetLLDBThread(const llvm::json::Object &arguments) {
469437
auto tid = GetInteger<int64_t>(arguments, "threadId")
470438
.value_or(LLDB_INVALID_THREAD_ID);
@@ -1074,32 +1042,6 @@ DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) {
10741042
return inst_bp;
10751043
}
10761044

1077-
FunctionBreakpoint *DAP::GetFunctionBPFromStopReason(lldb::SBThread &thread) {
1078-
const auto num = thread.GetStopReasonDataCount();
1079-
FunctionBreakpoint *func_bp = nullptr;
1080-
for (size_t i = 0; i < num; i += 2) {
1081-
// thread.GetStopReasonDataAtIndex(i) will return the bp ID and
1082-
// thread.GetStopReasonDataAtIndex(i+1) will return the location
1083-
// within that breakpoint. We only care about the bp ID so we can
1084-
// see if this is an function breakpoint that is getting hit.
1085-
lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i);
1086-
func_bp = GetFunctionBreakPoint(bp_id);
1087-
// If any breakpoint is not an function breakpoint, then stop and
1088-
// report this as a normal breakpoint
1089-
if (func_bp == nullptr)
1090-
return nullptr;
1091-
}
1092-
return func_bp;
1093-
}
1094-
1095-
FunctionBreakpoint *DAP::GetFunctionBreakPoint(const lldb::break_id_t bp_id) {
1096-
for (auto &bp : function_breakpoints) {
1097-
if (bp.second.bp.GetID() == bp_id)
1098-
return &bp.second;
1099-
}
1100-
return nullptr;
1101-
}
1102-
11031045
lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) {
11041046
switch (variablesReference) {
11051047
case VARREF_LOCALS:

lldb/tools/lldb-dap/DAP.h

+60
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,66 @@ struct DAP {
392392

393393
void SetThreadFormat(llvm::StringRef format);
394394

395+
template <typename BreakpointType>
396+
BreakpointType *GetBreakpointFromStopReason(lldb::SBThread &thread) {
397+
// Check to see if have hit the <BreakpointType> breakpoint and change the
398+
// reason accordingly, but only do so if all breakpoints that were
399+
// hit are of <BreakpointType>.
400+
const auto num = thread.GetStopReasonDataCount();
401+
BreakpointType *bp = nullptr;
402+
for (size_t i = 0; i < num; i += 2) {
403+
lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i);
404+
// If any breakpoint is not the <BreakpointType>, then stop and
405+
// report this as a normal breakpoint
406+
bp = GetBreakpoint<BreakpointType>(bp_id);
407+
if (bp == nullptr)
408+
return nullptr;
409+
}
410+
return bp;
411+
}
412+
413+
template <typename BreakpointType>
414+
BreakpointType *GetBreakpoint(const lldb::break_id_t bp_id);
415+
416+
template <>
417+
FunctionBreakpoint *
418+
GetBreakpoint<FunctionBreakpoint>(const lldb::break_id_t bp_id) {
419+
for (auto &bp : function_breakpoints) {
420+
if (bp.second.bp.GetID() == bp_id)
421+
return &bp.second;
422+
}
423+
return nullptr;
424+
}
425+
426+
template <>
427+
InstructionBreakpoint *
428+
GetBreakpoint<InstructionBreakpoint>(const lldb::break_id_t bp_id) {
429+
for (auto &bp : instruction_breakpoints) {
430+
if (bp.second.bp.GetID() == bp_id)
431+
return &bp.second;
432+
}
433+
return nullptr;
434+
}
435+
436+
template <>
437+
ExceptionBreakpoint *
438+
GetBreakpoint<ExceptionBreakpoint>(const lldb::break_id_t bp_id) {
439+
// See comment in the other GetExceptionBreakpoint().
440+
PopulateExceptionBreakpoints();
441+
442+
for (auto &bp : *exception_breakpoints) {
443+
if (bp.bp.GetID() == bp_id)
444+
return &bp;
445+
}
446+
return nullptr;
447+
}
448+
449+
FunctionBreakpoint *GetFunctionBPFromStopReason(lldb::SBThread &thread);
450+
451+
FunctionBreakpoint *GetFunctionBreakPoint(const lldb::break_id_t bp_id);
452+
453+
void WaitWorkerThreadsToExit();
454+
395455
private:
396456
// Send the JSON in "json_str" to the "out" stream. Correctly send the
397457
// "Content-Length:" field followed by the length, followed by the raw

lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,8 @@ void ExceptionInfoRequestHandler::operator()(
123123
if (stopReason == lldb::eStopReasonSignal)
124124
body.try_emplace("exceptionId", "signal");
125125
else if (stopReason == lldb::eStopReasonBreakpoint) {
126-
ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread);
126+
ExceptionBreakpoint *exc_bp =
127+
dap.GetBreakpointFromStopReason<ExceptionBreakpoint>(thread);
127128
if (exc_bp) {
128129
EmplaceSafeString(body, "exceptionId", exc_bp->filter);
129130
EmplaceSafeString(body, "description", exc_bp->label);

lldb/tools/lldb-dap/JSONUtils.cpp

+14-5
Original file line numberDiff line numberDiff line change
@@ -962,19 +962,20 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread,
962962
body.try_emplace("reason", "step");
963963
break;
964964
case lldb::eStopReasonBreakpoint: {
965-
ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread);
965+
ExceptionBreakpoint *exc_bp =
966+
dap.GetBreakpointFromStopReason<ExceptionBreakpoint>(thread);
966967
if (exc_bp) {
967968
body.try_emplace("reason", "exception");
968969
EmplaceSafeString(body, "description", exc_bp->label);
969970
} else {
970-
std::string reason = "breakpoint";
971+
llvm::StringRef reason = "breakpoint";
971972
InstructionBreakpoint *inst_bp =
972-
dap.GetInstructionBPFromStopReason(thread);
973+
dap.GetBreakpointFromStopReason<InstructionBreakpoint>(thread);
973974
if (inst_bp) {
974975
reason = "instruction breakpoint";
975976
} else {
976977
FunctionBreakpoint *function_bp =
977-
dap.GetFunctionBPFromStopReason(thread);
978+
dap.GetBreakpointFromStopReason<FunctionBreakpoint>(thread);
978979
if (function_bp) {
979980
reason = "function breakpoint";
980981
}
@@ -989,7 +990,15 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread,
989990
EmplaceSafeString(body, "description", desc_str);
990991
}
991992
} break;
992-
case lldb::eStopReasonWatchpoint:
993+
case lldb::eStopReasonWatchpoint: {
994+
// Assuming that all watch points are data breakpoints.
995+
body.try_emplace("reason", "data breakpoint");
996+
lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(0);
997+
lldb::break_id_t bp_loc_id = thread.GetStopReasonDataAtIndex(1);
998+
std::string desc_str =
999+
llvm::formatv("data breakpoint {0}.{1}", bp_id, bp_loc_id);
1000+
EmplaceSafeString(body, "description", desc_str);
1001+
} break;
9931002
case lldb::eStopReasonInstrumentation:
9941003
body.try_emplace("reason", "breakpoint");
9951004
break;

0 commit comments

Comments
 (0)