================ @@ -0,0 +1,210 @@ +//===----------------------------------------------------------------------===// +// +// 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); + + 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::FromErrorStringWithFormatv( + "WebAssembly runtime exited with exit code {0}", **exit_code); ---------------- JDevlieghere wrote:
Funny you mention that, it's what I had originally. I ended up going with this because the runtime exiting is always more interesting: ``` (lldb) run WebAssembly runtime exited with exit code 1 Timed out connecting to localhost:12345 ``` But on the other hand it's not nice to drop an error message so I'll revive it. https://github.com/llvm/llvm-project/pull/171507 _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
