https://github.com/JDevlieghere updated 
https://github.com/llvm/llvm-project/pull/171507

>From 417bf4882e9a6be920e6a728e5de1d62eedc9e38 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Mon, 8 Dec 2025 17:01:18 -0800
Subject: [PATCH 1/2] [lldb] Add WebAssembly platform

This PR adds a platform for WebAssembly. Inspired by QemuUser, the
platform lets you configure a WebAssembly runtime to run a Wasm binary.

For example, the following configuration can be used to launch binaries
under the WebAssembly Micro Runtime (WARM):

```
settings set -- platform.plugin.wasm.runtime-args --heap-size=1048576
settings set -- platform.plugin.wasm.port-arg -g=127.0.0.1:
settings set -- platform.plugin.wasm.runtime-path /path/to/iwasm-2.4.0
```
---
 lldb/source/Plugins/Platform/CMakeLists.txt   |   1 +
 .../Platform/WebAssembly/CMakeLists.txt       |  23 ++
 .../Platform/WebAssembly/PlatformWasm.cpp     | 197 ++++++++++++++++++
 .../Platform/WebAssembly/PlatformWasm.h       |  79 +++++++
 .../WebAssembly/PlatformWasmProperties.td     |  21 ++
 5 files changed, 321 insertions(+)
 create mode 100644 lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt
 create mode 100644 lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
 create mode 100644 lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h
 create mode 100644 
lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td

diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt 
b/lldb/source/Plugins/Platform/CMakeLists.txt
index f4753ab47ce11..cc1432aa4754b 100644
--- a/lldb/source/Plugins/Platform/CMakeLists.txt
+++ b/lldb/source/Plugins/Platform/CMakeLists.txt
@@ -15,4 +15,5 @@ add_subdirectory(NetBSD)
 add_subdirectory(OpenBSD)
 add_subdirectory(POSIX)
 add_subdirectory(QemuUser)
+add_subdirectory(WebAssembly)
 add_subdirectory(Windows)
