[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 &GTA,
+              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 &GTA) {
+  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