blob: 72580d2224a186a63c331dd0caeab9fe926e58a9 [file] [log] [blame] [edit]
//===-- RestartRequestHandler.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 "DAPError.h"
#include "EventHelper.h"
#include "LLDBUtils.h"
#include "Protocol/ProtocolRequests.h"
#include "RequestHandler.h"
using namespace lldb_dap;
using namespace lldb_dap::protocol;
/// 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.");
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(arguments->configuration, false);
dap.ConfigureSourceMaps();
}
}
// Keep track of the old PID so when we get a "process exited" event from the
// killed process we can detect it and not shut down the whole session.
lldb::SBProcess process = dap.target.GetProcess();
dap.restarting_process_id = process.GetProcessID();
// Stop the current process if necessary. The logic here is similar to
// CommandObjectProcessLaunchOrAttach::StopProcessIfNecessary, except that
// we don't ask the user for confirmation.
if (process.IsValid()) {
ScopeSyncMode scope_sync_mode(dap.debugger);
lldb::StateType state = process.GetState();
if (state != lldb::eStateConnected) {
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.
dap.thread_ids.clear();
}
// FIXME: Should we run 'preRunCommands'?
// FIXME: Should we add a 'preRestartCommands'?
if (llvm::Error error = LaunchProcess(*dap.last_launch_request))
return error;
SendProcessEvent(dap, Launch);
// This is normally done after receiving a "configuration done" request.
// Because we're restarting, configuration has already happened so we can
// continue the process right away.
if (dap.stop_at_entry)
return SendThreadStoppedEvent(dap, /*on_entry=*/true);
return ToError(dap.target.GetProcess().Continue());
}