https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/133624
>From 3240fe49515e5f59c5b9ff9c02423b77504d8a43 Mon Sep 17 00:00:00 2001 From: John Harrison <harj...@google.com> Date: Fri, 28 Mar 2025 14:02:53 -0700 Subject: [PATCH 1/2] [lldb-dap] Refactoring lldb-dap 'launch' request to use typed RequestHandler<>. This converts a number of json::Value's into well defined types that are used throughout lldb-dap and updates the 'launch' command to use the new well defined types. --- .../test/tools/lldb-dap/dap_server.py | 3 +- .../test/tools/lldb-dap/lldbdap_testcase.py | 2 +- .../tools/lldb-dap/launch/TestDAP_launch.py | 6 +- .../restart/TestDAP_restart_runInTerminal.py | 4 +- .../runInTerminal/TestDAP_runInTerminal.py | 16 +- lldb/tools/lldb-dap/DAP.cpp | 82 +++++--- lldb/tools/lldb-dap/DAP.h | 44 +++-- .../lldb-dap/Handler/AttachRequestHandler.cpp | 33 ++-- .../lldb-dap/Handler/CompletionsHandler.cpp | 7 +- .../Handler/EvaluateRequestHandler.cpp | 3 +- .../lldb-dap/Handler/LaunchRequestHandler.cpp | 118 +++--------- .../tools/lldb-dap/Handler/RequestHandler.cpp | 96 +++++----- lldb/tools/lldb-dap/Handler/RequestHandler.h | 19 +- .../Handler/RestartRequestHandler.cpp | 54 ++++-- .../Handler/SetVariableRequestHandler.cpp | 3 +- .../Handler/StackTraceRequestHandler.cpp | 2 +- .../Handler/VariablesRequestHandler.cpp | 20 +- lldb/tools/lldb-dap/JSONUtils.cpp | 48 ++--- lldb/tools/lldb-dap/JSONUtils.h | 11 +- .../lldb-dap/Protocol/ProtocolRequests.cpp | 175 +++++++++++++++++- .../lldb-dap/Protocol/ProtocolRequests.h | 150 +++++++++++++++ lldb/tools/lldb-dap/SourceBreakpoint.cpp | 6 +- 22 files changed, 616 insertions(+), 286 deletions(-) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index 01ef4b68f2653..6e13fcddcc933 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -862,7 +862,8 @@ def request_launch( args_dict["enableAutoVariableSummaries"] = enableAutoVariableSummaries args_dict["enableSyntheticChildDebugging"] = enableSyntheticChildDebugging args_dict["displayExtendedBacktrace"] = displayExtendedBacktrace - args_dict["commandEscapePrefix"] = commandEscapePrefix + if commandEscapePrefix: + args_dict["commandEscapePrefix"] = commandEscapePrefix command_dict = {"command": "launch", "type": "request", "arguments": args_dict} response = self.send_recv(command_dict) diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py index 70b04b051e0ec..9ab8a905a79dd 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/lldbdap_testcase.py @@ -443,7 +443,7 @@ def cleanup(): if not (response and response["success"]): self.assertTrue( - response["success"], "launch failed (%s)" % (response["message"]) + response["success"], "launch failed (%s)" % (response["body"]["error"]["format"]) ) return response diff --git a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py index 64c99019a1c9b..c6a3e9cc879a4 100644 --- a/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py +++ b/lldb/test/API/tools/lldb-dap/launch/TestDAP_launch.py @@ -41,7 +41,9 @@ def test_termination(self): self.dap_server.request_disconnect() # Wait until the underlying lldb-dap process dies. - self.dap_server.process.wait(timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval) + self.dap_server.process.wait( + timeout=lldbdap_testcase.DAPTestCaseBase.timeoutval + ) # Check the return code self.assertEqual(self.dap_server.process.poll(), 0) @@ -459,7 +461,7 @@ def test_failing_launch_commands(self): self.assertFalse(response["success"]) self.assertRegex( - response["message"], + response["body"]["error"]["format"], r"Failed to run launch commands\. See the Debug Console for more details", ) diff --git a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py index 5a9938c25c2c8..a94c9860c1508 100644 --- a/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py +++ b/lldb/test/API/tools/lldb-dap/restart/TestDAP_restart_runInTerminal.py @@ -21,7 +21,7 @@ def isTestSupported(self): return False @skipIfWindows - @skipIf(archs=["arm"]) # Always times out on buildbot + @skipIf(oslist=["linux"], archs=["arm"]) # Always times out on buildbot def test_basic_functionality(self): """ Test basic restarting functionality when the process is running in @@ -61,7 +61,7 @@ def test_basic_functionality(self): ) @skipIfWindows - @skipIf(archs=["arm"]) # Always times out on buildbot + @skipIf(oslist=["linux"], archs=["arm"]) # Always times out on buildbot def test_stopOnEntry(self): """ Check that stopOnEntry works correctly when using runInTerminal. diff --git a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py index 9141565ac1b9b..9aab7ca3293db 100644 --- a/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py +++ b/lldb/test/API/tools/lldb-dap/runInTerminal/TestDAP_runInTerminal.py @@ -44,7 +44,7 @@ def isTestSupported(self): return False @skipIfWindows - @skipIf(archs=no_match(["x86_64"])) + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_runInTerminal(self): if not self.isTestSupported(): return @@ -90,7 +90,7 @@ def test_runInTerminal(self): env = self.dap_server.request_evaluate("foo")["body"]["result"] self.assertIn("bar", env) - @skipIf(archs=no_match(["x86_64"])) + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_runInTerminalWithObjectEnv(self): if not self.isTestSupported(): return @@ -114,7 +114,7 @@ def test_runInTerminalWithObjectEnv(self): self.assertEqual("BAR", request_envs["FOO"]) @skipIfWindows - @skipIf(archs=no_match(["x86_64"])) + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_runInTerminalInvalidTarget(self): if not self.isTestSupported(): return @@ -133,7 +133,7 @@ def test_runInTerminalInvalidTarget(self): ) @skipIfWindows - @skipIf(archs=no_match(["x86_64"])) + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_missingArgInRunInTerminalLauncher(self): if not self.isTestSupported(): return @@ -148,7 +148,7 @@ def test_missingArgInRunInTerminalLauncher(self): ) @skipIfWindows - @skipIf(archs=no_match(["x86_64"])) + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_FakeAttachedRunInTerminalLauncherWithInvalidProgram(self): if not self.isTestSupported(): return @@ -175,7 +175,7 @@ def test_FakeAttachedRunInTerminalLauncherWithInvalidProgram(self): self.assertIn("No such file or directory", stderr) @skipIfWindows - @skipIf(archs=no_match(["x86_64"])) + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_FakeAttachedRunInTerminalLauncherWithValidProgram(self): if not self.isTestSupported(): return @@ -202,7 +202,7 @@ def test_FakeAttachedRunInTerminalLauncherWithValidProgram(self): self.assertIn("foo", stdout) @skipIfWindows - @skipIf(archs=no_match(["x86_64"])) + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_FakeAttachedRunInTerminalLauncherAndCheckEnvironment(self): if not self.isTestSupported(): return @@ -223,7 +223,7 @@ def test_FakeAttachedRunInTerminalLauncherAndCheckEnvironment(self): self.assertIn("FOO=BAR", stdout) @skipIfWindows - @skipIf(archs=no_match(["x86_64"])) + @skipIf(oslist=["linux"], archs=no_match(["x86_64"])) def test_NonAttachedRunInTerminalLauncher(self): if not self.isTestSupported(): return diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 23f0400c8bd4d..52dd377bc40fb 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -14,6 +14,7 @@ #include "LLDBUtils.h" #include "OutputRedirector.h" #include "Protocol/ProtocolBase.h" +#include "Protocol/ProtocolRequests.h" #include "Protocol/ProtocolTypes.h" #include "Transport.h" #include "lldb/API/SBBreakpoint.h" @@ -73,11 +74,8 @@ DAP::DAP(llvm::StringRef path, Log *log, const ReplMode default_repl_mode, std::vector<std::string> pre_init_commands, Transport &transport) : debug_adapter_path(path), log(log), transport(transport), broadcaster("lldb-dap"), exception_breakpoints(), + focus_tid(LLDB_INVALID_THREAD_ID), is_attach(false), pre_init_commands(std::move(pre_init_commands)), - focus_tid(LLDB_INVALID_THREAD_ID), stop_at_entry(false), is_attach(false), - enable_auto_variable_summaries(false), - enable_synthetic_child_debugging(false), - display_extended_backtrace(false), restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done_sent(false), waiting_for_run_in_terminal(false), progress_event_reporter( @@ -505,8 +503,9 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, bool partial_expression) { // Check for the escape hatch prefix. if (!expression.empty() && - llvm::StringRef(expression).starts_with(command_escape_prefix)) { - expression = expression.substr(command_escape_prefix.size()); + llvm::StringRef(expression) + .starts_with(configuration.commandEscapePrefix)) { + expression = expression.substr(configuration.commandEscapePrefix.size()); return ReplMode::Command; } @@ -546,7 +545,7 @@ ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, << "Warning: Expression '" << term << "' is both an LLDB command and variable. It will be evaluated as " "a variable. To evaluate the expression as an LLDB command, use '" - << command_escape_prefix << "' as a prefix.\n"; + << configuration.commandEscapePrefix << "' as a prefix.\n"; } // Variables take preference to commands in auto, since commands can always @@ -593,7 +592,7 @@ DAP::RunLaunchCommands(llvm::ArrayRef<std::string> launch_commands) { } llvm::Error DAP::RunInitCommands() { - if (!RunLLDBCommands("Running initCommands:", init_commands)) + if (!RunLLDBCommands("Running initCommands:", configuration.initCommands)) return createRunLLDBCommandsErrorMessage("initCommands"); return llvm::Error::success(); } @@ -605,29 +604,31 @@ llvm::Error DAP::RunPreInitCommands() { } llvm::Error DAP::RunPreRunCommands() { - if (!RunLLDBCommands("Running preRunCommands:", pre_run_commands)) + if (!RunLLDBCommands("Running preRunCommands:", configuration.preRunCommands)) return createRunLLDBCommandsErrorMessage("preRunCommands"); return llvm::Error::success(); } void DAP::RunPostRunCommands() { - RunLLDBCommands("Running postRunCommands:", post_run_commands); + RunLLDBCommands("Running postRunCommands:", configuration.postRunCommands); } void DAP::RunStopCommands() { - RunLLDBCommands("Running stopCommands:", stop_commands); + RunLLDBCommands("Running stopCommands:", configuration.stopCommands); } void DAP::RunExitCommands() { - RunLLDBCommands("Running exitCommands:", exit_commands); + RunLLDBCommands("Running exitCommands:", configuration.exitCommands); } void DAP::RunTerminateCommands() { - RunLLDBCommands("Running terminateCommands:", terminate_commands); + RunLLDBCommands("Running terminateCommands:", + configuration.terminateCommands); } -lldb::SBTarget -DAP::CreateTargetFromArguments(const llvm::json::Object &arguments, - lldb::SBError &error) { +lldb::SBTarget DAP::CreateTargetFromArguments(llvm::StringRef program, + llvm::StringRef targetTriple, + llvm::StringRef platformName, + lldb::SBError &error) { // Grab the name of the program we need to debug and create a target using // the given program as an argument. Executable file can be a source of target // architecture and platform, if they differ from the host. Setting exe path @@ -638,15 +639,10 @@ DAP::CreateTargetFromArguments(const llvm::json::Object &arguments, // enough information to determine correct arch and platform (or ELF can be // omitted at all), so it is good to leave the user an apportunity to specify // those. Any of those three can be left empty. - const llvm::StringRef target_triple = - GetString(arguments, "targetTriple").value_or(""); - const llvm::StringRef platform_name = - GetString(arguments, "platformName").value_or(""); - const llvm::StringRef program = GetString(arguments, "program").value_or(""); - auto target = this->debugger.CreateTarget( - program.data(), target_triple.data(), platform_name.data(), - true, // Add dependent modules. - error); + auto target = this->debugger.CreateTarget(program.data(), targetTriple.data(), + platformName.data(), + true, // Add dependent modules. + error); if (error.Fail()) { // Update message if there was an error. @@ -802,7 +798,7 @@ llvm::Error DAP::Loop() { return llvm::Error::success(); } -lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) { +lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { lldb::SBError error; lldb::SBProcess process = target.GetProcess(); if (!process.IsValid()) { @@ -837,8 +833,8 @@ lldb::SBError DAP::WaitForProcessToStop(uint32_t seconds) { } std::this_thread::sleep_for(std::chrono::microseconds(250)); } - error.SetErrorStringWithFormat("process failed to stop within %u seconds", - seconds); + error.SetErrorStringWithFormat("process failed to stop within %lld seconds", + seconds.count()); return error; } @@ -1035,6 +1031,36 @@ bool SendEventRequestHandler::DoExecute(lldb::SBDebugger debugger, return true; } +void DAP::ConfigureSourceMaps() { + if (configuration.sourceMap.empty() && !configuration.sourcePath) + return; + + std::string sourceMapCommand; + llvm::raw_string_ostream strm(sourceMapCommand); + strm << "settings set target.source-map "; + + if (!configuration.sourceMap.empty()) { + for (const auto &kv : configuration.sourceMap) { + strm << "\"" << kv.first << "\" \"" << kv.second << "\" "; + } + } else if (configuration.sourcePath) { + strm << "\".\" \"" << *configuration.sourcePath << "\""; + } + + RunLLDBCommands("Setting source map:", {sourceMapCommand}); +} + +void DAP::SetConfiguration(const protocol::DAPConfiguration &config, + bool is_attach) { + configuration = config; + this->is_attach = is_attach; + + if (configuration.customFrameFormat) + SetFrameFormat(*configuration.customFrameFormat); + if (configuration.customThreadFormat) + SetThreadFormat(*configuration.customThreadFormat); +} + void DAP::SetFrameFormat(llvm::StringRef format) { if (format.empty()) return; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 6689980806047..f3c4a7bf22798 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -35,6 +35,7 @@ #include "lldb/lldb-types.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/FunctionExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Error.h" @@ -128,21 +129,21 @@ struct Variables { struct StartDebuggingRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; - explicit StartDebuggingRequestHandler(DAP &d) : dap(d) {}; + explicit StartDebuggingRequestHandler(DAP &d) : dap(d){}; bool DoExecute(lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) override; }; struct ReplModeRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; - explicit ReplModeRequestHandler(DAP &d) : dap(d) {}; + explicit ReplModeRequestHandler(DAP &d) : dap(d){}; bool DoExecute(lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) override; }; struct SendEventRequestHandler : public lldb::SBCommandPluginInterface { DAP &dap; - explicit SendEventRequestHandler(DAP &d) : dap(d) {}; + explicit SendEventRequestHandler(DAP &d) : dap(d){}; bool DoExecute(lldb::SBDebugger debugger, char **command, lldb::SBCommandReturnObject &result) override; }; @@ -165,26 +166,21 @@ struct DAP { InstructionBreakpointMap instruction_breakpoints; std::optional<std::vector<ExceptionBreakpoint>> exception_breakpoints; llvm::once_flag init_exception_breakpoints_flag; - std::vector<std::string> pre_init_commands; - std::vector<std::string> init_commands; - std::vector<std::string> pre_run_commands; - std::vector<std::string> post_run_commands; - std::vector<std::string> exit_commands; - std::vector<std::string> stop_commands; - std::vector<std::string> terminate_commands; + // Map step in target id to list of function targets that user can choose. llvm::DenseMap<lldb::addr_t, std::string> step_in_targets; - // A copy of the last LaunchRequest or AttachRequest so we can reuse its - // arguments if we get a RestartRequest. - std::optional<llvm::json::Object> last_launch_or_attach_request; + // A copy of the last LaunchRequest so we can reuse its arguments if we get a + // RestartRequest. Restarting an AttachRequest is not supported. + std::optional<protocol::LaunchRequestArguments> last_launch_request; lldb::tid_t focus_tid; bool disconnecting = false; llvm::once_flag terminated_event_flag; - bool stop_at_entry; bool is_attach; - bool enable_auto_variable_summaries; - bool enable_synthetic_child_debugging; - bool display_extended_backtrace; + bool stop_at_entry; + /// pre_init_commands are configured by a CLI flag and are not part of the + /// common launching/attaching definition. + std::vector<std::string> pre_init_commands; + protocol::DAPConfiguration configuration; // The process event thread normally responds to process exited events by // shutting down the entire adapter. When we're restarting, we keep the id of // the old process here so we can detect this case and keep running. @@ -201,7 +197,6 @@ struct DAP { llvm::SmallDenseMap<int64_t, std::unique_ptr<ResponseHandler>> inflight_reverse_requests; ReplMode repl_mode; - std::string command_escape_prefix = "`"; lldb::SBFormat frame_format; lldb::SBFormat thread_format; // This is used to allow request_evaluate to handle empty expressions @@ -249,6 +244,13 @@ struct DAP { /// Stop event handler threads. void StopEventHandlers(); + /// Configures the debug adapter for launching/attaching. + void SetConfiguration(const protocol::DAPConfiguration &confing, + bool is_attach); + + /// Configure source maps based on the current `DAPConfiguration`. + void ConfigureSourceMaps(); + /// Serialize the JSON value into a string and send the JSON packet to the /// "out" stream. void SendJSON(const llvm::json::Value &json); @@ -320,7 +322,9 @@ struct DAP { /// /// \return /// An SBTarget object. - lldb::SBTarget CreateTargetFromArguments(const llvm::json::Object &arguments, + lldb::SBTarget CreateTargetFromArguments(llvm::StringRef program, + llvm::StringRef targetTriple, + llvm::StringRef platformName, lldb::SBError &error); /// Set given target object as a current target for lldb-dap and start @@ -395,7 +399,7 @@ struct DAP { /// The number of seconds to poll the process to wait until it is stopped. /// /// \return Error if waiting for the process fails, no error if succeeds. - lldb::SBError WaitForProcessToStop(uint32_t seconds); + lldb::SBError WaitForProcessToStop(std::chrono::seconds seconds); void SetFrameFormat(llvm::StringRef format); diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp index 20f7c80a1ed90..cd7fbf4f7be9f 100644 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp @@ -43,10 +43,8 @@ namespace lldb_dap { // acknowledgement, so no body field is required." // }] // } - void AttachRequestHandler::operator()(const llvm::json::Object &request) const { dap.is_attach = true; - dap.last_launch_or_attach_request = request; llvm::json::Object response; lldb::SBError error; FillResponse(request, response); @@ -63,11 +61,13 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const { attach_info.SetProcessID(pid); const auto wait_for = GetBoolean(arguments, "waitFor").value_or(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"); + 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 = @@ -75,16 +75,15 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const { dap.stop_at_entry = core_file.empty() ? GetBoolean(arguments, "stopOnEntry").value_or(false) : true; - dap.post_run_commands = GetStrings(arguments, "postRunCommands"); const llvm::StringRef debuggerRoot = GetString(arguments, "debuggerRoot").value_or(""); - dap.enable_auto_variable_summaries = + dap.configuration.enableAutoVariableSummaries = GetBoolean(arguments, "enableAutoVariableSummaries").value_or(false); - dap.enable_synthetic_child_debugging = + dap.configuration.enableSyntheticChildDebugging = GetBoolean(arguments, "enableSyntheticChildDebugging").value_or(false); - dap.display_extended_backtrace = + dap.configuration.displayExtendedBacktrace = GetBoolean(arguments, "displayExtendedBacktrace").value_or(false); - dap.command_escape_prefix = + dap.configuration.commandEscapePrefix = GetString(arguments, "commandEscapePrefix").value_or("`"); dap.SetFrameFormat(GetString(arguments, "customFrameFormat").value_or("")); dap.SetThreadFormat(GetString(arguments, "customThreadFormat").value_or("")); @@ -108,8 +107,14 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const { SetSourceMapFromArguments(*arguments); + llvm::StringRef program = GetString(arguments, "program").value_or(""); + llvm::StringRef target_triple = + GetString(arguments, "targetTriple").value_or(""); + llvm::StringRef platform_name = + GetString(arguments, "platformName").value_or(""); lldb::SBError status; - dap.SetTarget(dap.CreateTargetFromArguments(*arguments, status)); + dap.SetTarget(dap.CreateTargetFromArguments(program, target_triple, + platform_name, status)); if (status.Fail()) { response["success"] = llvm::json::Value(false); EmplaceSafeString(response, "message", status.GetCString()); @@ -179,7 +184,7 @@ void AttachRequestHandler::operator()(const llvm::json::Object &request) const { // 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); + error = dap.WaitForProcessToStop(std::chrono::seconds(timeout_seconds)); } if (error.Success() && core_file.empty()) { diff --git a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp index 5414aaeb2c317..c72fc5686cd5b 100644 --- a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp @@ -157,19 +157,20 @@ void CompletionsRequestHandler::operator()( llvm::json::Array targets; bool had_escape_prefix = - llvm::StringRef(text).starts_with(dap.command_escape_prefix); + llvm::StringRef(text).starts_with(dap.configuration.commandEscapePrefix); ReplMode completion_mode = dap.DetectReplMode(frame, text, true); // Handle the offset change introduced by stripping out the // `command_escape_prefix`. if (had_escape_prefix) { - if (offset < static_cast<int64_t>(dap.command_escape_prefix.size())) { + if (offset < + static_cast<int64_t>(dap.configuration.commandEscapePrefix.size())) { body.try_emplace("targets", std::move(targets)); response.try_emplace("body", std::move(body)); dap.SendJSON(llvm::json::Value(std::move(response))); return; } - offset -= dap.command_escape_prefix.size(); + offset -= dap.configuration.commandEscapePrefix.size(); } // While the user is typing then we likely have an incomplete input and cannot diff --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp index e9f08a1017abc..8ed09fa2a931a 100644 --- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp @@ -205,7 +205,8 @@ void EvaluateRequestHandler::operator()( else EmplaceSafeString(response, "message", "evaluate failed"); } else { - VariableDescription desc(value, dap.enable_auto_variable_summaries); + VariableDescription desc(value, + dap.configuration.enableAutoVariableSummaries); EmplaceSafeString(body, "result", desc.GetResult(context)); EmplaceSafeString(body, "type", desc.display_type_name); int64_t var_ref = 0; diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp index f64c186376a36..66e37b02db0a3 100644 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp @@ -9,70 +9,18 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" #include "llvm/Support/FileSystem.h" namespace lldb_dap { -// "LaunchRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Launch request; value of command field is 'launch'.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "launch" ] -// }, -// "arguments": { -// "$ref": "#/definitions/LaunchRequestArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "LaunchRequestArguments": { -// "type": "object", -// "description": "Arguments for 'launch' request.", -// "properties": { -// "noDebug": { -// "type": "boolean", -// "description": "If noDebug is true the launch request should launch -// the program without enabling debugging." -// } -// } -// }, -// "LaunchResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'launch' request. This is just an -// acknowledgement, so no body field is required." -// }] -// } -void LaunchRequestHandler::operator()(const llvm::json::Object &request) const { - dap.is_attach = false; - dap.last_launch_or_attach_request = request; - llvm::json::Object response; - FillResponse(request, response); - const auto *arguments = request.getObject("arguments"); - 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"); - dap.post_run_commands = GetStrings(arguments, "postRunCommands"); - dap.stop_at_entry = GetBoolean(arguments, "stopOnEntry").value_or(false); - const llvm::StringRef debuggerRoot = - GetString(arguments, "debuggerRoot").value_or(""); - dap.enable_auto_variable_summaries = - GetBoolean(arguments, "enableAutoVariableSummaries").value_or(false); - dap.enable_synthetic_child_debugging = - GetBoolean(arguments, "enableSyntheticChildDebugging").value_or(false); - dap.display_extended_backtrace = - GetBoolean(arguments, "displayExtendedBacktrace").value_or(false); - dap.command_escape_prefix = - GetString(arguments, "commandEscapePrefix").value_or("`"); - dap.SetFrameFormat(GetString(arguments, "customFrameFormat").value_or("")); - dap.SetThreadFormat(GetString(arguments, "customThreadFormat").value_or("")); +/// Launch request; value of command field is 'launch'. +llvm::Expected<protocol::LaunchResponseBody> LaunchRequestHandler::Run( + const protocol::LaunchRequestArguments &arguments) const { + dap.SetConfiguration(arguments.configuration, /*is_attach=*/false); + dap.last_launch_request = arguments; + dap.stop_at_entry = arguments.stopOnEntry; PrintWelcomeMessage(); @@ -80,55 +28,47 @@ void LaunchRequestHandler::operator()(const llvm::json::Object &request) 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 debuggerRoot = dap.configuration.debuggerRoot.value_or(""); if (!debuggerRoot.empty()) llvm::sys::fs::set_current_path(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 // the targets - preRunCommands are run with the target. - 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.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; - } + dap.SetTarget(dap.CreateTargetFromArguments( + arguments.program.value_or(""), arguments.targetTriple.value_or(""), + arguments.platformName.value_or(""), status)); + if (status.Fail()) + return llvm::make_error<DAPError>(status.GetCString()); // 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 (llvm::Error err = dap.RunPreRunCommands()) + return err; - status = LaunchProcess(request); + if (llvm::Error err = LaunchProcess(arguments)) + return err; - if (status.Fail()) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString(response, "message", std::string(status.GetCString())); - } else { - dap.RunPostRunCommands(); - } + dap.RunPostRunCommands(); - dap.SendJSON(llvm::json::Value(std::move(response))); + return protocol::LaunchResponseBody(); +} - if (!status.Fail()) { +void LaunchRequestHandler::PostRun() const { + if (dap.target.GetProcess().IsValid()) { if (dap.is_attach) - SendProcessEvent(dap, Attach); // this happens when doing runInTerminal + // this happens when doing runInTerminal + SendProcessEvent(dap, Attach); else SendProcessEvent(dap, Launch); } + dap.SendJSON(CreateEventObject("initialized")); } + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index f067dfc5544fe..23904848de5cb 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -10,8 +10,10 @@ #include "DAP.h" #include "Handler/ResponseHandler.h" #include "JSONUtils.h" -#include "LLDBUtils.h" +#include "Protocol/ProtocolRequests.h" #include "RunInTerminal.h" +#include "lldb/API/SBDefines.h" +#include "lldb/API/SBEnvironment.h" #include "llvm/Support/Error.h" #if !defined(_WIN32) @@ -33,15 +35,12 @@ MakeArgv(const llvm::ArrayRef<std::string> &strs) { return argv; } -static uint32_t SetLaunchFlag(uint32_t flags, const llvm::json::Object *obj, - llvm::StringRef key, lldb::LaunchFlags mask) { - if (const auto opt_value = GetBoolean(obj, key)) { - if (*opt_value) - flags |= mask; - else - flags &= ~mask; - } - +static uint32_t SetLaunchFlag(uint32_t flags, bool opt, + lldb::LaunchFlags mask) { + if (opt) + flags |= mask; + else + flags &= ~mask; return flags; } @@ -95,14 +94,17 @@ void BaseRequestHandler::SetSourceMapFromArguments( } } -static llvm::Error RunInTerminal(DAP &dap, - const llvm::json::Object &launch_request, - const uint64_t timeout_seconds) { +static llvm::Error +RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { if (!dap.clientFeatures.contains( protocol::eClientFeatureRunInTerminalRequest)) return llvm::make_error<DAPError>("Cannot use runInTerminal, feature is " "not supported by the connected client"); + if (!arguments.program || arguments.program->empty()) + return llvm::make_error<DAPError>( + "program must be set to when using runInTerminal"); + dap.is_attach = true; lldb::SBAttachInfo attach_info; @@ -118,8 +120,11 @@ static llvm::Error RunInTerminal(DAP &dap, #if !defined(_WIN32) debugger_pid = getpid(); #endif + llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest( - launch_request, dap.debug_adapter_path, comm_file.m_path, debugger_pid); + *arguments.program, arguments.args, arguments.env, + arguments.cwd.value_or(""), dap.debug_adapter_path, comm_file.m_path, + debugger_pid); dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal", std::move(reverse_request)); @@ -165,74 +170,75 @@ static llvm::Error RunInTerminal(DAP &dap, error.GetCString()); } -lldb::SBError -BaseRequestHandler::LaunchProcess(const llvm::json::Object &request) const { - lldb::SBError error; - const auto *arguments = request.getObject("arguments"); - auto launchCommands = GetStrings(arguments, "launchCommands"); +llvm::Error BaseRequestHandler::LaunchProcess( + const protocol::LaunchRequestArguments &arguments) const { + auto launchCommands = arguments.launchCommands; // Instantiate a launch info instance for the target. auto launch_info = dap.target.GetLaunchInfo(); // Grab the current working directory if there is one and set it in the // launch info. - const auto cwd = GetString(arguments, "cwd").value_or(""); + const auto cwd = arguments.cwd.value_or(""); if (!cwd.empty()) launch_info.SetWorkingDirectory(cwd.data()); // Extract any extra arguments and append them to our program arguments for // when we launch - auto args = GetStrings(arguments, "args"); - if (!args.empty()) - launch_info.SetArguments(MakeArgv(args).data(), true); + if (!arguments.args.empty()) + launch_info.SetArguments(MakeArgv(arguments.args).data(), true); // Pass any environment variables along that the user specified. - const auto envs = GetEnvironmentFromArguments(*arguments); - launch_info.SetEnvironment(envs, true); + if (!arguments.env.empty()) { + lldb::SBEnvironment env; + for (const auto &kv : arguments.env) + env.Set(kv.first().data(), kv.second.c_str(), true); + launch_info.SetEnvironment(env, true); + } auto flags = launch_info.GetLaunchFlags(); - flags = SetLaunchFlag(flags, arguments, "disableASLR", - lldb::eLaunchFlagDisableASLR); - flags = SetLaunchFlag(flags, arguments, "disableSTDIO", + flags = + SetLaunchFlag(flags, arguments.disableASLR, lldb::eLaunchFlagDisableASLR); + flags = SetLaunchFlag(flags, arguments.disableSTDIO, lldb::eLaunchFlagDisableSTDIO); - flags = SetLaunchFlag(flags, arguments, "shellExpandArguments", + flags = SetLaunchFlag(flags, arguments.shellExpandArguments, lldb::eLaunchFlagShellExpandArguments); - - const bool detachOnError = - GetBoolean(arguments, "detachOnError").value_or(false); - launch_info.SetDetachOnError(detachOnError); + launch_info.SetDetachOnError(arguments.detachOnError); launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug | lldb::eLaunchFlagStopAtEntry); - const auto timeout_seconds = - GetInteger<uint64_t>(arguments, "timeout").value_or(30); - if (GetBoolean(arguments, "runInTerminal").value_or(false)) { - if (llvm::Error err = RunInTerminal(dap, request, timeout_seconds)) - error.SetErrorString(llvm::toString(std::move(err)).c_str()); - } else if (launchCommands.empty()) { + if (arguments.runInTerminal) { + if (llvm::Error err = RunInTerminal(dap, arguments)) + return err; + } else if (!launchCommands) { + lldb::SBError error; // Disable async events so the launch will be successful when we return from // the launch call and the launch will happen synchronously dap.debugger.SetAsync(false); dap.target.Launch(launch_info, error); dap.debugger.SetAsync(true); + if (error.Fail()) + return llvm::make_error<DAPError>(error.GetCString()); } else { // Set the launch info so that run commands can access the configured // launch details. dap.target.SetLaunchInfo(launch_info); - if (llvm::Error err = dap.RunLaunchCommands(launchCommands)) { - error.SetErrorString(llvm::toString(std::move(err)).c_str()); - return error; - } + if (llvm::Error err = dap.RunLaunchCommands(*launchCommands)) + 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 launched and stopped at the entry point before // proceeding as the launch commands are not run using the synchronous // mode. - error = dap.WaitForProcessToStop(timeout_seconds); + lldb::SBError error = dap.WaitForProcessToStop(arguments.timeout); + if (error.Fail()) + return llvm::make_error<DAPError>(error.GetCString()); } - return error; + + return llvm::Error::success(); } void BaseRequestHandler::PrintWelcomeMessage() const { diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h index 396815b04c84a..aa3031fcce680 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.h @@ -69,7 +69,8 @@ class BaseRequestHandler { // runInTerminal if applicable. It doesn't do any of the additional // initialization and bookkeeping stuff that is needed for `request_launch`. // This way we can reuse the process launching logic for RestartRequest too. - lldb::SBError LaunchProcess(const llvm::json::Object &request) const; + llvm::Error + LaunchProcess(const protocol::LaunchRequestArguments &request) const; // Check if the step-granularity is `instruction`. bool HasInstructionGranularity(const llvm::json::Object &request) const; @@ -162,9 +163,15 @@ class RequestHandler : public BaseRequestHandler { } dap.Send(response); + + PostRun(); }; virtual llvm::Expected<Body> Run(const Args &) const = 0; + + /// A hook for a handler to asynchrounsly run an operation after the handler + /// is complete. + virtual void PostRun() const {}; }; class AttachRequestHandler : public LegacyRequestHandler { @@ -254,11 +261,15 @@ class InitializeRequestHandler Run(const protocol::InitializeRequestArguments &args) const override; }; -class LaunchRequestHandler : public LegacyRequestHandler { +class LaunchRequestHandler + : public RequestHandler<protocol::LaunchRequestArguments, + protocol::LaunchResponseBody> { public: - using LegacyRequestHandler::LegacyRequestHandler; + using RequestHandler::RequestHandler; static llvm::StringLiteral GetCommand() { return "launch"; } - void operator()(const llvm::json::Object &request) const override; + llvm::Expected<protocol::LaunchResponseBody> + Run(const protocol::LaunchRequestArguments &arguments) const override; + void PostRun() const override; }; class RestartRequestHandler : public LegacyRequestHandler { diff --git a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp index c8f43b7a76e8b..a009ad12ddd31 100644 --- a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp @@ -9,9 +9,11 @@ #include "DAP.h" #include "EventHelper.h" #include "JSONUtils.h" +#include "Protocol/ProtocolRequests.h" #include "RequestHandler.h" -#include "lldb/API/SBListener.h" -#include "llvm/Support/FileSystem.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/JSON.h" +#include "llvm/Support/raw_ostream.h" namespace lldb_dap { @@ -60,7 +62,7 @@ void RestartRequestHandler::operator()( const llvm::json::Object &request) const { llvm::json::Object response; FillResponse(request, response); - if (!dap.last_launch_or_attach_request) { + if (!dap.target.GetProcess().IsValid()) { response["success"] = llvm::json::Value(false); EmplaceSafeString(response, "message", "Restart request received but no process was launched."); @@ -77,7 +79,7 @@ void RestartRequestHandler::operator()( // implementation detail. The adapter *did* launch the process in response to // a "launch" command, so we can still stop it and re-run it. This is why we // don't just check `dap.is_attach`. - if (GetString(*dap.last_launch_or_attach_request, "command") == "attach") { + if (!dap.last_launch_request) { response["success"] = llvm::json::Value(false); EmplaceSafeString(response, "message", "Restarting an \"attach\" session is not supported."); @@ -85,15 +87,30 @@ void RestartRequestHandler::operator()( return; } - // The optional `arguments` field in RestartRequest can contain an updated - // version of the launch arguments. If there's one, use it. - const auto *restart_arguments = request.getObject("arguments"); - if (restart_arguments) { - const auto *launch_request_arguments = - restart_arguments->getObject("arguments"); - if (launch_request_arguments) { - (*dap.last_launch_or_attach_request)["arguments"] = - llvm::json::Value(llvm::json::Object(*launch_request_arguments)); + const llvm::json::Object *arguments = request.getObject("arguments"); + if (arguments) { + // The optional `arguments` field in RestartRequest can contain an updated + // version of the launch arguments. If there's one, use it. + const llvm::json::Value *restart_arguments = arguments->get("arguments"); + if (restart_arguments) { + protocol::LaunchRequestArguments updated_arguments; + llvm::json::Path::Root root; + if (!fromJSON(*restart_arguments, updated_arguments, root)) { + response["success"] = llvm::json::Value(false); + EmplaceSafeString( + response, "message", + llvm::formatv("Failed to parse updated launch arguments: {0}", + llvm::toString(root.getError())) + .str()); + dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } + dap.last_launch_request = updated_arguments; + // 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(); } } @@ -116,7 +133,15 @@ void RestartRequestHandler::operator()( dap.thread_ids.clear(); } dap.debugger.SetAsync(true); - LaunchProcess(*dap.last_launch_or_attach_request); + + // FIXME: Should we run 'preRunCommands'? + // FIXME: Should we add a 'preRestartCommands'? + if (llvm::Error err = LaunchProcess(*dap.last_launch_request)) { + response["success"] = llvm::json::Value(false); + EmplaceSafeString(response, "message", llvm::toString(std::move(err))); + dap.SendJSON(llvm::json::Value(std::move(response))); + return; + } // This is normally done after receiving a "configuration done" request. // Because we're restarting, configuration has already happened so we can @@ -129,4 +154,5 @@ void RestartRequestHandler::operator()( dap.SendJSON(llvm::json::Value(std::move(response))); } + } // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp index a7896b7fefa29..c48bcd84c9ddc 100644 --- a/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp @@ -145,7 +145,8 @@ void SetVariableRequestHandler::operator()( lldb::SBError error; bool success = variable.SetValueFromCString(value.data(), error); if (success) { - VariableDescription desc(variable, dap.enable_auto_variable_summaries); + VariableDescription desc(variable, + dap.configuration.enableAutoVariableSummaries); EmplaceSafeString(body, "value", desc.display_value); EmplaceSafeString(body, "type", desc.display_type_name); diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp index 220be0f99be6b..a58e3325af100 100644 --- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp @@ -70,7 +70,7 @@ static bool FillStackFrames(DAP &dap, lldb::SBThread &thread, stack_frames.emplace_back(CreateStackFrame(frame, dap.frame_format)); } - if (dap.display_extended_backtrace && reached_end_of_stack) { + if (dap.configuration.displayExtendedBacktrace && reached_end_of_stack) { // Check for any extended backtraces. for (uint32_t bt = 0; bt < thread.GetProcess().GetNumExtendedBacktraceTypes(); bt++) { diff --git a/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp index 6bb0a0f160499..19bcca2b22b9b 100644 --- a/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp @@ -180,10 +180,10 @@ void VariablesRequestHandler::operator()( return_var_ref = dap.variables.InsertVariable(stop_return_value, /*is_permanent=*/false); } - variables.emplace_back( - CreateVariable(renamed_return_value, return_var_ref, hex, - dap.enable_auto_variable_summaries, - dap.enable_synthetic_child_debugging, false)); + variables.emplace_back(CreateVariable( + renamed_return_value, return_var_ref, hex, + dap.configuration.enableAutoVariableSummaries, + dap.configuration.enableSyntheticChildDebugging, false)); } } @@ -197,8 +197,8 @@ void VariablesRequestHandler::operator()( int64_t var_ref = dap.variables.InsertVariable(variable, /*is_permanent=*/false); variables.emplace_back(CreateVariable( - variable, var_ref, hex, dap.enable_auto_variable_summaries, - dap.enable_synthetic_child_debugging, + variable, var_ref, hex, dap.configuration.enableAutoVariableSummaries, + dap.configuration.enableSyntheticChildDebugging, variable_name_counts[GetNonNullVariableName(variable)] > 1)); } } else { @@ -214,8 +214,8 @@ void VariablesRequestHandler::operator()( dap.variables.IsPermanentVariableReference(variablesReference); int64_t var_ref = dap.variables.InsertVariable(child, is_permanent); variables.emplace_back(CreateVariable( - child, var_ref, hex, dap.enable_auto_variable_summaries, - dap.enable_synthetic_child_debugging, + child, var_ref, hex, dap.configuration.enableAutoVariableSummaries, + dap.configuration.enableSyntheticChildDebugging, /*is_name_duplicated=*/false, custom_name)); }; const int64_t num_children = variable.GetNumChildren(); @@ -228,8 +228,8 @@ void VariablesRequestHandler::operator()( // "[raw]" child that can be used to inspect the raw version of a // synthetic member. That eliminates the need for the user to go to the // debug console and type `frame var <variable> to get these values. - if (dap.enable_synthetic_child_debugging && variable.IsSynthetic() && - i == num_children) + if (dap.configuration.enableSyntheticChildDebugging && + variable.IsSynthetic() && i == num_children) addChild(variable.GetNonSyntheticValue(), "[raw]"); } } diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index 9773b91a35a45..8e5b92e08c69f 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -1398,48 +1398,40 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) { /// See /// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal -llvm::json::Object -CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request, - llvm::StringRef debug_adapter_path, - llvm::StringRef comm_file, - lldb::pid_t debugger_pid) { +llvm::json::Object CreateRunInTerminalReverseRequest( + llvm::StringRef program, const std::vector<std::string> &args, + const llvm::StringMap<std::string> env, llvm::StringRef cwd, + llvm::StringRef debug_adapter_path, llvm::StringRef comm_file, + lldb::pid_t debugger_pid) { llvm::json::Object run_in_terminal_args; // This indicates the IDE to open an embedded terminal, instead of opening // the terminal in a new window. run_in_terminal_args.try_emplace("kind", "integrated"); - const auto *launch_request_arguments = launch_request.getObject("arguments"); // The program path must be the first entry in the "args" field - std::vector<std::string> args = {debug_adapter_path.str(), "--comm-file", - comm_file.str()}; + std::vector<std::string> req_args = {debug_adapter_path.str(), "--comm-file", + comm_file.str()}; if (debugger_pid != LLDB_INVALID_PROCESS_ID) { - args.push_back("--debugger-pid"); - args.push_back(std::to_string(debugger_pid)); + req_args.push_back("--debugger-pid"); + req_args.push_back(std::to_string(debugger_pid)); } - args.push_back("--launch-target"); - args.push_back( - GetString(launch_request_arguments, "program").value_or("").str()); - std::vector<std::string> target_args = - GetStrings(launch_request_arguments, "args"); - args.insert(args.end(), target_args.begin(), target_args.end()); + req_args.push_back("--launch-target"); + req_args.push_back(program.str()); + req_args.insert(req_args.end(), args.begin(), args.end()); run_in_terminal_args.try_emplace("args", args); - const auto cwd = GetString(launch_request_arguments, "cwd").value_or(""); if (!cwd.empty()) run_in_terminal_args.try_emplace("cwd", cwd); - auto envs = GetEnvironmentFromArguments(*launch_request_arguments); - llvm::json::Object env_json; - for (size_t index = 0, env_count = envs.GetNumValues(); index < env_count; - index++) { - llvm::StringRef key = envs.GetNameAtIndex(index); - llvm::StringRef value = envs.GetValueAtIndex(index); - - if (!key.empty()) - env_json.try_emplace(key, value); + if (!env.empty()) { + llvm::json::Object env_json; + for (const auto &kv : env) { + if (!kv.first().empty()) + env_json.try_emplace(kv.first(), kv.second); + } + run_in_terminal_args.try_emplace("env", + llvm::json::Value(std::move(env_json))); } - run_in_terminal_args.try_emplace("env", - llvm::json::Value(std::move(env_json))); return run_in_terminal_args; } diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 5d403d39a76d4..6bf180ba7e2c7 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -18,6 +18,7 @@ #include "lldb/API/SBType.h" #include "lldb/API/SBValue.h" #include "lldb/lldb-types.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" #include <cstdint> @@ -580,11 +581,11 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit); /// \return /// A "runInTerminal" JSON object that follows the specification outlined by /// Microsoft. -llvm::json::Object -CreateRunInTerminalReverseRequest(const llvm::json::Object &launch_request, - llvm::StringRef debug_adapter_path, - llvm::StringRef comm_file, - lldb::pid_t debugger_pid); +llvm::json::Object CreateRunInTerminalReverseRequest( + llvm::StringRef program, const std::vector<std::string> &args, + const llvm::StringMap<std::string> env, llvm::StringRef cwd, + llvm::StringRef debug_adapter_path, llvm::StringRef comm_file, + lldb::pid_t debugger_pid); /// Create a "Terminated" JSON object that contains statistics /// diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 9a613128739c2..84a21e5074447 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// #include "Protocol/ProtocolRequests.h" -#include "DAP.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" @@ -25,8 +25,7 @@ bool fromJSON(const json::Value &Params, DisconnectArguments &DA, O.mapOptional("suspendDebuggee", DA.suspendDebuggee); } -bool fromJSON(const llvm::json::Value &Params, PathFormat &PF, - llvm::json::Path P) { +bool fromJSON(const json::Value &Params, PathFormat &PF, json::Path P) { auto rawPathFormat = Params.getAsString(); if (!rawPathFormat) { P.report("expected a string"); @@ -47,7 +46,7 @@ bool fromJSON(const llvm::json::Value &Params, PathFormat &PF, return true; } -static const llvm::StringMap<ClientFeature> ClientFeatureByKey{ +static const StringMap<ClientFeature> ClientFeatureByKey{ {"supportsVariableType", eClientFeatureVariableType}, {"supportsVariablePaging", eClientFeatureVariablePaging}, {"supportsRunInTerminalRequest", eClientFeatureRunInTerminalRequest}, @@ -60,8 +59,8 @@ static const llvm::StringMap<ClientFeature> ClientFeatureByKey{ {"supportsStartDebuggingRequest", eClientFeatureStartDebuggingRequest}, {"supportsANSIStyling", eClientFeatureANSIStyling}}; -bool fromJSON(const llvm::json::Value &Params, InitializeRequestArguments &IRA, - llvm::json::Path P) { +bool fromJSON(const json::Value &Params, InitializeRequestArguments &IRA, + json::Path P) { json::ObjectMapper OM(Params, P); if (!OM) return false; @@ -82,6 +81,170 @@ bool fromJSON(const llvm::json::Value &Params, InitializeRequestArguments &IRA, OM.mapOptional("$__lldb_sourceInitFile", IRA.lldbExtSourceInitFile); } +static bool +parseSourceMap(const json::Value &Params, + std::vector<std::pair<std::string, std::string>> &sourceMap, + json::Path P) { + const json::Object *O = Params.getAsObject(); + if (!O) { + P.report("expected object"); + return false; + } + + const json::Value *value = O->get("sourceMap"); + if (!value) + return true; + + if (const json::Object *map_obj = value->getAsObject()) { + for (const auto &kv : *map_obj) { + const std::optional<StringRef> value = kv.second.getAsString(); + if (!value) { + P.field("sourceMap").field(kv.first).report("expected string value"); + return false; + } + sourceMap.emplace_back(std::make_pair(kv.first.str(), value->str())); + } + return true; + } + + if (const json::Array *env_arr = value->getAsArray()) { + for (size_t i = 0; i < env_arr->size(); ++i) { + const json::Array *kv = (*env_arr)[i].getAsArray(); + if (!kv) { + P.field("sourceMap").index(i).report("expected array"); + return false; + } + if (kv->size() != 2) { + P.field("sourceMap").index(i).report("expected array of pairs"); + return false; + } + const std::optional<StringRef> first = (*kv)[0].getAsString(); + if (!first) { + P.field("sourceMap").index(0).report("expected string"); + return false; + } + const std::optional<StringRef> second = (*kv)[1].getAsString(); + if (!second) { + P.field("sourceMap").index(1).report("expected string"); + return false; + } + sourceMap.emplace_back(std::make_pair(*first, second->str())); + } + + return true; + } + + P.report("invalid format, expected array or object"); + return false; +} + +bool fromJSON(const json::Value &Params, DAPConfiguration &C, json::Path P) { + json::ObjectMapper O(Params, P); + return O.mapOptional("debuggerRoot", C.debuggerRoot) && + O.mapOptional("enableAutoVariableSummaries", + C.enableAutoVariableSummaries) && + O.mapOptional("enableSyntheticChildDebugging", + C.enableSyntheticChildDebugging) && + O.mapOptional("displayExtendedBacktrace", + C.displayExtendedBacktrace) && + O.mapOptional("commandEscapePrefix", C.commandEscapePrefix) && + 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) && + parseSourceMap(Params, C.sourceMap, P); +} + +// The 'env' field is either an object as a map of strings or as an array of +// strings formatted like 'key=value'. +static bool parseEnv(const json::Value &Params, StringMap<std::string> &env, + json::Path P) { + const json::Object *O = Params.getAsObject(); + if (!O) { + P.report("expected object"); + return false; + } + + const json::Value *value = O->get("env"); + if (!value) + return true; + + if (const json::Object *env_obj = value->getAsObject()) { + for (const auto &kv : *env_obj) { + const std::optional<StringRef> value = kv.second.getAsString(); + if (!value) { + P.field("env").field(kv.first).report("expected string value"); + return false; + } + env.insert({kv.first.str(), value->str()}); + } + return true; + } + + if (const json::Array *env_arr = value->getAsArray()) { + for (size_t i = 0; i < env_arr->size(); ++i) { + const std::optional<StringRef> value = (*env_arr)[i].getAsString(); + if (!value) { + P.field("env").index(i).report("expected string"); + return false; + } + std::pair<StringRef, StringRef> kv = value->split("="); + env.insert({kv.first, kv.second.str()}); + } + + return true; + } + + P.field("env").report("invalid format, expected array or object"); + return false; +} + +bool parseTimeout(const json::Value &Params, std::chrono::seconds &S, + json::Path P) { + const json::Object *O = Params.getAsObject(); + if (!O) { + P.report("expected object"); + return false; + } + + const json::Value *value = O->get("timeout"); + if (!value) + return true; + std::optional<double> timeout = value->getAsNumber(); + if (!timeout) { + P.field("timeout").report("expected number"); + return false; + } + + S = std::chrono::duration_cast<std::chrono::seconds>( + std::chrono::duration<double>(*value->getAsNumber())); + return true; +} + +bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA, + json::Path P) { + json::ObjectMapper O(Params, P); + return O && fromJSON(Params, LRA.configuration, P) && + O.mapOptional("noDebug", LRA.noDebug) && + O.map("program", LRA.program) && + O.map("launchCommands", LRA.launchCommands) && O.map("cwd", LRA.cwd) && + O.mapOptional("args", LRA.args) && parseEnv(Params, LRA.env, P) && + O.map("targetTriple", LRA.targetTriple) && + O.map("platformName", LRA.platformName) && + 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) && + parseTimeout(Params, LRA.timeout, P); +} + bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) { json::ObjectMapper O(Params, P); return O && O.mapOptional("source", SA.source) && diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index c49a13711f8c7..388953e0ee041 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -22,7 +22,9 @@ #include "Protocol/ProtocolBase.h" #include "Protocol/ProtocolTypes.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/JSON.h" +#include <chrono> #include <cstdint> #include <optional> #include <string> @@ -117,6 +119,154 @@ bool fromJSON(const llvm::json::Value &, InitializeRequestArguments &, /// Response to `initialize` request. The capabilities of this debug adapter. using InitializeResponseBody = std::optional<Capabilities>; +/// DAP Launch and Attach common configurations. +struct DAPConfiguration { + /// 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; + + /// Enable auto generated summaries for variables when no summaries exist for + /// a given type. This feature can cause performance delays in large projects + /// when viewing variables. + bool enableAutoVariableSummaries = false; + + /// 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. + bool enableSyntheticChildDebugging = false; + + /// Enable language specific extended backtraces. + bool displayExtendedBacktrace = false; + + /// 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 + /// regular LLDB commands. + std::string commandEscapePrefix = "`"; + + /// If non-empty, stack frames will have descriptions generated based on the + /// provided format. See https://lldb.llvm.org/use/formatting.html for an + /// explanation on format strings for frames. If the format string contains + /// errors, an error message will be displayed on the Debug Console and the + /// 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; + + /// Same as `customFrameFormat`, but for threads instead of stack frames. + 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. + std::optional<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 + /// sourcePath. + std::vector<std::pair<std::string, std::string>> sourceMap; + + /// LLDB commands executed upon debugger startup prior to creating the LLDB + /// target. + std::vector<std::string> initCommands; + + /// LLDB commands executed just before launching/attaching, after the LLDB + /// target has been created. + std::vector<std::string> preRunCommands; + + /// LLDB commands executed just after launching/attaching, after the LLDB + /// target has been created. + std::vector<std::string> postRunCommands; + + /// LLDB commands executed just after each stop. + std::vector<std::string> stopCommands; + + /// LLDB commands executed when the program exits. + std::vector<std::string> exitCommands; + + /// LLDB commands executed when the debugging session ends. + std::vector<std::string> terminateCommands; +}; + +/// lldb-dap specific launch arguments. +struct LaunchRequestArguments { + /// Common lldb-dap configuration values for launching/attaching operations. + DAPConfiguration configuration; + + /// If true, the launch request should launch the program without enabling + /// debugging. + std::optional<bool> noDebug; + + /// Launch specific operations. + /// @{ + + /// Path to the executable to launch. + /// + /// *NOTE:* Either launchCommands or program must be configured. + std::optional<std::string> program; + + /// LLDB commands executed to launch the program. + /// + /// *NOTE:* Either launchCommands or program must be configured. + /// + /// If set, takes priority over the 'program' when launching the target. + std::optional<std::vector<std::string>> launchCommands; + + /// The program working directory. + std::optional<std::string> cwd; + + /// An array of command line argument strings to be passed to the program + /// being launched. + std::vector<std::string> args; + + /// Environment variables to set when launching the program. The format of + /// each environment variable string is "VAR=VALUE" for environment variables + /// with values or just "VAR" for environment variables with no values. + llvm::StringMap<std::string> env; + + /// Target triple for the program (arch-vendor-os). If not set, inferred from + /// the binary. + std::optional<std::string> targetTriple; + + /// Specify name of the platform to use for this target, creating the platform + /// if necessary. + std::optional<std::string> platformName; + + /// If set, then the client stub should detach rather than killing the debugee + /// if it loses connection with lldb. + bool detachOnError = false; + + /// Disable ASLR (Address Space Layout Randomization) when launching the + /// process. + bool disableASLR = false; + + /// Do not set up for terminal I/O to go to running process. + bool disableSTDIO = false; + + /// 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 &, + llvm::json::Path); + +/// Response to `launch` request. This is just an acknowledgement, so no body +/// field is required. +using LaunchResponseBody = VoidResponse; + /// Arguments for `source` request. struct SourceArguments { /// Specifies the source content to load. Either `source.path` or diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp index 4c6b36119c84f..39d06c0be32d9 100644 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ b/lldb/tools/lldb-dap/SourceBreakpoint.cpp @@ -319,9 +319,9 @@ bool SourceBreakpoint::BreakpointHitCallback( frame.GetValueForVariablePath(expr, lldb::eDynamicDontRunTarget); if (value.GetError().Fail()) value = frame.EvaluateExpression(expr); - output += - VariableDescription(value, bp->dap.enable_auto_variable_summaries) - .display_value; + output += VariableDescription( + value, bp->dap.configuration.enableAutoVariableSummaries) + .display_value; } else { output += messagePart.text; } >From 6965a7492d47b3f4170b5ec443d425882d1a9641 Mon Sep 17 00:00:00 2001 From: John Harrison <harj...@google.com> Date: Thu, 3 Apr 2025 10:50:12 -0700 Subject: [PATCH 2/2] Fixing up after merging. --- lldb/tools/lldb-dap/DAP.cpp | 4 ++-- lldb/tools/lldb-dap/DAP.h | 3 +-- lldb/tools/lldb-dap/Handler/RequestHandler.cpp | 3 +-- lldb/tools/lldb-dap/JSONUtils.cpp | 7 +++---- lldb/tools/lldb-dap/JSONUtils.h | 17 ++++++++++++----- .../lldb-dap/Protocol/ProtocolRequests.cpp | 2 +- lldb/tools/lldb-dap/Protocol/ProtocolRequests.h | 4 ++-- 7 files changed, 22 insertions(+), 18 deletions(-) diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp index 01b6bf1418731..e72a3b4859ec8 100644 --- a/lldb/tools/lldb-dap/DAP.cpp +++ b/lldb/tools/lldb-dap/DAP.cpp @@ -76,7 +76,7 @@ DAP::DAP(Log *log, const ReplMode default_repl_mode, std::vector<std::string> pre_init_commands, Transport &transport) : log(log), transport(transport), broadcaster("lldb-dap"), exception_breakpoints(), focus_tid(LLDB_INVALID_THREAD_ID), - stop_at_entry(false), is_attach(false), + is_attach(false), stop_at_entry(false), restarting_process_id(LLDB_INVALID_PROCESS_ID), configuration_done_sent(false), waiting_for_run_in_terminal(false), progress_event_reporter( @@ -1054,7 +1054,7 @@ void DAP::ConfigureSourceMaps() { RunLLDBCommands("Setting source map:", {sourceMapCommand}); } -void DAP::SetConfiguration(const protocol::DAPConfiguration &config, +void DAP::SetConfiguration(const protocol::Configuration &config, bool is_attach) { configuration = config; this->is_attach = is_attach; diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h index 8ec802d33c61d..408834583cce5 100644 --- a/lldb/tools/lldb-dap/DAP.h +++ b/lldb/tools/lldb-dap/DAP.h @@ -242,8 +242,7 @@ struct DAP { void StopEventHandlers(); /// Configures the debug adapter for launching/attaching. - void SetConfiguration(const protocol::DAPConfiguration &confing, - bool is_attach); + void SetConfiguration(const protocol::Configuration &confing, bool is_attach); /// Configure source maps based on the current `DAPConfiguration`. void ConfigureSourceMaps(); diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp index 23904848de5cb..1ff7695f42416 100644 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp @@ -123,8 +123,7 @@ RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest( *arguments.program, arguments.args, arguments.env, - arguments.cwd.value_or(""), dap.debug_adapter_path, comm_file.m_path, - debugger_pid); + arguments.cwd.value_or(""), comm_file.m_path, debugger_pid); dap.SendReverseRequest<LogFailureResponseHandler>("runInTerminal", std::move(reverse_request)); diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp index c59c10698c835..3dacca487e133 100644 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ b/lldb/tools/lldb-dap/JSONUtils.cpp @@ -1401,16 +1401,15 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) { llvm::json::Object CreateRunInTerminalReverseRequest( llvm::StringRef program, const std::vector<std::string> &args, const llvm::StringMap<std::string> env, llvm::StringRef cwd, - llvm::StringRef debug_adapter_path, llvm::StringRef comm_file, - lldb::pid_t debugger_pid) { + llvm::StringRef comm_file, lldb::pid_t debugger_pid) { llvm::json::Object run_in_terminal_args; // This indicates the IDE to open an embedded terminal, instead of opening // the terminal in a new window. run_in_terminal_args.try_emplace("kind", "integrated"); // The program path must be the first entry in the "args" field - std::vector<std::string> req_args = {debug_adapter_path.str(), "--comm-file", - comm_file.str()}; + std::vector<std::string> req_args = {DAP::debug_adapter_path.str(), + "--comm-file", comm_file.str()}; if (debugger_pid != LLDB_INVALID_PROCESS_ID) { req_args.push_back("--debugger-pid"); req_args.push_back(std::to_string(debugger_pid)); diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h index 8c24c7cf9f8f0..2d6348973b804 100644 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ b/lldb/tools/lldb-dap/JSONUtils.h @@ -562,9 +562,17 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit); /// Create a runInTerminal reverse request object /// -/// \param[in] launch_request -/// The original launch_request object whose fields are used to construct -/// the reverse request object. +/// \param[in] program +/// Path to the program to run in the terminal. +/// +/// \param[in] args +/// The arguments for the program. +/// +/// \param[in] env +/// The environment variables to set in the terminal. +/// +/// \param[in] cwd +/// The working directory for the run in terminal request. /// /// \param[in] comm_file /// The fifo file used to communicate the with the target launcher. @@ -580,8 +588,7 @@ llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit); llvm::json::Object CreateRunInTerminalReverseRequest( llvm::StringRef program, const std::vector<std::string> &args, const llvm::StringMap<std::string> env, llvm::StringRef cwd, - llvm::StringRef debug_adapter_path, llvm::StringRef comm_file, - lldb::pid_t debugger_pid); + llvm::StringRef comm_file, lldb::pid_t debugger_pid); /// Create a "Terminated" JSON object that contains statistics /// diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp index 84a21e5074447..f08126f231bfb 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp @@ -138,7 +138,7 @@ parseSourceMap(const json::Value &Params, return false; } -bool fromJSON(const json::Value &Params, DAPConfiguration &C, json::Path P) { +bool fromJSON(const json::Value &Params, Configuration &C, json::Path P) { json::ObjectMapper O(Params, P); return O.mapOptional("debuggerRoot", C.debuggerRoot) && O.mapOptional("enableAutoVariableSummaries", diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h index 86a025ae00074..8bf9617aa8d25 100644 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h @@ -22,8 +22,8 @@ #include "Protocol/ProtocolBase.h" #include "Protocol/ProtocolTypes.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/StringMap.h" #include "llvm/Support/JSON.h" #include <chrono> #include <cstdint> @@ -198,7 +198,7 @@ struct Configuration { /// lldb-dap specific launch arguments. struct LaunchRequestArguments { /// Common lldb-dap configuration values for launching/attaching operations. - DAPConfiguration configuration; + Configuration configuration; /// If true, the launch request should launch the program without enabling /// debugging. _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits