LLDB mainline
PlatformWasm.cpp
Go to the documentation of this file.
1//===----------------------------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
16#include "lldb/Target/Process.h"
17#include "lldb/Target/Target.h"
20#include "lldb/Utility/Log.h"
21#include "llvm/ADT/StringExtras.h"
22
23using namespace lldb;
24using namespace lldb_private;
25
27
28namespace {
29#define LLDB_PROPERTIES_platformwasm
30#include "PlatformWasmProperties.inc"
31
32enum {
33#define LLDB_PROPERTIES_platformwasm
34#include "PlatformWasmPropertiesEnum.inc"
35};
36
37class PluginProperties : public Properties {
38public:
39 PluginProperties() {
40 m_collection_sp = std::make_shared<OptionValueProperties>(
42 m_collection_sp->Initialize(g_platformwasm_properties);
43 }
44
45 FileSpec GetRuntimePath() const {
46 return GetPropertyAtIndexAs<FileSpec>(ePropertyRuntimePath, {});
47 }
48
49 Args GetRuntimeArgs() const {
50 Args result;
51 m_collection_sp->GetPropertyAtIndexAsArgs(ePropertyRuntimeArgs, result);
52 return result;
53 }
54
55 llvm::StringRef GetPortArg() const {
56 return GetPropertyAtIndexAs<llvm::StringRef>(ePropertyPortArg, {});
57 }
58};
59
60} // namespace
61
62static PluginProperties &GetGlobalProperties() {
63 static PluginProperties g_settings;
64 return g_settings;
65}
66
68 return "Platform for debugging Wasm";
69}
70
76
80
85 debugger, GetGlobalProperties().GetValueProperties(),
86 "Properties for the wasm platform plugin.",
87 /*is_global_property=*/true);
88 }
89}
90
93 LLDB_LOG(log, "force = {0}, arch = ({1}, {2})", force,
94 arch ? arch->GetArchitectureName() : "<null>",
95 arch ? arch->GetTriple().getTriple() : "<null>");
96
97 bool create = force;
98 if (!create && arch && arch->IsValid()) {
99 const llvm::Triple &triple = arch->GetTriple();
100 switch (triple.getArch()) {
101 case llvm::Triple::wasm32:
102 case llvm::Triple::wasm64:
103 create = true;
104 break;
105 default:
106 break;
107 }
108 }
109
110 LLDB_LOG(log, "create = {0}", create);
111 return create ? PlatformSP(new PlatformWasm()) : PlatformSP();
112}
113
114std::vector<ArchSpec>
116 return {ArchSpec("wasm32-unknown-unknown-wasm"),
117 ArchSpec("wasm64-unknown-unknown-wasm")};
118}
119
120static auto get_arg_range(const Args &args) {
121 return llvm::make_range(args.GetArgumentArrayRef().begin(),
122 args.GetArgumentArrayRef().end());
123}
124
126 Debugger &debugger, Target &target,
127 Status &error) {
129
130 const PluginProperties &properties = GetGlobalProperties();
131
132 FileSpec runtime = properties.GetRuntimePath();
134
135 if (!FileSystem::Instance().Exists(runtime)) {
137 "WebAssembly runtime does not exist: {0}", runtime.GetPath());
138 return nullptr;
139 }
140
141 uint16_t port = 0;
142 {
143 // Get the next available port by binding a socket to port 0.
144 TCPSocket listen_socket(true);
145 error = listen_socket.Listen("localhost:0", /*backlog=*/5);
146 if (error.Fail())
147 return nullptr;
148 port = listen_socket.GetLocalPortNumber();
149 }
150
151 if (error.Fail())
152 return nullptr;
153
154 Args args({runtime.GetPath(),
155 llvm::formatv("{0}{1}", properties.GetPortArg(), port).str()});
156 args.AppendArguments(properties.GetRuntimeArgs());
157 args.AppendArguments(launch_info.GetArguments());
158
159 launch_info.SetArguments(args, true);
160 launch_info.SetLaunchInSeparateProcessGroup(true);
161 launch_info.GetFlags().Clear(eLaunchFlagDebug);
162
163 auto exit_code = std::make_shared<std::optional<int>>();
164 launch_info.SetMonitorProcessCallback(
165 [=](lldb::pid_t pid, int signal, int status) {
166 LLDB_LOG(
167 log,
168 "WebAssembly runtime exited: pid = {0}, signal = {1}, status = {2}",
169 pid, signal, status);
170 exit_code->emplace(status);
171 });
172
173 // This is automatically done for host platform in
174 // Target::FinalizeFileActions, but we're not a host platform.
175 llvm::Error Err = launch_info.SetUpPtyRedirection();
176 LLDB_LOG_ERROR(log, std::move(Err), "SetUpPtyRedirection failed: {0}");
177
178 LLDB_LOG(log, "{0}", get_arg_range(launch_info.GetArguments()));
179 error = Host::LaunchProcess(launch_info);
180 if (error.Fail())
181 return nullptr;
182
183 ProcessSP process_sp = target.CreateProcess(
185 nullptr, true);
186 if (!process_sp) {
187 error = Status::FromErrorString("failed to create WebAssembly process");
188 return nullptr;
189 }
190
191 process_sp->HijackProcessEvents(launch_info.GetHijackListener());
192
193 error = process_sp->ConnectRemote(
194 llvm::formatv("connect://localhost:{0}", port).str());
195 if (error.Fail()) {
196 // If we know the runtime has exited, that's a better error message than
197 // failing to connect.
198 if (*exit_code)
199 error = Status::FromError(llvm::joinErrors(
200 llvm::createStringError(llvm::formatv(
201 "WebAssembly runtime exited with exit code {0}", **exit_code)),
202 error.takeError()));
203
204 return nullptr;
205 }
206
207 if (launch_info.GetPTY().GetPrimaryFileDescriptor() !=
209 process_sp->SetSTDIOFileDescriptor(
210 launch_info.GetPTY().ReleasePrimaryFileDescriptor());
211
212 return process_sp;
213}
static llvm::raw_ostream & error(Stream &strm)
static DynamicLoaderDarwinKernelProperties & GetGlobalProperties()
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:369
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:392
static auto get_arg_range(const Args &args)
static PluginProperties & GetGlobalProperties()
#define LLDB_PLUGIN_DEFINE(PluginName)
An architecture specification class.
Definition ArchSpec.h:31
bool IsValid() const
Tests if this ArchSpec is valid.
Definition ArchSpec.h:366
llvm::Triple & GetTriple()
Architecture triple accessor.
Definition ArchSpec.h:468
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition ArchSpec.cpp:548
A command line argument class.
Definition Args.h:33
llvm::ArrayRef< const char * > GetArgumentArrayRef() const
Gets the argument as an ArrayRef.
Definition Args.h:173
void AppendArguments(const Args &rhs)
Definition Args.cpp:307
A class to manage flag bits.
Definition Debugger.h:80
A file utility class.
Definition FileSpec.h:57
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:374
bool ResolveExecutableLocation(FileSpec &file_spec)
Call into the Host to see if it can help find the file.
static FileSystem & Instance()
ValueType Clear(ValueType mask=~static_cast< ValueType >(0))
Clear one or more flags.
Definition Flags.h:61
static Status LaunchProcess(ProcessLaunchInfo &launch_info)
Launch the process specified in launch_info.
static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch)
lldb::ProcessSP DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, Target &target, Status &error) override
Subclasses do not need to implement this function as it uses the Platform::LaunchProcess() followed b...
static void DebuggerInitialize(Debugger &debugger)
static llvm::StringRef GetPluginNameStatic()
std::vector< ArchSpec > GetSupportedArchitectures(const ArchSpec &process_host_arch) override
Get the platform's supported architectures in the order in which they should be searched.
static llvm::StringRef GetPluginDescriptionStatic()
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static lldb::OptionValuePropertiesSP GetSettingForPlatformPlugin(Debugger &debugger, llvm::StringRef setting_name)
static bool CreateSettingForPlatformPlugin(Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp, llvm::StringRef description, bool is_global_property)
static bool UnregisterPlugin(ABICreateInstance create_callback)
lldb::ListenerSP GetHijackListener() const
void SetArguments(const Args &args, bool first_arg_is_executable)
lldb::ListenerSP GetListener() const
void SetMonitorProcessCallback(Host::MonitorChildProcessCallback callback)
void SetLaunchInSeparateProcessGroup(bool separate)
@ invalid_fd
Invalid file descriptor value.
int GetPrimaryFileDescriptor() const
The primary file descriptor accessor.
int ReleasePrimaryFileDescriptor()
Release the primary file descriptor.
An error handling class.
Definition Status.h:118
static Status FromErrorString(const char *str)
Definition Status.h:141
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:137
Status Listen(llvm::StringRef name, int backlog) override
uint16_t GetLocalPortNumber() const
Definition TCPSocket.cpp:86
const lldb::ProcessSP & CreateProcess(lldb::ListenerSP listener_sp, llvm::StringRef plugin_name, const FileSpec *crash_file, bool can_connect)
Definition Target.cpp:300
static llvm::StringRef GetPluginNameStatic()
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
Definition Log.h:332
std::shared_ptr< lldb_private::Platform > PlatformSP
std::shared_ptr< lldb_private::Process > ProcessSP
uint64_t pid_t
Definition lldb-types.h:83