https://github.com/JDevlieghere updated https://github.com/llvm/llvm-project/pull/128262
>From e6cbcc3ab7a278c3ef01646db22872589486eb91 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere <jo...@devlieghere.com> Date: Fri, 21 Feb 2025 19:20:36 -0600 Subject: [PATCH 1/3] [lldb-dap] Move requests into their own object/file --- lldb/tools/lldb-dap/CMakeLists.txt | 5 + lldb/tools/lldb-dap/DAP.cpp | 23 +- lldb/tools/lldb-dap/DAP.h | 8 + lldb/tools/lldb-dap/Request/AttachRequest.cpp | 211 ++++++++++++++++++ lldb/tools/lldb-dap/Request/Request.cpp | 92 ++++++++ lldb/tools/lldb-dap/Request/Request.h | 45 ++++ lldb/tools/lldb-dap/lldb-dap.cpp | 190 +--------------- 7 files changed, 380 insertions(+), 194 deletions(-) create mode 100644 lldb/tools/lldb-dap/Request/AttachRequest.cpp create mode 100644 lldb/tools/lldb-dap/Request/Request.cpp create mode 100644 lldb/tools/lldb-dap/Request/Request.h diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index 43fc18873feb3..e97f7ecdbd31b 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -36,6 +36,9 @@ add_lldb_tool(lldb-dap SourceBreakpoint.cpp Watchpoint.cpp + Request/Request.cpp + Request/AttachRequest.cpp + LINK_LIBS liblldb lldbHost @@ -46,6 +49,8 @@ add_lldb_tool(lldb-dap Support ) +target_include_directories(lldb-dap PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + if(LLDB_DAP_WELCOME_MESSAGE) target_compile_definitions(lldb-dap PRIVATE diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index a67abe582abd4..80f083b1ab592 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -744,16 +744,25 @@ bool DAP::HandleObject(const llvm::json::Object &object) { const auto packet_type = GetString(object, "type"); if (packet_type == "request") { const auto command = GetString(object, "command"); + + // Try the new request handler first. + auto new_handler_pos = new_request_handlers.find(command); + if (new_handler_pos != new_request_handlers.end()) { + (*new_handler_pos->second)(object); + return true; // Success + } + + // FIXME: Remove request_handlers once everything has been migrated. auto handler_pos = request_handlers.find(command); - if (handler_pos == request_handlers.end()) { - if (log) - *log << "error: unhandled command \"" << command.data() << "\"" - << std::endl; - return false; // Fail + if (handler_pos != request_handlers.end()) { + handler_pos->second(*this, object); + return true; // Success } - handler_pos->second(*this, object); - return true; // Success + if (log) + *log << "error: unhandled command \"" << command.data() << "\"" + << std::endl; + return false; // Fail } if (packet_type == "response") { diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index b23be68ea002f..33507061e0750 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -16,6 +16,7 @@ #include "InstructionBreakpoint.h" #include "OutputRedirector.h" #include "ProgressEvent.h" +#include "Request/Request.h" #include "SourceBreakpoint.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" @@ -37,6 +38,7 @@ #include "llvm/Support/JSON.h" #include "llvm/Support/Threading.h" #include <map> +#include <memory> #include <mutex> #include <optional> #include <thread> @@ -184,6 +186,7 @@ struct DAP { lldb::pid_t restarting_process_id; bool configuration_done_sent; std::map<std::string, RequestCallback, std::less<>> request_handlers; + llvm::StringMap<std::unique_ptr<Request>> new_request_handlers; bool waiting_for_run_in_terminal; ProgressEventReporter progress_event_reporter; // Keep track of the last stop thread index IDs as threads won't go away @@ -330,6 +333,11 @@ struct DAP { /// IDE. void RegisterRequestCallback(std::string request, RequestCallback callback); + /// Registers a request handler. + template <typename Request> void RegisterRequest() { + new_request_handlers[Request::getName()] = std::make_unique<Request>(*this); + } + /// Debuggee will continue from stopped state. void WillContinue() { variables.Clear(); } diff --git a/lldb/tools/lldb-dap/Request/AttachRequest.cpp b/lldb/tools/lldb-dap/Request/AttachRequest.cpp new file mode 100644 index 0000000000000..f1b3bfc878427 --- /dev/null +++ b/lldb/tools/lldb-dap/Request/AttachRequest.cpp @@ -0,0 +1,211 @@ +//===-- AttachRequest.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 "JSONUtils.h" +#include "Request.h" +#include "lldb/API/SBListener.h" +#include "llvm/Support/FileSystem.h" + +namespace lldb_dap { +/// Prints a welcome message on the editor if the preprocessor variable +/// LLDB_DAP_WELCOME_MESSAGE is defined. +static void PrintWelcomeMessage(DAP &dap) { +#ifdef LLDB_DAP_WELCOME_MESSAGE + dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE); +#endif +} + +// "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 AttachRequest::operator()(const llvm::json::Object &request) { + dap.is_attach = true; + dap.last_launch_or_attach_request = request; + 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 = + GetUnsigned(arguments, "pid", LLDB_INVALID_PROCESS_ID); + const auto gdb_remote_port = + GetUnsigned(arguments, "gdb-remote-port", invalid_port); + const auto gdb_remote_hostname = + GetString(arguments, "gdb-remote-hostname", "localhost"); + if (pid != LLDB_INVALID_PROCESS_ID) + attach_info.SetProcessID(pid); + const auto wait_for = GetBoolean(arguments, "waitFor", false); + attach_info.SetWaitForLaunch(wait_for, false /*async*/); + dap.init_commands = GetStrings(arguments, "initCommands"); + dap.pre_run_commands = GetStrings(arguments, "preRunCommands"); + dap.stop_commands = GetStrings(arguments, "stopCommands"); + dap.exit_commands = GetStrings(arguments, "exitCommands"); + dap.terminate_commands = GetStrings(arguments, "terminateCommands"); + auto attachCommands = GetStrings(arguments, "attachCommands"); + llvm::StringRef core_file = GetString(arguments, "coreFile"); + const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30); + dap.stop_at_entry = + core_file.empty() ? GetBoolean(arguments, "stopOnEntry", false) : true; + dap.post_run_commands = GetStrings(arguments, "postRunCommands"); + const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot"); + dap.enable_auto_variable_summaries = + GetBoolean(arguments, "enableAutoVariableSummaries", false); + dap.enable_synthetic_child_debugging = + GetBoolean(arguments, "enableSyntheticChildDebugging", false); + dap.display_extended_backtrace = + GetBoolean(arguments, "displayExtendedBacktrace", false); + dap.command_escape_prefix = GetString(arguments, "commandEscapePrefix", "`"); + dap.SetFrameFormat(GetString(arguments, "customFrameFormat")); + dap.SetThreadFormat(GetString(arguments, "customThreadFormat")); + + PrintWelcomeMessage(dap); + + // 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); + + // 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; + } + + SetSourceMapFromArguments(*arguments); + + lldb::SBError status; + dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status)); + if (status.Fail()) { + response["success"] = llvm::json::Value(false); + EmplaceSafeString(response, "message", status.GetCString()); + dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } + + // 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 ((pid == LLDB_INVALID_PROCESS_ID || gdb_remote_port == invalid_port) && + wait_for) { + 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)); + } + if (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 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", + error); + } else { + // Attach by process name or id. + dap.target.Attach(attach_info, error); + } + } else + dap.target.LoadCore(core_file.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; + } + // 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(timeout_seconds); + } + + 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()) { + response["success"] = llvm::json::Value(false); + EmplaceSafeString(response, "message", std::string(error.GetCString())); + } else { + dap.RunPostRunCommands(); + } + + dap.SendJSON(llvm::json::Value(std::move(response))); + if (error.Success()) { + SendProcessEvent(Attach); + dap.SendJSON(CreateEventObject("initialized")); + } +} + +} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Request/Request.cpp b/lldb/tools/lldb-dap/Request/Request.cpp new file mode 100644 index 0000000000000..9fe2445be9d32 --- /dev/null +++ b/lldb/tools/lldb-dap/Request/Request.cpp @@ -0,0 +1,92 @@ +//===-- Request.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 "Request.h" +#include "DAP.h" +#include "JSONUtils.h" +#include "lldb/API/SBFileSpec.h" + +namespace lldb_dap { + +void Request::SendProcessEvent(Request::LaunchMethod launch_method) { + lldb::SBFileSpec exe_fspec = dap.target.GetExecutable(); + char exe_path[PATH_MAX]; + exe_fspec.GetPath(exe_path, sizeof(exe_path)); + llvm::json::Object event(CreateEventObject("process")); + llvm::json::Object body; + EmplaceSafeString(body, "name", std::string(exe_path)); + const auto pid = dap.target.GetProcess().GetProcessID(); + body.try_emplace("systemProcessId", (int64_t)pid); + body.try_emplace("isLocalProcess", true); + const char *startMethod = nullptr; + switch (launch_method) { + case Launch: + startMethod = "launch"; + break; + case Attach: + startMethod = "attach"; + break; + case AttachForSuspendedLaunch: + startMethod = "attachForSuspendedLaunch"; + break; + } + body.try_emplace("startMethod", startMethod); + event.try_emplace("body", std::move(body)); + dap.SendJSON(llvm::json::Value(std::move(event))); +} + +// 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 Request::SetSourceMapFromArguments(const llvm::json::Object &arguments) { + 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"); + + // 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}); + } +} + +} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Request/Request.h b/lldb/tools/lldb-dap/Request/Request.h new file mode 100644 index 0000000000000..339c3b1fb323f --- /dev/null +++ b/lldb/tools/lldb-dap/Request/Request.h @@ -0,0 +1,45 @@ +//===-- Request.h ---------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_REQUEST_REQUEST_H +#define LLDB_TOOLS_LLDB_DAP_REQUEST_REQUEST_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/JSON.h" + +namespace lldb_dap { +struct DAP; + +class Request { +public: + Request(DAP &dap) : dap(dap) {} + virtual ~Request() = default; + + virtual void operator()(const llvm::json::Object &request) = 0; + + static llvm::StringLiteral getName() { return "invalid"; }; + + enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch }; + + void SendProcessEvent(LaunchMethod launch_method); + void SetSourceMapFromArguments(const llvm::json::Object &arguments); + +protected: + DAP &dap; +}; + +class AttachRequest : public Request { +public: + using Request::Request; + static llvm::StringLiteral getName() { return "attach"; } + void operator()(const llvm::json::Object &request) override; +}; + +} // namespace lldb_dap + +#endif diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index e323990d8b6ed..997b654011b64 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -10,6 +10,7 @@ #include "FifoFiles.h" #include "JSONUtils.h" #include "LLDBUtils.h" +#include "Request/Request.h" #include "RunInTerminal.h" #include "Watchpoint.h" #include "lldb/API/SBDeclaration.h" @@ -726,192 +727,6 @@ bool FillStackFrames(DAP &dap, lldb::SBThread &thread, return reached_end_of_stack; } -// "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 request_attach(DAP &dap, const llvm::json::Object &request) { - dap.is_attach = true; - dap.last_launch_or_attach_request = request; - 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 = - GetUnsigned(arguments, "pid", LLDB_INVALID_PROCESS_ID); - const auto gdb_remote_port = - GetUnsigned(arguments, "gdb-remote-port", invalid_port); - const auto gdb_remote_hostname = - GetString(arguments, "gdb-remote-hostname", "localhost"); - if (pid != LLDB_INVALID_PROCESS_ID) - attach_info.SetProcessID(pid); - const auto wait_for = GetBoolean(arguments, "waitFor", false); - attach_info.SetWaitForLaunch(wait_for, false /*async*/); - dap.init_commands = GetStrings(arguments, "initCommands"); - dap.pre_run_commands = GetStrings(arguments, "preRunCommands"); - dap.stop_commands = GetStrings(arguments, "stopCommands"); - dap.exit_commands = GetStrings(arguments, "exitCommands"); - dap.terminate_commands = GetStrings(arguments, "terminateCommands"); - auto attachCommands = GetStrings(arguments, "attachCommands"); - llvm::StringRef core_file = GetString(arguments, "coreFile"); - const uint64_t timeout_seconds = GetUnsigned(arguments, "timeout", 30); - dap.stop_at_entry = - core_file.empty() ? GetBoolean(arguments, "stopOnEntry", false) : true; - dap.post_run_commands = GetStrings(arguments, "postRunCommands"); - const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot"); - dap.enable_auto_variable_summaries = - GetBoolean(arguments, "enableAutoVariableSummaries", false); - dap.enable_synthetic_child_debugging = - GetBoolean(arguments, "enableSyntheticChildDebugging", false); - dap.display_extended_backtrace = - GetBoolean(arguments, "displayExtendedBacktrace", false); - dap.command_escape_prefix = GetString(arguments, "commandEscapePrefix", "`"); - dap.SetFrameFormat(GetString(arguments, "customFrameFormat")); - dap.SetThreadFormat(GetString(arguments, "customThreadFormat")); - - PrintWelcomeMessage(dap); - - // 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); - - // 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; - } - - SetSourceMapFromArguments(dap, *arguments); - - lldb::SBError status; - dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status)); - if (status.Fail()) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString(response, "message", status.GetCString()); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - // 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 ((pid == LLDB_INVALID_PROCESS_ID || gdb_remote_port == invalid_port) && - wait_for) { - 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)); - } - if (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 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", - error); - } else { - // Attach by process name or id. - dap.target.Attach(attach_info, error); - } - } else - dap.target.LoadCore(core_file.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; - } - // 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(timeout_seconds); - } - - 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()) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString(response, "message", std::string(error.GetCString())); - } else { - dap.RunPostRunCommands(); - } - - dap.SendJSON(llvm::json::Value(std::move(response))); - if (error.Success()) { - SendProcessEvent(dap, Attach); - dap.SendJSON(CreateEventObject("initialized")); - } -} - // "BreakpointLocationsRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", @@ -4998,7 +4813,8 @@ void request_setInstructionBreakpoints(DAP &dap, } void RegisterRequestCallbacks(DAP &dap) { - dap.RegisterRequestCallback("attach", request_attach); + dap.RegisterRequest<AttachRequest>(); + dap.RegisterRequestCallback("breakpointLocations", request_breakpointLocations); dap.RegisterRequestCallback("completions", request_completions); >From 92322aee828df65ae4ca7523d17c60162e3802b3 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere <jo...@devlieghere.com> Date: Sat, 22 Feb 2025 12:10:00 -0600 Subject: [PATCH 2/3] Address review feedback --- lldb/tools/lldb-dap/CMakeLists.txt | 4 ++-- lldb/tools/lldb-dap/DAP.h | 9 ++++---- .../AttachHandler.cpp} | 6 ++--- .../RequestHandler.cpp} | 10 ++++---- .../Request.h => Handler/RequestHandler.h} | 23 ++++++++++--------- lldb/tools/lldb-dap/lldb-dap.cpp | 4 ++-- 6 files changed, 30 insertions(+), 26 deletions(-) rename lldb/tools/lldb-dap/{Request/AttachRequest.cpp => Handler/AttachHandler.cpp} (98%) rename lldb/tools/lldb-dap/{Request/Request.cpp => Handler/RequestHandler.cpp} (92%) rename lldb/tools/lldb-dap/{Request/Request.h => Handler/RequestHandler.h} (65%) diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index e97f7ecdbd31b..a3c605bf72391 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -36,8 +36,8 @@ add_lldb_tool(lldb-dap SourceBreakpoint.cpp Watchpoint.cpp - Request/Request.cpp - Request/AttachRequest.cpp + Handler/RequestHandler.cpp + Handler/AttachHandler.cpp LINK_LIBS liblldb diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 33507061e0750..5abd48d6363cf 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -12,11 +12,11 @@ #include "DAPForward.h" #include "ExceptionBreakpoint.h" #include "FunctionBreakpoint.h" +#include "Handler/RequestHandler.h" #include "IOStream.h" #include "InstructionBreakpoint.h" #include "OutputRedirector.h" #include "ProgressEvent.h" -#include "Request/Request.h" #include "SourceBreakpoint.h" #include "lldb/API/SBBroadcaster.h" #include "lldb/API/SBCommandInterpreter.h" @@ -186,7 +186,7 @@ struct DAP { lldb::pid_t restarting_process_id; bool configuration_done_sent; std::map<std::string, RequestCallback, std::less<>> request_handlers; - llvm::StringMap<std::unique_ptr<Request>> new_request_handlers; + llvm::StringMap<std::unique_ptr<RequestHandler>> new_request_handlers; bool waiting_for_run_in_terminal; ProgressEventReporter progress_event_reporter; // Keep track of the last stop thread index IDs as threads won't go away @@ -334,8 +334,9 @@ struct DAP { void RegisterRequestCallback(std::string request, RequestCallback callback); /// Registers a request handler. - template <typename Request> void RegisterRequest() { - new_request_handlers[Request::getName()] = std::make_unique<Request>(*this); + template <typename Handler> void RegisterRequest() { + new_request_handlers[Handler::getCommand()] = + std::make_unique<Handler>(*this); } /// Debuggee will continue from stopped state. diff --git a/lldb/tools/lldb-dap/Request/AttachRequest.cpp b/lldb/tools/lldb-dap/Handler/AttachHandler.cpp similarity index 98% rename from lldb/tools/lldb-dap/Request/AttachRequest.cpp rename to lldb/tools/lldb-dap/Handler/AttachHandler.cpp index f1b3bfc878427..3dcde2144246e 100644 --- a/lldb/tools/lldb-dap/Request/AttachRequest.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachHandler.cpp @@ -1,4 +1,4 @@ -//===-- AttachRequest.cpp -------------------------------------------------===// +//===-- AttachHandler.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -8,7 +8,7 @@ #include "DAP.h" #include "JSONUtils.h" -#include "Request.h" +#include "RequestHandler.h" #include "lldb/API/SBListener.h" #include "llvm/Support/FileSystem.h" @@ -50,7 +50,7 @@ static void PrintWelcomeMessage(DAP &dap) { // }] // } -void AttachRequest::operator()(const llvm::json::Object &request) { +void AttachRequestHandler::operator()(const llvm::json::Object &request) { dap.is_attach = true; dap.last_launch_or_attach_request = request; llvm::json::Object response; diff --git a/lldb/tools/lldb-dap/Request/Request.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp similarity index 92% rename from lldb/tools/lldb-dap/Request/Request.cpp rename to lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 9fe2445be9d32..ef091a805902d 100644 --- a/lldb/tools/lldb-dap/Request/Request.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -1,4 +1,4 @@ -//===-- Request.cpp -------------------------------------------------------===// +//===-- Handler.cpp -------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,14 +6,15 @@ // //===----------------------------------------------------------------------===// -#include "Request.h" +#include "RequestHandler.h" #include "DAP.h" #include "JSONUtils.h" #include "lldb/API/SBFileSpec.h" namespace lldb_dap { -void Request::SendProcessEvent(Request::LaunchMethod launch_method) { +void RequestHandler::SendProcessEvent( + RequestHandler::LaunchMethod launch_method) { lldb::SBFileSpec exe_fspec = dap.target.GetExecutable(); char exe_path[PATH_MAX]; exe_fspec.GetPath(exe_path, sizeof(exe_path)); @@ -42,7 +43,8 @@ void Request::SendProcessEvent(Request::LaunchMethod launch_method) { // 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 Request::SetSourceMapFromArguments(const llvm::json::Object &arguments) { +void RequestHandler::SetSourceMapFromArguments( + const llvm::json::Object &arguments) { const char *sourceMapHelp = "source must be be an array of two-element arrays, " "each containing a source and replacement path string.\n"; diff --git a/lldb/tools/lldb-dap/Request/Request.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h similarity index 65% rename from lldb/tools/lldb-dap/Request/Request.h rename to lldb/tools/lldb-dap/Handler/RequestHandler.h index 339c3b1fb323f..4a60a7f3d1142 100644 --- a/lldb/tools/lldb-dap/Request/Request.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_TOOLS_LLDB_DAP_REQUEST_REQUEST_H -#define LLDB_TOOLS_LLDB_DAP_REQUEST_REQUEST_H +#ifndef LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H +#define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" @@ -15,28 +15,29 @@ namespace lldb_dap { struct DAP; -class Request { +class RequestHandler { public: - Request(DAP &dap) : dap(dap) {} - virtual ~Request() = default; + RequestHandler(DAP &dap) : dap(dap) {} + virtual ~RequestHandler() = default; virtual void operator()(const llvm::json::Object &request) = 0; - static llvm::StringLiteral getName() { return "invalid"; }; - + /// Helpers used by multiple request handlers. + /// FIXME: Move these into the DAP class. + /// @{ enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch }; - void SendProcessEvent(LaunchMethod launch_method); void SetSourceMapFromArguments(const llvm::json::Object &arguments); + /// @} protected: DAP &dap; }; -class AttachRequest : public Request { +class AttachRequestHandler : public RequestHandler { public: - using Request::Request; - static llvm::StringLiteral getName() { return "attach"; } + using RequestHandler::RequestHandler; + static llvm::StringLiteral getCommand() { return "attach"; } void operator()(const llvm::json::Object &request) override; }; diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index 997b654011b64..c84eb5d7c7419 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -8,9 +8,9 @@ #include "DAP.h" #include "FifoFiles.h" +#include "Handler/RequestHandler.h" #include "JSONUtils.h" #include "LLDBUtils.h" -#include "Request/Request.h" #include "RunInTerminal.h" #include "Watchpoint.h" #include "lldb/API/SBDeclaration.h" @@ -4813,7 +4813,7 @@ void request_setInstructionBreakpoints(DAP &dap, } void RegisterRequestCallbacks(DAP &dap) { - dap.RegisterRequest<AttachRequest>(); + dap.RegisterRequest<AttachRequestHandler>(); dap.RegisterRequestCallback("breakpointLocations", request_breakpointLocations); >From e2728b6dfba0f9cef3cb9def7d01567dc3e9b6a8 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere <jo...@devlieghere.com> Date: Sat, 22 Feb 2025 13:54:22 -0600 Subject: [PATCH 3/3] Address review feedback --- lldb/tools/lldb-dap/Handler/RequestHandler.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 4a60a7f3d1142..a0b66997ffda9 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -18,6 +18,13 @@ struct DAP; class RequestHandler { public: RequestHandler(DAP &dap) : dap(dap) {} + + /// RequestHandler are not copyable. + /// @{ + RequestHandler(const RequestHandler &) = delete; + RequestHandler& operator=(const RequestHandler &) = delete; + /// @} + virtual ~RequestHandler() = default; virtual void operator()(const llvm::json::Object &request) = 0; _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits