[Lldb-commits] [lldb] [llvm] [lldb][lldb-dap] Implement jump to cursor (PR #130503)
Ebuka Ezike via lldb-commits
lldb-commits at lists.llvm.org
Wed Mar 26 15:06:59 PDT 2025
https://github.com/da-viper updated https://github.com/llvm/llvm-project/pull/130503
>From aa8ce4da16b9cf31974eb32ecefdeab403f3a497 Mon Sep 17 00:00:00 2001
From: Ezike Ebuka <yerimyah1 at gmail.com>
Date: Sun, 9 Mar 2025 12:46:54 +0000
Subject: [PATCH 01/26] [lldb-dap] implement jump to cursor.
---
lldb/cmake/modules/LLDBConfig.cmake | 2 +-
lldb/tools/lldb-dap/CMakeLists.txt | 2 +
lldb/tools/lldb-dap/DAP.cpp | 23 +++-
lldb/tools/lldb-dap/DAP.h | 27 +++-
.../lldb-dap/Handler/GoToRequestHandler.cpp | 103 +++++++++++++++
.../Handler/GoToTargetsRequestHandler.cpp | 120 ++++++++++++++++++
lldb/tools/lldb-dap/Handler/RequestHandler.h | 14 ++
lldb/tools/lldb-dap/lldb-dap.cpp | 2 +
8 files changed, 290 insertions(+), 3 deletions(-)
create mode 100644 lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
create mode 100644 lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index 9df71edd8b359..a2f9a29b6d5d5 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -57,7 +57,7 @@ add_optional_dependency(LLDB_ENABLE_CURSES "Enable curses support in LLDB" Curse
add_optional_dependency(LLDB_ENABLE_LZMA "Enable LZMA compression support in LLDB" LibLZMA LIBLZMA_FOUND)
add_optional_dependency(LLDB_ENABLE_LUA "Enable Lua scripting support in LLDB" LuaAndSwig LUAANDSWIG_FOUND)
add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND)
-add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION 2.8)
+add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION)
add_optional_dependency(LLDB_ENABLE_FBSDVMCORE "Enable libfbsdvmcore support in LLDB" FBSDVMCore FBSDVMCore_FOUND QUIET)
option(LLDB_USE_ENTITLEMENTS "When codesigning, use entitlements if available" ON)
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index e9773db7586e6..5169a1bb91ab8 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -46,6 +46,8 @@ add_lldb_tool(lldb-dap
Handler/DisconnectRequestHandler.cpp
Handler/EvaluateRequestHandler.cpp
Handler/ExceptionInfoRequestHandler.cpp
+ Handler/GoToRequestHandler.cpp
+ Handler/GoToTargetsRequestHandler.cpp
Handler/InitializeRequestHandler.cpp
Handler/LaunchRequestHandler.cpp
Handler/LocationsRequestHandler.cpp
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 65de0488729e5..986ac5c3bb408 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -81,7 +81,7 @@ DAP::DAP(llvm::StringRef path, Log *log, const ReplMode default_repl_mode,
configuration_done_sent(false), waiting_for_run_in_terminal(false),
progress_event_reporter(
[&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
- reverse_request_seq(0), repl_mode(default_repl_mode) {}
+ reverse_request_seq(0), repl_mode(default_repl_mode), goto_id_map() {}
DAP::~DAP() = default;
@@ -841,6 +841,27 @@ lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) {
return error;
}
+std::optional<lldb::SBLineEntry> Gotos::GetLineEntry(uint64_t id) const {
+ const auto iter = line_entries.find(id);
+ if (iter != line_entries.end())
+ return iter->second;
+
+ return std::nullopt;
+}
+
+uint64_t Gotos::InsertLineEntry(lldb::SBLineEntry line_entry) {
+ const auto spec_id = this->NewSpecId();
+ line_entries.insert(std::make_pair(spec_id, line_entry));
+ return spec_id;
+}
+
+void Gotos::Clear() {
+ new_id = 0UL;
+ line_entries.clear();
+}
+
+uint64_t Gotos::NewSpecId() { return new_id++; }
+
void Variables::Clear() {
locals.Clear();
globals.Clear();
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 4b4d471161137..c280adb57d0c5 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -77,6 +77,27 @@ enum class PacketStatus {
enum class ReplMode { Variable = 0, Command, Auto };
+class Gotos {
+public:
+ /// \return the line_entry corresponding with \p id
+ ///
+ /// If \p id is invalid std::nullopt is returned.
+ std::optional<lldb::SBLineEntry> GetLineEntry(uint64_t id) const;
+
+ /// Insert a new \p line_entry.
+ /// \return id assigned to this line_entry.
+ uint64_t InsertLineEntry(lldb::SBLineEntry line_entry);
+
+ /// clears all line entries and reset the generated ids.
+ void Clear();
+
+private:
+ uint64_t NewSpecId();
+
+ llvm::DenseMap<uint64_t, lldb::SBLineEntry> line_entries;
+ uint64_t new_id = 0ul;
+};
+
struct Variables {
/// Variable_reference start index of permanent expandable variable.
static constexpr int64_t PermanentVariableStartIndex = (1ll << 32);
@@ -205,6 +226,7 @@ struct DAP {
// empty; if the previous expression was a variable expression, this string
// will contain that expression.
std::string last_nonempty_var_expression;
+ Gotos goto_id_map;
/// Creates a new DAP sessions.
///
@@ -367,7 +389,10 @@ struct DAP {
llvm::StringMap<bool> GetCapabilities();
/// Debuggee will continue from stopped state.
- void WillContinue() { variables.Clear(); }
+ void WillContinue() {
+ variables.Clear();
+ goto_id_map.Clear();
+ }
/// Poll the process to wait for it to reach the eStateStopped state.
///
diff --git a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
new file mode 100644
index 0000000000000..06a50eb939828
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
@@ -0,0 +1,103 @@
+//===-- GoToRequestHandler.cpp --------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DAP.h"
+#include "EventHelper.h"
+#include "JSONUtils.h"
+
+namespace lldb_dap {
+
+// "GotoRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "The request sets the location where the debuggee will
+// continue to run.\nThis makes it possible to skip the execution of code or
+// to execute code again.\nThe code between the current location and the
+// goto target is not executed but skipped.\nThe debug adapter first sends
+// the response and then a `stopped` event with reason `goto`.\nClients
+// should only call this request if the corresponding capability
+// `supportsGotoTargetsRequest` is true (because only then goto targets
+// exist that can be passed as arguments).", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "goto" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/GotoArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// }
+// "GotoArguments": {
+// "type": "object",
+// "description": "Arguments for `goto` request.",
+// "properties": {
+// "threadId": {
+// "type": "integer",
+// "description": "Set the goto target for this thread."
+// },
+// "targetId": {
+// "type": "integer",
+// "description": "The location where the debuggee will continue to run."
+// }
+// },
+// "required": [ "threadId", "targetId" ]
+// }
+// "GotoResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to `goto` request. This is just an
+// acknowledgement, so no body field is required."
+// }]
+// }
+void GoToRequestHandler::operator()(const llvm::json::Object &request) const {
+ llvm::json::Object response;
+ FillResponse(request, response);
+
+ auto SendError = [&](auto &&message) {
+ response["success"] = false;
+ response["message"] = message;
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+ };
+
+ const auto *goto_arguments = request.getObject("arguments");
+ if (goto_arguments == nullptr) {
+ SendError("Arguments is empty");
+ return;
+ }
+
+ lldb::SBThread current_thread = dap.GetLLDBThread(*goto_arguments);
+ if (!current_thread.IsValid()) {
+ SendError(llvm::formatv("Thread id `{0}` is not valid",
+ current_thread.GetThreadID()));
+ return;
+ }
+
+ const auto target_id = GetInteger<uint64_t>(goto_arguments, "targetId");
+ const auto line_entry = dap.goto_id_map.GetLineEntry(target_id.value());
+ if (!target_id || !line_entry) {
+ SendError(llvm::formatv("Target id `{0}` is not valid",
+ current_thread.GetThreadID()));
+ return;
+ }
+
+ auto file_spec = line_entry->GetFileSpec();
+ const auto error =
+ current_thread.JumpToLine(file_spec, line_entry->GetLine());
+ if (error.Fail()) {
+ SendError(error.GetCString());
+ return;
+ }
+
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+
+ SendThreadStoppedEvent(dap);
+}
+
+} // namespace lldb_dap
\ No newline at end of file
diff --git a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
new file mode 100644
index 0000000000000..9481055ee0119
--- /dev/null
+++ b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
@@ -0,0 +1,120 @@
+//===-- GoToTargetsRequestHandler.cpp
+//--------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "DAP.h"
+
+#include "JSONUtils.h"
+
+#include <lldb/API/SBStream.h>
+
+namespace lldb_dap {
+
+// "GotoTargetsRequest": {
+// "allOf": [ { "$ref": "#/definitions/Request" }, {
+// "type": "object",
+// "description": "This request retrieves the possible goto targets for the
+// specified source location.\nThese targets can be used in the `goto`
+// request.\nClients should only call this request if the corresponding
+// capability `supportsGotoTargetsRequest` is true.", "properties": {
+// "command": {
+// "type": "string",
+// "enum": [ "gotoTargets" ]
+// },
+// "arguments": {
+// "$ref": "#/definitions/GotoTargetsArguments"
+// }
+// },
+// "required": [ "command", "arguments" ]
+// }]
+// },
+// "GotoTargetsArguments": {
+// "type": "object",
+// "description": "Arguments for `gotoTargets` request.",
+// "properties": {
+// "source": {
+// "$ref": "#/definitions/Source",
+// "description": "The source location for which the goto targets are
+// determined."
+// },
+// "line": {
+// "type": "integer",
+// "description": "The line location for which the goto targets are
+// determined."
+// },
+// "column": {
+// "type": "integer",
+// "description": "The position within `line` for which the goto targets
+// are determined. It is measured in UTF-16 code units and the client
+// capability `columnsStartAt1` determines whether it is 0- or 1-based."
+// }
+// },
+// "required": [ "source", "line" ]
+// },
+// "GotoTargetsResponse": {
+// "allOf": [ { "$ref": "#/definitions/Response" }, {
+// "type": "object",
+// "description": "Response to `gotoTargets` request.",
+// "properties": {
+// "body": {
+// "type": "object",
+// "properties": {
+// "targets": {
+// "type": "array",
+// "items": {
+// "$ref": "#/definitions/GotoTarget"
+// },
+// "description": "The possible goto targets of the specified
+// location."
+// }
+// },
+// "required": [ "targets" ]
+// }
+// },
+// "required": [ "body" ]
+// }]
+// },
+void GoToTargetsRequestHandler::operator()(
+ const llvm::json::Object &request) const {
+ llvm::json::Object response;
+ FillResponse(request, response);
+ const auto *arguments = request.getObject("arguments");
+ const auto *source = arguments->getObject("source");
+ const std::string path = GetString(source, "path").str();
+
+ const auto goto_line = GetInteger<uint64_t>(arguments, "line").value_or(0u);
+ const auto goto_column =
+ GetInteger<uint64_t>(arguments, "column").value_or(0u);
+
+ lldb::SBLineEntry line_entry{};
+ const lldb::SBFileSpec file_spec(path.c_str(), true);
+ line_entry.SetFileSpec(file_spec);
+ line_entry.SetLine(goto_line);
+ line_entry.SetColumn(goto_column);
+
+ const auto target_id = dap.goto_id_map.InsertLineEntry(line_entry);
+ llvm::json::Array response_targets;
+ const auto target_line = line_entry.GetLine();
+ const auto target_column = line_entry.GetColumn();
+ auto target = llvm::json::Object();
+ target.try_emplace("id", target_id);
+
+ lldb::SBStream stream;
+ line_entry.GetDescription(stream);
+ target.try_emplace("label",
+ llvm::StringRef(stream.GetData(), stream.GetSize()));
+ target.try_emplace("column", target_column);
+ target.try_emplace("line", target_line);
+
+ response_targets.push_back(std::move(target));
+ llvm::json::Object body;
+ body.try_emplace("targets", std::move(response_targets));
+ response.try_emplace("body", std::move(body));
+ dap.SendJSON(llvm::json::Value(std::move(response)));
+}
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 8971b02fcb92e..9929f7a7ed363 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -235,6 +235,20 @@ class ExceptionInfoRequestHandler : public LegacyRequestHandler {
void operator()(const llvm::json::Object &request) const override;
};
+class GoToRequestHandler : public LegacyRequestHandler {
+public:
+ using LegacyRequestHandler::LegacyRequestHandler;
+ static llvm::StringLiteral getCommand() { return "goto"; }
+ void operator()(const llvm::json::Object &request) const override;
+};
+
+class GoToTargetsRequestHandler : public LegacyRequestHandler {
+public:
+ using LegacyRequestHandler::LegacyRequestHandler;
+ static llvm::StringLiteral getCommand() { return "gotoTargets"; }
+ void operator()(const llvm::json::Object &request) const override;
+};
+
class InitializeRequestHandler : public LegacyRequestHandler {
public:
using LegacyRequestHandler::LegacyRequestHandler;
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 062c3a5f989f3..571a2c7df6818 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -127,6 +127,8 @@ static void RegisterRequestCallbacks(DAP &dap) {
dap.RegisterRequest<EvaluateRequestHandler>();
dap.RegisterRequest<ExceptionInfoRequestHandler>();
dap.RegisterRequest<InitializeRequestHandler>();
+ dap.RegisterRequest<GoToRequestHandler>();
+ dap.RegisterRequest<GoToTargetsRequestHandler>();
dap.RegisterRequest<LaunchRequestHandler>();
dap.RegisterRequest<LocationsRequestHandler>();
dap.RegisterRequest<NextRequestHandler>();
>From d7342ea95fd9cf459e637d6cca117698de7c74e6 Mon Sep 17 00:00:00 2001
From: Ezike Ebuka <yerimyah1 at gmail.com>
Date: Sun, 9 Mar 2025 18:30:24 +0000
Subject: [PATCH 02/26] [lldb][lldb-dap] add jump to cursor tests
---
.../test/tools/lldb-dap/dap_server.py | 27 +++++++++
.../API/tools/lldb-dap/gotoTarget/Makefile | 3 +
.../lldb-dap/gotoTarget/TestDAP_gotoTarget.py | 60 +++++++++++++++++++
.../test/API/tools/lldb-dap/gotoTarget/main.c | 11 ++++
4 files changed, 101 insertions(+)
create mode 100644 lldb/test/API/tools/lldb-dap/gotoTarget/Makefile
create mode 100644 lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
create mode 100644 lldb/test/API/tools/lldb-dap/gotoTarget/main.c
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 359ac718138b2..97498dc112efa 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
@@ -761,6 +761,33 @@ def request_exceptionInfo(self, threadId=None):
}
return self.send_recv(command_dict)
+ def request_goto(self, threadId: int, targetId: int):
+ command_dict = {
+ "command": "goto",
+ "type": "request",
+ "arguments": {
+ "threadId": threadId,
+ "targetId": targetId,
+ },
+ }
+ return self.send_recv(command_dict)
+
+ def request_gotoTargets(self, filename: str, path: str, line: int, column: int):
+ arguments = {
+ "source": {
+ "name": filename,
+ "path": path,
+ },
+ "line": line,
+ "column": column,
+ }
+ command_dict = {
+ "command": "gotoTargets",
+ "type": "request",
+ "arguments": arguments,
+ }
+ return self.send_recv(command_dict)
+
def request_initialize(self, sourceInitFile):
command_dict = {
"command": "initialize",
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/Makefile b/lldb/test/API/tools/lldb-dap/gotoTarget/Makefile
new file mode 100644
index 0000000000000..10495940055b6
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/gotoTarget/Makefile
@@ -0,0 +1,3 @@
+C_SOURCES := main.c
+
+include Makefile.rules
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py b/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
new file mode 100644
index 0000000000000..6d0f9ae478f33
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
@@ -0,0 +1,60 @@
+"""
+Test lldb-dap gotoTarget request
+"""
+
+from lldbsuite.test.lldbtest import line_number
+import lldbdap_testcase
+import os
+
+
+class TestDAP_gotoTarget(lldbdap_testcase.DAPTestCaseBase):
+
+ def test_default(self):
+ """
+ Tests the jump to cursor of a simple program. No arguments,
+ environment, or anything else is specified.
+ This does not run any statement between the current breakpoint
+ and the jump line location.
+ """
+ program = self.getBuildArtifact("a.out")
+ self.build_and_launch(program)
+
+ source_file = "main.c"
+ self.source_path = os.path.join(os.getcwd(), source_file)
+ self.set_source_breakpoints(
+ source_file, [line_number(source_file, "// breakpoint 1")]
+ )
+ self.continue_to_next_stop()
+
+ first_var_1_object = self.dap_server.get_local_variable("var_1")
+ self.assertEqual(first_var_1_object["value"], "10")
+
+ goto_line = line_number(source_file, "// goto 1")
+ goto_column = 1
+ response = self.dap_server.request_gotoTargets(
+ source_file, self.source_path, goto_line, goto_column
+ )
+
+ self.assertEqual(
+ response["success"], True, "expects success when request for targets"
+ )
+ target = response["body"]["targets"][0]
+ self.assertGreaterEqual(
+ target["id"], 0, "targetId should be greater than or equal to zero"
+ )
+
+ target_id = target["id"]
+ thread_id = self.dap_server.get_thread_id()
+ self.assertIsNotNone(thread_id, "thread Id should not be none")
+
+ response = self.dap_server.request_goto(thread_id, target_id)
+
+ self.assertEqual(
+ response["success"], True, "expects success to go to a target id"
+ )
+
+ var_1_object = self.dap_server.get_local_variable("var_1")
+ self.assertEqual(first_var_1_object["value"], var_1_object["value"])
+
+ self.continue_to_next_stop() # a stop event is sent after a successful goto response
+ self.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/main.c b/lldb/test/API/tools/lldb-dap/gotoTarget/main.c
new file mode 100644
index 0000000000000..74210e5877369
--- /dev/null
+++ b/lldb/test/API/tools/lldb-dap/gotoTarget/main.c
@@ -0,0 +1,11 @@
+
+int main() {
+
+ int var_1 = 10;
+
+ var_1 = 20; // breakpoint 1
+
+ int var_2 = 40; // goto 1
+
+ return 0;
+}
\ No newline at end of file
>From d468264063ed0ae736f3125dc9b8fe4207a02c03 Mon Sep 17 00:00:00 2001
From: Ezike Ebuka <yerimyah1 at gmail.com>
Date: Sun, 9 Mar 2025 18:47:44 +0000
Subject: [PATCH 03/26] [lldb-dap] Rever removing libXML version
---
lldb/cmake/modules/LLDBConfig.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake
index a2f9a29b6d5d5..9df71edd8b359 100644
--- a/lldb/cmake/modules/LLDBConfig.cmake
+++ b/lldb/cmake/modules/LLDBConfig.cmake
@@ -57,7 +57,7 @@ add_optional_dependency(LLDB_ENABLE_CURSES "Enable curses support in LLDB" Curse
add_optional_dependency(LLDB_ENABLE_LZMA "Enable LZMA compression support in LLDB" LibLZMA LIBLZMA_FOUND)
add_optional_dependency(LLDB_ENABLE_LUA "Enable Lua scripting support in LLDB" LuaAndSwig LUAANDSWIG_FOUND)
add_optional_dependency(LLDB_ENABLE_PYTHON "Enable Python scripting support in LLDB" PythonAndSwig PYTHONANDSWIG_FOUND)
-add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION)
+add_optional_dependency(LLDB_ENABLE_LIBXML2 "Enable Libxml 2 support in LLDB" LibXml2 LIBXML2_FOUND VERSION 2.8)
add_optional_dependency(LLDB_ENABLE_FBSDVMCORE "Enable libfbsdvmcore support in LLDB" FBSDVMCore FBSDVMCore_FOUND QUIET)
option(LLDB_USE_ENTITLEMENTS "When codesigning, use entitlements if available" ON)
>From bdfa47cad9d4608476f402d4d75161b7b5587d0c Mon Sep 17 00:00:00 2001
From: Ezike Ebuka <yerimyah1 at gmail.com>
Date: Sun, 9 Mar 2025 19:05:32 +0000
Subject: [PATCH 04/26] [lldb][lldb-dap] fix code format
---
lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py b/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
index 6d0f9ae478f33..9eb6d7b836d34 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
@@ -8,7 +8,6 @@
class TestDAP_gotoTarget(lldbdap_testcase.DAPTestCaseBase):
-
def test_default(self):
"""
Tests the jump to cursor of a simple program. No arguments,
>From 03f65986ac059fb31dd754c4bcc1eedb93545e2a Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <57949090+da-viper at users.noreply.github.com>
Date: Tue, 11 Mar 2025 13:19:21 +0000
Subject: [PATCH 05/26] Update
lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
Co-authored-by: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
---
lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
index 9481055ee0119..db676385a3d39 100644
--- a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
@@ -21,7 +21,8 @@ namespace lldb_dap {
// "description": "This request retrieves the possible goto targets for the
// specified source location.\nThese targets can be used in the `goto`
// request.\nClients should only call this request if the corresponding
-// capability `supportsGotoTargetsRequest` is true.", "properties": {
+// capability `supportsGotoTargetsRequest` is true.",
+//. "properties": {
// "command": {
// "type": "string",
// "enum": [ "gotoTargets" ]
>From 5bec4a975761cfc38949846d4a80cf0a48719441 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <57949090+da-viper at users.noreply.github.com>
Date: Tue, 11 Mar 2025 13:19:31 +0000
Subject: [PATCH 06/26] Update lldb/tools/lldb-dap/DAP.h
Co-authored-by: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
---
lldb/tools/lldb-dap/DAP.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index c280adb57d0c5..c64a668556e6e 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -88,7 +88,7 @@ class Gotos {
/// \return id assigned to this line_entry.
uint64_t InsertLineEntry(lldb::SBLineEntry line_entry);
- /// clears all line entries and reset the generated ids.
+ /// Clears all line entries and reset the generated ids.
void Clear();
private:
>From 31df5a3207c506117cb9cc3b1a2977a253166ab0 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <57949090+da-viper at users.noreply.github.com>
Date: Tue, 11 Mar 2025 13:34:07 +0000
Subject: [PATCH 07/26] Update
lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
Co-authored-by: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
---
lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
index 06a50eb939828..f36c0f483d1db 100644
--- a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
@@ -22,7 +22,8 @@ namespace lldb_dap {
// the response and then a `stopped` event with reason `goto`.\nClients
// should only call this request if the corresponding capability
// `supportsGotoTargetsRequest` is true (because only then goto targets
-// exist that can be passed as arguments).", "properties": {
+// exist that can be passed as arguments).",
+//. "properties": {
// "command": {
// "type": "string",
// "enum": [ "goto" ]
>From f02a34156e8e32be86b4b356d9ddff21590a4c7c Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Tue, 11 Mar 2025 13:36:51 +0000
Subject: [PATCH 08/26] [lldb][lldb-dap] add review commits
---
lldb/test/API/tools/lldb-dap/gotoTarget/main.c | 2 +-
lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp | 2 +-
lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/main.c b/lldb/test/API/tools/lldb-dap/gotoTarget/main.c
index 74210e5877369..8c0a2d4770f17 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTarget/main.c
+++ b/lldb/test/API/tools/lldb-dap/gotoTarget/main.c
@@ -8,4 +8,4 @@ int main() {
int var_2 = 40; // goto 1
return 0;
-}
\ No newline at end of file
+}
diff --git a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
index f36c0f483d1db..6a312ffef031e 100644
--- a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
@@ -101,4 +101,4 @@ void GoToRequestHandler::operator()(const llvm::json::Object &request) const {
SendThreadStoppedEvent(dap);
}
-} // namespace lldb_dap
\ No newline at end of file
+} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
index db676385a3d39..5fba6e65c28c7 100644
--- a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
@@ -1,5 +1,4 @@
-//===-- GoToTargetsRequestHandler.cpp
-//--------------------------------------===//
+//===-- GoToTargetsRequestHandler.cpp -------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
@@ -118,4 +117,5 @@ void GoToTargetsRequestHandler::operator()(
response.try_emplace("body", std::move(body));
dap.SendJSON(llvm::json::Value(std::move(response)));
}
+
} // namespace lldb_dap
>From 988b9cefa43ad92e5aa05cc8e17034d3504bf4d6 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Tue, 11 Mar 2025 13:40:19 +0000
Subject: [PATCH 09/26] [lldb][lldb-dap] add review changes
---
lldb/tools/lldb-dap/CMakeLists.txt | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt
index 5169a1bb91ab8..e163536972aea 100644
--- a/lldb/tools/lldb-dap/CMakeLists.txt
+++ b/lldb/tools/lldb-dap/CMakeLists.txt
@@ -46,8 +46,8 @@ add_lldb_tool(lldb-dap
Handler/DisconnectRequestHandler.cpp
Handler/EvaluateRequestHandler.cpp
Handler/ExceptionInfoRequestHandler.cpp
- Handler/GoToRequestHandler.cpp
- Handler/GoToTargetsRequestHandler.cpp
+ Handler/GoToRequestHandler.cpp
+ Handler/GoToTargetsRequestHandler.cpp
Handler/InitializeRequestHandler.cpp
Handler/LaunchRequestHandler.cpp
Handler/LocationsRequestHandler.cpp
>From ca875e4573635379b2dc3f7d9035fe594e3ff9cf Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Tue, 11 Mar 2025 14:26:59 +0000
Subject: [PATCH 10/26] [lldb][lldb-dap] Update jump to cursor test
---
.../lldb-dap/gotoTarget/TestDAP_gotoTarget.py | 38 +++++++++++++++----
1 file changed, 31 insertions(+), 7 deletions(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py b/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
index 9eb6d7b836d34..764949931c0cb 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
@@ -44,16 +44,40 @@ def test_default(self):
target_id = target["id"]
thread_id = self.dap_server.get_thread_id()
- self.assertIsNotNone(thread_id, "thread Id should not be none")
+ self.assertIsNotNone(thread_id, "threadId should not be none")
response = self.dap_server.request_goto(thread_id, target_id)
- self.assertEqual(
- response["success"], True, "expects success to go to a target id"
- )
+ self.assertEqual(response["success"], True, "expects success to go to targetId")
+
+ self.dap_server.request_next(thread_id)
+ self.continue_to_next_stop()
+
+ local_variables = self.dap_server.get_local_variables()
+ verify_variables = {
+ "var_1": {
+ "name": "var_1",
+ "type": "int",
+ "value": "10",
+ "variablesReference": 0,
+ },
+ "var_2": {
+ "name": "var_2",
+ "type": "int",
+ "value": "40",
+ "variablesReference": 0,
+ },
+ }
- var_1_object = self.dap_server.get_local_variable("var_1")
- self.assertEqual(first_var_1_object["value"], var_1_object["value"])
+ for variable in local_variables:
+ name = variable["name"]
+ verify_variable = verify_variables[name]
- self.continue_to_next_stop() # a stop event is sent after a successful goto response
+ for key, value in verify_variable.items():
+ actual_value = variable[key]
+ self.assertEqual(
+ actual_value,
+ value,
+ f"values does not match for key: `{key}` expected_value: `{value}`, actual_value: `{actual_value}`",
+ )
self.continue_to_exit()
>From 6373d10021c811b313727ff3de7d000cc8eb64b7 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Tue, 11 Mar 2025 15:56:42 +0000
Subject: [PATCH 11/26] [lldb][lldb-dap] add new test for goto execute again.
---
.../lldb-dap/gotoTarget/TestDAP_gotoTarget.py | 95 ++++++++++++++-----
.../test/API/tools/lldb-dap/gotoTarget/main.c | 9 ++
2 files changed, 79 insertions(+), 25 deletions(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py b/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
index 764949931c0cb..efb9b3d4ec04b 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
@@ -2,12 +2,26 @@
Test lldb-dap gotoTarget request
"""
+from typing import Dict, Any
+from unittest import SkipTest
+
from lldbsuite.test.lldbtest import line_number
import lldbdap_testcase
import os
class TestDAP_gotoTarget(lldbdap_testcase.DAPTestCaseBase):
+ def verify_variable(
+ self, actual_dict: Dict[str, Any], expected_dict: Dict[str, Any]
+ ):
+ for key, value in expected_dict.items():
+ actual_value = actual_dict[key]
+ self.assertEqual(
+ actual_value,
+ value,
+ f"values does not match for key: `{key}` expected_value: `{value}`, actual_value: `{actual_value}`",
+ )
+
def test_default(self):
"""
Tests the jump to cursor of a simple program. No arguments,
@@ -53,31 +67,62 @@ def test_default(self):
self.dap_server.request_next(thread_id)
self.continue_to_next_stop()
- local_variables = self.dap_server.get_local_variables()
- verify_variables = {
- "var_1": {
- "name": "var_1",
- "type": "int",
- "value": "10",
- "variablesReference": 0,
- },
- "var_2": {
- "name": "var_2",
- "type": "int",
- "value": "40",
- "variablesReference": 0,
- },
+ var1_variable = self.dap_server.get_local_variable("var_1")
+ var_1_expected = {
+ "name": "var_1",
+ "type": "int",
+ "value": "10",
+ "variablesReference": 0,
}
+ self.verify_variable(var1_variable, var_1_expected)
+
+ var2_variable = self.dap_server.get_local_variable("var_2")
+ var_2_expected = {
+ "name": "var_2",
+ "type": "int",
+ "value": "40",
+ "variablesReference": 0,
+ }
+ self.verify_variable(var2_variable, var_2_expected)
+
+ self.continue_to_exit()
- for variable in local_variables:
- name = variable["name"]
- verify_variable = verify_variables[name]
-
- for key, value in verify_variable.items():
- actual_value = variable[key]
- self.assertEqual(
- actual_value,
- value,
- f"values does not match for key: `{key}` expected_value: `{value}`, actual_value: `{actual_value}`",
- )
+ def test_execute_again(self):
+ program = self.getBuildArtifact("a.out")
+ self.build_and_launch(program)
+
+ source_file = "main.c"
+ self.source_path = os.path.join(os.getcwd(), source_file)
+ self.set_source_breakpoints(
+ source_file, [line_number(source_file, "// breakpoint 2")]
+ )
+ self.continue_to_next_stop()
+
+ end_var_3_value = self.dap_server.get_local_variable_value("var_3")
+ self.assertEqual(end_var_3_value, "99")
+
+ goto_line = line_number(source_file, "// goto 2")
+ goto_column = 1
+ response = self.dap_server.request_gotoTargets(
+ source_file, self.source_path, goto_line, goto_column
+ )
+
+ target = response["body"]["targets"][0]
+ self.assertGreaterEqual(
+ target["id"], 0, "targetId should be greater than or equal to zero"
+ )
+
+ target_id = target["id"]
+ thread_id = self.dap_server.get_thread_id()
+ self.assertIsNotNone(thread_id, "threadId should not be none")
+
+ response = self.dap_server.request_goto(thread_id, target_id)
+ self.assertEqual(response["success"], True, "expects success to go to targetId")
+ self.dap_server.request_next(thread_id)
+ self.continue_to_next_stop()
+
+ goto_var_3_value = self.dap_server.get_local_variable_value("var_3")
+ self.assertEqual(goto_var_3_value, "10")
+
+ self.continue_to_next_stop()
self.continue_to_exit()
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/main.c b/lldb/test/API/tools/lldb-dap/gotoTarget/main.c
index 8c0a2d4770f17..d67aeed25d411 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTarget/main.c
+++ b/lldb/test/API/tools/lldb-dap/gotoTarget/main.c
@@ -1,4 +1,12 @@
+int test_execute_again() {
+ int var_3 = 10; // goto 2
+
+ var_3 = 99;
+
+ return var_3; // breakpoint 2
+}
+
int main() {
int var_1 = 10;
@@ -7,5 +15,6 @@ int main() {
int var_2 = 40; // goto 1
+ int result = test_execute_again();
return 0;
}
>From 64a2b9c2c2a8f72646559206dfc32c156d71e648 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Wed, 12 Mar 2025 22:00:36 +0000
Subject: [PATCH 12/26] [lldb][lldb-dap] add helper function
`SendThreadGotoEvent`
LLDB currently does not have a `StopReason` for goto so I cannot use `SendThreadStoppedEvent` as I need to put the goto reason.
Signed-off-by: Ebuka Ezike <yerimyah1 at gmail.com>
---
.../lldb-dap/Handler/GoToRequestHandler.cpp | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
index 6a312ffef031e..bbbb48f0e0630 100644
--- a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
@@ -12,6 +12,21 @@
namespace lldb_dap {
+/// Creates an \p StoppedEvent with the reason \a goto
+static void SendThreadGotoEvent(DAP &dap, lldb::tid_t thread_id) {
+
+ llvm::json::Object event(CreateEventObject("stopped"));
+ llvm::json::Object body;
+ body.try_emplace("reason", "goto");
+ body.try_emplace("description", "Paused on Jump To Cursor");
+ body.try_emplace("threadId", thread_id);
+ body.try_emplace("preserveFocusHint", false);
+ body.try_emplace("allThreadsStopped", true);
+
+ event.try_emplace("body", std::move(body));
+ dap.SendJSON(llvm::json::Value(std::move(event)));
+}
+
// "GotoRequest": {
// "allOf": [ { "$ref": "#/definitions/Request" }, {
// "type": "object",
@@ -98,7 +113,7 @@ void GoToRequestHandler::operator()(const llvm::json::Object &request) const {
dap.SendJSON(llvm::json::Value(std::move(response)));
- SendThreadStoppedEvent(dap);
+ SendThreadGotoEvent(dap, current_thread.GetThreadID());
}
} // namespace lldb_dap
>From ae46dce6c88b999826ab61aea0f03bf87996512f Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Wed, 12 Mar 2025 22:01:50 +0000
Subject: [PATCH 13/26] [lldb][lldb-dap] Rename `gotoTarget` to `gotoTargets`
and improve validation.
Renamed test files, directories, and references from `gotoTarget` to `gotoTargets` for consistency. Added validation to confirm stopped events include a "goto" reason after goto requests in the test suite.
Signed-off-by: Ebuka Ezike <yerimyah1 at gmail.com>
---
.../lldb-dap/{gotoTarget => gotoTargets}/Makefile | 0
.../TestDAP_gotoTargets.py} | 14 ++++++++++++--
.../lldb-dap/{gotoTarget => gotoTargets}/main.c | 0
3 files changed, 12 insertions(+), 2 deletions(-)
rename lldb/test/API/tools/lldb-dap/{gotoTarget => gotoTargets}/Makefile (100%)
rename lldb/test/API/tools/lldb-dap/{gotoTarget/TestDAP_gotoTarget.py => gotoTargets/TestDAP_gotoTargets.py} (87%)
rename lldb/test/API/tools/lldb-dap/{gotoTarget => gotoTargets}/main.c (100%)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/Makefile b/lldb/test/API/tools/lldb-dap/gotoTargets/Makefile
similarity index 100%
rename from lldb/test/API/tools/lldb-dap/gotoTarget/Makefile
rename to lldb/test/API/tools/lldb-dap/gotoTargets/Makefile
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
similarity index 87%
rename from lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
rename to lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
index efb9b3d4ec04b..95f1a417e8884 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTarget/TestDAP_gotoTarget.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
@@ -10,7 +10,7 @@
import os
-class TestDAP_gotoTarget(lldbdap_testcase.DAPTestCaseBase):
+class TestDAP_gotoTargets(lldbdap_testcase.DAPTestCaseBase):
def verify_variable(
self, actual_dict: Dict[str, Any], expected_dict: Dict[str, Any]
):
@@ -61,9 +61,13 @@ def test_default(self):
self.assertIsNotNone(thread_id, "threadId should not be none")
response = self.dap_server.request_goto(thread_id, target_id)
-
self.assertEqual(response["success"], True, "expects success to go to targetId")
+ stopped_events = self.dap_server.wait_for_stopped()
+ is_goto = lambda event: event["body"]["reason"] == "goto"
+ has_goto_event = any(map(is_goto, stopped_events))
+ self.assertEqual(has_goto_event, True, "expects stopped event with reason goto")
+
self.dap_server.request_next(thread_id)
self.continue_to_next_stop()
@@ -118,6 +122,12 @@ def test_execute_again(self):
response = self.dap_server.request_goto(thread_id, target_id)
self.assertEqual(response["success"], True, "expects success to go to targetId")
+
+ stopped_events = self.dap_server.wait_for_stopped()
+ is_goto = lambda event: event["body"]["reason"] == "goto"
+ has_goto_event = any(map(is_goto, stopped_events))
+ self.assertEqual(has_goto_event, True, "expects stopped event with reason goto")
+
self.dap_server.request_next(thread_id)
self.continue_to_next_stop()
diff --git a/lldb/test/API/tools/lldb-dap/gotoTarget/main.c b/lldb/test/API/tools/lldb-dap/gotoTargets/main.c
similarity index 100%
rename from lldb/test/API/tools/lldb-dap/gotoTarget/main.c
rename to lldb/test/API/tools/lldb-dap/gotoTargets/main.c
>From 05a3ebb338ad8f142d21c33a4956a85b718ef684 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 13 Mar 2025 19:54:07 +0000
Subject: [PATCH 14/26] Update
lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
Co-authored-by: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
---
lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
index 95f1a417e8884..83e0fe2911dcd 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
@@ -49,7 +49,7 @@ def test_default(self):
)
self.assertEqual(
- response["success"], True, "expects success when request for targets"
+ response["success"], True, "request for gotoTargets should be successful"
)
target = response["body"]["targets"][0]
self.assertGreaterEqual(
>From e8697c7161cee76776e19ddf9846e50b49e6c4e1 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 13 Mar 2025 19:54:16 +0000
Subject: [PATCH 15/26] Update
lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
Co-authored-by: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
---
lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
index 83e0fe2911dcd..9d4eea5732015 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
@@ -61,7 +61,7 @@ def test_default(self):
self.assertIsNotNone(thread_id, "threadId should not be none")
response = self.dap_server.request_goto(thread_id, target_id)
- self.assertEqual(response["success"], True, "expects success to go to targetId")
+ self.assertEqual(response["success"], True, "goto request with targetId should be successful")
stopped_events = self.dap_server.wait_for_stopped()
is_goto = lambda event: event["body"]["reason"] == "goto"
>From 37d3487e9cfcb4a18171d0316fa7b5fe0c91206b Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 13 Mar 2025 19:54:47 +0000
Subject: [PATCH 16/26] Update
lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
Co-authored-by: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
---
lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
index 9d4eea5732015..5e21ac3b8c325 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
@@ -66,7 +66,7 @@ def test_default(self):
stopped_events = self.dap_server.wait_for_stopped()
is_goto = lambda event: event["body"]["reason"] == "goto"
has_goto_event = any(map(is_goto, stopped_events))
- self.assertEqual(has_goto_event, True, "expects stopped event with reason goto")
+ self.assertEqual(has_goto_event, True, "expected a stopped event with reason `goto`")
self.dap_server.request_next(thread_id)
self.continue_to_next_stop()
>From e0386715c9833dc5739447b7450ff6a6182fcbd6 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 13 Mar 2025 19:55:42 +0000
Subject: [PATCH 17/26] Update
lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
Co-authored-by: Adrian Vogelsgesang <adrian.vogelsgesang at tum.de>
---
.../test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
index 5e21ac3b8c325..4ce54f4f85df8 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
@@ -71,6 +71,9 @@ def test_default(self):
self.dap_server.request_next(thread_id)
self.continue_to_next_stop()
+ # Verify that `var_1=10` and `var_2=40`. This combination is only possible by
+ # skipping execution of a line from the original program. Observing this combination
+ # hence proves that our `goto` request actually skipped execution of the code line.
var1_variable = self.dap_server.get_local_variable("var_1")
var_1_expected = {
"name": "var_1",
>From 2d9b7a8b2e5de576fe9cf6ae4cad68e28780b54e Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Fri, 14 Mar 2025 18:18:55 +0000
Subject: [PATCH 18/26] [lldb][lldb-dap] use breakpoints to verify goto
location.
---
.../lldb-dap/Handler/GoToRequestHandler.cpp | 1 -
.../Handler/GoToTargetsRequestHandler.cpp | 100 +++++++++++++-----
2 files changed, 72 insertions(+), 29 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
index bbbb48f0e0630..72448498d9cdd 100644
--- a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
@@ -14,7 +14,6 @@ namespace lldb_dap {
/// Creates an \p StoppedEvent with the reason \a goto
static void SendThreadGotoEvent(DAP &dap, lldb::tid_t thread_id) {
-
llvm::json::Object event(CreateEventObject("stopped"));
llvm::json::Object body;
body.try_emplace("reason", "goto");
diff --git a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
index 5fba6e65c28c7..0dbe4379b636c 100644
--- a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
@@ -10,10 +10,51 @@
#include "JSONUtils.h"
+#include <lldb/API/SBBreakpointLocation.h>
+#include <lldb/API/SBListener.h>
#include <lldb/API/SBStream.h>
namespace lldb_dap {
+static llvm::SmallVector<lldb::SBLineEntry>
+GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) {
+ // disable breakpoint listeners so they do not send events to the DAP client.
+ lldb::SBListener listener = dap.debugger.GetListener();
+ lldb::SBBroadcaster broadcaster = dap.target.GetBroadcaster();
+ constexpr auto event_mask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
+ listener.StopListeningForEvents(broadcaster, event_mask);
+
+ // create a breakpoint to resolve the line if it is on an empty line.
+ lldb::SBBreakpoint goto_bp =
+ dap.target.BreakpointCreateByLocation(file_spec, line);
+ if (!goto_bp.IsValid())
+ return {};
+
+ llvm::SmallVector<lldb::SBLineEntry> entry_locations{};
+ const size_t resolved_count = goto_bp.GetNumResolvedLocations();
+ for (size_t idx = 0; idx < resolved_count; ++idx) {
+ lldb::SBBreakpointLocation location = goto_bp.GetLocationAtIndex(idx);
+ if (!location.IsValid())
+ continue;
+
+ lldb::SBAddress addr = location.GetAddress();
+ if (!addr.IsValid())
+ continue;
+
+ lldb::SBLineEntry line_entry = addr.GetLineEntry();
+ if (!line_entry.IsValid())
+ continue;
+
+ entry_locations.push_back(line_entry);
+ }
+
+ // clean up;
+ dap.target.BreakpointDelete(goto_bp.GetID());
+ listener.StartListeningForEvents(broadcaster, event_mask);
+
+ return entry_locations;
+}
+
// "GotoTargetsRequest": {
// "allOf": [ { "$ref": "#/definitions/Request" }, {
// "type": "object",
@@ -83,37 +124,40 @@ void GoToTargetsRequestHandler::operator()(
const llvm::json::Object &request) const {
llvm::json::Object response;
FillResponse(request, response);
- const auto *arguments = request.getObject("arguments");
- const auto *source = arguments->getObject("source");
- const std::string path = GetString(source, "path").str();
-
- const auto goto_line = GetInteger<uint64_t>(arguments, "line").value_or(0u);
- const auto goto_column =
- GetInteger<uint64_t>(arguments, "column").value_or(0u);
- lldb::SBLineEntry line_entry{};
+ const llvm::json::Object *arguments = request.getObject("arguments");
+ const llvm::json::Object *source = arguments->getObject("source");
+ const std::string path = GetString(source, "path").str();
const lldb::SBFileSpec file_spec(path.c_str(), true);
- line_entry.SetFileSpec(file_spec);
- line_entry.SetLine(goto_line);
- line_entry.SetColumn(goto_column);
-
- const auto target_id = dap.goto_id_map.InsertLineEntry(line_entry);
- llvm::json::Array response_targets;
- const auto target_line = line_entry.GetLine();
- const auto target_column = line_entry.GetColumn();
- auto target = llvm::json::Object();
- target.try_emplace("id", target_id);
-
- lldb::SBStream stream;
- line_entry.GetDescription(stream);
- target.try_emplace("label",
- llvm::StringRef(stream.GetData(), stream.GetSize()));
- target.try_emplace("column", target_column);
- target.try_emplace("line", target_line);
-
- response_targets.push_back(std::move(target));
+ const uint64_t goto_line =
+ GetInteger<uint64_t>(arguments, "line").value_or(1U);
+
llvm::json::Object body;
- body.try_emplace("targets", std::move(response_targets));
+
+ llvm::SmallVector<lldb::SBLineEntry> goto_locations =
+ GetLineValidEntry(dap, file_spec, goto_line);
+ if (goto_locations.empty()) {
+ response["success"] = false;
+ response["message"] = "Invalid jump location";
+ } else {
+ llvm::json::Array response_targets;
+ for (lldb::SBLineEntry &line_entry : goto_locations) {
+ const uint64_t target_id = dap.goto_id_map.InsertLineEntry(line_entry);
+ const uint32_t target_line = line_entry.GetLine();
+ auto target = llvm::json::Object();
+ target.try_emplace("id", target_id);
+
+ lldb::SBStream stream;
+ line_entry.GetDescription(stream);
+ target.try_emplace("label",
+ llvm::StringRef(stream.GetData(), stream.GetSize()));
+ target.try_emplace("line", target_line);
+ response_targets.push_back(std::move(target));
+ }
+
+ body.try_emplace("targets", std::move(response_targets));
+ }
+
response.try_emplace("body", std::move(body));
dap.SendJSON(llvm::json::Value(std::move(response)));
}
>From b36ca14fbb5838554e6b85ea2a9b11e736650ab8 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Tue, 18 Mar 2025 10:52:28 +0000
Subject: [PATCH 19/26] Add Release notes
---
llvm/docs/ReleaseNotes.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md
index 445599fb9b770..bf3e017115a3d 100644
--- a/llvm/docs/ReleaseNotes.md
+++ b/llvm/docs/ReleaseNotes.md
@@ -216,6 +216,8 @@ Changes to LLDB
* Breakpoints can now be set for specific columns within a line.
* Function return value is now displayed on step-out.
+* Jump to cursor is supported implementing the debug adapter
+ protocol's capability `supportsGotoTargetsRequest`.
Changes to BOLT
---------------------------------
>From 39776451fe809d1897e977c3e0deafaad9ef01b1 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 20 Mar 2025 10:37:04 +0000
Subject: [PATCH 20/26] [lldb-dap] Update with review changes
---
lldb/tools/lldb-dap/DAP.cpp | 8 ++++----
lldb/tools/lldb-dap/DAP.h | 8 ++++----
.../lldb-dap/Handler/GoToRequestHandler.cpp | 20 ++++++++-----------
.../Handler/GoToTargetsRequestHandler.cpp | 6 +++---
4 files changed, 19 insertions(+), 23 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 986ac5c3bb408..ee9953fecb377 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -81,7 +81,7 @@ DAP::DAP(llvm::StringRef path, Log *log, const ReplMode default_repl_mode,
configuration_done_sent(false), waiting_for_run_in_terminal(false),
progress_event_reporter(
[&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }),
- reverse_request_seq(0), repl_mode(default_repl_mode), goto_id_map() {}
+ reverse_request_seq(0), repl_mode(default_repl_mode), gotos() {}
DAP::~DAP() = default;
@@ -850,17 +850,17 @@ std::optional<lldb::SBLineEntry> Gotos::GetLineEntry(uint64_t id) const {
}
uint64_t Gotos::InsertLineEntry(lldb::SBLineEntry line_entry) {
- const auto spec_id = this->NewSpecId();
+ const auto spec_id = this->NewSpecID();
line_entries.insert(std::make_pair(spec_id, line_entry));
return spec_id;
}
void Gotos::Clear() {
- new_id = 0UL;
+ new_id = 0;
line_entries.clear();
}
-uint64_t Gotos::NewSpecId() { return new_id++; }
+uint64_t Gotos::NewSpecID() { return new_id++; }
void Variables::Clear() {
locals.Clear();
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index c64a668556e6e..08808d49be05e 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -92,10 +92,10 @@ class Gotos {
void Clear();
private:
- uint64_t NewSpecId();
+ uint64_t NewSpecID();
llvm::DenseMap<uint64_t, lldb::SBLineEntry> line_entries;
- uint64_t new_id = 0ul;
+ uint64_t new_id = 0;
};
struct Variables {
@@ -226,7 +226,7 @@ struct DAP {
// empty; if the previous expression was a variable expression, this string
// will contain that expression.
std::string last_nonempty_var_expression;
- Gotos goto_id_map;
+ Gotos gotos;
/// Creates a new DAP sessions.
///
@@ -391,7 +391,7 @@ struct DAP {
/// Debuggee will continue from stopped state.
void WillContinue() {
variables.Clear();
- goto_id_map.Clear();
+ gotos.Clear();
}
/// Poll the process to wait for it to reach the eStateStopped state.
diff --git a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
index 72448498d9cdd..064b35ce343c0 100644
--- a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
@@ -12,7 +12,7 @@
namespace lldb_dap {
-/// Creates an \p StoppedEvent with the reason \a goto
+/// Creates an \p StoppedEvent with the reason \a goto.
static void SendThreadGotoEvent(DAP &dap, lldb::tid_t thread_id) {
llvm::json::Object event(CreateEventObject("stopped"));
llvm::json::Object body;
@@ -83,31 +83,27 @@ void GoToRequestHandler::operator()(const llvm::json::Object &request) const {
const auto *goto_arguments = request.getObject("arguments");
if (goto_arguments == nullptr) {
- SendError("Arguments is empty");
- return;
+ return SendError("Arguments is empty");
}
lldb::SBThread current_thread = dap.GetLLDBThread(*goto_arguments);
if (!current_thread.IsValid()) {
- SendError(llvm::formatv("Thread id `{0}` is not valid",
- current_thread.GetThreadID()));
- return;
+ return SendError(llvm::formatv("Thread id `{0}` is not valid",
+ current_thread.GetThreadID()));
}
const auto target_id = GetInteger<uint64_t>(goto_arguments, "targetId");
- const auto line_entry = dap.goto_id_map.GetLineEntry(target_id.value());
+ const auto line_entry = dap.gotos.GetLineEntry(target_id.value());
if (!target_id || !line_entry) {
- SendError(llvm::formatv("Target id `{0}` is not valid",
- current_thread.GetThreadID()));
- return;
+ return SendError(llvm::formatv("Target id `{0}` is not valid",
+ current_thread.GetThreadID()));
}
auto file_spec = line_entry->GetFileSpec();
const auto error =
current_thread.JumpToLine(file_spec, line_entry->GetLine());
if (error.Fail()) {
- SendError(error.GetCString());
- return;
+ return SendError(error.GetCString());
}
dap.SendJSON(llvm::json::Value(std::move(response)));
diff --git a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
index 0dbe4379b636c..e17cf8e0bf17c 100644
--- a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
@@ -18,13 +18,13 @@ namespace lldb_dap {
static llvm::SmallVector<lldb::SBLineEntry>
GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) {
- // disable breakpoint listeners so they do not send events to the DAP client.
+ // Disable breakpoint listeners so they do not send events to the DAP client.
lldb::SBListener listener = dap.debugger.GetListener();
lldb::SBBroadcaster broadcaster = dap.target.GetBroadcaster();
constexpr auto event_mask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
listener.StopListeningForEvents(broadcaster, event_mask);
- // create a breakpoint to resolve the line if it is on an empty line.
+ // Create a breakpoint to resolve the line if it is on an empty line.
lldb::SBBreakpoint goto_bp =
dap.target.BreakpointCreateByLocation(file_spec, line);
if (!goto_bp.IsValid())
@@ -142,7 +142,7 @@ void GoToTargetsRequestHandler::operator()(
} else {
llvm::json::Array response_targets;
for (lldb::SBLineEntry &line_entry : goto_locations) {
- const uint64_t target_id = dap.goto_id_map.InsertLineEntry(line_entry);
+ const uint64_t target_id = dap.gotos.InsertLineEntry(line_entry);
const uint32_t target_line = line_entry.GetLine();
auto target = llvm::json::Object();
target.try_emplace("id", target_id);
>From cdaf3b4716fc237fcb0b1905483a558184f107fc Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 20 Mar 2025 15:47:31 +0000
Subject: [PATCH 21/26] [lldb-dap] update gototargets to use the new protocol
---
.../gotoTargets/TestDAP_gotoTargets.py | 4 +-
.../lldb-dap/Handler/GoToRequestHandler.cpp | 94 +++----------
.../Handler/GoToTargetsRequestHandler.cpp | 128 ++++--------------
lldb/tools/lldb-dap/Handler/RequestHandler.h | 24 ++--
.../lldb-dap/Protocol/ProtocolRequests.cpp | 20 +++
.../lldb-dap/Protocol/ProtocolRequests.h | 37 +++++
.../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 11 ++
lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 28 ++++
lldb/tools/lldb-dap/lldb-dap.cpp | 4 +-
9 files changed, 164 insertions(+), 186 deletions(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
index 4ce54f4f85df8..3fd06532d832c 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
@@ -63,7 +63,7 @@ def test_default(self):
response = self.dap_server.request_goto(thread_id, target_id)
self.assertEqual(response["success"], True, "goto request with targetId should be successful")
- stopped_events = self.dap_server.wait_for_stopped()
+ stopped_events = self.dap_server.wait_for_stopped(timeout=0.200)
is_goto = lambda event: event["body"]["reason"] == "goto"
has_goto_event = any(map(is_goto, stopped_events))
self.assertEqual(has_goto_event, True, "expected a stopped event with reason `goto`")
@@ -126,7 +126,7 @@ def test_execute_again(self):
response = self.dap_server.request_goto(thread_id, target_id)
self.assertEqual(response["success"], True, "expects success to go to targetId")
- stopped_events = self.dap_server.wait_for_stopped()
+ stopped_events = self.dap_server.wait_for_stopped(timeout=0.200) # 200ms
is_goto = lambda event: event["body"]["reason"] == "goto"
has_goto_event = any(map(is_goto, stopped_events))
self.assertEqual(has_goto_event, True, "expects stopped event with reason goto")
diff --git a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
index 064b35ce343c0..89c29fbb23bb7 100644
--- a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
@@ -9,6 +9,8 @@
#include "DAP.h"
#include "EventHelper.h"
#include "JSONUtils.h"
+#include "Protocol/ProtocolRequests.h"
+#include "RequestHandler.h"
namespace lldb_dap {
@@ -26,89 +28,35 @@ static void SendThreadGotoEvent(DAP &dap, lldb::tid_t thread_id) {
dap.SendJSON(llvm::json::Value(std::move(event)));
}
-// "GotoRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "The request sets the location where the debuggee will
-// continue to run.\nThis makes it possible to skip the execution of code or
-// to execute code again.\nThe code between the current location and the
-// goto target is not executed but skipped.\nThe debug adapter first sends
-// the response and then a `stopped` event with reason `goto`.\nClients
-// should only call this request if the corresponding capability
-// `supportsGotoTargetsRequest` is true (because only then goto targets
-// exist that can be passed as arguments).",
-//. "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "goto" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/GotoArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// }
-// "GotoArguments": {
-// "type": "object",
-// "description": "Arguments for `goto` request.",
-// "properties": {
-// "threadId": {
-// "type": "integer",
-// "description": "Set the goto target for this thread."
-// },
-// "targetId": {
-// "type": "integer",
-// "description": "The location where the debuggee will continue to run."
-// }
-// },
-// "required": [ "threadId", "targetId" ]
-// }
-// "GotoResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to `goto` request. This is just an
-// acknowledgement, so no body field is required."
-// }]
-// }
-void GoToRequestHandler::operator()(const llvm::json::Object &request) const {
- llvm::json::Object response;
- FillResponse(request, response);
+llvm::Expected<protocol::GotoResponseBody>
+GotoRequestHandler::Run(const protocol::GotoArguments &args) const {
+ const lldb::tid_t thread_id = args.threadId;
+ lldb::SBThread current_thread =
+ dap.target.GetProcess().GetThreadByID(thread_id);
- auto SendError = [&](auto &&message) {
- response["success"] = false;
- response["message"] = message;
- dap.SendJSON(llvm::json::Value(std::move(response)));
- };
-
- const auto *goto_arguments = request.getObject("arguments");
- if (goto_arguments == nullptr) {
- return SendError("Arguments is empty");
- }
-
- lldb::SBThread current_thread = dap.GetLLDBThread(*goto_arguments);
if (!current_thread.IsValid()) {
- return SendError(llvm::formatv("Thread id `{0}` is not valid",
- current_thread.GetThreadID()));
+ return llvm::createStringError(llvm::formatv("Thread id `{0}` is not valid",
+ current_thread.GetThreadID()));
}
- const auto target_id = GetInteger<uint64_t>(goto_arguments, "targetId");
- const auto line_entry = dap.gotos.GetLineEntry(target_id.value());
- if (!target_id || !line_entry) {
- return SendError(llvm::formatv("Target id `{0}` is not valid",
- current_thread.GetThreadID()));
+ const uint64_t target_id = args.targetId;
+ const std::optional<lldb::SBLineEntry> line_entry =
+ dap.gotos.GetLineEntry(target_id);
+ if (!line_entry) {
+ return llvm::createStringError(
+ llvm::formatv("Target id `{0}` is not valid", thread_id));
}
- auto file_spec = line_entry->GetFileSpec();
- const auto error =
+ lldb::SBFileSpec file_spec = line_entry->GetFileSpec();
+ const lldb::SBError error =
current_thread.JumpToLine(file_spec, line_entry->GetLine());
+
if (error.Fail()) {
- return SendError(error.GetCString());
+ return llvm::createStringError(error.GetCString());
}
- dap.SendJSON(llvm::json::Value(std::move(response)));
-
- SendThreadGotoEvent(dap, current_thread.GetThreadID());
+ SendThreadGotoEvent(dap, thread_id);
+ return protocol::GotoResponseBody();
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
index e17cf8e0bf17c..78029b850f751 100644
--- a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
@@ -9,6 +9,8 @@
#include "DAP.h"
#include "JSONUtils.h"
+#include "Protocol/ProtocolRequests.h"
+#include "RequestHandler.h"
#include <lldb/API/SBBreakpointLocation.h>
#include <lldb/API/SBListener.h>
@@ -20,7 +22,7 @@ static llvm::SmallVector<lldb::SBLineEntry>
GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) {
// Disable breakpoint listeners so they do not send events to the DAP client.
lldb::SBListener listener = dap.debugger.GetListener();
- lldb::SBBroadcaster broadcaster = dap.target.GetBroadcaster();
+ const lldb::SBBroadcaster broadcaster = dap.target.GetBroadcaster();
constexpr auto event_mask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
listener.StopListeningForEvents(broadcaster, event_mask);
@@ -55,111 +57,35 @@ GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) {
return entry_locations;
}
-// "GotoTargetsRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "This request retrieves the possible goto targets for the
-// specified source location.\nThese targets can be used in the `goto`
-// request.\nClients should only call this request if the corresponding
-// capability `supportsGotoTargetsRequest` is true.",
-//. "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "gotoTargets" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/GotoTargetsArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "GotoTargetsArguments": {
-// "type": "object",
-// "description": "Arguments for `gotoTargets` request.",
-// "properties": {
-// "source": {
-// "$ref": "#/definitions/Source",
-// "description": "The source location for which the goto targets are
-// determined."
-// },
-// "line": {
-// "type": "integer",
-// "description": "The line location for which the goto targets are
-// determined."
-// },
-// "column": {
-// "type": "integer",
-// "description": "The position within `line` for which the goto targets
-// are determined. It is measured in UTF-16 code units and the client
-// capability `columnsStartAt1` determines whether it is 0- or 1-based."
-// }
-// },
-// "required": [ "source", "line" ]
-// },
-// "GotoTargetsResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to `gotoTargets` request.",
-// "properties": {
-// "body": {
-// "type": "object",
-// "properties": {
-// "targets": {
-// "type": "array",
-// "items": {
-// "$ref": "#/definitions/GotoTarget"
-// },
-// "description": "The possible goto targets of the specified
-// location."
-// }
-// },
-// "required": [ "targets" ]
-// }
-// },
-// "required": [ "body" ]
-// }]
-// },
-void GoToTargetsRequestHandler::operator()(
- const llvm::json::Object &request) const {
- llvm::json::Object response;
- FillResponse(request, response);
-
- const llvm::json::Object *arguments = request.getObject("arguments");
- const llvm::json::Object *source = arguments->getObject("source");
- const std::string path = GetString(source, "path").str();
- const lldb::SBFileSpec file_spec(path.c_str(), true);
- const uint64_t goto_line =
- GetInteger<uint64_t>(arguments, "line").value_or(1U);
-
- llvm::json::Object body;
+/// GotoTargets request; value of command field is 'gotoTargets'.
+llvm::Expected<protocol::GotoTargetsResponseBody>
+GotoTargetsRequestHandler::Run(
+ const protocol::GotoTargetsArguments &args) const {
+ const lldb::SBFileSpec file_spec(args.source.path.value_or("").c_str(), true);
+ const uint64_t goto_line = args.line;
llvm::SmallVector<lldb::SBLineEntry> goto_locations =
GetLineValidEntry(dap, file_spec, goto_line);
- if (goto_locations.empty()) {
- response["success"] = false;
- response["message"] = "Invalid jump location";
- } else {
- llvm::json::Array response_targets;
- for (lldb::SBLineEntry &line_entry : goto_locations) {
- const uint64_t target_id = dap.gotos.InsertLineEntry(line_entry);
- const uint32_t target_line = line_entry.GetLine();
- auto target = llvm::json::Object();
- target.try_emplace("id", target_id);
-
- lldb::SBStream stream;
- line_entry.GetDescription(stream);
- target.try_emplace("label",
- llvm::StringRef(stream.GetData(), stream.GetSize()));
- target.try_emplace("line", target_line);
- response_targets.push_back(std::move(target));
- }
-
- body.try_emplace("targets", std::move(response_targets));
+
+ if (goto_locations.empty())
+ return llvm::createStringError("Invalid jump location");
+
+ protocol::GotoTargetsResponseBody body{};
+
+ for (lldb::SBLineEntry &line_entry : goto_locations) {
+ const uint64_t target_id = dap.gotos.InsertLineEntry(line_entry);
+ const uint32_t target_line = line_entry.GetLine();
+ protocol::GotoTarget target{};
+ target.id = target_id;
+
+ lldb::SBStream stream;
+ line_entry.GetDescription(stream);
+ target.label = std::string(stream.GetData(), stream.GetSize());
+ target.line = target_line;
+ body.targets.emplace_back(target);
}
- response.try_emplace("body", std::move(body));
- dap.SendJSON(llvm::json::Value(std::move(response)));
+ return body;
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 9929f7a7ed363..772de6e533522 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -235,18 +235,26 @@ class ExceptionInfoRequestHandler : public LegacyRequestHandler {
void operator()(const llvm::json::Object &request) const override;
};
-class GoToRequestHandler : public LegacyRequestHandler {
+class GotoRequestHandler final
+ : public RequestHandler<protocol::GotoArguments,
+ protocol::GotoResponseBody> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
- static llvm::StringLiteral getCommand() { return "goto"; }
- void operator()(const llvm::json::Object &request) const override;
+ using RequestHandler::RequestHandler;
+ static llvm::StringLiteral GetCommand() { return "goto"; }
+
+ llvm::Expected<protocol::GotoResponseBody>
+ Run(const protocol::GotoArguments &args) const override;
};
-class GoToTargetsRequestHandler : public LegacyRequestHandler {
+class GotoTargetsRequestHandler final
+ : public RequestHandler<protocol::GotoTargetsArguments,
+ protocol::GotoTargetsResponseBody> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
- static llvm::StringLiteral getCommand() { return "gotoTargets"; }
- void operator()(const llvm::json::Object &request) const override;
+ using RequestHandler::RequestHandler;
+ static llvm::StringLiteral GetCommand() { return "gotoTargets"; }
+
+ llvm::Expected<protocol::GotoTargetsResponseBody>
+ Run(const protocol::GotoTargetsArguments &args) const override;
};
class InitializeRequestHandler : public LegacyRequestHandler {
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index 5cc5429227439..44ed1f3605713 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -22,6 +22,26 @@ bool fromJSON(const json::Value &Params, DisconnectArguments &DA,
O.mapOptional("terminateDebuggee", DA.terminateDebuggee) &&
O.mapOptional("suspendDebuggee", DA.suspendDebuggee);
}
+bool fromJSON(const llvm::json::Value &Params, GotoArguments &GA,
+ llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("targetId", GA.targetId) && O.map("threadId", GA.threadId);
+}
+
+bool fromJSON(const llvm::json::Value &Params, GotoTargetsArguments >A,
+ llvm::json::Path P) {
+ json::ObjectMapper O(Params, P);
+ return O && O.map("source", GTA.source) && O.map("line", GTA.line) &&
+ O.mapOptional("column", GTA.column);
+}
+
+llvm::json::Value toJSON(const GotoTargetsResponseBody >A) {
+ json::Array targets;
+ for (const auto &target : GTA.targets) {
+ targets.emplace_back(target);
+ }
+ return json::Object{{"targets", std::move(targets)}};
+}
bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) {
json::ObjectMapper O(Params, P);
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index 5dc4a589178d2..48be745607136 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -54,6 +54,43 @@ bool fromJSON(const llvm::json::Value &, DisconnectArguments &,
/// body field is required.
using DisconnectResponse = VoidResponse;
+/// Arguments for `goto` request.
+struct GotoArguments {
+ /// Set the goto target for this thread.
+ uint64_t threadId;
+
+ /// The location where the debuggee will continue to run.
+ uint64_t targetId;
+};
+bool fromJSON(const llvm::json::Value &, GotoArguments &, llvm::json::Path);
+
+/// Response to goto request. This is just an acknowledgement, so no
+/// body field is required.
+using GotoResponseBody = VoidResponse;
+
+/// Arguments for `gotoTargets` request.
+struct GotoTargetsArguments {
+ /// The source location for which the goto targets are determined.
+ Source source;
+
+ /// The line location for which the goto targets are determined.
+ uint64_t line;
+
+ /// The position within `line` for which the goto targets are determined. It
+ /// is
+ /// measured in UTF-16 code units and the client capability `columnsStartAt1`
+ /// determines whether it is 0- or 1-based.
+ std::optional<uint64_t> column;
+};
+bool fromJSON(const llvm::json::Value &, GotoTargetsArguments &,
+ llvm::json::Path);
+
+struct GotoTargetsResponseBody {
+ /// The possible goto targets of the specified location.
+ llvm::SmallVector<GotoTarget> targets;
+};
+llvm::json::Value toJSON(const GotoTargetsResponseBody &);
+
/// Arguments for `source` request.
struct SourceArguments {
/// Specifies the source content to load. Either `source.path` or
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
index efb5c3abe32bf..8553b83c5df26 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp
@@ -37,6 +37,17 @@ bool fromJSON(const json::Value &Params, Source::PresentationHint &PH,
return true;
}
+llvm::json::Value toJSON(const GotoTarget &target) {
+ return llvm::json::Object{
+ {"id", target.id},
+ {"label", target.label},
+ {"line", target.line},
+ {"column", target.column},
+ {"endLine", target.endLine},
+ {"endColumn", target.endColumn},
+ {"instructionPointerReference", target.instructionPointerReference}};
+}
+
bool fromJSON(const json::Value &Params, Source &S, json::Path P) {
json::ObjectMapper O(Params, P);
return O && O.mapOptional("name", S.name) && O.mapOptional("path", S.path) &&
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
index b54d76cb29a77..606dc2b6ea133 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h
@@ -27,6 +27,34 @@
namespace lldb_dap::protocol {
+/// A `GotoTarget` describes a code location that can be used as a target
+/// in the goto request. The possible goto targets can be determined via the
+/// gotoTargets request.
+struct GotoTarget {
+ /// Unique identifier for a goto target. This is used in the `goto` request.
+ uint64_t id;
+
+ /// The name of the goto target (shown in the UI).
+ std::string label;
+
+ /// The line of the goto target.
+ uint64_t line;
+
+ /// The column of the goto target.
+ std::optional<uint64_t> column;
+
+ /// The end line of the range covered by the goto target.
+ std::optional<uint64_t> endLine;
+
+ /// The end column of the range covered by the goto target.
+ std::optional<uint64_t> endColumn;
+
+ /// A memory reference for the instruction pointer value represented by this
+ /// target.
+ std::optional<std::string> instructionPointerReference;
+};
+llvm::json::Value toJSON(const GotoTarget &);
+
/// A `Source` is a descriptor for source code. It is returned from the debug
/// adapter as part of a `StackFrame` and it is used by clients when specifying
/// breakpoints.
diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp
index 571a2c7df6818..10f027b0913ae 100644
--- a/lldb/tools/lldb-dap/lldb-dap.cpp
+++ b/lldb/tools/lldb-dap/lldb-dap.cpp
@@ -127,8 +127,8 @@ static void RegisterRequestCallbacks(DAP &dap) {
dap.RegisterRequest<EvaluateRequestHandler>();
dap.RegisterRequest<ExceptionInfoRequestHandler>();
dap.RegisterRequest<InitializeRequestHandler>();
- dap.RegisterRequest<GoToRequestHandler>();
- dap.RegisterRequest<GoToTargetsRequestHandler>();
+ dap.RegisterRequest<GotoRequestHandler>();
+ dap.RegisterRequest<GotoTargetsRequestHandler>();
dap.RegisterRequest<LaunchRequestHandler>();
dap.RegisterRequest<LocationsRequestHandler>();
dap.RegisterRequest<NextRequestHandler>();
>From 9173d8cf11008c6383fe3535fc66c70e601bf9dc Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 20 Mar 2025 16:04:44 +0000
Subject: [PATCH 22/26] [lldb-dap] Fix code format
---
.../API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
index 3fd06532d832c..abce981b0a8a3 100644
--- a/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
+++ b/lldb/test/API/tools/lldb-dap/gotoTargets/TestDAP_gotoTargets.py
@@ -61,12 +61,16 @@ def test_default(self):
self.assertIsNotNone(thread_id, "threadId should not be none")
response = self.dap_server.request_goto(thread_id, target_id)
- self.assertEqual(response["success"], True, "goto request with targetId should be successful")
+ self.assertEqual(
+ response["success"], True, "goto request with targetId should be successful"
+ )
stopped_events = self.dap_server.wait_for_stopped(timeout=0.200)
is_goto = lambda event: event["body"]["reason"] == "goto"
has_goto_event = any(map(is_goto, stopped_events))
- self.assertEqual(has_goto_event, True, "expected a stopped event with reason `goto`")
+ self.assertEqual(
+ has_goto_event, True, "expected a stopped event with reason `goto`"
+ )
self.dap_server.request_next(thread_id)
self.continue_to_next_stop()
>From 17e6c85b4df387c526d449e3f0e34fe7782ccdd0 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Thu, 20 Mar 2025 16:08:29 +0000
Subject: [PATCH 23/26] [lldb][lldb-dap] enable gotoTargets capability
---
lldb/tools/lldb-dap/DAP.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index ee9953fecb377..b34b5f73fb483 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -1174,13 +1174,13 @@ llvm::StringMap<bool> DAP::GetCapabilities() {
capabilities["supportsDelayedStackTraceLoading"] = true;
capabilities["supportsEvaluateForHovers"] = true;
capabilities["supportsExceptionOptions"] = true;
+ capabilities["supportsGotoTargetsRequest"] = true;
capabilities["supportsLogPoints"] = true;
capabilities["supportsProgressReporting"] = true;
capabilities["supportsSteppingGranularity"] = true;
capabilities["supportsValueFormattingOptions"] = true;
// Unsupported capabilities.
- capabilities["supportsGotoTargetsRequest"] = false;
capabilities["supportsLoadedSourcesRequest"] = false;
capabilities["supportsRestartFrame"] = false;
capabilities["supportsStepBack"] = false;
>From 066f2e2adad204cc6de0cd5f703ddbc4ef4310bf Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Wed, 26 Mar 2025 13:44:45 +0000
Subject: [PATCH 24/26] [lldb][lldb-dap] use std::vector instead of
llvm::DenseMap.
---
lldb/tools/lldb-dap/DAP.cpp | 19 ++++++-------------
lldb/tools/lldb-dap/DAP.h | 5 +----
2 files changed, 7 insertions(+), 17 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index b34b5f73fb483..e9c74c73004a4 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -842,25 +842,18 @@ lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) {
}
std::optional<lldb::SBLineEntry> Gotos::GetLineEntry(uint64_t id) const {
- const auto iter = line_entries.find(id);
- if (iter != line_entries.end())
- return iter->second;
+ if (id > line_entries.size())
+ return std::nullopt;
- return std::nullopt;
+ return line_entries[id - 1]; // id starts at one.
}
uint64_t Gotos::InsertLineEntry(lldb::SBLineEntry line_entry) {
- const auto spec_id = this->NewSpecID();
- line_entries.insert(std::make_pair(spec_id, line_entry));
- return spec_id;
+ line_entries.emplace_back(line_entry);
+ return line_entries.size();
}
-void Gotos::Clear() {
- new_id = 0;
- line_entries.clear();
-}
-
-uint64_t Gotos::NewSpecID() { return new_id++; }
+void Gotos::Clear() { line_entries.clear(); }
void Variables::Clear() {
locals.Clear();
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index 08808d49be05e..ec49732633aac 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -92,10 +92,7 @@ class Gotos {
void Clear();
private:
- uint64_t NewSpecID();
-
- llvm::DenseMap<uint64_t, lldb::SBLineEntry> line_entries;
- uint64_t new_id = 0;
+ std::vector<lldb::SBLineEntry> line_entries;
};
struct Variables {
>From 3ff328198f8a260073c56e1930a1d44e85d03bf7 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Wed, 26 Mar 2025 21:02:29 +0000
Subject: [PATCH 25/26] [lldb][lldb-dap] use llvm::smallVector as gotargets are
usually few
---
lldb/tools/lldb-dap/DAP.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h
index ec49732633aac..251abfd3a06e0 100644
--- a/lldb/tools/lldb-dap/DAP.h
+++ b/lldb/tools/lldb-dap/DAP.h
@@ -92,7 +92,7 @@ class Gotos {
void Clear();
private:
- std::vector<lldb::SBLineEntry> line_entries;
+ llvm::SmallVector<lldb::SBLineEntry> line_entries;
};
struct Variables {
>From 5c6140cffe00913c28586e4420a2fcdb47d9f5e1 Mon Sep 17 00:00:00 2001
From: Ebuka Ezike <yerimyah1 at gmail.com>
Date: Wed, 26 Mar 2025 22:02:33 +0000
Subject: [PATCH 26/26] [lldb][lldb-dap] Update with review changes
Remove disabling the breakpoint event listener.
Some of the error are not meant to be user facing as they cannot do anything with the message received.
---
lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp | 2 +-
lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp | 8 +-------
2 files changed, 2 insertions(+), 8 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
index 89c29fbb23bb7..11e0c6647c784 100644
--- a/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToRequestHandler.cpp
@@ -52,7 +52,7 @@ GotoRequestHandler::Run(const protocol::GotoArguments &args) const {
current_thread.JumpToLine(file_spec, line_entry->GetLine());
if (error.Fail()) {
- return llvm::createStringError(error.GetCString());
+ return llvm::make_error<DAPError>(error.GetCString());
}
SendThreadGotoEvent(dap, thread_id);
diff --git a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
index 78029b850f751..ed4e93dd92c16 100644
--- a/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/GoToTargetsRequestHandler.cpp
@@ -20,11 +20,6 @@ namespace lldb_dap {
static llvm::SmallVector<lldb::SBLineEntry>
GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) {
- // Disable breakpoint listeners so they do not send events to the DAP client.
- lldb::SBListener listener = dap.debugger.GetListener();
- const lldb::SBBroadcaster broadcaster = dap.target.GetBroadcaster();
- constexpr auto event_mask = lldb::SBTarget::eBroadcastBitBreakpointChanged;
- listener.StopListeningForEvents(broadcaster, event_mask);
// Create a breakpoint to resolve the line if it is on an empty line.
lldb::SBBreakpoint goto_bp =
@@ -52,7 +47,6 @@ GetLineValidEntry(DAP &dap, const lldb::SBFileSpec &file_spec, uint32_t line) {
// clean up;
dap.target.BreakpointDelete(goto_bp.GetID());
- listener.StartListeningForEvents(broadcaster, event_mask);
return entry_locations;
}
@@ -68,7 +62,7 @@ GotoTargetsRequestHandler::Run(
GetLineValidEntry(dap, file_spec, goto_line);
if (goto_locations.empty())
- return llvm::createStringError("Invalid jump location");
+ return llvm::make_error<DAPError>("Invalid jump location");
protocol::GotoTargetsResponseBody body{};
More information about the lldb-commits
mailing list