146 lines · cpp
1//===-- RestartRequestHandler.cpp -----------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "DAP.h"10#include "EventHelper.h"11#include "JSONUtils.h"12#include "LLDBUtils.h"13#include "Protocol/ProtocolRequests.h"14#include "RequestHandler.h"15#include "llvm/Support/JSON.h"16#include "llvm/Support/raw_ostream.h"17 18namespace lldb_dap {19 20// "RestartRequest": {21// "allOf": [ { "$ref": "#/definitions/Request" }, {22// "type": "object",23// "description": "Restarts a debug session. Clients should only call this24// request if the corresponding capability `supportsRestartRequest` is25// true.\nIf the capability is missing or has the value false, a typical26// client emulates `restart` by terminating the debug adapter first and then27// launching it anew.",28// "properties": {29// "command": {30// "type": "string",31// "enum": [ "restart" ]32// },33// "arguments": {34// "$ref": "#/definitions/RestartArguments"35// }36// },37// "required": [ "command" ]38// }]39// },40// "RestartArguments": {41// "type": "object",42// "description": "Arguments for `restart` request.",43// "properties": {44// "arguments": {45// "oneOf": [46// { "$ref": "#/definitions/LaunchRequestArguments" },47// { "$ref": "#/definitions/AttachRequestArguments" }48// ],49// "description": "The latest version of the `launch` or `attach`50// configuration."51// }52// }53// },54// "RestartResponse": {55// "allOf": [ { "$ref": "#/definitions/Response" }, {56// "type": "object",57// "description": "Response to `restart` request. This is just an58// acknowledgement, so no body field is required."59// }]60// },61void RestartRequestHandler::operator()(62 const llvm::json::Object &request) const {63 llvm::json::Object response;64 FillResponse(request, response);65 if (!dap.target.GetProcess().IsValid()) {66 response["success"] = llvm::json::Value(false);67 EmplaceSafeString(response, "message",68 "Restart request received but no process was launched.");69 dap.SendJSON(llvm::json::Value(std::move(response)));70 return;71 }72 73 const llvm::json::Object *arguments = request.getObject("arguments");74 if (arguments) {75 // The optional `arguments` field in RestartRequest can contain an updated76 // version of the launch arguments. If there's one, use it.77 if (const llvm::json::Value *restart_arguments =78 arguments->get("arguments")) {79 protocol::LaunchRequestArguments updated_arguments;80 llvm::json::Path::Root root;81 if (!fromJSON(*restart_arguments, updated_arguments, root)) {82 response["success"] = llvm::json::Value(false);83 EmplaceSafeString(84 response, "message",85 llvm::formatv("Failed to parse updated launch arguments: {0}",86 llvm::toString(root.getError()))87 .str());88 dap.SendJSON(llvm::json::Value(std::move(response)));89 return;90 }91 dap.last_launch_request = updated_arguments;92 // Update DAP configuration based on the latest copy of the launch93 // arguments.94 dap.SetConfiguration(updated_arguments.configuration, false);95 dap.ConfigureSourceMaps();96 }97 }98 99 // Keep track of the old PID so when we get a "process exited" event from the100 // killed process we can detect it and not shut down the whole session.101 lldb::SBProcess process = dap.target.GetProcess();102 dap.restarting_process_id = process.GetProcessID();103 104 // Stop the current process if necessary. The logic here is similar to105 // CommandObjectProcessLaunchOrAttach::StopProcessIfNecessary, except that106 // we don't ask the user for confirmation.107 if (process.IsValid()) {108 ScopeSyncMode scope_sync_mode(dap.debugger);109 lldb::StateType state = process.GetState();110 if (state != lldb::eStateConnected) {111 process.Kill();112 }113 // Clear the list of thread ids to avoid sending "thread exited" events114 // for threads of the process we are terminating.115 dap.thread_ids.clear();116 }117 118 // FIXME: Should we run 'preRunCommands'?119 // FIXME: Should we add a 'preRestartCommands'?120 if (llvm::Error err = LaunchProcess(*dap.last_launch_request)) {121 response["success"] = llvm::json::Value(false);122 EmplaceSafeString(response, "message", llvm::toString(std::move(err)));123 dap.SendJSON(llvm::json::Value(std::move(response)));124 return;125 }126 127 SendProcessEvent(dap, Launch);128 129 // This is normally done after receiving a "configuration done" request.130 // Because we're restarting, configuration has already happened so we can131 // continue the process right away.132 if (dap.stop_at_entry) {133 if (llvm::Error err = SendThreadStoppedEvent(dap, /*on_entry=*/true)) {134 EmplaceSafeString(response, "message", llvm::toString(std::move(err)));135 dap.SendJSON(llvm::json::Value(std::move(response)));136 return;137 }138 } else {139 dap.target.GetProcess().Continue();140 }141 142 dap.SendJSON(llvm::json::Value(std::move(response)));143}144 145} // namespace lldb_dap146