diff --git a/lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt 
b/lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt
new file mode 100644
index 0000000000000..7fb17b295fbb8
--- /dev/null
+++ b/lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt
@@ -0,0 +1,23 @@
+lldb_tablegen(PlatformWasmProperties.inc -gen-lldb-property-defs
+  SOURCE PlatformWasmProperties.td
+  TARGET LLDBPluginPlatformWasmPropertiesGen)
+
+lldb_tablegen(PlatformWasmPropertiesEnum.inc -gen-lldb-property-enum-defs
+  SOURCE PlatformWasmProperties.td
+  TARGET LLDBPluginPlatformWasmPropertiesEnumGen)
+
+add_lldb_library(lldbPluginPlatformWasm PLUGIN
+  PlatformWasm.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbHost
+    lldbTarget
+    lldbUtility
+  LINK_COMPONENTS
+    Support
+  )
+
+add_dependencies(lldbPluginPlatformWasm
+  LLDBPluginPlatformWasmPropertiesGen
+  LLDBPluginPlatformWasmPropertiesEnumGen)
diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp 
b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
new file mode 100644
index 0000000000000..fc00db50ffc0c
--- /dev/null
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
@@ -0,0 +1,197 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "Plugins/Process/wasm/ProcessWasm.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/ProcessLaunchInfo.h"
+#include "lldb/Host/common/TCPSocket.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Listener.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/StringExtras.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(PlatformWasm)
+
+namespace {
+#define LLDB_PROPERTIES_platformwasm
+#include "PlatformWasmProperties.inc"
+
+enum {
+#define LLDB_PROPERTIES_platformwasm
+#include "PlatformWasmPropertiesEnum.inc"
+};
+
+class PluginProperties : public Properties {
+public:
+  PluginProperties() {
+    m_collection_sp = std::make_shared<OptionValueProperties>(
+        PlatformWasm::GetPluginNameStatic());
+    m_collection_sp->Initialize(g_platformwasm_properties);
+  }
+
+  FileSpec GetRuntimePath() const {
+    return GetPropertyAtIndexAs<FileSpec>(ePropertyRuntimePath, {});
+  }
+
+  Args GetRuntimeArgs() const {
+    Args result;
+    m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyRuntimeArgs, result);
+    return result;
+  }
+
+  llvm::StringRef GetPortArg() const {
+    return GetPropertyAtIndexAs<llvm::StringRef>(ePropertyPortArg, {});
+  }
+};
+
+} // namespace
+
+static PluginProperties &GetGlobalProperties() {
+  static PluginProperties g_settings;
+  return g_settings;
+}
+
+llvm::StringRef PlatformWasm::GetPluginDescriptionStatic() {
+  return "Platform for debugging Wasm";
+}
+
+void PlatformWasm::Initialize() {
+  PluginManager::RegisterPlugin(
+      GetPluginNameStatic(), GetPluginDescriptionStatic(),
+      PlatformWasm::CreateInstance, PlatformWasm::DebuggerInitialize);
+}
+
+void PlatformWasm::Terminate() {
+  PluginManager::UnregisterPlugin(PlatformWasm::CreateInstance);
+}
+
+void PlatformWasm::DebuggerInitialize(Debugger &debugger) {
+  if (!PluginManager::GetSettingForPlatformPlugin(debugger,
+                                                  GetPluginNameStatic())) {
+    PluginManager::CreateSettingForPlatformPlugin(
+        debugger, GetGlobalProperties().GetValueProperties(),
+        "Properties for the wasm platform plugin.",
+        /*is_global_property=*/true);
+  }
+}
+
+PlatformSP PlatformWasm::CreateInstance(bool force, const ArchSpec *arch) {
+  Log *log = GetLog(LLDBLog::Platform);
+  LLDB_LOG(log, "force = {0}, arch = ({1}, {2})", force,
+           arch ? arch->GetArchitectureName() : "<null>",
+           arch ? arch->GetTriple().getTriple() : "<null>");
+
+  bool create = force;
+  if (!create && arch && arch->IsValid()) {
+    const llvm::Triple &triple = arch->GetTriple();
+    switch (triple.getArch()) {
+    case llvm::Triple::wasm32:
+    case llvm::Triple::wasm64:
+      create = true;
+      break;
+    default:
+      break;
+    }
+  }
+
+  LLDB_LOG(log, "create = {0}", create);
+  return create ? PlatformSP(new PlatformWasm()) : PlatformSP();
+}
+
+std::vector<ArchSpec>
+PlatformWasm::GetSupportedArchitectures(const ArchSpec &process_host_arch) {
+  return {ArchSpec("wasm32-unknown-unknown-wasm"),
+          ArchSpec("wasm64-unknown-unknown-wasm")};
+}
+
+static auto get_arg_range(const Args &args) {
+  return llvm::make_range(args.GetArgumentArrayRef().begin(),
+                          args.GetArgumentArrayRef().end());
+}
+
+lldb::ProcessSP PlatformWasm::DebugProcess(ProcessLaunchInfo &launch_info,
+                                           Debugger &debugger, Target &target,
+                                           Status &error) {
+  Log *log = GetLog(LLDBLog::Platform);
+
+  const PluginProperties &properties = GetGlobalProperties();
+
+  FileSpec runtime = properties.GetRuntimePath();
+  FileSystem::Instance().ResolveExecutableLocation(runtime);
+
+  if (!FileSystem::Instance().Exists(runtime)) {
+    error = Status::FromErrorStringWithFormatv(
+        "WebAssembly runtime does not exist: {0}", runtime.GetPath());
+    return nullptr;
+  }
+
+  uint16_t port = 0;
+  {
+    TCPSocket listen_socket(true);
+    error = listen_socket.Listen("localhost:0", 5);
+    if (error.Fail())
+      return nullptr;
+    port = listen_socket.GetLocalPortNumber();
+  }
+
+  if (error.Fail())
+    return nullptr;
+
+  Args args({runtime.GetPath(),
+             llvm::formatv("{0}{1}", properties.GetPortArg(), port).str()});
+  args.AppendArguments(properties.GetRuntimeArgs());
+  args.AppendArguments(launch_info.GetArguments());
+
+  launch_info.SetArguments(args, true);
+  launch_info.SetLaunchInSeparateProcessGroup(true);
+  launch_info.GetFlags().Clear(eLaunchFlagDebug);
+  
launch_info.SetMonitorProcessCallback(ProcessLaunchInfo::NoOpMonitorCallback);
+
+  LLDB_LOG(log, "{0}", get_arg_range(launch_info.GetArguments()));
+
+  // This is automatically done for host platform in
+  // Target::FinalizeFileActions, but we're not a host platform.
+  llvm::Error Err = launch_info.SetUpPtyRedirection();
+  LLDB_LOG_ERROR(log, std::move(Err), "SetUpPtyRedirection failed: {0}");
+
+  error = Host::LaunchProcess(launch_info);
+  if (error.Fail())
+    return nullptr;
+
+  ProcessSP process_sp = target.CreateProcess(
+      launch_info.GetListener(), wasm::ProcessWasm::GetPluginNameStatic(),
+      nullptr, true);
+  if (!process_sp) {
+    error = Status::FromErrorString("failed to create WebAssembly process");
+    return nullptr;
+  }
+
+  process_sp->HijackProcessEvents(launch_info.GetHijackListener());
+
+  error = process_sp->ConnectRemote(
+      llvm::formatv("connect://localhost:{0}", port).str());
+  if (error.Fail())
+    return nullptr;
+
+  if (launch_info.GetPTY().GetPrimaryFileDescriptor() !=
+      PseudoTerminal::invalid_fd)
+    process_sp->SetSTDIOFileDescriptor(
+        launch_info.GetPTY().ReleasePrimaryFileDescriptor());
+
+  return process_sp;
+
+  return {};
+}
diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h 
b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h
new file mode 100644
index 0000000000000..cba4c7c549cb0
--- /dev/null
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_SOURCE_PLUGINS_PLATFORM_WASM_PLATFORMWASM_H
+#define LLDB_SOURCE_PLUGINS_PLATFORM_WASM_PLATFORMWASM_H
+
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Target/Platform.h"
+
+namespace lldb_private {
+
+class PlatformWasm : public Platform {
+public:
+  static void Initialize();
+  static void Terminate();
+
+  static llvm::StringRef GetPluginNameStatic() { return "wasm"; }
+  static llvm::StringRef GetPluginDescriptionStatic();
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+  llvm::StringRef GetDescription() override {
+    return GetPluginDescriptionStatic();
+  }
+
+  UserIDResolver &GetUserIDResolver() override {
+    return HostInfo::GetUserIDResolver();
+  }
+
+  std::vector<ArchSpec>
+  GetSupportedArchitectures(const ArchSpec &process_host_arch) override;
+
+  lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
+                               Debugger &debugger, Target &target,
+                               Status &error) override;
+
+  lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger,
+                         Target *target, Status &status) override {
+    status = Status::FromErrorString("Not supported");
+    return nullptr;
+  }
+
+  uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info,
+                         ProcessInstanceInfoList &proc_infos) override {
+    return 0;
+  }
+
+  bool GetProcessInfo(lldb::pid_t pid,
+                      ProcessInstanceInfo &proc_info) override {
+    return false;
+  }
+
+  bool IsConnected() const override { return true; }
+
+  void CalculateTrapHandlerSymbolNames() override {}
+
+  MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,
+                                  lldb::addr_t length, unsigned prot,
+                                  unsigned flags, lldb::addr_t fd,
+                                  lldb::addr_t offset) override {
+    return Platform::GetHostPlatform()->GetMmapArgumentList(
+        arch, addr, length, prot, flags, fd, offset);
+  }
+
+private:
+  static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
+  static void DebuggerInitialize(Debugger &debugger);
+
+  PlatformWasm() : Platform(/*is_host=*/true) {}
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PLATFORM_WASM_PLATFORMWASM_H
diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td 
b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td
new file mode 100644
index 0000000000000..9fcd3fca121cb
--- /dev/null
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td
@@ -0,0 +1,21 @@
+include "../../../../include/lldb/Core/PropertiesBase.td"
+
+let Definition = "platformwasm" in {
+  def RuntimePath
+      : Property<"runtime-path", "FileSpec">,
+        Global,
+        DefaultStringValue<"">,
+        Desc<"Path to the WebAssembly runtime binary. If the path does not "
+             "contain a directory separator, the filename is looked up in the "
+             "PATH environment variable. If empty, the filename is derived "
+             "from the architecture setting.">;
+  def RuntimeArgs : Property<"runtime-args", "Args">,
+                    Global,
+                    DefaultStringValue<"">,
+                    Desc<"Extra arguments to pass to the WebAssembly 
runtime.">;
+  def PortArg : Property<"port-arg", "String">,
+                Global,
+                DefaultStringValue<"">,
+                Desc<"Argument to the WebAssembly runtime to specify the "
+                     "GDB remote port.">;
+}

