Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lldb/source/Plugins/Platform/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ add_subdirectory(NetBSD)
add_subdirectory(OpenBSD)
add_subdirectory(POSIX)
add_subdirectory(QemuUser)
add_subdirectory(WebAssembly)
add_subdirectory(Windows)
23 changes: 23 additions & 0 deletions lldb/source/Plugins/Platform/WebAssembly/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
213 changes: 213 additions & 0 deletions lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
//===----------------------------------------------------------------------===//
//
// 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;
{
// 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())
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);

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;

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()) {
// If we know the runtime has exited, that's a better error message than
// failing to connect.
if (*exit_code)
error = Status::FromError(llvm::joinErrors(
llvm::createStringError(llvm::formatv(
"WebAssembly runtime exited with exit code {0}", **exit_code)),
error.takeError()));

return nullptr;
}

if (launch_info.GetPTY().GetPrimaryFileDescriptor() !=
PseudoTerminal::invalid_fd)
process_sp->SetSTDIOFileDescriptor(
launch_info.GetPTY().ReleasePrimaryFileDescriptor());

return process_sp;
}
79 changes: 79 additions & 0 deletions lldb/source/Plugins/Platform/WebAssembly/PlatformWasm.h
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
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.">;
def PortArg : Property<"port-arg", "String">,
Global,
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 `.">;
def RuntimeArgs : Property<"runtime-args", "Args">,
Global,
DefaultStringValue<"">,
Desc<"Extra arguments to pass to the WebAssembly runtime. "
"For the argument that specifies the GDB remote port, "
"use port-arg instead.">;
}
7 changes: 5 additions & 2 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,13 +243,16 @@ Changes to LLDB

* LLDB can now set breakpoints, show backtraces, and display variables when
debugging Wasm with supported runtimes (WAMR and V8).
* LLDB no longer stops processes by default when receiving SIGWINCH signals
* LLDB now has a Wasm platform, which can be configured to run WebAssembly
binaries directly under a Wasm runtime. Configurable through the
platform.plugin.wasm settings.
* LLDB no longer stops processes by default when receiving SIGWINCH signals
(window resize events) on Linux. This is the default on other Unix platforms.
You can re-enable it using `process handle --notify=true --stop=true SIGWINCH`.
* The `show-progress` setting, which became a NOOP with the introduction of the
statusline, now defaults to off and controls using OSC escape codes to show a
native progress bar in supporting terminals like Ghostty and ConEmu.
* The default PDB reader on Windows was changed from DIA to native, which uses
* The default PDB reader on Windows was changed from DIA to native, which uses
LLVM's PDB and CodeView support. You can switch back to the DIA reader with
`settings set plugin.symbol-file.pdb.reader dia`. Note that support for the
DIA reader will be removed in a future version of LLDB.
Expand Down
Loading