https://github.com/DrSergei updated https://github.com/llvm/llvm-project/pull/167237
>From 482c89dcee876a9d50b0ecc0a9e90482a2d9c94a Mon Sep 17 00:00:00 2001 From: Druzhkov Sergei <[email protected]> Date: Sat, 8 Nov 2025 22:41:39 +0300 Subject: [PATCH 1/6] [lldb-dap] Add data breakpoints for bytes --- .../test/tools/lldb-dap/dap_server.py | 20 ++++--- .../TestDAP_setDataBreakpoints.py | 52 +++++++++++++++++++ .../DataBreakpointInfoRequestHandler.cpp | 44 +++++++++++----- lldb/tools/lldb-dap/Handler/RequestHandler.h | 3 ++ 4 files changed, 100 insertions(+), 19 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index ac550962cfb85..aaa6f76001aa3 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -1234,16 +1234,24 @@ def request_setFunctionBreakpoints(self, names, condition=None, hitCondition=Non return response def request_dataBreakpointInfo( - self, variablesReference, name, frameIndex=0, threadId=None + self, variablesReference, name, size=None, frameIndex=0, threadId=None ): stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) if stackFrame is None: return [] - args_dict = { - "variablesReference": variablesReference, - "name": name, - "frameId": stackFrame["id"], - } + args_dict = ( + { + "variablesReference": variablesReference, + "name": name, + "frameId": stackFrame["id"], + } + if size is None + else { + "bytes": size, + "name": name, + "asAddress": True, + } + ) command_dict = { "command": "dataBreakpointInfo", "type": "request", 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 a542a318050dd..7afc42f89ce55 100644 --- a/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py @@ -171,3 +171,55 @@ def test_functionality(self): self.continue_to_next_stop() x_val = self.dap_server.get_local_variable_value("x") self.assertEqual(x_val, "10") + + @skipIfWindows + def test_bytes(self): + """Tests setting data breakpoints on memory range.""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = "main.cpp" + first_loop_break_line = line_number(source, "// first loop breakpoint") + self.set_source_breakpoints(source, [first_loop_break_line]) + self.continue_to_next_stop() + # Test write watchpoints on x, arr[2] + x = self.dap_server.get_local_variable("x") + response_x = self.dap_server.request_dataBreakpointInfo( + 0, x["memoryReference"], 4 + ) + arr_2 = self.dap_server.get_local_variable_child("arr", "[2]") + response_arr_2 = self.dap_server.request_dataBreakpointInfo( + 0, arr_2["memoryReference"], 4 + ) + + # Test response from dataBreakpointInfo request. + self.assertEqual( + response_x["body"]["dataId"].split("/"), [x["memoryReference"][2:], "4"] + ) + self.assertEqual(response_x["body"]["accessTypes"], self.accessTypes) + self.assertEqual( + response_arr_2["body"]["dataId"].split("/"), + [arr_2["memoryReference"][2:], "4"], + ) + self.assertEqual(response_arr_2["body"]["accessTypes"], self.accessTypes) + dataBreakpoints = [ + {"dataId": response_x["body"]["dataId"], "accessType": "write"}, + {"dataId": response_arr_2["body"]["dataId"], "accessType": "write"}, + ] + set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) + self.assertEqual( + set_response["body"]["breakpoints"], + [{"verified": True}, {"verified": True}], + ) + + self.continue_to_next_stop() + x_val = self.dap_server.get_local_variable_value("x") + i_val = self.dap_server.get_local_variable_value("i") + self.assertEqual(x_val, "2") + self.assertEqual(i_val, "1") + + self.continue_to_next_stop() + arr_2 = self.dap_server.get_local_variable_child("arr", "[2]") + i_val = self.dap_server.get_local_variable_value("i") + self.assertEqual(arr_2["value"], "42") + self.assertEqual(i_val, "2") + self.dap_server.request_setDataBreakpoint([]) diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp index 87b93fc999ecd..c55b165c6b783 100644 --- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp @@ -16,6 +16,20 @@ namespace lldb_dap { +static bool CheckAddress(DAP &dap, lldb::addr_t load_addr) { + lldb::SBMemoryRegionInfo region; + lldb::SBError err = + dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region); + // Only lldb-server supports "qMemoryRegionInfo". So, don't fail this + // request if SBProcess::GetMemoryRegionInfo returns error. + if (err.Success()) { + if (!(region.IsReadable() || region.IsWritable())) { + return false; + } + } + return true; +} + /// Obtains information on a possible data breakpoint that could be set on an /// expression or variable. Clients should only call this request if the /// corresponding capability supportsDataBreakpoints is true. @@ -23,7 +37,6 @@ llvm::Expected<protocol::DataBreakpointInfoResponseBody> DataBreakpointInfoRequestHandler::Run( const protocol::DataBreakpointInfoArguments &args) const { protocol::DataBreakpointInfoResponseBody response; - lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); lldb::SBValue variable = dap.variables.FindVariable( args.variablesReference.value_or(0), args.name); std::string addr, size; @@ -43,7 +56,8 @@ DataBreakpointInfoRequestHandler::Run( addr = llvm::utohexstr(load_addr); size = llvm::utostr(byte_size); } - } else if (args.variablesReference.value_or(0) == 0 && frame.IsValid()) { + } else if (lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); + args.variablesReference.value_or(0) == 0 && frame.IsValid()) { lldb::SBValue value = frame.EvaluateExpression(args.name.c_str()); if (value.GetError().Fail()) { lldb::SBError error = value.GetError(); @@ -58,17 +72,10 @@ DataBreakpointInfoRequestHandler::Run( if (data.IsValid()) { size = llvm::utostr(data.GetByteSize()); addr = llvm::utohexstr(load_addr); - lldb::SBMemoryRegionInfo region; - lldb::SBError err = - dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region); - // Only lldb-server supports "qMemoryRegionInfo". So, don't fail this - // request if SBProcess::GetMemoryRegionInfo returns error. - if (err.Success()) { - if (!(region.IsReadable() || region.IsWritable())) { - is_data_ok = false; - response.description = "memory region for address " + addr + - " has no read or write permissions"; - } + if (!CheckAddress(dap, load_addr)) { + is_data_ok = false; + response.description = "memory region for address " + addr + + " has no read or write permissions"; } } else { is_data_ok = false; @@ -76,6 +83,17 @@ DataBreakpointInfoRequestHandler::Run( "unable to get byte size for expression: " + args.name; } } + } else if (args.asAddress) { + size = llvm::utostr(args.bytes.value_or(1)); + if (llvm::StringRef(args.name).starts_with("0x")) + addr = args.name.substr(2); + else + addr = llvm::utohexstr(std::stoull(args.name)); + if (!CheckAddress(dap, std::stoull(addr, 0, 16))) { + is_data_ok = false; + response.description = "memory region for address " + addr + + " has no read or write permissions"; + } } else { is_data_ok = false; response.description = "variable not found: " + args.name; diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index bc22133d92453..c9cafd33327a8 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -432,6 +432,9 @@ class DataBreakpointInfoRequestHandler public: using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "dataBreakpointInfo"; } + FeatureSet GetSupportedFeatures() const override { + return {protocol::eAdapterFeatureDataBreakpointBytes}; + } llvm::Expected<protocol::DataBreakpointInfoResponseBody> Run(const protocol::DataBreakpointInfoArguments &args) const override; }; >From 36466ae461bb3fde20bc63f1570156ad4e1a6b4c Mon Sep 17 00:00:00 2001 From: Druzhkov Sergei <[email protected]> Date: Mon, 10 Nov 2025 22:18:40 +0300 Subject: [PATCH 2/6] Fix review comments --- .../test/tools/lldb-dap/dap_server.py | 20 +++++++------------ .../DataBreakpointInfoRequestHandler.cpp | 6 +++--- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index aaa6f76001aa3..1f31b800e2cd9 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -1239,19 +1239,13 @@ def request_dataBreakpointInfo( stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) if stackFrame is None: return [] - args_dict = ( - { - "variablesReference": variablesReference, - "name": name, - "frameId": stackFrame["id"], - } - if size is None - else { - "bytes": size, - "name": name, - "asAddress": True, - } - ) + args_dict = {"name": name} + if size is None: + args_dict["variablesReference"] = variablesReference + args_dict["frameId"] = stackFrame["id"] + else: + args_dict["asAddress"] = True + args_dict["bytes"] = size command_dict = { "command": "dataBreakpointInfo", "type": "request", diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp index c55b165c6b783..850a490f6890b 100644 --- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp @@ -16,7 +16,7 @@ namespace lldb_dap { -static bool CheckAddress(DAP &dap, lldb::addr_t load_addr) { +static bool IsRW(DAP &dap, lldb::addr_t load_addr) { lldb::SBMemoryRegionInfo region; lldb::SBError err = dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region); @@ -72,7 +72,7 @@ DataBreakpointInfoRequestHandler::Run( if (data.IsValid()) { size = llvm::utostr(data.GetByteSize()); addr = llvm::utohexstr(load_addr); - if (!CheckAddress(dap, load_addr)) { + if (!IsRW(dap, load_addr)) { is_data_ok = false; response.description = "memory region for address " + addr + " has no read or write permissions"; @@ -89,7 +89,7 @@ DataBreakpointInfoRequestHandler::Run( addr = args.name.substr(2); else addr = llvm::utohexstr(std::stoull(args.name)); - if (!CheckAddress(dap, std::stoull(addr, 0, 16))) { + if (!IsRW(dap, std::stoull(addr, 0, 16))) { is_data_ok = false; response.description = "memory region for address " + addr + " has no read or write permissions"; >From b4ce53e84a13c3e64611ddf4ab2f83d8cdccdb34 Mon Sep 17 00:00:00 2001 From: Druzhkov Sergei <[email protected]> Date: Mon, 24 Nov 2025 18:30:00 +0300 Subject: [PATCH 3/6] Fix comments --- .../DataBreakpointInfoRequestHandler.cpp | 22 ++++++++++++------- lldb/tools/lldb-dap/JSONUtils.cpp | 2 +- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp index 850a490f6890b..5be7092a31005 100644 --- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp @@ -10,6 +10,7 @@ #include "EventHelper.h" #include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" +#include "lldb/API/SBAddress.h" #include "lldb/API/SBMemoryRegionInfo.h" #include "llvm/ADT/StringExtras.h" #include <optional> @@ -17,6 +18,8 @@ namespace lldb_dap { static bool IsRW(DAP &dap, lldb::addr_t load_addr) { + if (!lldb::SBAddress(load_addr, dap.target).IsValid()) + return false; lldb::SBMemoryRegionInfo region; lldb::SBError err = dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region); @@ -84,15 +87,18 @@ DataBreakpointInfoRequestHandler::Run( } } } else if (args.asAddress) { - size = llvm::utostr(args.bytes.value_or(1)); - if (llvm::StringRef(args.name).starts_with("0x")) - addr = args.name.substr(2); - else - addr = llvm::utohexstr(std::stoull(args.name)); - if (!IsRW(dap, std::stoull(addr, 0, 16))) { + size = llvm::utostr(args.bytes.value_or(dap.target.GetAddressByteSize())); + lldb::addr_t load_addr; + if (llvm::StringRef(args.name).getAsInteger<lldb::addr_t>(0, load_addr)) { is_data_ok = false; - response.description = "memory region for address " + addr + - " has no read or write permissions"; + response.description = args.name + " is not a valid address"; + } else { + addr = llvm::utohexstr(load_addr); + if (!IsRW(dap, load_addr)) { + is_data_ok = false; + response.description = "memory region for address " + addr + + " has no read or write permissions"; + } } } else { is_data_ok = false; diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 1a3a6701b194d..e6ae745a44a0e 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -678,7 +678,7 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, } break; case lldb::eStopReasonWatchpoint: case lldb::eStopReasonInstrumentation: - body.try_emplace("reason", "breakpoint"); + body.try_emplace("reason", "data breakpoint"); break; case lldb::eStopReasonProcessorTrace: body.try_emplace("reason", "processor trace"); >From 848e7a0261b5a93bbe9bc2bdedabd7ec7e25ae93 Mon Sep 17 00:00:00 2001 From: Druzhkov Sergei <[email protected]> Date: Fri, 28 Nov 2025 13:05:30 +0300 Subject: [PATCH 4/6] Add watchpoint ids --- .../test/tools/lldb-dap/lldbdap_testcase.py | 1 + .../TestDAP_setDataBreakpoints.py | 73 +++++++++++-------- lldb/tools/lldb-dap/JSONUtils.cpp | 11 ++- lldb/tools/lldb-dap/Watchpoint.cpp | 1 + 4 files changed, 55 insertions(+), 31 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 71ca60ebe8d34..c7d302cc2dea2 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -169,6 +169,7 @@ def verify_breakpoint_hit(self, breakpoint_ids: List[Union[int, str]]): if ( body["reason"] != "breakpoint" and body["reason"] != "instruction breakpoint" + and body["reason"] != "data breakpoint" ): continue if "hitBreakpointIds" not in body: 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 7afc42f89ce55..df029ca16d667 100644 --- a/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py +++ b/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py @@ -39,18 +39,21 @@ def test_duplicate_start_addresses(self): {"dataId": response_x["body"]["dataId"], "accessType": "write"}, ] set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) - self.assertEqual( - set_response["body"]["breakpoints"], - [{"verified": False}, {"verified": True}, {"verified": True}], - ) - - self.continue_to_next_stop() + breakpoints = set_response["body"]["breakpoints"] + self.assertEqual(len(breakpoints), 3) + self.assertFalse(breakpoints[0]["verified"]) + self.assertTrue(breakpoints[1]["verified"]) + self.assertTrue(breakpoints[2]["verified"]) + + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[2]["id"]]) x_val = self.dap_server.get_local_variable_value("x") i_val = self.dap_server.get_local_variable_value("i") self.assertEqual(x_val, "2") self.assertEqual(i_val, "1") - self.continue_to_next_stop() + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[1]["id"]]) arr_2 = self.dap_server.get_local_variable_child("arr", "[2]") i_val = self.dap_server.get_local_variable_value("i") self.assertEqual(arr_2["value"], "42") @@ -79,18 +82,20 @@ def test_expression(self): {"dataId": response_arr_2["body"]["dataId"], "accessType": "write"}, ] set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) - self.assertEqual( - set_response["body"]["breakpoints"], - [{"verified": True}, {"verified": True}], - ) + breakpoints = set_response["body"]["breakpoints"] + self.assertEqual(len(breakpoints), 2) + self.assertTrue(breakpoints[0]["verified"]) + self.assertTrue(breakpoints[1]["verified"]) - self.continue_to_next_stop() + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[0]["id"]]) x_val = self.dap_server.get_local_variable_value("x") i_val = self.dap_server.get_local_variable_value("i") self.assertEqual(x_val, "2") self.assertEqual(i_val, "1") - self.continue_to_next_stop() + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[1]["id"]]) arr_2 = self.dap_server.get_local_variable_child("arr", "[2]") i_val = self.dap_server.get_local_variable_value("i") self.assertEqual(arr_2["value"], "42") @@ -123,18 +128,20 @@ def test_functionality(self): {"dataId": response_arr_2["body"]["dataId"], "accessType": "write"}, ] set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) - self.assertEqual( - set_response["body"]["breakpoints"], - [{"verified": True}, {"verified": True}], - ) + breakpoints = set_response["body"]["breakpoints"] + self.assertEqual(len(breakpoints), 2) + self.assertTrue(breakpoints[0]["verified"]) + self.assertTrue(breakpoints[1]["verified"]) - self.continue_to_next_stop() + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[0]["id"]]) x_val = self.dap_server.get_local_variable_value("x") i_val = self.dap_server.get_local_variable_value("i") self.assertEqual(x_val, "2") self.assertEqual(i_val, "1") - self.continue_to_next_stop() + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[1]["id"]]) arr_2 = self.dap_server.get_local_variable_child("arr", "[2]") i_val = self.dap_server.get_local_variable_value("i") self.assertEqual(arr_2["value"], "42") @@ -153,8 +160,11 @@ def test_functionality(self): } ] set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) - self.assertEqual(set_response["body"]["breakpoints"], [{"verified": True}]) - self.continue_to_next_stop() + breakpoints = set_response["body"]["breakpoints"] + self.assertEqual(len(breakpoints), 1) + self.assertTrue(breakpoints[0]["verified"]) + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[0]["id"]]) x_val = self.dap_server.get_local_variable_value("x") self.assertEqual(x_val, "3") @@ -167,8 +177,11 @@ def test_functionality(self): } ] set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) - self.assertEqual(set_response["body"]["breakpoints"], [{"verified": True}]) - self.continue_to_next_stop() + breakpoints = set_response["body"]["breakpoints"] + self.assertEqual(len(breakpoints), 1) + self.assertTrue(breakpoints[0]["verified"]) + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[0]["id"]]) x_val = self.dap_server.get_local_variable_value("x") self.assertEqual(x_val, "10") @@ -206,18 +219,20 @@ def test_bytes(self): {"dataId": response_arr_2["body"]["dataId"], "accessType": "write"}, ] set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) - self.assertEqual( - set_response["body"]["breakpoints"], - [{"verified": True}, {"verified": True}], - ) + breakpoints = set_response["body"]["breakpoints"] + self.assertEqual(len(breakpoints), 2) + self.assertTrue(breakpoints[0]["verified"]) + self.assertTrue(breakpoints[1]["verified"]) - self.continue_to_next_stop() + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[0]["id"]]) x_val = self.dap_server.get_local_variable_value("x") i_val = self.dap_server.get_local_variable_value("i") self.assertEqual(x_val, "2") self.assertEqual(i_val, "1") - self.continue_to_next_stop() + self.dap_server.request_continue() + self.verify_breakpoint_hit([breakpoints[1]["id"]]) arr_2 = self.dap_server.get_local_variable_child("arr", "[2]") i_val = self.dap_server.get_local_variable_value("i") self.assertEqual(arr_2["value"], "42") diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index e6ae745a44a0e..512c85c13310c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -676,9 +676,16 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, EmplaceSafeString(body, "description", desc_str); } } break; - case lldb::eStopReasonWatchpoint: - case lldb::eStopReasonInstrumentation: + case lldb::eStopReasonWatchpoint: { body.try_emplace("reason", "data breakpoint"); + lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(0); + std::vector<lldb::break_id_t> bp_ids = {bp_id}; + body.try_emplace("hitBreakpointIds", llvm::json::Array(bp_ids)); + EmplaceSafeString(body, "description", + llvm::formatv("data breakpoint {0}", bp_id).str()); + } break; + case lldb::eStopReasonInstrumentation: + body.try_emplace("reason", "breakpoint"); break; case lldb::eStopReasonProcessorTrace: body.try_emplace("reason", "processor trace"); diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp index 0acc980890be8..e730e71c0dc31 100644 --- a/lldb/tools/lldb-dap/Watchpoint.cpp +++ b/lldb/tools/lldb-dap/Watchpoint.cpp @@ -45,6 +45,7 @@ protocol::Breakpoint Watchpoint::ToProtocolBreakpoint() { breakpoint.message = m_error.GetCString(); } else { breakpoint.verified = true; + breakpoint.id = m_wp.GetID(); } return breakpoint; >From 4d5fdf70afa8d66b6f2d1895247e7856c9401127 Mon Sep 17 00:00:00 2001 From: Druzhkov Sergei <[email protected]> Date: Fri, 28 Nov 2025 16:22:22 +0300 Subject: [PATCH 5/6] Rework error handling --- .../DataBreakpointInfoRequestHandler.cpp | 23 +++++++++---------- lldb/tools/lldb-dap/JSONUtils.cpp | 4 ++-- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp index 5be7092a31005..5d03905b88259 100644 --- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "DAP.h" +#include "DAPError.h" #include "EventHelper.h" #include "Protocol/ProtocolTypes.h" #include "RequestHandler.h" @@ -89,17 +90,12 @@ DataBreakpointInfoRequestHandler::Run( } else if (args.asAddress) { size = llvm::utostr(args.bytes.value_or(dap.target.GetAddressByteSize())); lldb::addr_t load_addr; - if (llvm::StringRef(args.name).getAsInteger<lldb::addr_t>(0, load_addr)) { - is_data_ok = false; - response.description = args.name + " is not a valid address"; - } else { - addr = llvm::utohexstr(load_addr); - if (!IsRW(dap, load_addr)) { - is_data_ok = false; - response.description = "memory region for address " + addr + - " has no read or write permissions"; - } - } + if (llvm::StringRef(args.name).getAsInteger<lldb::addr_t>(0, load_addr)) + return llvm::make_error<DAPError>(args.name + " is not a valid address"); + addr = llvm::utohexstr(load_addr); + if (!IsRW(dap, load_addr)) + return llvm::make_error<DAPError>("memory region for address " + addr + + " has no read or write permissions"); } else { is_data_ok = false; response.description = "variable not found: " + args.name; @@ -110,7 +106,10 @@ DataBreakpointInfoRequestHandler::Run( response.accessTypes = {protocol::eDataBreakpointAccessTypeRead, protocol::eDataBreakpointAccessTypeWrite, protocol::eDataBreakpointAccessTypeReadWrite}; - response.description = size + " bytes at " + addr + " " + args.name; + if (args.asAddress) + response.description = size + " bytes at " + addr; + else + response.description = size + " bytes at " + addr + " " + args.name; } return response; diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 512c85c13310c..c730355dd0e9c 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -679,8 +679,8 @@ llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, case lldb::eStopReasonWatchpoint: { body.try_emplace("reason", "data breakpoint"); lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(0); - std::vector<lldb::break_id_t> bp_ids = {bp_id}; - body.try_emplace("hitBreakpointIds", llvm::json::Array(bp_ids)); + body.try_emplace("hitBreakpointIds", + llvm::json::Array{llvm::json::Value(bp_id)}); EmplaceSafeString(body, "description", llvm::formatv("data breakpoint {0}", bp_id).str()); } break; >From 5071adfa482b80f8a9c8666dd79a748e26ef82c4 Mon Sep 17 00:00:00 2001 From: Druzhkov Sergei <[email protected]> Date: Fri, 28 Nov 2025 18:05:01 +0300 Subject: [PATCH 6/6] Fix double error message --- .../lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp index 5d03905b88259..245d92c18e59e 100644 --- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp @@ -89,13 +89,15 @@ DataBreakpointInfoRequestHandler::Run( } } else if (args.asAddress) { size = llvm::utostr(args.bytes.value_or(dap.target.GetAddressByteSize())); - lldb::addr_t load_addr; + lldb::addr_t load_addr = LLDB_INVALID_ADDRESS; if (llvm::StringRef(args.name).getAsInteger<lldb::addr_t>(0, load_addr)) - return llvm::make_error<DAPError>(args.name + " is not a valid address"); + return llvm::make_error<DAPError>(args.name + " is not a valid address", + llvm::inconvertibleErrorCode(), false); addr = llvm::utohexstr(load_addr); if (!IsRW(dap, load_addr)) return llvm::make_error<DAPError>("memory region for address " + addr + - " has no read or write permissions"); + " has no read or write permissions", + llvm::inconvertibleErrorCode(), false); } else { is_data_ok = false; response.description = "variable not found: " + args.name; _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
