[Lldb-commits] [lldb] [lldb-dap] Migrate attach to typed RequestHandler. (PR #137911)
John Harrison via lldb-commits
lldb-commits at lists.llvm.org
Tue May 6 17:01:32 PDT 2025
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/137911
>From a43b90dba56bd411b09257d47e3a3091faa09efd Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Tue, 29 Apr 2025 17:36:46 -0700
Subject: [PATCH 1/7] [lldb-dap] Migrate attach to typed RequestHandler.
This updates the `attach` request to the typed `RequestHandler<protocol::AttachRequestArguments, protocol::AttachResponse>`.
Added a few more overlapping configurations to `lldb_dap::protocol::Configuration` that are shared between launching and attaching.
There may be some additional code we could clean-up that is no longer referenced now that this has migrated to use well defined types.
---
lldb/tools/lldb-dap/DAP.cpp | 26 +--
.../lldb-dap/Handler/AttachRequestHandler.cpp | 214 ++++++------------
.../Handler/InitializeRequestHandler.cpp | 2 +-
.../lldb-dap/Handler/LaunchRequestHandler.cpp | 6 +-
.../tools/lldb-dap/Handler/RequestHandler.cpp | 64 +-----
lldb/tools/lldb-dap/Handler/RequestHandler.h | 21 +-
.../Handler/RestartRequestHandler.cpp | 1 -
.../lldb-dap/Protocol/ProtocolRequests.cpp | 35 ++-
.../lldb-dap/Protocol/ProtocolRequests.h | 87 +++++--
lldb/tools/lldb-dap/package.json | 13 +-
10 files changed, 204 insertions(+), 265 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index b593353110787..abed9983118f9 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -675,12 +675,11 @@ lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) {
// enough information to determine correct arch and platform (or ELF can be
// omitted at all), so it is good to leave the user an opportunity to specify
// those. Any of those three can be left empty.
- auto target = this->debugger.CreateTarget(
- configuration.program.value_or("").data(),
- configuration.targetTriple.value_or("").data(),
- configuration.platformName.value_or("").data(),
- true, // Add dependent modules.
- error);
+ auto target = this->debugger.CreateTarget(configuration.program.data(),
+ configuration.targetTriple.data(),
+ configuration.platformName.data(),
+ true, // Add dependent modules.
+ error);
return target;
}
@@ -1192,7 +1191,7 @@ bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger,
}
void DAP::ConfigureSourceMaps() {
- if (configuration.sourceMap.empty() && !configuration.sourcePath)
+ if (configuration.sourceMap.empty() && configuration.sourcePath.empty())
return;
std::string sourceMapCommand;
@@ -1203,8 +1202,8 @@ void DAP::ConfigureSourceMaps() {
for (const auto &kv : configuration.sourceMap) {
strm << "\"" << kv.first << "\" \"" << kv.second << "\" ";
}
- } else if (configuration.sourcePath) {
- strm << "\".\" \"" << *configuration.sourcePath << "\"";
+ } else if (!configuration.sourcePath.empty()) {
+ strm << "\".\" \"" << configuration.sourcePath << "\"";
}
RunLLDBCommands("Setting source map:", {sourceMapCommand});
@@ -1213,12 +1212,13 @@ void DAP::ConfigureSourceMaps() {
void DAP::SetConfiguration(const protocol::Configuration &config,
bool is_attach) {
configuration = config;
+ stop_at_entry = config.stopOnEntry;
this->is_attach = is_attach;
- if (configuration.customFrameFormat)
- SetFrameFormat(*configuration.customFrameFormat);
- if (configuration.customThreadFormat)
- SetThreadFormat(*configuration.customThreadFormat);
+ if (!configuration.customFrameFormat.empty())
+ SetFrameFormat(configuration.customFrameFormat);
+ if (!configuration.customThreadFormat.empty())
+ SetThreadFormat(configuration.customThreadFormat);
}
void DAP::SetFrameFormat(llvm::StringRef format) {
diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
index 3ef87cbef873c..fd19a4f835686 100644
--- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
@@ -9,203 +9,135 @@
#include "DAP.h"
#include "EventHelper.h"
#include "JSONUtils.h"
+#include "LLDBUtils.h"
+#include "Protocol/ProtocolRequests.h"
#include "RequestHandler.h"
#include "lldb/API/SBListener.h"
+#include "lldb/lldb-defines.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
+using namespace llvm;
+using namespace lldb_dap::protocol;
+
namespace lldb_dap {
-// "AttachRequest": {
-// "allOf": [ { "$ref": "#/definitions/Request" }, {
-// "type": "object",
-// "description": "Attach request; value of command field is 'attach'.",
-// "properties": {
-// "command": {
-// "type": "string",
-// "enum": [ "attach" ]
-// },
-// "arguments": {
-// "$ref": "#/definitions/AttachRequestArguments"
-// }
-// },
-// "required": [ "command", "arguments" ]
-// }]
-// },
-// "AttachRequestArguments": {
-// "type": "object",
-// "description": "Arguments for 'attach' request.\nThe attach request has no
-// standardized attributes."
-// },
-// "AttachResponse": {
-// "allOf": [ { "$ref": "#/definitions/Response" }, {
-// "type": "object",
-// "description": "Response to 'attach' request. This is just an
-// acknowledgement, so no body field is required."
-// }]
-// }
-void AttachRequestHandler::operator()(const llvm::json::Object &request) const {
- dap.is_attach = true;
- llvm::json::Object response;
- lldb::SBError error;
- FillResponse(request, response);
- lldb::SBAttachInfo attach_info;
- const int invalid_port = 0;
- const auto *arguments = request.getObject("arguments");
- const lldb::pid_t pid =
- GetInteger<uint64_t>(arguments, "pid").value_or(LLDB_INVALID_PROCESS_ID);
- const auto gdb_remote_port =
- GetInteger<uint64_t>(arguments, "gdb-remote-port").value_or(invalid_port);
- const auto gdb_remote_hostname =
- GetString(arguments, "gdb-remote-hostname").value_or("localhost");
- if (pid != LLDB_INVALID_PROCESS_ID)
- attach_info.SetProcessID(pid);
- const auto wait_for = GetBoolean(arguments, "waitFor").value_or(false);
- attach_info.SetWaitForLaunch(wait_for, false /*async*/);
- dap.configuration.initCommands = GetStrings(arguments, "initCommands");
- dap.configuration.preRunCommands = GetStrings(arguments, "preRunCommands");
- dap.configuration.postRunCommands = GetStrings(arguments, "postRunCommands");
- dap.configuration.stopCommands = GetStrings(arguments, "stopCommands");
- dap.configuration.exitCommands = GetStrings(arguments, "exitCommands");
- dap.configuration.terminateCommands =
- GetStrings(arguments, "terminateCommands");
- auto attachCommands = GetStrings(arguments, "attachCommands");
- llvm::StringRef core_file = GetString(arguments, "coreFile").value_or("");
- const uint64_t timeout_seconds =
- GetInteger<uint64_t>(arguments, "timeout").value_or(30);
- dap.stop_at_entry = core_file.empty()
- ? GetBoolean(arguments, "stopOnEntry").value_or(false)
- : true;
- const llvm::StringRef debuggerRoot =
- GetString(arguments, "debuggerRoot").value_or("");
- dap.configuration.enableAutoVariableSummaries =
- GetBoolean(arguments, "enableAutoVariableSummaries").value_or(false);
- dap.configuration.enableSyntheticChildDebugging =
- GetBoolean(arguments, "enableSyntheticChildDebugging").value_or(false);
- dap.configuration.displayExtendedBacktrace =
- GetBoolean(arguments, "displayExtendedBacktrace").value_or(false);
- dap.configuration.commandEscapePrefix =
- GetString(arguments, "commandEscapePrefix").value_or("`");
- dap.configuration.program = GetString(arguments, "program");
- dap.configuration.targetTriple = GetString(arguments, "targetTriple");
- dap.configuration.platformName = GetString(arguments, "platformName");
- dap.SetFrameFormat(GetString(arguments, "customFrameFormat").value_or(""));
- dap.SetThreadFormat(GetString(arguments, "customThreadFormat").value_or(""));
+/// The `attach` request is sent from the client to the debug adapter to attach
+/// to a debuggee that is already running.
+///
+/// Since attaching is debugger/runtime specific, the arguments for this request
+/// are not part of this specification.
+Error AttachRequestHandler::Run(const AttachRequestArguments &args) const {
+ dap.SetConfiguration(args.configuration, true);
+ if (!args.coreFile.empty())
+ dap.stop_at_entry = true;
+
+ // If both pid and port numbers are specified.
+ 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");
PrintWelcomeMessage();
// This is a hack for loading DWARF in .o files on Mac where the .o files
- // in the debug map of the main executable have relative paths which require
- // the lldb-dap binary to have its working directory set to that relative
- // root for the .o files in order to be able to load debug info.
- if (!debuggerRoot.empty())
- llvm::sys::fs::set_current_path(debuggerRoot);
+ // in the debug map of the main executable have relative paths which
+ // require the lldb-dap binary to have its working directory set to that
+ // relative root for the .o files in order to be able to load debug info.
+ if (!dap.configuration.debuggerRoot.empty())
+ sys::fs::set_current_path(dap.configuration.debuggerRoot);
// Run any initialize LLDB commands the user specified in the launch.json
- if (llvm::Error err = dap.RunInitCommands()) {
- response["success"] = false;
- EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
- }
+ if (llvm::Error err = dap.RunInitCommands())
+ return err;
- SetSourceMapFromArguments(*arguments);
+ dap.ConfigureSourceMaps();
- lldb::SBError status;
- dap.SetTarget(dap.CreateTarget(status));
- if (status.Fail()) {
- response["success"] = llvm::json::Value(false);
- EmplaceSafeString(response, "message", status.GetCString());
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
- }
+ lldb::SBError error;
+ lldb::SBTarget target = dap.CreateTarget(error);
+ if (error.Fail())
+ return ToError(error);
+
+ dap.SetTarget(target);
// Run any pre run LLDB commands the user specified in the launch.json
- if (llvm::Error err = dap.RunPreRunCommands()) {
- response["success"] = false;
- EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
- }
+ if (Error err = dap.RunPreRunCommands())
+ return err;
- if ((pid == LLDB_INVALID_PROCESS_ID || gdb_remote_port == invalid_port) &&
- wait_for) {
+ if ((args.pid == LLDB_INVALID_PROCESS_ID ||
+ args.gdbRemotePort == LLDB_DAP_INVALID_PORT) &&
+ args.waitFor) {
char attach_msg[256];
auto attach_msg_len = snprintf(attach_msg, sizeof(attach_msg),
"Waiting to attach to \"%s\"...",
dap.target.GetExecutable().GetFilename());
- dap.SendOutput(OutputType::Console,
- llvm::StringRef(attach_msg, attach_msg_len));
+ dap.SendOutput(OutputType::Console, StringRef(attach_msg, attach_msg_len));
}
- if (attachCommands.empty()) {
+
+ if (args.attachCommands.empty()) {
// No "attachCommands", just attach normally.
// Disable async events so the attach will be successful when we return from
// the launch call and the launch will happen synchronously
dap.debugger.SetAsync(false);
- if (core_file.empty()) {
- if ((pid != LLDB_INVALID_PROCESS_ID) &&
- (gdb_remote_port != invalid_port)) {
- // If both pid and port numbers are specified.
- error.SetErrorString("The user can't specify both pid and port");
- } else if (gdb_remote_port != invalid_port) {
+ if (args.coreFile.empty()) {
+ if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) {
// If port is specified and pid is not.
lldb::SBListener listener = dap.debugger.GetListener();
// If the user hasn't provided the hostname property, default localhost
// being used.
std::string connect_url =
- llvm::formatv("connect://{0}:", gdb_remote_hostname);
- connect_url += std::to_string(gdb_remote_port);
- dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote",
+ llvm::formatv("connect://{0}:", args.gdbRemoteHostname);
+ connect_url += std::to_string(args.gdbRemotePort);
+ dap.target.ConnectRemote(listener, connect_url.data(), "gdb-remote",
error);
} else {
// Attach by process name or id.
+ lldb::SBAttachInfo attach_info;
+ if (!args.configuration.program.empty())
+ attach_info.SetExecutable(args.configuration.program.data());
+ if (args.pid != LLDB_INVALID_PROCESS_ID)
+ attach_info.SetProcessID(args.pid);
+ attach_info.SetWaitForLaunch(args.waitFor, false /*async*/);
dap.target.Attach(attach_info, error);
}
} else
- dap.target.LoadCore(core_file.data(), error);
+ dap.target.LoadCore(args.coreFile.data(), error);
// Reenable async events
dap.debugger.SetAsync(true);
} else {
// We have "attachCommands" that are a set of commands that are expected
// to execute the commands after which a process should be created. If there
// is no valid process after running these commands, we have failed.
- if (llvm::Error err = dap.RunAttachCommands(attachCommands)) {
- response["success"] = false;
- EmplaceSafeString(response, "message", llvm::toString(std::move(err)));
- dap.SendJSON(llvm::json::Value(std::move(response)));
- return;
- }
+ if (llvm::Error err = dap.RunAttachCommands(args.attachCommands))
+ return err;
+
// The custom commands might have created a new target so we should use the
// selected target after these commands are run.
dap.target = dap.debugger.GetSelectedTarget();
// Make sure the process is attached and stopped before proceeding as the
// the launch commands are not run using the synchronous mode.
- error = dap.WaitForProcessToStop(std::chrono::seconds(timeout_seconds));
+ error = dap.WaitForProcessToStop(dap.configuration.timeout);
}
- if (error.Success() && core_file.empty()) {
- auto attached_pid = dap.target.GetProcess().GetProcessID();
- if (attached_pid == LLDB_INVALID_PROCESS_ID) {
- if (attachCommands.empty())
- error.SetErrorString("failed to attach to a process");
- else
- error.SetErrorString("attachCommands failed to attach to a process");
- }
- }
+ if (error.Fail())
+ return ToError(error);
- if (error.Fail()) {
- response["success"] = llvm::json::Value(false);
- EmplaceSafeString(response, "message", std::string(error.GetCString()));
- } else {
- dap.RunPostRunCommands();
- }
+ if (args.coreFile.empty() && !dap.target.GetProcess().IsValid())
+ return make_error<DAPError>("failed to attach to process");
- dap.SendJSON(llvm::json::Value(std::move(response)));
- if (error.Success()) {
+ dap.RunPostRunCommands();
+
+ return Error::success();
+}
+
+void AttachRequestHandler::PostRun() const {
+ if (dap.target.GetProcess().IsValid()) {
SendProcessEvent(dap, Attach);
- dap.SendJSON(CreateEventObject("initialized"));
}
+
+ dap.SendJSON(CreateEventObject("initialized"));
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
index ce34c52bcc334..7a2adef4b2faf 100644
--- a/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp
@@ -277,7 +277,7 @@ static void EventThreadFunction(DAP &dap) {
}
/// Initialize request; value of command field is 'initialize'.
-llvm::Expected<InitializeResponseBody> InitializeRequestHandler::Run(
+llvm::Expected<InitializeResponse> InitializeRequestHandler::Run(
const InitializeRequestArguments &arguments) const {
dap.clientFeatures = arguments.supportedFeatures;
diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
index 3e4532e754ec6..fd0846bd00f45 100644
--- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
@@ -24,7 +24,6 @@ namespace lldb_dap {
Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const {
dap.SetConfiguration(arguments.configuration, /*is_attach=*/false);
dap.last_launch_request = arguments;
- dap.stop_at_entry = arguments.stopOnEntry;
if (!arguments.launchCommands.empty() && arguments.runInTerminal)
return make_error<DAPError>(
@@ -36,9 +35,8 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const {
// in the debug map of the main executable have relative paths which
// require the lldb-dap binary to have its working directory set to that
// relative root for the .o files in order to be able to load debug info.
- const std::string debugger_root = dap.configuration.debuggerRoot.value_or("");
- if (!debugger_root.empty())
- sys::fs::set_current_path(debugger_root);
+ if (!dap.configuration.debuggerRoot.empty())
+ sys::fs::set_current_path(dap.configuration.debuggerRoot);
// Run any initialize LLDB commands the user specified in the launch.json.
// This is run before target is created, so commands can't do anything with
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index b7d3c8ced69f1..dbfb1da635cbb 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -49,56 +49,6 @@ static uint32_t SetLaunchFlag(uint32_t flags, bool flag,
return flags;
}
-// Both attach and launch take either a sourcePath or a sourceMap
-// argument (or neither), from which we need to set the target.source-map.
-void BaseRequestHandler::SetSourceMapFromArguments(
- const llvm::json::Object &arguments) const {
- const char *sourceMapHelp =
- "source must be be an array of two-element arrays, "
- "each containing a source and replacement path string.\n";
-
- std::string sourceMapCommand;
- llvm::raw_string_ostream strm(sourceMapCommand);
- strm << "settings set target.source-map ";
- const auto sourcePath = GetString(arguments, "sourcePath").value_or("");
-
- // sourceMap is the new, more general form of sourcePath and overrides it.
- constexpr llvm::StringRef sourceMapKey = "sourceMap";
-
- if (const auto *sourceMapArray = arguments.getArray(sourceMapKey)) {
- for (const auto &value : *sourceMapArray) {
- const auto *mapping = value.getAsArray();
- if (mapping == nullptr || mapping->size() != 2 ||
- (*mapping)[0].kind() != llvm::json::Value::String ||
- (*mapping)[1].kind() != llvm::json::Value::String) {
- dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
- return;
- }
- const auto mapFrom = GetAsString((*mapping)[0]);
- const auto mapTo = GetAsString((*mapping)[1]);
- strm << "\"" << mapFrom << "\" \"" << mapTo << "\" ";
- }
- } else if (const auto *sourceMapObj = arguments.getObject(sourceMapKey)) {
- for (const auto &[key, value] : *sourceMapObj) {
- if (value.kind() == llvm::json::Value::String) {
- strm << "\"" << key.str() << "\" \"" << GetAsString(value) << "\" ";
- }
- }
- } else {
- if (ObjectContainsKey(arguments, sourceMapKey)) {
- dap.SendOutput(OutputType::Console, llvm::StringRef(sourceMapHelp));
- return;
- }
- if (sourcePath.empty())
- return;
- // Do any source remapping needed before we create our targets
- strm << "\".\" \"" << sourcePath << "\"";
- }
- if (!sourceMapCommand.empty()) {
- dap.RunLLDBCommands("Setting source map:", {sourceMapCommand});
- }
-}
-
static llvm::Error
RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
if (!dap.clientFeatures.contains(
@@ -106,8 +56,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
return llvm::make_error<DAPError>("Cannot use runInTerminal, feature is "
"not supported by the connected client");
- if (!arguments.configuration.program ||
- arguments.configuration.program->empty())
+ if (arguments.configuration.program.empty())
return llvm::make_error<DAPError>(
"program must be set to when using runInTerminal");
@@ -128,8 +77,8 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) {
#endif
llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest(
- *arguments.configuration.program, arguments.args, arguments.env,
- arguments.cwd.value_or(""), comm_file.m_path, debugger_pid);
+ arguments.configuration.program, arguments.args, arguments.env,
+ arguments.cwd, comm_file.m_path, debugger_pid);
dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal",
std::move(reverse_request));
@@ -209,9 +158,8 @@ llvm::Error BaseRequestHandler::LaunchProcess(
// Grab the current working directory if there is one and set it in the
// launch info.
- const auto cwd = arguments.cwd.value_or("");
- if (!cwd.empty())
- launch_info.SetWorkingDirectory(cwd.data());
+ if (!arguments.cwd.empty())
+ launch_info.SetWorkingDirectory(arguments.cwd.data());
// Extract any extra arguments and append them to our program arguments for
// when we launch
@@ -262,7 +210,7 @@ llvm::Error BaseRequestHandler::LaunchProcess(
// Make sure the process is launched and stopped at the entry point before
// proceeding as the launch commands are not run using the synchronous
// mode.
- lldb::SBError error = dap.WaitForProcessToStop(arguments.timeout);
+ lldb::SBError error = dap.WaitForProcessToStop(dap.configuration.timeout);
if (error.Fail())
return llvm::make_error<DAPError>(error.GetCString());
}
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index fa3d76ed4a125..a726254f53640 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -59,10 +59,6 @@ class BaseRequestHandler {
/// FIXME: Move these into the DAP class?
/// @{
- /// Both attach and launch take a either a sourcePath or sourceMap
- /// argument (or neither), from which we need to set the target.source-map.
- void SetSourceMapFromArguments(const llvm::json::Object &arguments) const;
-
/// Prints a welcome message on the editor if the preprocessor variable
/// LLDB_DAP_WELCOME_MESSAGE is defined.
void PrintWelcomeMessage() const;
@@ -197,11 +193,14 @@ class RequestHandler : public BaseRequestHandler {
}
};
-class AttachRequestHandler : public LegacyRequestHandler {
+class AttachRequestHandler
+ : public RequestHandler<protocol::AttachRequestArguments,
+ protocol::AttachResponse> {
public:
- using LegacyRequestHandler::LegacyRequestHandler;
+ using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "attach"; }
- void operator()(const llvm::json::Object &request) const override;
+ llvm::Error Run(const protocol::AttachRequestArguments &args) const override;
+ void PostRun() const override;
};
class BreakpointLocationsRequestHandler : public LegacyRequestHandler {
@@ -276,17 +275,17 @@ class ExceptionInfoRequestHandler : public LegacyRequestHandler {
class InitializeRequestHandler
: public RequestHandler<protocol::InitializeRequestArguments,
- llvm::Expected<protocol::InitializeResponseBody>> {
+ llvm::Expected<protocol::InitializeResponse>> {
public:
using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "initialize"; }
- llvm::Expected<protocol::InitializeResponseBody>
+ llvm::Expected<protocol::InitializeResponse>
Run(const protocol::InitializeRequestArguments &args) const override;
};
class LaunchRequestHandler
: public RequestHandler<protocol::LaunchRequestArguments,
- protocol::LaunchResponseBody> {
+ protocol::LaunchResponse> {
public:
using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "launch"; }
@@ -503,7 +502,7 @@ class ReadMemoryRequestHandler : public LegacyRequestHandler {
class CancelRequestHandler
: public RequestHandler<protocol::CancelArguments,
- protocol::CancelResponseBody> {
+ protocol::CancelResponse> {
public:
using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "cancel"; }
diff --git a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
index e6f2d9ec669cb..a2d1639c9b91f 100644
--- a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp
@@ -108,7 +108,6 @@ void RestartRequestHandler::operator()(
// Update DAP configuration based on the latest copy of the launch
// arguments.
dap.SetConfiguration(updated_arguments.configuration, false);
- dap.stop_at_entry = updated_arguments.stopOnEntry;
dap.ConfigureSourceMaps();
}
}
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
index 61fea66490c30..d48c11e53d190 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp
@@ -223,26 +223,29 @@ bool fromJSON(const json::Value &Params, InitializeRequestArguments &IRA,
bool fromJSON(const json::Value &Params, Configuration &C, json::Path P) {
json::ObjectMapper O(Params, P);
- return O.map("debuggerRoot", C.debuggerRoot) &&
+ return O.mapOptional("debuggerRoot", C.debuggerRoot) &&
O.mapOptional("enableAutoVariableSummaries",
C.enableAutoVariableSummaries) &&
O.mapOptional("enableSyntheticChildDebugging",
C.enableSyntheticChildDebugging) &&
O.mapOptional("displayExtendedBacktrace",
C.displayExtendedBacktrace) &&
+ O.mapOptional("stopOnEntry", C.stopOnEntry) &&
O.mapOptional("commandEscapePrefix", C.commandEscapePrefix) &&
- O.map("customFrameFormat", C.customFrameFormat) &&
- O.map("customThreadFormat", C.customThreadFormat) &&
- O.map("sourcePath", C.sourcePath) &&
+ O.mapOptional("customFrameFormat", C.customFrameFormat) &&
+ O.mapOptional("customThreadFormat", C.customThreadFormat) &&
+ O.mapOptional("sourcePath", C.sourcePath) &&
O.mapOptional("initCommands", C.initCommands) &&
O.mapOptional("preRunCommands", C.preRunCommands) &&
O.mapOptional("postRunCommands", C.postRunCommands) &&
O.mapOptional("stopCommands", C.stopCommands) &&
O.mapOptional("exitCommands", C.exitCommands) &&
O.mapOptional("terminateCommands", C.terminateCommands) &&
- O.map("program", C.program) && O.map("targetTriple", C.targetTriple) &&
- O.map("platformName", C.platformName) &&
- parseSourceMap(Params, C.sourceMap, P);
+ O.mapOptional("program", C.program) &&
+ O.mapOptional("targetTriple", C.targetTriple) &&
+ O.mapOptional("platformName", C.platformName) &&
+ parseSourceMap(Params, C.sourceMap, P) &&
+ parseTimeout(Params, C.timeout, P);
}
bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
@@ -251,14 +254,26 @@ bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
return O && fromJSON(Params, LRA.configuration, P) &&
O.mapOptional("noDebug", LRA.noDebug) &&
O.mapOptional("launchCommands", LRA.launchCommands) &&
- O.map("cwd", LRA.cwd) && O.mapOptional("args", LRA.args) &&
+ 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("stopOnEntry", LRA.stopOnEntry) &&
+
O.mapOptional("runInTerminal", LRA.runInTerminal) &&
- parseEnv(Params, LRA.env, P) && parseTimeout(Params, LRA.timeout, P);
+ parseEnv(Params, LRA.env, P);
+}
+
+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);
}
bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) {
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index 33f93cc38799a..8c4c11b9fe7eb 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -23,6 +23,7 @@
#include "Protocol/ProtocolBase.h"
#include "Protocol/ProtocolTypes.h"
#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/Support/JSON.h"
@@ -51,7 +52,7 @@ bool fromJSON(const llvm::json::Value &, CancelArguments &, llvm::json::Path);
/// Response to `cancel` request. This is just an acknowledgement, so no body
/// field is required.
-using CancelResponseBody = VoidResponse;
+using CancelResponse = VoidResponse;
/// Arguments for `disconnect` request.
struct DisconnectArguments {
@@ -139,15 +140,18 @@ bool fromJSON(const llvm::json::Value &, InitializeRequestArguments &,
llvm::json::Path);
/// Response to `initialize` request. The capabilities of this debug adapter.
-using InitializeResponseBody = std::optional<Capabilities>;
+using InitializeResponse = std::optional<Capabilities>;
/// DAP Launch and Attach common configurations.
+///
+/// See package.json debuggers > configurationAttributes > launch or attach >
+/// properties for common configurations.
struct Configuration {
/// Specify a working directory to use when launching `lldb-dap`. If the debug
/// information in your executable contains relative paths, this option can be
/// used so that `lldb-dap` can find source files and object files that have
/// relative paths.
- std::optional<std::string> debuggerRoot;
+ std::string debuggerRoot = "";
/// Enable auto generated summaries for variables when no summaries exist for
/// a given type. This feature can cause performance delays in large projects
@@ -163,6 +167,13 @@ struct Configuration {
/// Enable language specific extended backtraces.
bool displayExtendedBacktrace = false;
+ /// Stop at the entry point of the program when launching or attaching.
+ bool stopOnEntry = false;
+
+ /// Optional timeout when waiting for the program to `runInTermianl` or
+ /// attach.
+ std::chrono::seconds timeout = std::chrono::seconds(30);
+
/// The escape prefix to use for executing regular LLDB commands in the Debug
/// Console, instead of printing variables. Defaults to a backtick. If it's an
/// empty string, then all expression in the Debug Console are treated as
@@ -176,14 +187,14 @@ struct Configuration {
/// default frame names will be used. This might come with a performance cost
/// because debug information might need to be processed to generate the
/// description.
- std::optional<std::string> customFrameFormat;
+ std::string customFrameFormat = "";
/// Same as `customFrameFormat`, but for threads instead of stack frames.
- std::optional<std::string> customThreadFormat;
+ std::string customThreadFormat = "";
/// Specify a source path to remap "./" to allow full paths to be used when
/// setting breakpoints in binaries that have relative source paths.
- std::optional<std::string> sourcePath;
+ std::string sourcePath = "";
/// Specify an array of path re-mappings. Each element in the array must be a
/// two element array containing a source and destination pathname. Overrides
@@ -219,15 +230,15 @@ struct Configuration {
///
/// *NOTE:* When launching, either `launchCommands` or `program` must be
/// configured. If both are configured then `launchCommands` takes priority.
- std::optional<std::string> program;
+ std::string program = "";
/// Target triple for the program (arch-vendor-os). If not set, inferred from
/// the binary.
- std::optional<std::string> targetTriple;
+ std::string targetTriple = "";
/// Specify name of the platform to use for this target, creating the platform
/// if necessary.
- std::optional<std::string> platformName;
+ std::string platformName = "";
};
/// lldb-dap specific launch arguments.
@@ -240,6 +251,9 @@ struct LaunchRequestArguments {
bool noDebug = false;
/// Launch specific operations.
+ ///
+ /// See package.json debuggers > configurationAttributes > launch >
+ /// properties.
/// @{
/// LLDB commands executed to launch the program.
@@ -250,7 +264,7 @@ struct LaunchRequestArguments {
std::vector<std::string> launchCommands;
/// The program working directory.
- std::optional<std::string> cwd;
+ std::string cwd = "";
/// An array of command line argument strings to be passed to the program
/// being launched.
@@ -275,16 +289,10 @@ struct LaunchRequestArguments {
/// Set whether to shell expand arguments to the process when launching.
bool shellExpandArguments = false;
- /// Stop at the entry point of the program when launching a process.
- bool stopOnEntry = false;
-
/// Launch the program inside an integrated terminal in the IDE. Useful for
/// debugging interactive command line programs.
bool runInTerminal = false;
- /// Optional timeout for `runInTerminal` requests.
- std::chrono::seconds timeout = std::chrono::seconds(30);
-
/// @}
};
bool fromJSON(const llvm::json::Value &, LaunchRequestArguments &,
@@ -292,7 +300,52 @@ bool fromJSON(const llvm::json::Value &, LaunchRequestArguments &,
/// Response to `launch` request. This is just an acknowledgement, so no body
/// field is required.
-using LaunchResponseBody = VoidResponse;
+using LaunchResponse = VoidResponse;
+
+#define LLDB_DAP_INVALID_PORT -1
+
+/// lldb-dap specific attach arguments.
+struct AttachRequestArguments {
+ /// Common lldb-dap configuration values for launching/attaching operations.
+ Configuration configuration;
+
+ /// Attach specific operations.
+ ///
+ /// See package.json debuggers > configurationAttributes > attach >
+ /// properties.
+ /// @{
+
+ /// Custom commands that are executed instead of attaching to a process ID or
+ /// to a process by name. These commands may optionally create a new target
+ /// and must perform an attach. A valid process must exist after these
+ /// commands complete or the `"attach"` will fail.
+ std::vector<std::string> attachCommands;
+
+ /// System process ID to attach to.
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ /// Wait for the process to launch.
+ bool waitFor = false;
+
+ /// TCP/IP port to attach to a remote system. Specifying both pid and port is
+ /// an error.
+ int32_t gdbRemotePort = LLDB_DAP_INVALID_PORT;
+
+ /// The hostname to connect to a remote system. The default hostname being
+ /// used `localhost`.
+ std::string gdbRemoteHostname = "localhost";
+
+ /// Path to the core file to debug.
+ std::string coreFile = "";
+
+ /// @}
+};
+bool fromJSON(const llvm::json::Value &, AttachRequestArguments &,
+ llvm::json::Path);
+
+/// Response to `attach` request. This is just an acknowledgement, so no body
+/// field is required.
+using AttachResponse = VoidResponse;
/// Arguments for `source` request.
struct SourceArguments {
diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json
index 5cfd79849b17f..27d97ed43a53f 100644
--- a/lldb/tools/lldb-dap/package.json
+++ b/lldb/tools/lldb-dap/package.json
@@ -417,10 +417,7 @@
"description": "Path to the program to attach to."
},
"pid": {
- "type": [
- "number",
- "string"
- ],
+ "type": "number",
"description": "System process ID to attach to."
},
"waitFor": {
@@ -536,15 +533,13 @@
"description": "The time in seconds to wait for a program to stop when attaching using \"attachCommands\". Defaults to 30 seconds."
},
"gdb-remote-port": {
- "type": [
- "number",
- "string"
- ],
+ "type": "number",
"description": "TCP/IP port to attach to a remote system. Specifying both pid and port is an error."
},
"gdb-remote-hostname": {
"type": "string",
- "description": "The hostname to connect to a remote system. The default hostname being used localhost."
+ "description": "The hostname to connect to a remote system. The default hostname being used localhost.",
+ "default": "localhost"
},
"enableAutoVariableSummaries": {
"type": "boolean",
>From 087ab33212f5ca523747208d960e4e5483fb3469 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Wed, 30 Apr 2025 08:51:53 -0700
Subject: [PATCH 2/7] Applying clang-format.
---
lldb/tools/lldb-dap/Handler/RequestHandler.h | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h
index a726254f53640..0dd9928ce0861 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.h
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h
@@ -500,9 +500,8 @@ class ReadMemoryRequestHandler : public LegacyRequestHandler {
void operator()(const llvm::json::Object &request) const override;
};
-class CancelRequestHandler
- : public RequestHandler<protocol::CancelArguments,
- protocol::CancelResponse> {
+class CancelRequestHandler : public RequestHandler<protocol::CancelArguments,
+ protocol::CancelResponse> {
public:
using RequestHandler::RequestHandler;
static llvm::StringLiteral GetCommand() { return "cancel"; }
>From b11201f0c7937dab4e901075333b1c4b19b4551e Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 1 May 2025 16:23:51 -0700
Subject: [PATCH 3/7] Using an optional for frame and thread format
---
lldb/tools/lldb-dap/DAP.cpp | 8 ++++----
lldb/tools/lldb-dap/Protocol/ProtocolRequests.h | 14 +++++++-------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index abed9983118f9..1dab9e69e827e 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -1215,10 +1215,10 @@ void DAP::SetConfiguration(const protocol::Configuration &config,
stop_at_entry = config.stopOnEntry;
this->is_attach = is_attach;
- if (!configuration.customFrameFormat.empty())
- SetFrameFormat(configuration.customFrameFormat);
- if (!configuration.customThreadFormat.empty())
- SetThreadFormat(configuration.customThreadFormat);
+ if (configuration.customFrameFormat)
+ SetFrameFormat(*configuration.customFrameFormat);
+ if (configuration.customThreadFormat)
+ SetThreadFormat(*configuration.customThreadFormat);
}
void DAP::SetFrameFormat(llvm::StringRef format) {
diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
index 8c4c11b9fe7eb..98c3cb18d3863 100644
--- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
+++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h
@@ -160,8 +160,8 @@ struct Configuration {
/// If a variable is displayed using a synthetic children, also display the
/// actual contents of the variable at the end under a [raw] entry. This is
- /// useful when creating sythetic child plug-ins as it lets you see the actual
- /// contents of the variable.
+ /// useful when creating synthetic child plug-ins as it lets you see the
+ /// actual contents of the variable.
bool enableSyntheticChildDebugging = false;
/// Enable language specific extended backtraces.
@@ -170,7 +170,7 @@ struct Configuration {
/// Stop at the entry point of the program when launching or attaching.
bool stopOnEntry = false;
- /// Optional timeout when waiting for the program to `runInTermianl` or
+ /// Optional timeout when waiting for the program to `runInTerminal` or
/// attach.
std::chrono::seconds timeout = std::chrono::seconds(30);
@@ -187,10 +187,10 @@ struct Configuration {
/// default frame names will be used. This might come with a performance cost
/// because debug information might need to be processed to generate the
/// description.
- std::string customFrameFormat = "";
+ std::optional<std::string> customFrameFormat;
/// Same as `customFrameFormat`, but for threads instead of stack frames.
- std::string customThreadFormat = "";
+ std::optional<std::string> customThreadFormat;
/// Specify a source path to remap "./" to allow full paths to be used when
/// setting breakpoints in binaries that have relative source paths.
@@ -275,8 +275,8 @@ struct LaunchRequestArguments {
/// with values or just "VAR" for environment variables with no values.
llvm::StringMap<std::string> env;
- /// If set, then the client stub should detach rather than killing the debugee
- /// if it loses connection with lldb.
+ /// If set, then the client stub should detach rather than killing the
+ /// debuggee if it loses connection with lldb.
bool detachOnError = false;
/// Disable ASLR (Address Space Layout Randomization) when launching the
>From dfcdb0d6f60845dd273003ca2636b9ed110ceb2e Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Thu, 1 May 2025 16:48:50 -0700
Subject: [PATCH 4/7] Fix merge and return an error if `attachCommands` fails
to make a valid target.
---
lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
index 0265da3cdc077..c20c8166e270b 100644
--- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
@@ -80,8 +80,7 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const {
// Disable async events so the attach will be successful when we return from
// the launch call and the launch will happen synchronously
ScopeSyncMode scope_sync_mode(dap.debugger);
-
- dap.debugger.SetAsync(false);
+
if (args.coreFile.empty()) {
if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) {
lldb::SBListener listener = dap.debugger.GetListener();
@@ -112,6 +111,9 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const {
// The custom commands might have created a new target so we should use the
// selected target after these commands are run.
dap.target = dap.debugger.GetSelectedTarget();
+ if (!dap.target.IsValid())
+ return make_error<DAPError>(
+ "attachCommands failed to create a valid target");
// Make sure the process is attached and stopped before proceeding as the
// the launch commands are not run using the synchronous mode.
>From 163847c552cba14d16e622cd14a3be427768aab8 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Fri, 2 May 2025 17:52:35 -0700
Subject: [PATCH 5/7] Remove the empty check on formatters, since that is a
valid formatter from the CLI.
---
lldb/tools/lldb-dap/DAP.cpp | 4 ----
1 file changed, 4 deletions(-)
diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp
index 8d714cadc7a84..4fef1cef70300 100644
--- a/lldb/tools/lldb-dap/DAP.cpp
+++ b/lldb/tools/lldb-dap/DAP.cpp
@@ -1222,8 +1222,6 @@ void DAP::SetConfiguration(const protocol::Configuration &config,
}
void DAP::SetFrameFormat(llvm::StringRef format) {
- if (format.empty())
- return;
lldb::SBError error;
frame_format = lldb::SBFormat(format.str().c_str(), error);
if (error.Fail()) {
@@ -1236,8 +1234,6 @@ void DAP::SetFrameFormat(llvm::StringRef format) {
}
void DAP::SetThreadFormat(llvm::StringRef format) {
- if (format.empty())
- return;
lldb::SBError error;
thread_format = lldb::SBFormat(format.str().c_str(), error);
if (error.Fail()) {
>From 063192b479f6c8a99ad3b405639afff0920c0e49 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Tue, 6 May 2025 16:49:15 -0700
Subject: [PATCH 6/7] Apply clang-format.
---
lldb/tools/lldb-dap/Handler/RequestHandler.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index bf117bac4f36d..7c2a42ca0647e 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -215,7 +215,8 @@ llvm::Error BaseRequestHandler::LaunchProcess(
// Make sure the process is launched and stopped at the entry point before
// proceeding.
- lldb::SBError error = dap.WaitForProcessToStop(arguments.configuration.timeout);
+ lldb::SBError error =
+ dap.WaitForProcessToStop(arguments.configuration.timeout);
if (error.Fail())
return ToError(error);
>From 48e34e75447c70c3a9bc961836e9a7e86a087377 Mon Sep 17 00:00:00 2001
From: John Harrison <harjohn at google.com>
Date: Tue, 6 May 2025 17:01:01 -0700
Subject: [PATCH 7/7] Reworked attach and launch to have the same flow for
collecting the initial_thread_list and simplifying the number of if branches
in the attach request handler.
---
.../lldb-dap/Handler/AttachRequestHandler.cpp | 51 +++++++++----------
.../lldb-dap/Handler/LaunchRequestHandler.cpp | 28 ++++++----
.../tools/lldb-dap/Handler/RequestHandler.cpp | 9 ----
3 files changed, 42 insertions(+), 46 deletions(-)
diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
index 48c8206801679..297cc30f4c844 100644
--- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp
@@ -78,34 +78,7 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const {
// Perform the launch in synchronous mode so that we don't have to worry
// about process state changes during the launch.
ScopeSyncMode scope_sync_mode(dap.debugger);
- if (args.attachCommands.empty()) {
- // No "attachCommands", just attach normally.
- if (args.coreFile.empty()) {
- if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) {
- // If port is specified and pid is not.
- lldb::SBListener listener = dap.debugger.GetListener();
-
- // If the user hasn't provided the hostname property, default
- // localhost being used.
- std::string connect_url =
- llvm::formatv("connect://{0}:", args.gdbRemoteHostname);
- connect_url += std::to_string(args.gdbRemotePort);
- dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote",
- error);
- } else {
- // Attach by pid or process name.
- lldb::SBAttachInfo attach_info;
- if (args.pid != LLDB_INVALID_PROCESS_ID)
- attach_info.SetProcessID(args.pid);
- else if (!dap.configuration.program.empty())
- attach_info.SetExecutable(dap.configuration.program.data());
- attach_info.SetWaitForLaunch(args.waitFor, false /*async*/);
- dap.target.Attach(attach_info, error);
- }
- } else {
- dap.target.LoadCore(args.coreFile.data(), error);
- }
- } else {
+ if (!args.attachCommands.empty()) {
// We have "attachCommands" that are a set of commands that are expected
// to execute the commands after which a process should be created. If
// there is no valid process after running these commands, we have failed.
@@ -115,6 +88,28 @@ Error AttachRequestHandler::Run(const AttachRequestArguments &args) const {
// The custom commands might have created a new target so we should use
// the selected target after these commands are run.
dap.target = dap.debugger.GetSelectedTarget();
+ } else if (!args.coreFile.empty()) {
+ dap.target.LoadCore(args.coreFile.data(), error);
+ } else if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) {
+ // If port is specified and pid is not.
+ lldb::SBListener listener = dap.debugger.GetListener();
+
+ // If the user hasn't provided the hostname property, default
+ // localhost being used.
+ std::string connect_url =
+ llvm::formatv("connect://{0}:", args.gdbRemoteHostname);
+ connect_url += std::to_string(args.gdbRemotePort);
+ dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote",
+ error);
+ } else {
+ // Attach by pid or process name.
+ lldb::SBAttachInfo attach_info;
+ if (args.pid != LLDB_INVALID_PROCESS_ID)
+ attach_info.SetProcessID(args.pid);
+ else if (!dap.configuration.program.empty())
+ attach_info.SetExecutable(dap.configuration.program.data());
+ attach_info.SetWaitForLaunch(args.waitFor, false /*async*/);
+ dap.target.Attach(attach_info, error);
}
}
diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
index 4973b7b411bb2..c6243b597a973 100644
--- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp
@@ -66,15 +66,25 @@ Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const {
}
void LaunchRequestHandler::PostRun() const {
- if (dap.target.GetProcess().IsValid()) {
- // Attach happens when launching with runInTerminal.
- SendProcessEvent(dap, dap.is_attach ? Attach : Launch);
-
- if (dap.stop_at_entry)
- SendThreadStoppedEvent(dap);
- else
- dap.target.GetProcess().Continue();
- }
+ if (!dap.target.GetProcess().IsValid())
+ return;
+
+ // Clients can request a baseline of currently existing threads after
+ // we acknowledge the configurationDone request.
+ // Client requests the baseline of currently existing threads after
+ // a successful or attach by sending a 'threads' request
+ // right after receiving the configurationDone response.
+ // Obtain the list of threads before we resume the process
+ dap.initial_thread_list =
+ GetThreads(dap.target.GetProcess(), dap.thread_format);
+
+ // Attach happens when launching with runInTerminal.
+ SendProcessEvent(dap, dap.is_attach ? Attach : Launch);
+
+ if (dap.stop_at_entry)
+ SendThreadStoppedEvent(dap);
+ else
+ dap.target.GetProcess().Continue();
}
} // namespace lldb_dap
diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
index 7c2a42ca0647e..93bc80a38e29d 100644
--- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
+++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp
@@ -220,15 +220,6 @@ llvm::Error BaseRequestHandler::LaunchProcess(
if (error.Fail())
return ToError(error);
- // Clients can request a baseline of currently existing threads after
- // we acknowledge the configurationDone request.
- // Client requests the baseline of currently existing threads after
- // a successful or attach by sending a 'threads' request
- // right after receiving the configurationDone response.
- // Obtain the list of threads before we resume the process
- dap.initial_thread_list =
- GetThreads(dap.target.GetProcess(), dap.thread_format);
-
return llvm::Error::success();
}
More information about the lldb-commits
mailing list