>From 1c6c87545f3eface721997d9d9f6be39b4054707 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Wed, 10 Dec 2025 11:26:13 -0800
Subject: [PATCH 2/2] Address David's feedback

---
 .../Platform/WebAssembly/PlatformWasm.cpp     | 23 +++++++++++++++----
 .../WebAssembly/PlatformWasmProperties.td     | 16 ++++++-------
 2 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp 
b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
index fc00db50ffc0c..3fe44d7604244 100644
--- a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
@@ -158,15 +158,23 @@ lldb::ProcessSP 
PlatformWasm::DebugProcess(ProcessLaunchInfo &launch_info,
   launch_info.SetArguments(args, true);
   launch_info.SetLaunchInSeparateProcessGroup(true);
   launch_info.GetFlags().Clear(eLaunchFlagDebug);
-  
launch_info.SetMonitorProcessCallback(ProcessLaunchInfo::NoOpMonitorCallback);
 
-  LLDB_LOG(log, "{0}", get_arg_range(launch_info.GetArguments()));
+  auto exit_code = std::make_shared<std::optional<int>>();
+  launch_info.SetMonitorProcessCallback(
+      [=](lldb::pid_t pid, int signal, int status) {
+        LLDB_LOG(
+            log,
+            "WebAssembly runtime exited: pid = {0}, signal = {1}, status = 
{2}",
+            pid, signal, status);
+        exit_code->emplace(status);
+      });
 
   // This is automatically done for host platform in
   // Target::FinalizeFileActions, but we're not a host platform.
   llvm::Error Err = launch_info.SetUpPtyRedirection();
   LLDB_LOG_ERROR(log, std::move(Err), "SetUpPtyRedirection failed: {0}");
 
+  LLDB_LOG(log, "{0}", get_arg_range(launch_info.GetArguments()));
   error = Host::LaunchProcess(launch_info);
   if (error.Fail())
     return nullptr;
@@ -183,8 +191,15 @@ lldb::ProcessSP 
PlatformWasm::DebugProcess(ProcessLaunchInfo &launch_info,
 
   error = process_sp->ConnectRemote(
       llvm::formatv("connect://localhost:{0}", port).str());
-  if (error.Fail())
+  if (error.Fail()) {
+    // If we know the runtime has exited, that's a better error message than
+    // failing to connect.
+    if (*exit_code)
+      error = Status::FromErrorStringWithFormatv(
+          "WebAssembly runtime exited with exit code {0}", **exit_code);
+
     return nullptr;
+  }
 
   if (launch_info.GetPTY().GetPrimaryFileDescriptor() !=
       PseudoTerminal::invalid_fd)
@@ -192,6 +207,4 @@ lldb::ProcessSP 
PlatformWasm::DebugProcess(ProcessLaunchInfo &launch_info,
         launch_info.GetPTY().ReleasePrimaryFileDescriptor());
 
   return process_sp;
-
-  return {};
 }
diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td 
b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td
index 9fcd3fca121cb..36b4b39c05c88 100644
--- a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasmProperties.td
@@ -1,14 +1,10 @@
 include "../../../../include/lldb/Core/PropertiesBase.td"
 
 let Definition = "platformwasm" in {
-  def RuntimePath
-      : Property<"runtime-path", "FileSpec">,
-        Global,
-        DefaultStringValue<"">,
-        Desc<"Path to the WebAssembly runtime binary. If the path does not "
-             "contain a directory separator, the filename is looked up in the "
-             "PATH environment variable. If empty, the filename is derived "
-             "from the architecture setting.">;
+  def RuntimePath : Property<"runtime-path", "FileSpec">,
+                    Global,
+                    DefaultStringValue<"">,
+                    Desc<"Path to the WebAssembly runtime binary.">;
   def RuntimeArgs : Property<"runtime-args", "Args">,
                     Global,
                     DefaultStringValue<"">,
@@ -17,5 +13,7 @@ let Definition = "platformwasm" in {
                 Global,
                 DefaultStringValue<"">,
                 Desc<"Argument to the WebAssembly runtime to specify the "
-                     "GDB remote port.">;
+                     "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.">;
 }

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to