https://github.com/DrSergei updated 
https://github.com/llvm/llvm-project/pull/172488

>From 614c66c30d341eaf560bb6806e5c8c634f239666 Mon Sep 17 00:00:00 2001
From: Druzhkov Sergei <[email protected]>
Date: Sun, 14 Dec 2025 23:29:11 +0300
Subject: [PATCH 1/3] [lldb-dap] Migrate restart request to structured types

---
 lldb/tools/lldb-dap/Handler/RequestHandler.h  |   9 +-
 .../Handler/RestartRequestHandler.cpp         | 117 ++++--------------
 .../lldb-dap/Protocol/ProtocolRequests.cpp    |  88 ++++++++++---
 .../lldb-dap/Protocol/ProtocolRequests.h      |  13 ++
 lldb/unittests/DAP/ProtocolRequestsTest.cpp   |  40 ++++++
 5 files changed, 154 insertions(+), 113 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h 
b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index 0669be50597e9..a18a8049c804d 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -340,11 +340,14 @@ class LaunchRequestHandler
   void PostRun() const override;
 };
 
-class RestartRequestHandler : public LegacyRequestHandler {
+class RestartRequestHandler
+    : public RequestHandler<std::optional<protocol::RestartArguments>,
+                            protocol::RestartResponse> {
 public:
-  using LegacyRequestHandler::LegacyRequestHandler;
+  using RequestHandler::RequestHandler;
   static llvm::StringLiteral GetCommand() { return "restart"; }
-  void operator()(const llvm::json::Object &request) const override;
+  llvm::Error
+  Run(const std::optional<protocol::RestartArguments> &args) const override;
 };
 
 class NextRequestHandler
diff --git a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
index 100173bfc3082..3a2be3f30c7cf 100644
--- a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
@@ -7,91 +7,37 @@
 
//===----------------------------------------------------------------------===//
 
 #include "DAP.h"
+#include "DAPError.h"
 #include "EventHelper.h"
-#include "JSONUtils.h"
 #include "LLDBUtils.h"
 #include "Protocol/ProtocolRequests.h"
 #include "RequestHandler.h"
-#include "llvm/Support/JSON.h"
-#include "llvm/Support/raw_ostream.h"
 
-namespace lldb_dap {
+using namespace lldb_dap;
+using namespace lldb_dap::protocol;
 
-// "RestartRequest": {
-//   "allOf": [ { "$ref": "#/definitions/Request" }, {
-//     "type": "object",
-//     "description": "Restarts a debug session. Clients should only call this
-//     request if the corresponding capability `supportsRestartRequest` is
-//     true.\nIf the capability is missing or has the value false, a typical
-//     client emulates `restart` by terminating the debug adapter first and 
then
-//     launching it anew.",
-//     "properties": {
-//       "command": {
-//         "type": "string",
-//         "enum": [ "restart" ]
-//       },
-//       "arguments": {
-//         "$ref": "#/definitions/RestartArguments"
-//       }
-//     },
-//     "required": [ "command" ]
-//   }]
-// },
-// "RestartArguments": {
-//   "type": "object",
-//   "description": "Arguments for `restart` request.",
-//   "properties": {
-//     "arguments": {
-//       "oneOf": [
-//         { "$ref": "#/definitions/LaunchRequestArguments" },
-//         { "$ref": "#/definitions/AttachRequestArguments" }
-//       ],
-//       "description": "The latest version of the `launch` or `attach`
-//       configuration."
-//     }
-//   }
-// },
-// "RestartResponse": {
-//   "allOf": [ { "$ref": "#/definitions/Response" }, {
-//     "type": "object",
-//     "description": "Response to `restart` request. This is just an
-//     acknowledgement, so no body field is required."
-//   }]
-// },
-void RestartRequestHandler::operator()(
-    const llvm::json::Object &request) const {
-  llvm::json::Object response;
-  FillResponse(request, response);
-  if (!dap.target.GetProcess().IsValid()) {
-    response["success"] = llvm::json::Value(false);
-    EmplaceSafeString(response, "message",
-                      "Restart request received but no process was launched.");
-    dap.SendJSON(llvm::json::Value(std::move(response)));
-    return;
-  }
+/// Restarts a debug session. Clients should only call this request if the
+/// corresponding capability `supportsRestartRequest` is true.
+/// If the capability is missing or has the value false, a typical client
+/// emulates `restart` by terminating the debug adapter first and then 
launching
+/// it anew.
+llvm::Error
+RestartRequestHandler::Run(const std::optional<RestartArguments> &args) const {
+  if (!dap.target.GetProcess().IsValid())
+    return llvm::make_error<DAPError>(
+        "Restart request received but no process was launched.");
 
-  const llvm::json::Object *arguments = request.getObject("arguments");
-  if (arguments) {
-    // The optional `arguments` field in RestartRequest can contain an updated
-    // version of the launch arguments. If there's one, use it.
-    if (const llvm::json::Value *restart_arguments =
-            arguments->get("arguments")) {
-      protocol::LaunchRequestArguments updated_arguments;
-      llvm::json::Path::Root root;
-      if (!fromJSON(*restart_arguments, updated_arguments, root)) {
-        response["success"] = llvm::json::Value(false);
-        EmplaceSafeString(
-            response, "message",
-            llvm::formatv("Failed to parse updated launch arguments: {0}",
-                          llvm::toString(root.getError()))
-                .str());
-        dap.SendJSON(llvm::json::Value(std::move(response)));
-        return;
-      }
-      dap.last_launch_request = updated_arguments;
+  if (args) {
+    if (std::holds_alternative<AttachRequestArguments>(args->arguments))
+      return llvm::make_error<DAPError>(
+          "Restarting an AttachRequest is not supported.");
+    if (const auto *arguments =
+            std::get_if<LaunchRequestArguments>(&args->arguments);
+        arguments) {
+      dap.last_launch_request = *arguments;
       // Update DAP configuration based on the latest copy of the launch
       // arguments.
-      dap.SetConfiguration(updated_arguments.configuration, false);
+      dap.SetConfiguration(arguments->configuration, false);
       dap.ConfigureSourceMaps();
     }
   }
@@ -117,12 +63,8 @@ void RestartRequestHandler::operator()(
 
   // FIXME: Should we run 'preRunCommands'?
   // FIXME: Should we add a 'preRestartCommands'?
-  if (llvm::Error err = LaunchProcess(*dap.last_launch_request)) {
-    response["success"] = llvm::json::Value(false);
-    EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-    dap.SendJSON(llvm::json::Value(std::move(response)));
-    return;
-  }
+  if (llvm::Error err = LaunchProcess(*dap.last_launch_request))
+    return llvm::make_error<DAPError>(llvm::toString(std::move(err)));
 
   SendProcessEvent(dap, Launch);
 
@@ -130,16 +72,11 @@ void RestartRequestHandler::operator()(
   // Because we're restarting, configuration has already happened so we can
   // continue the process right away.
   if (dap.stop_at_entry) {
-    if (llvm::Error err = SendThreadStoppedEvent(dap, /*on_entry=*/true)) {
-      EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
-      dap.SendJSON(llvm::json::Value(std::move(response)));
-      return;
-    }
+    if (llvm::Error err = SendThreadStoppedEvent(dap, /*on_entry=*/true))
+      return llvm::make_error<DAPError>(llvm::toString(std::move(err)));
   } else {
     dap.target.GetProcess().Continue();
   }
 
-  dap.SendJSON(llvm::json::Value(std::move(response)));
+  return llvm::Error::success();
 }
-
-} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index bf470b78077df..1c2cd158ffd29 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -296,31 +296,53 @@ bool fromJSON(const json::Value &Params, Console &C, 
json::Path P) {
 bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
               json::Path P) {
   json::ObjectMapper O(Params, P);
-  return O && fromJSON(Params, LRA.configuration, P) &&
-         O.mapOptional("noDebug", LRA.noDebug) &&
-         O.mapOptional("launchCommands", LRA.launchCommands) &&
-         O.mapOptional("cwd", LRA.cwd) && O.mapOptional("args", LRA.args) &&
-         O.mapOptional("detachOnError", LRA.detachOnError) &&
-         O.mapOptional("disableASLR", LRA.disableASLR) &&
-         O.mapOptional("disableSTDIO", LRA.disableSTDIO) &&
-         O.mapOptional("shellExpandArguments", LRA.shellExpandArguments) &&
-         O.mapOptional("runInTerminal", LRA.console) &&
-         O.mapOptional("console", LRA.console) &&
-         O.mapOptional("stdio", LRA.stdio) && parseEnv(Params, LRA.env, P);
+  bool success =
+      O && fromJSON(Params, LRA.configuration, P) &&
+      O.mapOptional("noDebug", LRA.noDebug) &&
+      O.mapOptional("launchCommands", LRA.launchCommands) &&
+      O.mapOptional("cwd", LRA.cwd) && O.mapOptional("args", LRA.args) &&
+      O.mapOptional("detachOnError", LRA.detachOnError) &&
+      O.mapOptional("disableASLR", LRA.disableASLR) &&
+      O.mapOptional("disableSTDIO", LRA.disableSTDIO) &&
+      O.mapOptional("shellExpandArguments", LRA.shellExpandArguments) &&
+      O.mapOptional("runInTerminal", LRA.console) &&
+      O.mapOptional("console", LRA.console) &&
+      O.mapOptional("stdio", LRA.stdio) && parseEnv(Params, LRA.env, P);
+  if (!success)
+    return false;
+  if (LRA.configuration.program.empty() && LRA.launchCommands.empty()) {
+    P.report("`program` or `launchCommands` should be provided");
+    return false;
+  }
+  return true;
 }
 
 bool fromJSON(const json::Value &Params, AttachRequestArguments &ARA,
               json::Path P) {
   json::ObjectMapper O(Params, P);
-  return O && fromJSON(Params, ARA.configuration, P) &&
-         O.mapOptional("attachCommands", ARA.attachCommands) &&
-         O.mapOptional("pid", ARA.pid) &&
-         O.mapOptional("waitFor", ARA.waitFor) &&
-         O.mapOptional("gdb-remote-port", ARA.gdbRemotePort) &&
-         O.mapOptional("gdb-remote-hostname", ARA.gdbRemoteHostname) &&
-         O.mapOptional("coreFile", ARA.coreFile) &&
-         O.mapOptional("targetId", ARA.targetId) &&
-         O.mapOptional("debuggerId", ARA.debuggerId);
+  bool success = O && fromJSON(Params, ARA.configuration, P) &&
+                 O.mapOptional("attachCommands", ARA.attachCommands) &&
+                 O.mapOptional("pid", ARA.pid) &&
+                 O.mapOptional("waitFor", ARA.waitFor) &&
+                 O.mapOptional("gdb-remote-port", ARA.gdbRemotePort) &&
+                 O.mapOptional("gdb-remote-hostname", ARA.gdbRemoteHostname) &&
+                 O.mapOptional("coreFile", ARA.coreFile) &&
+                 O.mapOptional("targetId", ARA.targetId) &&
+                 O.mapOptional("debuggerId", ARA.debuggerId);
+  if (!success)
+    return false;
+  if (ARA.debuggerId.has_value())
+    return true;
+  if (ARA.targetId.has_value())
+    return true;
+  if ((ARA.pid == LLDB_INVALID_PROCESS_ID) &&
+      ARA.configuration.program.empty() && ARA.attachCommands.empty() &&
+      ARA.coreFile.empty() && (ARA.gdbRemotePort == LLDB_DAP_INVALID_PORT)) {
+    P.report("`pid` or `program` or `attachCommands` or `coreFile` or "
+             "`gdbRemotePort` should be provided");
+    return false;
+  }
+  return true;
 }
 
 bool fromJSON(const json::Value &Params, ContinueArguments &CA, json::Path P) {
@@ -737,4 +759,30 @@ llvm::json::Value toJSON(const 
TestGetTargetBreakpointsResponseBody &Body) {
   return result;
 }
 
+bool fromJSON(const llvm::json::Value &Params, RestartArguments &Args,
+              llvm::json::Path Path) {
+  const json::Object *O = Params.getAsObject();
+  if (!O) {
+    Path.report("expected object");
+    return false;
+  }
+  const json::Value *arguments = O->get("arguments");
+  if (arguments == nullptr)
+    return true;
+  LaunchRequestArguments launchArguments;
+  llvm::json::Path::Root root;
+  if (fromJSON(*arguments, launchArguments, root)) {
+    Args.arguments = std::move(launchArguments);
+    return true;
+  }
+  AttachRequestArguments attachArguments;
+  if (fromJSON(*arguments, attachArguments, root)) {
+    Args.arguments = std::move(attachArguments);
+    return true;
+  }
+  Path.report(
+      "failed to parse arguments, expected `launch` or `attach` arguments");
+  return false;
+}
+
 } // namespace lldb_dap::protocol
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index cc123943ec0b6..33fcaae1710b5 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -31,6 +31,7 @@
 #include <cstdint>
 #include <optional>
 #include <string>
+#include <variant>
 #include <vector>
 
 namespace lldb_dap::protocol {
@@ -1255,6 +1256,18 @@ struct TestGetTargetBreakpointsResponseBody {
 };
 llvm::json::Value toJSON(const TestGetTargetBreakpointsResponseBody &);
 
+/// Arguments for `restart` request.
+struct RestartArguments {
+  /// The latest version of the `launch` or `attach` configuration.
+  std::variant<std::monostate, LaunchRequestArguments, AttachRequestArguments>
+      arguments = std::monostate{};
+};
+bool fromJSON(const llvm::json::Value &, RestartArguments &, llvm::json::Path);
+
+/// Response to `restart` request. This is just an acknowledgement, so no body
+/// field is required.
+using RestartResponse = VoidResponse;
+
 } // namespace lldb_dap::protocol
 
 #endif
diff --git a/lldb/unittests/DAP/ProtocolRequestsTest.cpp 
b/lldb/unittests/DAP/ProtocolRequestsTest.cpp
index 710b78960ef09..c639e40453fb0 100644
--- a/lldb/unittests/DAP/ProtocolRequestsTest.cpp
+++ b/lldb/unittests/DAP/ProtocolRequestsTest.cpp
@@ -304,3 +304,43 @@ TEST(ProtocolRequestsTest, 
TestGetTargetBreakpointsResponseBody) {
   ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
   EXPECT_EQ(PrettyPrint(*expected), PrettyPrint(body));
 }
+
+TEST(ProtocolRequestsTest, RestartArguments) {
+  llvm::Expected<RestartArguments> expected = parse<RestartArguments>(R"({})");
+  ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
+  EXPECT_TRUE(std::holds_alternative<std::monostate>(expected->arguments));
+
+  // Check missed keys.
+  expected = parse<RestartArguments>(R"({
+    "arguments": {}
+  })");
+  EXPECT_THAT_EXPECTED(expected,
+                       FailedWithMessage("failed to parse arguments, expected "
+                                         "`launch` or `attach` arguments"));
+
+  // Check launch arguments.
+  expected = parse<RestartArguments>(R"({
+    "arguments": {
+      "program": "main.exe",
+      "cwd": "/home/root"
+    }
+  })");
+  ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
+  const LaunchRequestArguments *launch_args =
+      std::get_if<LaunchRequestArguments>(&expected->arguments);
+  EXPECT_NE(launch_args, nullptr);
+  EXPECT_EQ(launch_args->configuration.program, "main.exe");
+  EXPECT_EQ(launch_args->cwd, "/home/root");
+
+  // Check attach arguments.
+  expected = parse<RestartArguments>(R"({
+    "arguments": {
+      "pid": 123
+    }
+  })");
+  ASSERT_THAT_EXPECTED(expected, llvm::Succeeded());
+  const AttachRequestArguments *attach_args =
+      std::get_if<AttachRequestArguments>(&expected->arguments);
+  EXPECT_NE(attach_args, nullptr);
+  EXPECT_EQ(attach_args->pid, 123U);
+}

>From 7253c4840bdae1ee2ff2d5f66a884edb783783f4 Mon Sep 17 00:00:00 2001
From: Druzhkov Sergei <[email protected]>
Date: Tue, 16 Dec 2025 21:14:18 +0300
Subject: [PATCH 2/3] Fix review comments

---
 .../tools/lldb-dap/attach/TestDAP_attach.py   |  2 +-
 .../tools/lldb-dap/launch/TestDAP_launch.py   |  2 +-
 .../lldb-dap/Handler/AttachRequestHandler.cpp | 22 -----------
 .../lldb-dap/Handler/LaunchRequestHandler.cpp |  6 ---
 .../Handler/RestartRequestHandler.cpp         |  4 +-
 .../lldb-dap/Protocol/ProtocolRequests.cpp    | 37 ++++++++++++++-----
 6 files changed, 31 insertions(+), 42 deletions(-)

diff --git a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py 
b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
index d6287397a93b0..e333ff84c100f 100644
--- a/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
+++ b/lldb/test/API/tools/lldb-dap/attach/TestDAP_attach.py
@@ -87,7 +87,7 @@ def test_attach_with_missing_debuggerId_or_targetId(self):
         resp = self.attach(targetId=99999, expectFailure=True)
         self.assertFalse(resp["success"])
         self.assertIn(
-            "Both debuggerId and targetId must be specified together",
+            "Both 'debuggerId' and 'targetId' must be specified together",
             resp["body"]["error"]["format"],
         )
 
diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py 
b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
index ca881f1d817c5..0cab7ed44740f 100644
--- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
+++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py
@@ -57,7 +57,7 @@ def test_failing_launch_commands_and_console(self):
         )
         self.assertFalse(response["success"])
         self.assertTrue(self.get_dict_value(response, ["body", "error", 
"showUser"]))
-        self.assertEqual(
+        self.assertIn(
             "'launchCommands' and non-internal 'console' are mutually 
exclusive",
             self.get_dict_value(response, ["body", "error", "format"]),
         )
diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
index f0996eb3ff0f4..1c14dcd16e5e6 100644
--- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
@@ -35,33 +35,11 @@ Error AttachRequestHandler::Run(const 
AttachRequestArguments &args) const {
   std::optional<int> debugger_id = args.debuggerId;
   std::optional<lldb::user_id_t> target_id = args.targetId;
 
-  // Validate that both debugger_id and target_id are provided together.
-  if (debugger_id.has_value() != target_id.has_value()) {
-    return llvm::createStringError(
-        "Both debuggerId and targetId must be specified together for debugger "
-        "reuse, or both must be omitted to create a new debugger");
-  }
-
   if (Error err = debugger_id && target_id
                       ? dap.InitializeDebugger(*debugger_id, *target_id)
                       : dap.InitializeDebugger())
     return err;
 
-  // Validate that we have a well formed attach request.
-  if (args.attachCommands.empty() && args.coreFile.empty() &&
-      args.configuration.program.empty() &&
-      args.pid == LLDB_INVALID_PROCESS_ID &&
-      args.gdbRemotePort == LLDB_DAP_INVALID_PORT && !target_id.has_value())
-    return make_error<DAPError>(
-        "expected one of 'pid', 'program', 'attachCommands', "
-        "'coreFile', 'gdb-remote-port', or target_id to be specified");
-
-  // Check if we have mutually exclusive arguments.
-  if ((args.pid != LLDB_INVALID_PROCESS_ID) &&
-      (args.gdbRemotePort != LLDB_DAP_INVALID_PORT))
-    return make_error<DAPError>(
-        "'pid' and 'gdb-remote-port' are mutually exclusive");
-
   dap.SetConfiguration(args.configuration, /*is_attach=*/true);
   if (!args.coreFile.empty())
     dap.stop_at_entry = true;
diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
index 329f0a7bf6453..33563cc7a5cee 100644
--- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
@@ -26,12 +26,6 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments 
&arguments) const {
   if (Error err = dap.InitializeDebugger())
     return err;
 
-  // Validate that we have a well formed launch request.
-  if (!arguments.launchCommands.empty() &&
-      arguments.console != protocol::eConsoleInternal)
-    return make_error<DAPError>(
-        "'launchCommands' and non-internal 'console' are mutually exclusive");
-
   dap.SetConfiguration(arguments.configuration, /*is_attach=*/false);
   dap.last_launch_request = arguments;
 
diff --git a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
index 3a2be3f30c7cf..804d982d5d199 100644
--- a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
@@ -64,7 +64,7 @@ RestartRequestHandler::Run(const 
std::optional<RestartArguments> &args) const {
   // FIXME: Should we run 'preRunCommands'?
   // FIXME: Should we add a 'preRestartCommands'?
   if (llvm::Error err = LaunchProcess(*dap.last_launch_request))
-    return llvm::make_error<DAPError>(llvm::toString(std::move(err)));
+    return err;
 
   SendProcessEvent(dap, Launch);
 
@@ -73,7 +73,7 @@ RestartRequestHandler::Run(const 
std::optional<RestartArguments> &args) const {
   // continue the process right away.
   if (dap.stop_at_entry) {
     if (llvm::Error err = SendThreadStoppedEvent(dap, /*on_entry=*/true))
-      return llvm::make_error<DAPError>(llvm::toString(std::move(err)));
+      return err;
   } else {
     dap.target.GetProcess().Continue();
   }
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp 
b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index 1c2cd158ffd29..c87111d8f1b78 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -310,8 +310,15 @@ bool fromJSON(const json::Value &Params, 
LaunchRequestArguments &LRA,
       O.mapOptional("stdio", LRA.stdio) && parseEnv(Params, LRA.env, P);
   if (!success)
     return false;
+  // Validate that we have a well formed launch request.
+  if (!LRA.launchCommands.empty() &&
+      LRA.console != protocol::eConsoleInternal) {
+    P.report(
+        "'launchCommands' and non-internal 'console' are mutually exclusive");
+    return false;
+  }
   if (LRA.configuration.program.empty() && LRA.launchCommands.empty()) {
-    P.report("`program` or `launchCommands` should be provided");
+    P.report("'program' or 'launchCommands' should be provided");
     return false;
   }
   return true;
@@ -331,15 +338,25 @@ bool fromJSON(const json::Value &Params, 
AttachRequestArguments &ARA,
                  O.mapOptional("debuggerId", ARA.debuggerId);
   if (!success)
     return false;
-  if (ARA.debuggerId.has_value())
-    return true;
-  if (ARA.targetId.has_value())
-    return true;
-  if ((ARA.pid == LLDB_INVALID_PROCESS_ID) &&
-      ARA.configuration.program.empty() && ARA.attachCommands.empty() &&
-      ARA.coreFile.empty() && (ARA.gdbRemotePort == LLDB_DAP_INVALID_PORT)) {
-    P.report("`pid` or `program` or `attachCommands` or `coreFile` or "
-             "`gdbRemotePort` should be provided");
+  // Validate that we have a well formed attach request.
+  if (ARA.attachCommands.empty() && ARA.coreFile.empty() &&
+      ARA.configuration.program.empty() && ARA.pid == LLDB_INVALID_PROCESS_ID 
&&
+      ARA.gdbRemotePort == LLDB_DAP_INVALID_PORT && !ARA.targetId.has_value()) 
{
+    P.report("expected one of 'pid', 'program', 'attachCommands', "
+             "'coreFile', 'gdb-remote-port', or 'targetId' to be specified");
+    return false;
+  }
+  // Check if we have mutually exclusive arguments.
+  if ((ARA.pid != LLDB_INVALID_PROCESS_ID) &&
+      (ARA.gdbRemotePort != LLDB_DAP_INVALID_PORT)) {
+    P.report("'pid' and 'gdb-remote-port' are mutually exclusive");
+    return false;
+  }
+  // Validate that both debugger_id and target_id are provided together.
+  if (ARA.debuggerId.has_value() != ARA.targetId.has_value()) {
+    P.report(
+        "Both 'debuggerId' and 'targetId' must be specified together for "
+        "debugger reuse, or both must be omitted to create a new debugger");
     return false;
   }
   return true;

>From 03974147a6e0f1ccb5642932eb739b49c4058910 Mon Sep 17 00:00:00 2001
From: Druzhkov Sergei <[email protected]>
Date: Tue, 16 Dec 2025 23:53:36 +0300
Subject: [PATCH 3/3] Improve error handling

---
 .../lldb-dap/Handler/RestartRequestHandler.cpp    | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp 
b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
index 804d982d5d199..2562a8f050c96 100644
--- a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
@@ -12,6 +12,7 @@
 #include "LLDBUtils.h"
 #include "Protocol/ProtocolRequests.h"
 #include "RequestHandler.h"
+#include "lldb/API/SBError.h"
 
 using namespace lldb_dap;
 using namespace lldb_dap::protocol;
@@ -54,7 +55,8 @@ RestartRequestHandler::Run(const 
std::optional<RestartArguments> &args) const {
     ScopeSyncMode scope_sync_mode(dap.debugger);
     lldb::StateType state = process.GetState();
     if (state != lldb::eStateConnected) {
-      process.Kill();
+      if (lldb::SBError error = process.Kill(); error.Fail())
+        return ToError(error);
     }
     // Clear the list of thread ids to avoid sending "thread exited" events
     // for threads of the process we are terminating.
@@ -63,8 +65,8 @@ RestartRequestHandler::Run(const 
std::optional<RestartArguments> &args) const {
 
   // FIXME: Should we run 'preRunCommands'?
   // FIXME: Should we add a 'preRestartCommands'?
-  if (llvm::Error err = LaunchProcess(*dap.last_launch_request))
-    return err;
+  if (llvm::Error error = LaunchProcess(*dap.last_launch_request))
+    return error;
 
   SendProcessEvent(dap, Launch);
 
@@ -72,10 +74,11 @@ RestartRequestHandler::Run(const 
std::optional<RestartArguments> &args) const {
   // Because we're restarting, configuration has already happened so we can
   // continue the process right away.
   if (dap.stop_at_entry) {
-    if (llvm::Error err = SendThreadStoppedEvent(dap, /*on_entry=*/true))
-      return err;
+    if (llvm::Error error = SendThreadStoppedEvent(dap, /*on_entry=*/true))
+      return error;
   } else {
-    dap.target.GetProcess().Continue();
+    if (lldb::SBError error = dap.target.GetProcess().Continue(); error.Fail())
+      return ToError(error);
   }
 
   return llvm::Error::success();

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to