| //===-- 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()); |
| } |