[Lldb-commits] [lldb] [lldb] Add PlatformWebInspectorWasm (PR #188751)
Jonas Devlieghere via lldb-commits
lldb-commits at lists.llvm.org
Thu Mar 26 07:14:04 PDT 2026
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/188751
Add a new PlatformWebInspectorWasm, which is a Wasm platform that automatically connects to the WebInspector platform server.
>From 8012c9569af7f329a58342afbeb983e787a93133 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <jonas at devlieghere.com>
Date: Tue, 24 Mar 2026 17:36:21 -0500
Subject: [PATCH] [lldb] Add PlatformWebInspectorWasm
Add a new PlatformWebInspectorWasm, which is a Wasm platform that
automatically connects to the WebInspector platform server.
---
.../Platform/WebAssembly/CMakeLists.txt | 1 +
.../Platform/WebAssembly/PlatformWasm.cpp | 34 ++--
.../Platform/WebAssembly/PlatformWasm.h | 13 +-
.../WebAssembly/PlatformWebInspectorWasm.cpp | 177 ++++++++++++++++++
.../WebAssembly/PlatformWebInspectorWasm.h | 58 ++++++
5 files changed, 264 insertions(+), 19 deletions(-)
create mode 100644 lldb/source/Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.cpp
create mode 100644 lldb/source/Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.h
diff --git a/lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt b/lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt
index e049937dffd47..3149189cbe32c 100644
--- a/lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt
+++ b/lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt
@@ -9,6 +9,7 @@ lldb_tablegen(PlatformWasmPropertiesEnum.inc -gen-lldb-property-enum-defs
add_lldb_library(lldbPluginPlatformWasm PLUGIN
PlatformWasm.cpp
PlatformWasmRemoteGDBServer.cpp
+ PlatformWebInspectorWasm.cpp
LINK_LIBS
lldbCore
diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
index bcc71f83a017d..c9af2551281e9 100644
--- a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
@@ -8,6 +8,7 @@
#include "Plugins/Platform/WebAssembly/PlatformWasm.h"
#include "Plugins/Platform/WebAssembly/PlatformWasmRemoteGDBServer.h"
+#include "Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.h"
#include "Plugins/Process/wasm/ProcessWasm.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/FileSystem.h"
@@ -71,6 +72,7 @@ llvm::StringRef PlatformWasm::GetPluginDescriptionStatic() {
}
void PlatformWasm::Initialize() {
+ PlatformWebInspectorWasm::Initialize();
PluginManager::RegisterPlugin(
GetPluginNameStatic(), GetPluginDescriptionStatic(),
PlatformWasm::CreateInstance, PlatformWasm::DebuggerInitialize);
@@ -78,6 +80,7 @@ void PlatformWasm::Initialize() {
void PlatformWasm::Terminate() {
PluginManager::UnregisterPlugin(PlatformWasm::CreateInstance);
+ PlatformWebInspectorWasm::Terminate();
}
void PlatformWasm::DebuggerInitialize(Debugger &debugger) {
@@ -113,17 +116,20 @@ PlatformSP PlatformWasm::CreateInstance(bool force, const ArchSpec *arch) {
return create ? PlatformSP(new PlatformWasm()) : PlatformSP();
}
+llvm::Expected<uint16_t> PlatformWasm::FindFreeTCPPort() {
+ TCPSocket sock(true);
+ Status status = sock.Listen("localhost:0", /*backlog=*/5);
+ if (status.Fail())
+ return status.takeError();
+ return sock.GetLocalPortNumber();
+}
+
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::Attach(ProcessAttachInfo &attach_info,
Debugger &debugger, Target *target,
Status &status) {
@@ -155,18 +161,12 @@ lldb::ProcessSP PlatformWasm::DebugProcess(ProcessLaunchInfo &launch_info,
return nullptr;
}
- uint16_t port = 0;
- {
- // Get the next available port by binding a socket to port 0.
- TCPSocket listen_socket(true);
- error = listen_socket.Listen("localhost:0", /*backlog=*/5);
- if (error.Fail())
- return nullptr;
- port = listen_socket.GetLocalPortNumber();
- }
-
- if (error.Fail())
+ llvm::Expected<uint16_t> expected_port = FindFreeTCPPort();
+ if (!expected_port) {
+ error = Status::FromError(expected_port.takeError());
return nullptr;
+ }
+ uint16_t port = *expected_port;
Args args({runtime.GetPath(),
llvm::formatv("{0}{1}", properties.GetPortArg(), port).str()});
@@ -192,7 +192,7 @@ lldb::ProcessSP PlatformWasm::DebugProcess(ProcessLaunchInfo &launch_info,
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()));
+ LLDB_LOG(log, "{0}", GetArgRange(launch_info.GetArguments()));
error = Host::LaunchProcess(launch_info);
if (error.Fail())
return nullptr;
diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h
index 5744ca7d0ca22..e752b8bae9840 100644
--- a/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h
@@ -55,11 +55,20 @@ class PlatformWasm : public RemoteAwarePlatform {
arch, addr, length, prot, flags, fd, offset);
}
+protected:
+ /// Find a free TCP port by binding to port 0.
+ static llvm::Expected<uint16_t> FindFreeTCPPort();
+
+ static auto GetArgRange(const Args &args) {
+ return llvm::make_range(args.GetArgumentArrayRef().begin(),
+ args.GetArgumentArrayRef().end());
+ }
+
+ PlatformWasm() : RemoteAwarePlatform(/*is_host=*/false) {}
+
private:
static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
static void DebuggerInitialize(Debugger &debugger);
-
- PlatformWasm() : RemoteAwarePlatform(/*is_host=*/false) {}
};
} // namespace lldb_private
diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.cpp b/lldb/source/Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.cpp
new file mode 100644
index 0000000000000..fc60a98f46862
--- /dev/null
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.cpp
@@ -0,0 +1,177 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "PlatformWebInspectorWasm.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/FileSystem.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/ProcessLaunchInfo.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorExtras.h"
+
+#include <chrono>
+#include <csignal>
+#include <thread>
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(PlatformWebInspectorWasm)
+
+static constexpr llvm::StringLiteral kServerBinary =
+ "/System/Cryptexes/App/usr/libexec/webinspector-wasm-lldb-platform";
+static constexpr uint8_t kConnectAttempts = 5;
+static constexpr auto kConnectDelay = std::chrono::milliseconds(100);
+
+llvm::StringRef PlatformWebInspectorWasm::GetPluginDescriptionStatic() {
+ return "Platform for debugging Wasm via WebInspector";
+}
+
+void PlatformWebInspectorWasm::Initialize() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ PlatformWebInspectorWasm::CreateInstance);
+}
+
+void PlatformWebInspectorWasm::Terminate() {
+ PluginManager::UnregisterPlugin(PlatformWebInspectorWasm::CreateInstance);
+}
+
+PlatformSP PlatformWebInspectorWasm::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>");
+ return force ? PlatformSP(new PlatformWebInspectorWasm()) : PlatformSP();
+}
+
+PlatformWebInspectorWasm::~PlatformWebInspectorWasm() {
+ if (m_server_pid != LLDB_INVALID_PROCESS_ID)
+ Host::Kill(m_server_pid, SIGTERM);
+}
+
+llvm::Error PlatformWebInspectorWasm::LaunchPlatformServer() {
+ Log *log = GetLog(LLDBLog::Platform);
+
+ if (!FileSystem::Instance().Exists(FileSpec(kServerBinary)))
+ return llvm::createStringErrorV("platform binary not found: {0}",
+ kServerBinary);
+
+ // Find two free TCP ports.
+ llvm::Expected<uint16_t> expected_platform_port = FindFreeTCPPort();
+ if (!expected_platform_port)
+ return expected_platform_port.takeError();
+ uint16_t platform_port = *expected_platform_port;
+
+ llvm::Expected<uint16_t> expected_debugserver_port = FindFreeTCPPort();
+ if (!expected_debugserver_port)
+ return expected_debugserver_port.takeError();
+ uint16_t debugserver_port = *expected_debugserver_port;
+
+ ProcessLaunchInfo launch_info;
+ launch_info.SetExecutableFile(FileSpec(kServerBinary),
+ /*add_exe_file_as_first_arg=*/true);
+ Args args;
+ args.AppendArgument(kServerBinary);
+ args.AppendArgument("--platform");
+ args.AppendArgument(llvm::utostr(platform_port));
+ args.AppendArgument("--debugserver");
+ args.AppendArgument(llvm::utostr(debugserver_port));
+ launch_info.SetArguments(args, /*first_arg_is_executable=*/true);
+ launch_info.SetLaunchInSeparateProcessGroup(true);
+ launch_info.GetFlags().Clear(eLaunchFlagDebug);
+
+ launch_info.SetMonitorProcessCallback(
+ [log](lldb::pid_t pid, int signal, int status) {
+ LLDB_LOG(log,
+ "Platform exited: pid = {0}, signal = "
+ "{1}, status = {2}",
+ pid, signal, status);
+ });
+
+ LLDB_LOG(log, "{0}", GetArgRange(launch_info.GetArguments()));
+
+ Status status = Host::LaunchProcess(launch_info);
+ if (status.Fail())
+ return status.takeError();
+
+ m_server_pid = launch_info.GetProcessID();
+ LLDB_LOG(log, "Platform launched: pid = {0}", m_server_pid);
+
+ Args connect_args;
+ connect_args.AppendArgument(
+ llvm::formatv("connect://localhost:{0}", platform_port).str());
+
+ // The platform may need some time to bind a socket to the requested port.
+ for (uint8_t attempt = 0; attempt < kConnectAttempts; attempt++) {
+ status = PlatformWasm::ConnectRemote(connect_args);
+ if (status.Success())
+ return llvm::Error::success();
+
+ LLDB_LOG(
+ log,
+ "[{0}/{1}] platform not yet listening on port {2}: trying again in {3}",
+ attempt, kConnectAttempts, platform_port, kConnectDelay);
+ std::this_thread::sleep_for(kConnectDelay);
+ }
+ return status.takeError();
+}
+
+llvm::Error PlatformWebInspectorWasm::EnsureConnected() {
+ if (m_remote_platform_sp)
+ return llvm::Error::success();
+ return LaunchPlatformServer();
+}
+
+Status PlatformWebInspectorWasm::ConnectRemote(Args &args) {
+ if (args.GetArgumentCount() == 0)
+ return Status::FromError(LaunchPlatformServer());
+ return PlatformWasm::ConnectRemote(args);
+}
+
+ProcessSP PlatformWebInspectorWasm::Attach(ProcessAttachInfo &attach_info,
+ Debugger &debugger, Target *target,
+ Status &status) {
+ status = Status::FromError(EnsureConnected());
+ if (status.Fail())
+ return nullptr;
+ return PlatformWasm::Attach(attach_info, debugger, target, status);
+}
+
+uint32_t PlatformWebInspectorWasm::FindProcesses(
+ const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &proc_infos) {
+ if (llvm::Error err = EnsureConnected()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Platform), std::move(err),
+ "EnsureConnected failed: {0}");
+ return 0;
+ }
+ return PlatformWasm::FindProcesses(match_info, proc_infos);
+}
+
+bool PlatformWebInspectorWasm::GetProcessInfo(lldb::pid_t pid,
+ ProcessInstanceInfo &proc_info) {
+ if (llvm::Error err = EnsureConnected()) {
+ LLDB_LOG_ERROR(GetLog(LLDBLog::Platform), std::move(err),
+ "EnsureConnected failed: {0}");
+ return false;
+ }
+ return PlatformWasm::GetProcessInfo(pid, proc_info);
+}
+
+lldb::ProcessSP
+PlatformWebInspectorWasm::DebugProcess(ProcessLaunchInfo &launch_info,
+ Debugger &debugger, Target &target,
+ Status &error) {
+ error = Status::FromErrorStringWithFormatv("{0} does not support launching",
+ GetPluginNameStatic());
+ return nullptr;
+}
diff --git a/lldb/source/Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.h b/lldb/source/Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.h
new file mode 100644
index 0000000000000..52286b4532ebc
--- /dev/null
+++ b/lldb/source/Plugins/Platform/WebAssembly/PlatformWebInspectorWasm.h
@@ -0,0 +1,58 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_WEBASSEMBLY_PLATFORMWEBINSPECTORWASM_H
+#define LLDB_SOURCE_PLUGINS_PLATFORM_WEBASSEMBLY_PLATFORMWEBINSPECTORWASM_H
+
+#include "PlatformWasm.h"
+
+namespace lldb_private {
+
+class PlatformWebInspectorWasm : public PlatformWasm {
+public:
+ static void Initialize();
+ static void Terminate();
+
+ static llvm::StringRef GetPluginNameStatic() { return "webinspector-wasm"; }
+ static llvm::StringRef GetPluginDescriptionStatic();
+
+ llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+ llvm::StringRef GetDescription() override {
+ return GetPluginDescriptionStatic();
+ }
+
+ ~PlatformWebInspectorWasm() override;
+
+ Status ConnectRemote(Args &args) override;
+
+ lldb::ProcessSP Attach(ProcessAttachInfo &attach_info, Debugger &debugger,
+ Target *target, Status &status) override;
+
+ lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info,
+ Debugger &debugger, Target &target,
+ Status &error) override;
+
+ uint32_t FindProcesses(const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &proc_infos) override;
+
+ bool GetProcessInfo(lldb::pid_t pid, ProcessInstanceInfo &proc_info) override;
+
+private:
+ static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
+
+ PlatformWebInspectorWasm() = default;
+
+ llvm::Error LaunchPlatformServer();
+ llvm::Error EnsureConnected();
+
+ lldb::pid_t m_server_pid = LLDB_INVALID_PROCESS_ID;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PLATFORM_WEBASSEMBLY_PLATFORMWEBINSPECTORWASM_H
More information about the lldb-commits
mailing list