[Lldb-commits] [lldb] [lldb-dap] Preserve watchpoints from console (PR #215228)
Sergei Druzhkov via lldb-commits
lldb-commits at lists.llvm.org
Wed Aug 12 08:32:38 PDT 2026
https://github.com/DrSergei updated https://github.com/llvm/llvm-project/pull/215228
>From 6d1c6459ea0da00ea7073b455959f012b8510061 Mon Sep 17 00:00:00 2001
From: Sergei Druzhkov <serzhdruzhok at gmail.com>
Date: Mon, 10 Aug 2026 12:17:03 +0300
Subject: [PATCH 1/2] [lldb-dap] Preserve watchpoints from console
---
.../TestDAP_setDataBreakpoints.py | 41 +++++++++++++++++++
lldb/tools/lldb-dap/DAP.h | 1 +
.../SetDataBreakpointsRequestHandler.cpp | 8 +++-
lldb/tools/lldb-dap/Watchpoint.h | 2 +
4 files changed, 51 insertions(+), 1 deletion(-)
diff --git a/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py b/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py
index 225a947674351..bad48b0ffbf0f 100644
--- a/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py
+++ b/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py
@@ -182,6 +182,47 @@ def test_functionality(self):
stop_event = session.continue_to_breakpoint(self.expect_not_none(bp_cond.id))
self.assertEqual(session.top_frame_from(stop_event).locals["x"].value, "10")
+ @skipIfWindows
+ def test_console_watchpoint_preserved(self):
+ """Test setDataBreakpoints must not delete watchpoints created via the console."""
+ source = "main.cpp"
+ program = self.getBuildArtifact("a.out")
+ session = self.build_and_create_session()
+ first_loop_break_line = line_number(source, "// first loop breakpoint")
+ with session.configure(LaunchArgs(program)) as ctx:
+ session.resolve_source_breakpoints(source, [first_loop_break_line])
+ stop_event = session.verify_stopped_on_breakpoint(after=ctx.process_event)
+ top_frame = session.top_frame_from(stop_event)
+
+ # Create a watchpoint via the LLDB console.
+ resp_body = session.evaluate("`watchpoint set variable x", context="repl")
+ session.verify_evaluate(resp_body, matches=r".*Watchpoint created.*")
+ resp_body = session.evaluate("`watchpoint list", context="repl")
+ session.verify_evaluate(resp_body, matches=r".*Watchpoint 1:.*")
+
+ # Set a data breakpoint via DAP.
+ arr = top_frame.locals["arr"]
+ arr_var_ref = self.expect_not_none(arr.variablesReference)
+ response_arr_2 = session.data_breakpoint_info(
+ "[2]", arr_var_ref, top_frame.frame.id
+ )
+ arr_2_data_id = self.expect_not_none(response_arr_2.body.dataId)
+ set_response = session.set_data_breakpoints(
+ [DataBreakpoint(dataId=arr_2_data_id, accessType="write")]
+ )
+ [bp_arr_2] = set_response.body.breakpoints
+ self.assertTrue(bp_arr_2.verified)
+
+ resp_body = session.evaluate("`watchpoint list", context="repl")
+ session.verify_evaluate(resp_body, matches=r".*Watchpoint 1:.*")
+
+ session.set_data_breakpoints([])
+ resp_body = session.evaluate("`watchpoint list", context="repl")
+ session.verify_evaluate(resp_body, matches=r".*Watchpoint 1:.*")
+
+ session.evaluate("`watchpoint delete 1", context="repl")
+ session.continue_to_exit()
+
@skipIfWindows
def test_bytes(self):
"""Tests setting data breakpoints on memory range."""
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 3e2b1d4782147..c09b149ae3f53 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -107,6 +107,7 @@ struct DAP final : public DAPTransport::MessageHandler {
FunctionBreakpointMap function_breakpoints;
InstructionBreakpointMap instruction_breakpoints;
std::vector<ExceptionBreakpoint> exception_breakpoints;
+ std::vector<lldb::watch_id_t> data_breakpoints;
/// Map step in target id to list of function targets that user can choose.
llvm::DenseMap<lldb::addr_t, std::string> step_in_targets;
diff --git a/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp
index 1caaa23bf06f6..0540dfcd9d255 100644
--- a/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp
@@ -25,7 +25,10 @@ SetDataBreakpointsRequestHandler::Run(
const protocol::SetDataBreakpointsArguments &args) const {
std::vector<protocol::Breakpoint> response_breakpoints;
- dap.target.DeleteAllWatchpoints();
+ for (lldb::watch_id_t watch_id : dap.data_breakpoints)
+ dap.target.DeleteWatchpoint(watch_id);
+ dap.data_breakpoints.clear();
+
std::vector<Watchpoint> watchpoints;
for (const auto &bp : args.breakpoints)
watchpoints.emplace_back(dap, bp);
@@ -38,6 +41,9 @@ SetDataBreakpointsRequestHandler::Run(
if (addresses.count(iter->GetAddress()) == 0) {
iter->SetWatchpoint();
addresses.insert(iter->GetAddress());
+ if (lldb::watch_id_t watch_id = iter->GetID();
+ watch_id != LLDB_INVALID_WATCH_ID)
+ dap.data_breakpoints.push_back(watch_id);
}
}
for (auto wp : watchpoints)
diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h
index d943e1218bdcd..f73b89e674329 100644
--- a/lldb/tools/lldb-dap/Watchpoint.h
+++ b/lldb/tools/lldb-dap/Watchpoint.h
@@ -34,6 +34,8 @@ class Watchpoint : public BreakpointBase {
lldb::addr_t GetAddress() const { return m_addr; }
+ lldb::watch_id_t GetID() { return m_wp.GetID(); }
+
protected:
lldb::addr_t m_addr;
size_t m_size;
>From 9f479360cf0993483cc44cbfe6d48621c7c8c16c Mon Sep 17 00:00:00 2001
From: Sergei Druzhkov <serzhdruzhok at gmail.com>
Date: Wed, 12 Aug 2026 18:32:13 +0300
Subject: [PATCH 2/2] Fix review comments
---
.../lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py b/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py
index bad48b0ffbf0f..a3cf2bbb5b360 100644
--- a/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py
+++ b/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py
@@ -5,7 +5,7 @@
from lldbsuite.test.decorators import skipIfWasm, skipIfWindows
from lldbsuite.test.lldbtest import line_number
from lldbsuite.test.tools.lldb_dap import DAPTestCaseBase
-from lldbsuite.test.tools.lldb_dap.types import DataBreakpoint, LaunchArgs
+from lldbsuite.test.tools.lldb_dap.types import DataBreakpoint, LaunchArgs, StoppedReason
@skipIfWasm # data breakpoints map to watchpoints.
@@ -220,6 +220,10 @@ def test_console_watchpoint_preserved(self):
resp_body = session.evaluate("`watchpoint list", context="repl")
session.verify_evaluate(resp_body, matches=r".*Watchpoint 1:.*")
+ # Verify watchpoint from console.
+ stop_event = session.continue_to_next_stop(exp_reason=StoppedReason.DATA_BREAKPOINT)
+ self.assertEqual(session.top_frame_from(stop_event).locals["x"].value, "2")
+
session.evaluate("`watchpoint delete 1", context="repl")
session.continue_to_exit()
More information about the lldb-commits
mailing list