[Lldb-commits] [lldb] [lldb] Add WebAssembly Process Plugin (PR #150143)
David Spickett via lldb-commits
lldb-commits at lists.llvm.org
Mon Jul 28 02:26:17 PDT 2025
================
@@ -0,0 +1,127 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 "ProcessWasm.h"
+#include "ThreadWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Utility/DataBufferHeap.h"
+
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private::wasm;
+
+LLDB_PLUGIN_DEFINE(ProcessWasm)
+
+ProcessWasm::ProcessWasm(lldb::TargetSP target_sp, ListenerSP listener_sp)
+ : ProcessGDBRemote(target_sp, listener_sp) {
+ // Always use Linux signals for Wasm process.
+ m_unix_signals_sp = UnixSignals::Create(ArchSpec{"wasm32-Ant-wasi-wasm"});
+}
+
+void ProcessWasm::Initialize() {
+ static llvm::once_flag g_once_flag;
+
+ llvm::call_once(g_once_flag, []() {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(), CreateInstance,
+ DebuggerInitialize);
+ });
+}
+
+void ProcessWasm::DebuggerInitialize(Debugger &debugger) {
+ ProcessGDBRemote::DebuggerInitialize(debugger);
+}
+
+llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); }
+
+llvm::StringRef ProcessWasm::GetPluginNameStatic() { return "wasm"; }
+
+llvm::StringRef ProcessWasm::GetPluginDescriptionStatic() {
+ return "GDB Remote protocol based WebAssembly debugging plug-in.";
+}
+
+void ProcessWasm::Terminate() {
+ PluginManager::UnregisterPlugin(ProcessWasm::CreateInstance);
+}
+
+lldb::ProcessSP ProcessWasm::CreateInstance(lldb::TargetSP target_sp,
+ ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect) {
+ if (crash_file_path == nullptr)
+ return std::make_shared<ProcessWasm>(target_sp, listener_sp);
+ return {};
+}
+
+bool ProcessWasm::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ if (plugin_specified_by_name)
+ return true;
+
+ if (Module *exe_module = target_sp->GetExecutableModulePointer()) {
+ if (ObjectFile *exe_objfile = exe_module->GetObjectFile())
+ return exe_objfile->GetArchitecture().GetMachine() ==
+ llvm::Triple::wasm32;
+ }
+ // However, if there is no wasm module, we return false, otherwise,
+ // we might use ProcessWasm to attach gdb remote.
+ return false;
+}
+
+std::shared_ptr<ThreadGDBRemote> ProcessWasm::CreateThread(lldb::tid_t tid) {
+ return std::make_shared<ThreadWasm>(*this, tid);
+}
+
+size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Status &error) {
+ wasm_addr_t wasm_addr(vm_addr);
+
+ switch (wasm_addr.GetType()) {
+ case WasmAddressType::Memory:
+ case WasmAddressType::Object:
+ return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+ case WasmAddressType::Invalid:
+ error.FromErrorStringWithFormat(
+ "Wasm read failed for invalid address 0x%" PRIx64, vm_addr);
+ return 0;
+ }
+}
+
+llvm::Expected<std::vector<lldb::addr_t>>
+ProcessWasm::GetWasmCallStack(lldb::tid_t tid) {
+ StreamString packet;
+ packet.Printf("qWasmCallStack:");
+ packet.Printf("%llx", tid);
+
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success)
+ return llvm::createStringError("failed to send qWasmCallStack");
+
+ if (!response.IsNormalResponse())
+ return llvm::createStringError("failed to get response for qWasmCallStack");
+
+ WritableDataBufferSP data_buffer_sp =
+ std::make_shared<DataBufferHeap>(response.GetStringRef().size() / 2, 0);
+ const size_t bytes = response.GetHexBytes(data_buffer_sp->GetData(), '\xcc');
+ if (bytes == 0 || bytes % sizeof(uint64_t) != 0)
+ return llvm::createStringError("invalid response for qWasmCallStack");
+
+ std::vector<lldb::addr_t> call_stack_pcs;
+ DataExtractor data(data_buffer_sp, GetByteOrder(), GetAddressByteSize());
----------------
DavidSpickett wrote:
I thought I should put my time where my curiosity is, but...
WAMR is not tested for AArch64_BE, does not support s390x (surprisingly) and that leaves MIPS which I don't care to setup tools for - https://github.com/bytecodealliance/wasm-micro-runtime?tab=readme-ov-file#supported-architectures-and-platforms.
Then I looked at the source (Apache 2.0 in case you have professional restrictions) and the endian sent by the debug stub is always little: https://github.com/bytecodealliance/wasm-micro-runtime/blob/d298a66d38960719e17fbe27e8f529d6515bad26/core/iwasm/libraries/debug-engine/handler.c#L249
So if someone did report that memory was backwards on MIPS, AArch64_BE or s390x, that's definitely the runtime's problem.
https://github.com/llvm/llvm-project/pull/150143
More information about the lldb-commits
mailing list