Author: Jonas Devlieghere Date: 2026-09-02T14:50:04-07:00 New Revision: 32e83eafa73dbdd8edd113de787e2819ea049357
URL: https://github.com/llvm/llvm-project/commit/32e83eafa73dbdd8edd113de787e2819ea049357 DIFF: https://github.com/llvm/llvm-project/commit/32e83eafa73dbdd8edd113de787e2819ea049357.diff LOG: [lldb] Pass Wasm runtime-args before the port argument (#220700) A runtime that dispatches on a leading subcommand, such as WasmKit's `wasmkit run`, could not be driven directly: runtime-args landed after the port argument, so the subcommand did too and the runtime rejected it. Naming the subcommand required a wrapper script. Move runtime-args ahead of the port argument so the setting can carry it. Extract the command line assembly into PlatformWasm::MakeRuntimeCommand so the ordering is covered by unit tests, and clarify that port-arg has to carry its value in the same argument. Added: lldb/unittests/Platform/PlatformWasmTest.cpp Modified: lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td lldb/source/Plugins/Process/wasm/ProcessWasm.cpp lldb/source/Plugins/Process/wasm/ProcessWasm.h lldb/unittests/Platform/CMakeLists.txt llvm/docs/ReleaseNotes.md Removed: ################################################################################ diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp index eb1cdac11c146..2dee06e414c5b 100644 --- a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp +++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp @@ -146,6 +146,36 @@ lldb::ProcessSP PlatformWasm::Attach(ProcessAttachInfo &attach_info, return nullptr; } +Args PlatformWasm::MakeRuntimeCommand(llvm::StringRef runtime_path, + const Args &runtime_args, + llvm::StringRef port_arg, uint16_t port, + llvm::StringRef env_arg, + const Environment &env, + llvm::StringRef module_path, + const Args &inferior_args) { + Args args({runtime_path}); + args.AppendArguments(runtime_args); + args.AppendArgument(llvm::formatv("{0}{1}", port_arg, port).str()); + + if (!env_arg.empty()) + for (const auto &kv : env) + args.AppendArgument( + llvm::formatv("{0}{1}", env_arg, Environment::compose(kv)).str()); + + // The runtime resolves the module as a host path, while arg0 is the name the + // platform reports for the executable and need not resolve here. + Args module_args = inferior_args; + if (!module_path.empty()) { + if (module_args.GetArgumentCount() > 0) + module_args.ReplaceArgumentAtIndex(0, module_path); + else + module_args.AppendArgument(module_path); + } + args.AppendArguments(module_args); + + return args; +} + lldb::ProcessSP PlatformWasm::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target &target, Status &error) { @@ -173,30 +203,14 @@ lldb::ProcessSP PlatformWasm::DebugProcess(ProcessLaunchInfo &launch_info, } uint16_t port = *expected_port; - Args args({runtime.GetPath(), - llvm::formatv("{0}{1}", properties.GetPortArg(), port).str()}); - args.AppendArguments(properties.GetRuntimeArgs()); - - // Forward the inferior's environment into the WASI runtime. How arguments are - // passed is configurable. When not configured, no environment is passed. - if (llvm::StringRef env_arg = properties.GetEnvArg(); !env_arg.empty()) - for (const auto &kv : launch_info.GetEnvironment()) - args.AppendArgument( - llvm::formatv("{0}{1}", env_arg, Environment::compose(kv)).str()); + std::string module_path; + if (ModuleSP exe_module_sp = target.GetExecutableModule()) + module_path = exe_module_sp->GetFileSpec().GetPath(); - // The runtime is handed the module to run as a path on this host. A launch - // takes its executable from the name the module goes by on the platform, - // which for a module reported by a stub is a name of the stub's choosing - // rather than a path that resolves here, so run the file the target has. - Args inferior_args = launch_info.GetArguments(); - if (ModuleSP exe_module_sp = target.GetExecutableModule()) { - const std::string exe_path = exe_module_sp->GetFileSpec().GetPath(); - if (inferior_args.GetArgumentCount() > 0) - inferior_args.ReplaceArgumentAtIndex(0, exe_path); - else - inferior_args.AppendArgument(exe_path); - } - args.AppendArguments(inferior_args); + Args args = MakeRuntimeCommand( + runtime.GetPath(), properties.GetRuntimeArgs(), properties.GetPortArg(), + port, properties.GetEnvArg(), launch_info.GetEnvironment(), module_path, + launch_info.GetArguments()); launch_info.SetArguments(args, true); launch_info.SetLaunchInSeparateProcessGroup(true); diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h index e752b8bae9840..0fba3c09df5bd 100644 --- a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h +++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h @@ -43,6 +43,16 @@ class PlatformWasm : public RemoteAwarePlatform { lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger, Target *target, Status &status) override; + /// Assemble the command line that launches the runtime on \p module_path, + /// serving its GDB remote stub on \p port. Extra \p runtime_args precede the + /// port argument, so they can carry a subcommand the runtime expects first, + /// such as WasmKit's `run`. An empty \p env_arg forwards no environment. + static Args + MakeRuntimeCommand(llvm::StringRef runtime_path, const Args &runtime_args, + llvm::StringRef port_arg, uint16_t port, + llvm::StringRef env_arg, const Environment &env, + llvm::StringRef module_path, const Args &inferior_args); + Status ConnectRemote(Args &args) override; void CalculateTrapHandlerSymbolNames() override {} diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td index 1fe27d9caf44d..21b4985524d1b 100644 --- a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td +++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td @@ -12,8 +12,9 @@ let Definition = "platformwasm", Path = "platform.plugin.wasm" in { DefaultStringValue<"">, Desc<"Argument to the WebAssembly runtime to specify the " "GDB remote port. The port number chosen by LLDB will be " - "concatenated to this argument. For example: " - "`-g=127.0.0.1:` or `--debugger-port `.">; + "concatenated to this argument, which therefore has to " + "carry its value in the same argument. For example: " + "`-g=127.0.0.1:` or `--debugger-port=`.">; def EnvArg : Property<"env-arg", "String">, Global, DefaultStringValue<"">, @@ -26,6 +27,8 @@ let Definition = "platformwasm", Path = "platform.plugin.wasm" in { Global, DefaultStringValue<"">, Desc<"Extra arguments to pass to the WebAssembly runtime. " + "They precede the port argument, so a runtime that " + "dispatches on a leading subcommand names it here. " "For the argument that specifies the GDB remote port, " "use port-arg instead.">; } diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp index 3e2bf05e00a0c..87c3a32f0cd5d 100644 --- a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp @@ -48,8 +48,6 @@ void ProcessWasm::DebuggerInitialize(Debugger &debugger) { llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); } -llvm::StringRef ProcessWasm::GetPluginNameStatic() { return "wasm"; } - llvm::StringRef ProcessWasm::GetPluginDescriptionStatic() { return "GDB Remote protocol based WebAssembly debugging plug-in."; } diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h index cffff2fa54093..d44c1fc6defd0 100644 --- a/lldb/source/Plugins/Process/wasm/ProcessWasm.h +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h @@ -32,7 +32,7 @@ class ProcessWasm : public process_gdb_remote::ProcessGDBRemote { static void DebuggerInitialize(Debugger &debugger); static void Terminate(); - static llvm::StringRef GetPluginNameStatic(); + static llvm::StringRef GetPluginNameStatic() { return "wasm"; } static llvm::StringRef GetPluginDescriptionStatic(); llvm::StringRef GetPluginName() override; diff --git a/lldb/unittests/Platform/CMakeLists.txt b/lldb/unittests/Platform/CMakeLists.txt index b3c87b33527bd..693faa07e53f8 100644 --- a/lldb/unittests/Platform/CMakeLists.txt +++ b/lldb/unittests/Platform/CMakeLists.txt @@ -5,6 +5,7 @@ add_lldb_unittest(LLDBPlatformTests PlatformMacOSXTest.cpp PlatformSiginfoTest.cpp PlatformTest.cpp + PlatformWasmTest.cpp LINK_COMPONENTS Support @@ -13,6 +14,7 @@ add_lldb_unittest(LLDBPlatformTests lldbPluginPlatformLinux lldbPluginPlatformMacOSX lldbPluginPlatformNetBSD + lldbPluginPlatformWasm lldbUtilityHelpers LLVMTestingSupport ) diff --git a/lldb/unittests/Platform/PlatformWasmTest.cpp b/lldb/unittests/Platform/PlatformWasmTest.cpp new file mode 100644 index 0000000000000..f24e4e66c8671 --- /dev/null +++ b/lldb/unittests/Platform/PlatformWasmTest.cpp @@ -0,0 +1,98 @@ +//===----------------------------------------------------------------------===// +// +// 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 "Plugins/Platform/WebAssembly/PlatformWasm.h" +#include "lldb/Utility/Args.h" +#include "lldb/Utility/Environment.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" + +using namespace lldb_private; +using ::testing::ElementsAre; + +static std::vector<std::string> GetArgStrings(const Args &args) { + std::vector<std::string> result; + for (const Args::ArgEntry &entry : args) + result.push_back(entry.c_str()); + return result; +} + +TEST(PlatformWasmTest, MakeRuntimeCommand) { + Args args = PlatformWasm::MakeRuntimeCommand( + "/bin/runtime", Args(), "-g=127.0.0.1:", 1234, /*env_arg=*/"", + Environment(), "/tmp/module.wasm", Args()); + + EXPECT_THAT( + GetArgStrings(args), + ElementsAre("/bin/runtime", "-g=127.0.0.1:1234", "/tmp/module.wasm")); +} + +TEST(PlatformWasmTest, MakeRuntimeCommandRuntimeArgsPrecedePort) { + // A runtime dispatching on a leading subcommand names it through + // runtime-args, which is only usable if those come before the port. + Args runtime_args; + runtime_args.AppendArgument("run"); + + Args args = PlatformWasm::MakeRuntimeCommand( + "/bin/runtime", runtime_args, "--debugger-port=", 1234, /*env_arg=*/"", + Environment(), "/tmp/module.wasm", Args()); + + EXPECT_THAT(GetArgStrings(args), + ElementsAre("/bin/runtime", "run", "--debugger-port=1234", + "/tmp/module.wasm")); +} + +TEST(PlatformWasmTest, MakeRuntimeCommandForwardsEnvironment) { + Environment env; + env["KEY"] = "value"; + + Args args = PlatformWasm::MakeRuntimeCommand("/bin/runtime", Args(), + "-g=", 1234, "--env=", env, + "/tmp/module.wasm", Args()); + + EXPECT_THAT(GetArgStrings(args), + ElementsAre("/bin/runtime", "-g=1234", "--env=KEY=value", + "/tmp/module.wasm")); +} + +TEST(PlatformWasmTest, MakeRuntimeCommandWithoutEnvArgDropsEnvironment) { + Environment env; + env["KEY"] = "value"; + + Args args = PlatformWasm::MakeRuntimeCommand( + "/bin/runtime", Args(), "-g=", 1234, + /*env_arg=*/"", env, "/tmp/module.wasm", Args()); + + EXPECT_THAT(GetArgStrings(args), + ElementsAre("/bin/runtime", "-g=1234", "/tmp/module.wasm")); +} + +TEST(PlatformWasmTest, MakeRuntimeCommandModulePathReplacesArgZero) { + Args inferior_args; + inferior_args.AppendArgument("module.wasm"); + inferior_args.AppendArgument("--flag"); + + Args args = PlatformWasm::MakeRuntimeCommand( + "/bin/runtime", Args(), "-g=", 1234, /*env_arg=*/"", Environment(), + "/tmp/module.wasm", inferior_args); + + EXPECT_THAT(GetArgStrings(args), ElementsAre("/bin/runtime", "-g=1234", + "/tmp/module.wasm", "--flag")); +} + +TEST(PlatformWasmTest, MakeRuntimeCommandWithoutModulePath) { + Args inferior_args; + inferior_args.AppendArgument("module.wasm"); + + Args args = PlatformWasm::MakeRuntimeCommand( + "/bin/runtime", Args(), "-g=", 1234, /*env_arg=*/"", Environment(), + /*module_path=*/"", inferior_args); + + EXPECT_THAT(GetArgStrings(args), + ElementsAre("/bin/runtime", "-g=1234", "module.wasm")); +} diff --git a/llvm/docs/ReleaseNotes.md b/llvm/docs/ReleaseNotes.md index 9b858caadb6c3..ce9c48723bff1 100644 --- a/llvm/docs/ReleaseNotes.md +++ b/llvm/docs/ReleaseNotes.md @@ -248,6 +248,11 @@ Makes programs 10x faster by doing Special New Thing. ### Changes to LLDB +* `platform.plugin.wasm.runtime-args` now precede the port argument on the Wasm + runtime's command line instead of following it. A runtime that dispatches on a + leading subcommand can therefore name that subcommand through this setting, + rather than needing a wrapper script. + #### SBAPI * A [bug](https://github.com/llvm/llvm-project/issues/211787) involving SBValues _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
