[Lldb-commits] [lldb] [lldb] Implement WebAssembly debugging (PR #76683)
Paolo Severini via lldb-commits
lldb-commits at lists.llvm.org
Mon Jan 1 07:31:25 PST 2024
https://github.com/paolosevMSFT created https://github.com/llvm/llvm-project/pull/76683
Add support for source-level debugging of WebAssembly code.
>From 739b26b03fd3661d1c22b975e241cbbe60ca6531 Mon Sep 17 00:00:00 2001
From: Paolo Severini <paolosev at microsoft.com>
Date: Mon, 1 Jan 2024 06:55:40 -0800
Subject: [PATCH] [lldb] Implement WebAssembly debugging
Add support for source-level debugging of WebAssembly code.
---
lldb/include/lldb/Target/Process.h | 40 +++
lldb/include/lldb/Target/UnwindWasm.h | 47 +++
lldb/source/Core/Value.cpp | 2 +-
lldb/source/Expression/DWARFExpression.cpp | 42 +++
.../source/Interpreter/CommandInterpreter.cpp | 18 ++
lldb/source/Plugins/Process/CMakeLists.txt | 1 +
.../Process/gdb-remote/ProcessGDBRemote.cpp | 7 +-
.../Process/gdb-remote/ProcessGDBRemote.h | 2 +
.../Plugins/Process/wasm/CMakeLists.txt | 15 +
.../Plugins/Process/wasm/ProcessWasm.cpp | 296 ++++++++++++++++++
.../source/Plugins/Process/wasm/ProcessWasm.h | 135 ++++++++
.../Plugins/Process/wasm/ThreadWasm.cpp | 57 ++++
lldb/source/Plugins/Process/wasm/ThreadWasm.h | 47 +++
.../Plugins/Process/wasm/UnwindWasm.cpp | 79 +++++
lldb/source/Plugins/Process/wasm/UnwindWasm.h | 58 ++++
.../Process/wasm/wasmRegisterContext.cpp | 103 ++++++
.../Process/wasm/wasmRegisterContext.h | 70 +++++
lldb/source/Target/Platform.cpp | 8 +
18 files changed, 1025 insertions(+), 2 deletions(-)
create mode 100644 lldb/include/lldb/Target/UnwindWasm.h
create mode 100644 lldb/source/Plugins/Process/wasm/CMakeLists.txt
create mode 100644 lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
create mode 100644 lldb/source/Plugins/Process/wasm/ProcessWasm.h
create mode 100644 lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
create mode 100644 lldb/source/Plugins/Process/wasm/ThreadWasm.h
create mode 100644 lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
create mode 100644 lldb/source/Plugins/Process/wasm/UnwindWasm.h
create mode 100644 lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp
create mode 100644 lldb/source/Plugins/Process/wasm/wasmRegisterContext.h
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 24c599e044c78f..587ae085b479b7 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1548,6 +1548,46 @@ class Process : public std::enable_shared_from_this<Process>,
virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
Status &error);
+ /// Read of memory from a process.
+ ///
+ /// This function will read memory from the current process's address space
+ /// and remove any traps that may have been inserted into the memory.
+ ///
+ /// This overloads accepts an ExecutionContext as additional argument. By
+ /// default, it calls the previous overload without the ExecutionContext
+ /// argument, but it can be overridden by Process subclasses.
+ ///
+ /// \param[in] vm_addr
+ /// A virtual load address that indicates where to start reading
+ /// memory from.
+ ///
+ /// \param[out] buf
+ /// A byte buffer that is at least \a size bytes long that
+ /// will receive the memory bytes.
+ ///
+ /// \param[in] size
+ /// The number of bytes to read.
+ ///
+ /// \param[in] exe_ctx
+ /// The current execution context, if available.
+ ///
+ /// \param[out] error
+ /// An error that indicates the success or failure of this
+ /// operation. If error indicates success (error.Success()),
+ /// then the value returned can be trusted, otherwise zero
+ /// will be returned.
+ ///
+ /// \return
+ /// The number of bytes that were actually read into \a buf. If
+ /// the returned number is greater than zero, yet less than \a
+ /// size, then this function will get called again with \a
+ /// vm_addr, \a buf, and \a size updated appropriately. Zero is
+ /// returned in the case of an error.
+ virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ ExecutionContext *exe_ctx, Status &error) {
+ return ReadMemory(vm_addr, buf, size, error);
+ }
+
/// Read of memory from a process.
///
/// This function has the same semantics of ReadMemory except that it
diff --git a/lldb/include/lldb/Target/UnwindWasm.h b/lldb/include/lldb/Target/UnwindWasm.h
new file mode 100644
index 00000000000000..3880f1dd62edf2
--- /dev/null
+++ b/lldb/include/lldb/Target/UnwindWasm.h
@@ -0,0 +1,47 @@
+//===-- UnwindWasm.h --------------------------------------------*- C++ -*-===//
+//
+// 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_TARGET_UNWINDWASM_H
+#define LLDB_TARGET_UNWINDWASM_H
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Unwind.h"
+#include <vector>
+
+namespace lldb_private {
+
+class UnwindWasm : public Unwind {
+public:
+ UnwindWasm(lldb_private::Thread &thread)
+ : Unwind(thread), m_frames(), m_unwind_complete(false) {}
+ ~UnwindWasm() override = default;
+
+protected:
+ void DoClear() override {
+ m_frames.clear();
+ m_unwind_complete = false;
+ }
+
+ uint32_t DoGetFrameCount() override;
+
+ bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
+ lldb::addr_t &pc,
+ bool &behaves_like_zeroth_frame) override;
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+
+private:
+ std::vector<lldb::addr_t> m_frames;
+ bool m_unwind_complete;
+
+ DISALLOW_COPY_AND_ASSIGN(UnwindWasm);
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_TARGET_UNWINDWASM_H
diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
index 995cc934c82044..47a5fdee773886 100644
--- a/lldb/source/Core/Value.cpp
+++ b/lldb/source/Core/Value.cpp
@@ -552,7 +552,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
if (process) {
const size_t bytes_read =
- process->ReadMemory(address, dst, byte_size, error);
+ process->ReadMemory(address, dst, byte_size, exe_ctx, error);
if (bytes_read != byte_size)
error.SetErrorStringWithFormat(
"read memory from 0x%" PRIx64 " failed (%u of %u bytes read)",
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index fe4928d4f43a43..1693e390c2e920 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -346,6 +346,17 @@ static offset_t GetOpcodeDataSize(const DataExtractor &data,
return (offset - data_offset) + subexpr_len;
}
+ case DW_OP_WASM_location: {
+ uint8_t wasm_op = data.GetU8(&offset);
+ if (wasm_op == 3) {
+ data.GetU32(&offset);
+ }
+ else {
+ data.GetULEB128(&offset);
+ }
+ return offset - data_offset;
+ }
+
default:
if (!dwarf_cu) {
return LLDB_INVALID_OFFSET;
@@ -2595,6 +2606,37 @@ bool DWARFExpression::Evaluate(
break;
}
+ case DW_OP_WASM_location: {
+ uint8_t wasm_op = opcodes.GetU8(&offset);
+ uint32_t index;
+
+ /* LLDB doesn't have an address space to represents WebAssembly Locals,
+ * GLobals and operand stacks.
+ * We encode these elements into virtual registers:
+ * | tag: 2 bits | index: 30 bits |
+ * where tag is:
+ * 0: Not a WebAssembly location
+ * 1: Local
+ * 2: Global
+ * 3: Operand stack value
+ */
+ if (wasm_op == 3) {
+ index = opcodes.GetU32(&offset);
+ wasm_op = 1;
+ } else {
+ index = opcodes.GetULEB128(&offset);
+ }
+
+ reg_num = (((wasm_op + 1) & 0x03) << 30) | (index & 0x3fffffff);
+
+ if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+ stack.push_back(tmp);
+ else
+ return false;
+
+ break;
+ }
+
default:
if (dwarf_cu) {
if (dwarf_cu->GetSymbolFileDWARF().ParseVendorDWARFOpcode(
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 00651df48b6224..bcacc7aabb66ca 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -794,6 +794,24 @@ void CommandInterpreter::LoadCommandDictionary() {
}
}
+ std::unique_ptr<CommandObjectRegexCommand> connect_wasm_cmd_up(
+ new CommandObjectRegexCommand(
+ *this, "wasm",
+ "Connect to a WebAssembly process via remote GDB server. "
+ "If no host is specifed, localhost is assumed.",
+ "wasm [<hostname>:]<portnum>", 0, false));
+ if (connect_wasm_cmd_up) {
+ if (connect_wasm_cmd_up->AddRegexCommand(
+ "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
+ "process connect --plugin wasm connect://%1:%2") &&
+ connect_wasm_cmd_up->AddRegexCommand(
+ "^([[:digit:]]+)$",
+ "process connect --plugin wasm connect://localhost:%1")) {
+ CommandObjectSP command_sp(connect_wasm_cmd_up.release());
+ m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
+ }
+ }
+
std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
new CommandObjectRegexCommand(
*this, "kdp-remote",
diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt
index a51d0f7afd1759..be109a303e8669 100644
--- a/lldb/source/Plugins/Process/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/CMakeLists.txt
@@ -19,3 +19,4 @@ add_subdirectory(elf-core)
add_subdirectory(mach-core)
add_subdirectory(minidump)
add_subdirectory(FreeBSDKernel)
+add_subdirectory(wasm)
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 316be471df9295..674bbc9ff4fd0b 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1628,6 +1628,11 @@ void ProcessGDBRemote::ParseExpeditedRegisters(
}
}
+std::shared_ptr<ThreadGDBRemote>
+ProcessGDBRemote::CreateThread(lldb::tid_t tid) {
+ return std::make_shared<ThreadGDBRemote>(*this, tid);
+}
+
ThreadSP ProcessGDBRemote::SetThreadStopInfo(
lldb::tid_t tid, ExpeditedRegisterMap &expedited_register_map,
uint8_t signo, const std::string &thread_name, const std::string &reason,
@@ -1652,7 +1657,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
if (!thread_sp) {
// Create the thread if we need to
- thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid);
+ thread_sp = CreateThread(tid);
m_thread_list_real.AddThread(thread_sp);
}
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index c1ea1cc7905587..0463e39b7a63a4 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -355,6 +355,8 @@ class ProcessGDBRemote : public Process,
MonitorDebugserverProcess(std::weak_ptr<ProcessGDBRemote> process_wp,
lldb::pid_t pid, int signo, int exit_status);
+ virtual std::shared_ptr<ThreadGDBRemote> CreateThread(lldb::tid_t tid);
+
lldb::StateType SetThreadStopInfo(StringExtractor &stop_packet);
bool
diff --git a/lldb/source/Plugins/Process/wasm/CMakeLists.txt b/lldb/source/Plugins/Process/wasm/CMakeLists.txt
new file mode 100644
index 00000000000000..c47eec7464ed8a
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/CMakeLists.txt
@@ -0,0 +1,15 @@
+# This file comes from https://reviews.llvm.org/D78978.
+# Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+add_lldb_library(lldbPluginProcessWasm PLUGIN
+ ProcessWasm.cpp
+ ThreadWasm.cpp
+ UnwindWasm.cpp
+ wasmRegisterContext.cpp
+
+ LINK_LIBS
+ lldbCore
+ ${LLDB_PLUGINS}
+ LINK_COMPONENTS
+ Support
+ )
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
new file mode 100644
index 00000000000000..1c1f9885b6395f
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
@@ -0,0 +1,296 @@
+// This file comes from https://reviews.llvm.org/D78978.
+// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+//===-- ProcessWasm.cpp ---------------------------------------------------===//
+//
+// 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/Utility/DataBufferHeap.h"
+
+#include "lldb/Target/UnixSignals.h"
+#include "llvm/ADT/ArrayRef.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private::wasm;
+
+LLDB_PLUGIN_DEFINE(ProcessWasm)
+
+// ProcessGDBRemote constructor
+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);
+}
+
+// PluginInterface
+llvm::StringRef ProcessWasm::GetPluginName() { return GetPluginNameStatic(); }
+
+ConstString ProcessWasm::GetPluginNameStatic() {
+ static ConstString g_name("wasm");
+ return g_name;
+}
+
+const char *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) {
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == nullptr)
+ process_sp = std::make_shared<ProcessWasm>(target_sp, listener_sp);
+ return process_sp;
+}
+
+bool ProcessWasm::CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) {
+ if (plugin_specified_by_name)
+ return true;
+
+ Module *exe_module = target_sp->GetExecutableModulePointer();
+ if (exe_module) {
+ 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:
+ assert(false); // Sholud never get here?
+ return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+ case WasmAddressType::Object:
+ // TODO
+ return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+ case WasmAddressType::Invalid:
+ default:
+ error.SetErrorStringWithFormat(
+ "Wasm read failed for invalid address 0x%" PRIx64, vm_addr);
+ return 0;
+ }
+}
+
+size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ ExecutionContext *exe_ctx, Status &error) {
+ wasm_addr_t wasm_addr(vm_addr);
+
+ switch (wasm_addr.GetType()) {
+ case WasmAddressType::Memory: {
+ // If we don't have a valid module_id, this is actually a read from the
+ // Wasm memory space. We can calculate the module_id from the execution
+ // context.
+ if (wasm_addr.module_id == 0 && exe_ctx != nullptr) {
+ StackFrame *frame = exe_ctx->GetFramePtr();
+ assert(frame->CalculateTarget()->GetArchitecture().GetMachine() ==
+ llvm::Triple::wasm32);
+ wasm_addr.module_id = wasm_addr_t(frame->GetStackID().GetPC()).module_id;
+ wasm_addr.type = WasmAddressType::Memory;
+ }
+ if (WasmReadMemory(wasm_addr.module_id, wasm_addr.offset, buf, size))
+ return size;
+ error.SetErrorStringWithFormat("Wasm memory read failed for 0x%" PRIx64,
+ vm_addr);
+ return 0;
+ }
+ case WasmAddressType::Object:
+ // TODO ?
+ return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+ case WasmAddressType::Invalid:
+ default:
+ error.SetErrorStringWithFormat(
+ "Wasm read failed for invalid address 0x%" PRIx64, vm_addr);
+ return 0;
+ }
+}
+
+size_t ProcessWasm::WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr,
+ void *buf, size_t buffer_size) {
+ char packet[64];
+ int packet_len =
+ ::snprintf(packet, sizeof(packet), "qWasmMem:%d;%" PRIx64 ";%" PRIx64,
+ wasm_module_id, static_cast<uint64_t>(addr),
+ static_cast<uint64_t>(buffer_size));
+ assert(packet_len + 1 < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ return response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
+ static_cast<uint8_t *>(buf), buffer_size),
+ '\xdd');
+ }
+ }
+ return 0;
+}
+
+size_t ProcessWasm::WasmReadData(uint32_t wasm_module_id, lldb::addr_t addr,
+ void *buf, size_t buffer_size) {
+ char packet[64];
+ int packet_len =
+ ::snprintf(packet, sizeof(packet), "qWasmData:%d;%" PRIx64 ";%" PRIx64,
+ wasm_module_id, static_cast<uint64_t>(addr),
+ static_cast<uint64_t>(buffer_size));
+ assert(packet_len + 1 < (int)sizeof(packet));
+ UNUSED_IF_ASSERT_DISABLED(packet_len);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) ==
+ GDBRemoteCommunication::PacketResult::Success) {
+ if (response.IsNormalResponse()) {
+ return response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
+ static_cast<uint8_t *>(buf), buffer_size),
+ '\xdd');
+ }
+ }
+ return 0;
+}
+
+bool ProcessWasm::GetWasmLocal(int frame_index, int index, void *buf,
+ size_t buffer_size, size_t &size) {
+ StreamString packet;
+ packet.Printf("qWasmLocal:");
+ packet.Printf("%d;%d", frame_index, index);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success) {
+ return false;
+ }
+
+ if (!response.IsNormalResponse()) {
+ return false;
+ }
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ size = buffer_sp->GetByteSize();
+ if (size <= buffer_size) {
+ memcpy(buf, buffer_sp->GetBytes(), size);
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessWasm::GetWasmGlobal(int frame_index, int index, void *buf,
+ size_t buffer_size, size_t &size) {
+ StreamString packet;
+ packet.PutCString("qWasmGlobal:");
+ packet.Printf("%d;%d", frame_index, index);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success) {
+ return false;
+ }
+
+ if (!response.IsNormalResponse()) {
+ return false;
+ }
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ size = buffer_sp->GetByteSize();
+ if (size <= buffer_size) {
+ memcpy(buf, buffer_sp->GetBytes(), size);
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessWasm::GetWasmStackValue(int frame_index, int index, void *buf,
+ size_t buffer_size, size_t &size) {
+ StreamString packet;
+ packet.PutCString("qWasmStackValue:");
+ packet.Printf("%d;%d", frame_index, index);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success) {
+ return false;
+ }
+
+ if (!response.IsNormalResponse()) {
+ return false;
+ }
+
+ WritableDataBufferSP buffer_sp(
+ new DataBufferHeap(response.GetStringRef().size() / 2, 0));
+ response.GetHexBytes(buffer_sp->GetData(), '\xcc');
+ size = buffer_sp->GetByteSize();
+ if (size <= buffer_size) {
+ memcpy(buf, buffer_sp->GetBytes(), size);
+ return true;
+ }
+
+ return false;
+}
+
+bool ProcessWasm::GetWasmCallStack(lldb::tid_t tid,
+ std::vector<lldb::addr_t> &call_stack_pcs) {
+ call_stack_pcs.clear();
+ StreamString packet;
+ packet.Printf("qWasmCallStack:");
+ packet.Printf("%llx", tid);
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+ GDBRemoteCommunication::PacketResult::Success) {
+ return false;
+ }
+
+ if (!response.IsNormalResponse()) {
+ return false;
+ }
+
+ addr_t buf[1024 / sizeof(addr_t)];
+ size_t bytes = response.GetHexBytes(
+ llvm::MutableArrayRef<uint8_t>((uint8_t *)buf, sizeof(buf)), '\xdd');
+ if (bytes == 0) {
+ return false;
+ }
+
+ for (size_t i = 0; i < bytes / sizeof(addr_t); i++) {
+ call_stack_pcs.push_back(buf[i]);
+ }
+ return true;
+}
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
new file mode 100644
index 00000000000000..c4579390daf082
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
@@ -0,0 +1,135 @@
+// This file comes from https://reviews.llvm.org/D78978.
+// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+//===-- ProcessWasm.h -------------------------------------------*- C++ -*-===//
+//
+// 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_PROCESS_WASM_PROCESSWASM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H
+
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "lldb/Target/RegisterContext.h"
+
+namespace lldb_private {
+namespace wasm {
+
+// Each WebAssembly module has separated address spaces for Code and Memory.
+// A WebAssembly module also has a Data section which, when the module is
+// loaded, gets mapped into a region in the module Memory.
+// For the purpose of debugging, we can represent all these separated 32-bit
+// address spaces with a single virtual 64-bit address space.
+//
+// Struct wasm_addr_t provides this encoding using bitfields
+//
+enum WasmAddressType {
+ Memory = 0x00,
+ Object = 0x01,
+ Invalid = 0x03
+};
+struct wasm_addr_t {
+ uint64_t offset : 32;
+ uint64_t module_id : 30;
+ uint64_t type : 2;
+
+ wasm_addr_t(lldb::addr_t addr)
+ : type(addr >> 62), module_id((addr & 0x00ffffff00000000) >> 32),
+ offset(addr & 0x00000000ffffffff) {}
+
+ wasm_addr_t(WasmAddressType type_, uint32_t module_id_, uint32_t offset_)
+ : type(type_), module_id(module_id_), offset(offset_) {}
+
+ WasmAddressType GetType() { return static_cast<WasmAddressType>(type); }
+ operator lldb::addr_t() { return *(uint64_t *)this; }
+};
+
+/// ProcessWasm provides the access to the Wasm program state
+/// retrieved from the Wasm engine.
+class ProcessWasm : public process_gdb_remote::ProcessGDBRemote {
+public:
+ ProcessWasm(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
+ ~ProcessWasm() override = default;
+
+ static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
+ lldb::ListenerSP listener_sp,
+ const FileSpec *crash_file_path,
+ bool can_connect);
+
+ static void Initialize();
+ static void DebuggerInitialize(Debugger &debugger);
+ static void Terminate();
+ static ConstString GetPluginNameStatic();
+ static const char *GetPluginDescriptionStatic();
+
+ /// PluginInterface protocol.
+ /// \{
+ llvm::StringRef GetPluginName() override;
+ /// \}
+
+ /// Process protocol.
+ /// \{
+ size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Status &error) override;
+
+ size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ ExecutionContext *exe_ctx, Status &error) override;
+ /// \}
+
+ /// Query the value of a WebAssembly local variable from the WebAssembly
+ /// remote process.
+ bool GetWasmLocal(int frame_index, int index, void *buf, size_t buffer_size,
+ size_t &size);
+
+ /// Query the value of a WebAssembly global variable from the WebAssembly
+ /// remote process.
+ bool GetWasmGlobal(int frame_index, int index, void *buf, size_t buffer_size,
+ size_t &size);
+
+ /// Query the value of an item in the WebAssembly operand stack from the
+ /// WebAssembly remote process.
+ bool GetWasmStackValue(int frame_index, int index, void *buf,
+ size_t buffer_size, size_t &size);
+
+ /// Read from the WebAssembly Memory space.
+ size_t WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr, void *buf,
+ size_t buffer_size);
+
+ /// Read from the WebAssembly Data space.
+ size_t WasmReadData(uint32_t wasm_module_id, lldb::addr_t addr, void *buf,
+ size_t buffer_size);
+
+ /// Retrieve the current call stack from the WebAssembly remote process.
+ bool GetWasmCallStack(lldb::tid_t tid,
+ std::vector<lldb::addr_t> &call_stack_pcs);
+
+ // Check if a given Process
+ bool CanDebug(lldb::TargetSP target_sp,
+ bool plugin_specified_by_name) override;
+
+protected:
+ /// ProcessGDBRemote protocol.
+ /// \{
+ std::shared_ptr<process_gdb_remote::ThreadGDBRemote>
+ CreateThread(lldb::tid_t tid);
+ /// \}
+
+private:
+ friend class UnwindWasm;
+ friend class ThreadWasm;
+
+ process_gdb_remote::GDBRemoteDynamicRegisterInfoSP &GetRegisterInfo() {
+ return m_register_info_sp;
+ }
+
+ ProcessWasm(const ProcessWasm &);
+ const ProcessWasm &operator=(const ProcessWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H
diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
new file mode 100644
index 00000000000000..d9715dd23b637a
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
@@ -0,0 +1,57 @@
+// This file comes from https://reviews.llvm.org/D78978.
+// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+//===-- ThreadWasm.cpp ----------------------------------------------------===//
+//
+// 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 "ThreadWasm.h"
+
+#include "ProcessWasm.h"
+#include "UnwindWasm.h"
+#include "lldb/Target/Target.h"
+#include "wasmRegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+Unwind &ThreadWasm::GetUnwinder() {
+ if (!m_unwinder_up) {
+ assert(CalculateTarget()->GetArchitecture().GetMachine() ==
+ llvm::Triple::wasm32);
+ m_unwinder_up.reset(new wasm::UnwindWasm(*this));
+ }
+ return *m_unwinder_up;
+}
+
+bool ThreadWasm::GetWasmCallStack(std::vector<lldb::addr_t> &call_stack_pcs) {
+ ProcessSP process_sp(GetProcess());
+ if (process_sp) {
+ ProcessWasm *wasm_process = static_cast<ProcessWasm *>(process_sp.get());
+ return wasm_process->GetWasmCallStack(GetID(), call_stack_pcs);
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+ThreadWasm::CreateRegisterContextForFrame(StackFrame *frame) {
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+ ProcessSP process_sp(GetProcess());
+ ProcessWasm *wasm_process = static_cast<ProcessWasm *>(process_sp.get());
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0) {
+ reg_ctx_sp = std::make_shared<WasmRegisterContext>(*this, concrete_frame_idx, wasm_process->GetRegisterInfo());
+ } else {
+ reg_ctx_sp = GetUnwinder().CreateRegisterContextForFrame(frame);
+ }
+ return reg_ctx_sp;
+}
diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.h b/lldb/source/Plugins/Process/wasm/ThreadWasm.h
new file mode 100644
index 00000000000000..eb731f8d335063
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.h
@@ -0,0 +1,47 @@
+// This file comes from https://reviews.llvm.org/D78978.
+// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+//===-- ThreadWasm.h --------------------------------------------*- C++ -*-===//
+//
+// 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_PROCESS_WASM_THREADWASM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H
+
+#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h"
+
+namespace lldb_private {
+namespace wasm {
+
+/// ProcessWasm provides the access to the Wasm program state
+/// retrieved from the Wasm engine.
+class ThreadWasm : public process_gdb_remote::ThreadGDBRemote {
+public:
+ ThreadWasm(Process &process, lldb::tid_t tid)
+ : process_gdb_remote::ThreadGDBRemote(process, tid) {}
+ ~ThreadWasm() override = default;
+
+ /// Retrieve the current call stack from the WebAssembly remote process.
+ bool GetWasmCallStack(std::vector<lldb::addr_t> &call_stack_pcs);
+
+ lldb::RegisterContextSP
+ CreateRegisterContextForFrame(StackFrame *frame) override;
+
+protected:
+ /// Thread protocol.
+ /// \{
+ Unwind &GetUnwinder() override;
+ /// \}
+
+ ThreadWasm(const ThreadWasm &);
+ const ThreadWasm &operator=(const ThreadWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H
diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
new file mode 100644
index 00000000000000..081d0209c091f3
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
@@ -0,0 +1,79 @@
+// This file comes from https://reviews.llvm.org/D78978.
+// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+//===-- UnwindWasm.cpp ----------------------------------------------------===//
+//
+// 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 "UnwindWasm.h"
+#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h"
+#include "Plugins/Process/wasm/ProcessWasm.h"
+#include "Plugins/Process/wasm/ThreadWasm.h"
+#include "lldb/lldb-forward.h"
+#include "wasmRegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace process_gdb_remote;
+using namespace wasm;
+
+class WasmGDBRemoteRegisterContext : public GDBRemoteRegisterContext {
+public:
+ WasmGDBRemoteRegisterContext(ThreadGDBRemote &thread,
+ uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfoSP ®_info_sp,
+ uint64_t pc)
+ : GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false,
+ false) {
+ PrivateSetRegisterValue(0, pc);
+ }
+};
+
+lldb::RegisterContextSP
+UnwindWasm::DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) {
+ if (m_frames.size() <= frame->GetFrameIndex()) {
+ return lldb::RegisterContextSP();
+ }
+
+ ThreadSP thread = frame->GetThread();
+ ProcessSP process_sp = thread->GetProcess();
+ ThreadWasm *wasm_thread = static_cast<ThreadWasm *>(thread.get());
+ ProcessWasm *wasm_process = static_cast<ProcessWasm *>(process_sp.get());
+ std::shared_ptr<WasmRegisterContext> reg_ctx_sp =
+ std::make_shared<WasmRegisterContext>(*wasm_thread,
+ frame->GetConcreteFrameIndex(),
+ wasm_process->GetRegisterInfo());
+ return reg_ctx_sp;
+}
+
+uint32_t UnwindWasm::DoGetFrameCount() {
+ if (!m_unwind_complete) {
+ m_unwind_complete = true;
+ m_frames.clear();
+
+ ThreadWasm &wasm_thread = static_cast<ThreadWasm &>(GetThread());
+ if (!wasm_thread.GetWasmCallStack(m_frames))
+ m_frames.clear();
+ }
+ return m_frames.size();
+}
+
+bool UnwindWasm::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
+ lldb::addr_t &pc,
+ bool &behaves_like_zeroth_frame) {
+ if (m_frames.size() == 0) {
+ DoGetFrameCount();
+ }
+
+ if (frame_idx < m_frames.size()) {
+ behaves_like_zeroth_frame = (frame_idx == 0);
+ cfa = 0;
+ pc = m_frames[frame_idx];
+ return true;
+ }
+ return false;
+}
\ No newline at end of file
diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.h b/lldb/source/Plugins/Process/wasm/UnwindWasm.h
new file mode 100644
index 00000000000000..01c36ce442b9b6
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.h
@@ -0,0 +1,58 @@
+// This file comes from https://reviews.llvm.org/D78978.
+// Author: [@paolosev](https://reviews.llvm.org/p/paolosev/).
+
+//===-- UnwindWasm.h --------------------------------------------*- C++ -*-===//
+//
+// 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_UnwindWasm_h_
+#define lldb_UnwindWasm_h_
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Unwind.h"
+#include <vector>
+
+namespace lldb_private {
+namespace wasm {
+
+/// UnwindWasm manages stack unwinding for a WebAssembly process.
+class UnwindWasm : public lldb_private::Unwind {
+public:
+ UnwindWasm(lldb_private::Thread &thread)
+ : Unwind(thread), m_frames(), m_unwind_complete(false) {}
+ ~UnwindWasm() override = default;
+
+protected:
+ /// Unwind protocol.
+ /// \{
+ void DoClear() override {
+ m_frames.clear();
+ m_unwind_complete = false;
+ }
+
+ uint32_t DoGetFrameCount() override;
+
+ bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
+ lldb::addr_t &pc,
+ bool &behaves_like_zeroth_frame) override;
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+ /// \}
+
+private:
+ std::vector<lldb::addr_t> m_frames;
+ bool m_unwind_complete;
+
+ UnwindWasm(const UnwindWasm &);
+ const UnwindWasm &operator=(const UnwindWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // lldb_UnwindWasm_h_
diff --git a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp
new file mode 100644
index 00000000000000..2f8e24df14e7fb
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp
@@ -0,0 +1,103 @@
+//===---- wasmRegisterContext.cpp -----------------------------------------===//
+//
+// 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 "wasmRegisterContext.h"
+#include "Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h"
+#include "lldb/Utility/RegisterValue.h"
+#include "ProcessWasm.h"
+#include "ThreadWasm.h"
+#include <memory>
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private::wasm;
+
+WasmRegisterContext::WasmRegisterContext(
+ wasm::ThreadWasm &thread, uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfoSP reg_info_sp)
+ : GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false,
+ false) {}
+
+WasmRegisterContext::~WasmRegisterContext() = default;
+
+uint32_t WasmRegisterContext::ConvertRegisterKindToRegisterNumber(
+ lldb::RegisterKind kind, uint32_t num)
+{
+ return num;
+}
+
+size_t WasmRegisterContext::GetRegisterCount() { return 0; }
+
+const RegisterInfo *WasmRegisterContext::GetRegisterInfoAtIndex(size_t reg) {
+ uint32_t tag = (reg >> 30) & 0x03;
+ if (tag == 0) {
+ return m_reg_info_sp->GetRegisterInfoAtIndex(reg);
+ }
+
+ WasmVirtualRegisterKinds kind = static_cast<WasmVirtualRegisterKinds>(tag - 1);
+ return new WasmVirtualRegisterInfo(kind, reg & 0x3fffffff);
+}
+
+size_t WasmRegisterContext::GetRegisterSetCount() { return 0; }
+
+const RegisterSet *WasmRegisterContext::GetRegisterSet(size_t reg_set) {
+ return nullptr;
+}
+
+bool WasmRegisterContext::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) {
+ if (reg_info->name) {
+ return GDBRemoteRegisterContext::ReadRegister(reg_info, value);
+ }
+
+ ThreadWasm *thread = static_cast<ThreadWasm *>(&GetThread());
+ ProcessWasm *process = static_cast<ProcessWasm *>(thread->GetProcess().get());
+ if (!thread)
+ return false;
+
+//uint32_t frame_index = thread->GetSelectedFrameIndex(SelectMostRelevantFrame);
+ uint32_t frame_index = m_concrete_frame_idx;
+ WasmVirtualRegisterInfo *wasm_reg_info =
+ static_cast<WasmVirtualRegisterInfo *>(
+ const_cast<RegisterInfo *>(reg_info));
+ uint8_t buf[16];
+ size_t size = 0;
+ switch (wasm_reg_info->kind) {
+ case eLocal:
+ process->GetWasmLocal(frame_index, wasm_reg_info->index, buf, sizeof(buf),
+ size);
+ break;
+ case eGlobal:
+ process->GetWasmGlobal(frame_index, wasm_reg_info->index, buf, sizeof(buf),
+ size);
+ break;
+ case eOperandStack:
+ process->GetWasmStackValue(frame_index, wasm_reg_info->index, buf,
+ sizeof(buf), size);
+ break;
+ default:
+ return false;
+ }
+
+ DataExtractor reg_data(buf, size, process->GetByteOrder(),
+ process->GetAddressByteSize());
+ const bool partial_data_ok = false;
+ wasm_reg_info->byte_size = size;
+ wasm_reg_info->encoding = lldb::eEncodingUint;
+ Status error(value.SetValueFromData(*reg_info, reg_data,
+ reg_info->byte_offset, partial_data_ok));
+ return error.Success();
+}
+
+void WasmRegisterContext::InvalidateAllRegisters() {}
+
+bool WasmRegisterContext::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) {
+ return false;
+}
diff --git a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h
new file mode 100644
index 00000000000000..61fb95cef632c9
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h
@@ -0,0 +1,70 @@
+//===----- wasmRegisterContext.h --------------------------------*- C++ -*-===//
+//
+// 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_PROCESS_WASM_WASMREGISTERCONTEXT_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_WASMREGISTERCONTEXT_H
+
+#include "Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h"
+#include "ThreadWasm.h"
+#include "lldb/lldb-private-types.h"
+
+namespace lldb_private {
+namespace wasm {
+
+class WasmRegisterContext;
+
+typedef std::shared_ptr<WasmRegisterContext> WasmRegisterContextSP;
+
+enum WasmVirtualRegisterKinds {
+ eLocal = 0, ///< wasm local
+ eGlobal, ///< wasm global
+ eOperandStack, ///< wasm operand stack
+ kNumWasmVirtualRegisterKinds
+};
+
+struct WasmVirtualRegisterInfo : public RegisterInfo {
+ WasmVirtualRegisterKinds kind;
+ uint32_t index;
+
+ WasmVirtualRegisterInfo(WasmVirtualRegisterKinds kind, uint32_t index)
+ : RegisterInfo(), kind(kind), index(index) {}
+};
+
+class WasmRegisterContext
+ : public process_gdb_remote::GDBRemoteRegisterContext {
+public:
+ WasmRegisterContext(
+ wasm::ThreadWasm &thread, uint32_t concrete_frame_idx,
+ process_gdb_remote::GDBRemoteDynamicRegisterInfoSP reg_info_sp);
+
+ ~WasmRegisterContext() override;
+
+ uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+ uint32_t num) override;
+
+ void InvalidateAllRegisters() override;
+
+ size_t GetRegisterCount() override;
+
+ const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override;
+
+ size_t GetRegisterSetCount() override;
+
+ const RegisterSet *GetRegisterSet(size_t reg_set) override;
+
+ bool ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value) override;
+
+ bool WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value) override;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_WASMREGISTERCONTEXT_H
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index 4ce290dfbe035f..5e1579b3b63fa9 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -2112,6 +2112,14 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
trap_opcode_size = sizeof(g_loongarch_opcode);
} break;
+ case llvm::Triple::wasm32: {
+ static const uint8_t g_wasm_opcode[] = {
+ 0x00}; // wasm only support remote debugging, we don't need to know trap
+ // opcode
+ trap_opcode = g_wasm_opcode;
+ trap_opcode_size = sizeof(g_wasm_opcode);
+ } break;
+
default:
return 0;
}
More information about the lldb-commits
mailing list