llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) <details> <summary>Changes</summary> This PR implements a register context for Wasm, which uses virtual registers to resolve Wasm local, globals and stack values. The registers are used to implement supprot for `DW_OP_WASM_location` in the DWARF expression evaluator (#<!-- -->151010). This also adds a more comprehensive test, showing that we can use this to show local variables. --- Patch is 97.48 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/151056.diff 32 Files Affected: - (modified) lldb/docs/resources/lldbgdbremote.md (+55) - (modified) lldb/include/lldb/Expression/DWARFExpression.h (+8-4) - (modified) lldb/packages/Python/lldbsuite/test/lldbgdbclient.py (+2-2) - (modified) lldb/source/Expression/DWARFExpression.cpp (+36-4) - (modified) lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp (+5-1) - (modified) lldb/source/Plugins/Process/CMakeLists.txt (+1) - (modified) lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (+7-2) - (modified) lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (+2) - (added) lldb/source/Plugins/Process/wasm/CMakeLists.txt (+11) - (added) lldb/source/Plugins/Process/wasm/ProcessWasm.cpp (+194) - (added) lldb/source/Plugins/Process/wasm/ProcessWasm.h (+106) - (added) lldb/source/Plugins/Process/wasm/RegisterContextWasm.cpp (+128) - (added) lldb/source/Plugins/Process/wasm/RegisterContextWasm.h (+90) - (added) lldb/source/Plugins/Process/wasm/ThreadWasm.cpp (+54) - (added) lldb/source/Plugins/Process/wasm/ThreadWasm.h (+41) - (added) lldb/source/Plugins/Process/wasm/UnwindWasm.cpp (+85) - (added) lldb/source/Plugins/Process/wasm/UnwindWasm.h (+51) - (modified) lldb/source/Plugins/SymbolFile/DWARF/CMakeLists.txt (+1) - (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp (+3-1) - (modified) lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h (+5-3) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+4) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h (+3) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp (+5-3) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h (+2-1) - (added) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp (+78) - (added) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h (+34) - (modified) lldb/source/Target/Platform.cpp (+7) - (modified) lldb/test/API/functionalities/gdb_remote_client/TestWasm.py (+156-52) - (added) lldb/test/API/functionalities/gdb_remote_client/simple.c (+10) - (added) lldb/test/API/functionalities/gdb_remote_client/simple.yaml (+228) - (modified) lldb/unittests/Expression/CMakeLists.txt (+2) - (modified) lldb/unittests/Expression/DWARFExpressionTest.cpp (+409-147) ``````````diff diff --git a/lldb/docs/resources/lldbgdbremote.md b/lldb/docs/resources/lldbgdbremote.md index 80c68091ecd07..0b63d56d37acf 100644 --- a/lldb/docs/resources/lldbgdbremote.md +++ b/lldb/docs/resources/lldbgdbremote.md @@ -1998,6 +1998,61 @@ threads (live system debug) / cores (JTAG) in your program have stopped and allows LLDB to display and control your program correctly. +## qWasmCallStack + +Get the Wasm call stack for the given thread id. This returns a hex-encoded +list of PC values, one for each frame of the call stack. To match the Wasm +specification, the addresses are encoded in little endian byte order, even if +the endian of the Wasm runtime's host is not little endian. + +``` +send packet: $qWasmCallStack:202dbe040#08 +read packet: $9c01000000000040e501000000000040fe01000000000040# +``` + +**Priority to Implement:** Only required for Wasm support. This packed is +supported by the [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) +and [V8](https://v8.dev) Wasm runtimes. + +## qWasmGlobal + +Get the value of a Wasm global variable for the given frame index at the given +variable index. This returns a hex-encoded value. + +send packet: qWasmGlobal:frame_index;index +read packet: ... + +**Priority to Implement:** Only required for Wasm support. This packed is +supported by the [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) +and [V8](https://v8.dev) Wasm runtimes. + + +## qWasmLocal + +Get the value of a Wasm function argument or local variable for the given frame +index at the given variable index. This returns a hex-encoded value. + +send packet: qWasmGlobal:frame_index;index +read packet: ... + +**Priority to Implement:** Only required for Wasm support. This packed is +supported by the [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) +and [V8](https://v8.dev) Wasm runtimes. + + +## qWasmStackValue + +Get the value of a Wasm local variable from the Wasm operand stack, for the +given frame index at the given variable index. This returns a hex-encoded +value. + +send packet: qWasmStackValue:frame_index;index +read packet: ... + +**Priority to Implement:** Only required for Wasm support. This packed is +supported by the [WAMR](https://github.com/bytecodealliance/wasm-micro-runtime) +and [V8](https://v8.dev) Wasm runtimes. + ## qWatchpointSupportInfo Get the number of hardware watchpoints available on the remote target. diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h index 37853c0b5a8fc..8fcc5d37b91c9 100644 --- a/lldb/include/lldb/Expression/DWARFExpression.h +++ b/lldb/include/lldb/Expression/DWARFExpression.h @@ -52,10 +52,10 @@ class DWARFExpression { GetVendorDWARFOpcodeSize(const DataExtractor &data, const lldb::offset_t data_offset, const uint8_t op) const = 0; - virtual bool ParseVendorDWARFOpcode(uint8_t op, - const DataExtractor &opcodes, - lldb::offset_t &offset, - Stack &stack) const = 0; + virtual bool + ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes, + lldb::offset_t &offset, RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, Stack &stack) const = 0; Delegate(const Delegate &) = delete; Delegate &operator=(const Delegate &) = delete; @@ -163,6 +163,10 @@ class DWARFExpression { bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op) const; + static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + uint32_t reg_num, Value &value); + private: /// A data extractor capable of reading opcode bytes DataExtractor m_data; diff --git a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py index 459460b84fbae..599f7878e6edb 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py +++ b/lldb/packages/Python/lldbsuite/test/lldbgdbclient.py @@ -45,7 +45,7 @@ def createTarget(self, yaml_path): self.yaml2obj(yaml_path, obj_path) return self.dbg.CreateTarget(obj_path) - def connect(self, target): + def connect(self, target, plugin="gdb-remote"): """ Create a process by connecting to the mock GDB server. @@ -54,7 +54,7 @@ def connect(self, target): listener = self.dbg.GetListener() error = lldb.SBError() process = target.ConnectRemote( - listener, self.server.get_connect_url(), "gdb-remote", error + listener, self.server.get_connect_url(), plugin, error ) self.assertTrue(error.Success(), error.description) self.assertTrue(process, PROCESS_IS_VALID) diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 79bc6c87fa9c5..68093e9710a28 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -91,9 +91,10 @@ void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) { m_reg_kind = reg_kind; } -static llvm::Error ReadRegisterValueAsScalar(RegisterContext *reg_ctx, - lldb::RegisterKind reg_kind, - uint32_t reg_num, Value &value) { +llvm::Error +DWARFExpression::ReadRegisterValueAsScalar(RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + uint32_t reg_num, Value &value) { if (reg_ctx == nullptr) return llvm::createStringError("no register context in frame"); @@ -2300,9 +2301,40 @@ llvm::Expected<Value> 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 = 2; // Global + } else { + index = opcodes.GetULEB128(&offset); + } + + reg_num = (((wasm_op + 1) & 0x03) << 30) | (index & 0x3fffffff); + + if (llvm::Error error = + ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, tmp)) + return std::move(error); + stack.push_back(tmp); + break; + } + default: if (dwarf_cu) { - if (dwarf_cu->ParseVendorDWARFOpcode(op, opcodes, offset, stack)) { + if (dwarf_cu->ParseVendorDWARFOpcode(op, opcodes, offset, reg_ctx, + reg_kind, stack)) { break; } } diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp index 67963a790a4fe..b1efd25949379 100644 --- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -376,9 +376,13 @@ DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) { DataBufferSP buffer_sp(data_up.release()); data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); } + } else if (offset < m_data.GetByteSize()) { + size = + std::min(static_cast<uint64_t>(size), m_data.GetByteSize() - offset); + return DataExtractor(m_data.GetDataStart() + offset, size, GetByteOrder(), + GetAddressByteSize()); } } - data.SetByteOrder(GetByteOrder()); return data; } diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt index bd9b1b86dbf13..3413360e975fb 100644 --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -29,3 +29,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 a2c34ddfc252e..14dfdec6a6f62 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -323,6 +323,11 @@ ProcessGDBRemote::~ProcessGDBRemote() { KillDebugserverProcess(); } +std::shared_ptr<ThreadGDBRemote> +ProcessGDBRemote::CreateThread(lldb::tid_t tid) { + return std::make_shared<ThreadGDBRemote>(*this, tid); +} + bool ProcessGDBRemote::ParsePythonTargetDefinition( const FileSpec &target_definition_fspec) { ScriptInterpreter *interpreter = @@ -1594,7 +1599,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list, ThreadSP thread_sp( old_thread_list_copy.RemoveThreadByProtocolID(tid, false)); if (!thread_sp) { - thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid); + thread_sp = CreateThread(tid); LLDB_LOGV(log, "Making new thread: {0} for thread ID: {1:x}.", thread_sp.get(), thread_sp->GetID()); } else { @@ -1726,7 +1731,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 7ae33837fd067..7c3dfb179a4b3 100644 --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h @@ -246,6 +246,8 @@ class ProcessGDBRemote : public Process, ProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + virtual std::shared_ptr<ThreadGDBRemote> CreateThread(lldb::tid_t tid); + bool SupportsMemoryTagging() override; /// Broadcaster event bits definitions. diff --git a/lldb/source/Plugins/Process/wasm/CMakeLists.txt b/lldb/source/Plugins/Process/wasm/CMakeLists.txt new file mode 100644 index 0000000000000..779b97ec90d08 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/CMakeLists.txt @@ -0,0 +1,11 @@ +add_lldb_library(lldbPluginProcessWasm PLUGIN + ProcessWasm.cpp + RegisterContextWasm.cpp + ThreadWasm.cpp + UnwindWasm.cpp + + LINK_LIBS + lldbCore + 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 0000000000000..e244ab10f9faf --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp @@ -0,0 +1,194 @@ +//===----------------------------------------------------------------------===// +// +// 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) { + assert(target_sp); + // Wasm doesn't have any Unix-like signals as a platform concept, but pretend + // like it does to appease LLDB. + m_unix_signals_sp = UnixSignals::Create(target_sp->GetArchitecture()); +} + +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"); + + // To match the Wasm specification, the addresses are encoded in little endian + // byte order. + DataExtractor data(data_buffer_sp, lldb::eByteOrderLittle, + GetAddressByteSize()); + lldb::offset_t offset = 0; + std::vector<lldb::addr_t> call_stack_pcs; + while (offset < bytes) + call_stack_pcs.push_back(data.GetU64(&offset)); + + return call_stack_pcs; +} + +llvm::Expected<lldb::DataBufferSP> ProcessWasm::GetWasmLocal(int frame_index, + int index) { + 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 llvm::createStringError("failed to send qWasmLocal"); + + if (!response.IsNormalResponse()) + return llvm::createStringError("failed to get response for qWasmLocal"); + + WritableDataBufferSP buffer_sp( + new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + response.GetHexBytes(buffer_sp->GetData(), '\xcc'); + return buffer_sp; +} + +llvm::Expected<lldb::DataBufferSP> ProcessWasm::GetWasmGlobal(int frame_index, + int index) { + 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 llvm::createStringError("failed to send qWasmGlobal"); + + if (!response.IsNormalResponse()) + return llvm::createStringError("failed to get response for qWasmGlobal"); + + WritableDataBufferSP buffer_sp( + new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + response.GetHexBytes(buffer_sp->GetData(), '\xcc'); + return buffer_sp; +} + +llvm::Expected<lldb::DataBufferSP> +ProcessWasm::GetWasmStackValue(int frame_index, int index) { + 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 llvm::createStringError("failed to send qWasmStackValue"); + + if (!response.IsNormalResponse()) + return llvm::createStringError( + "failed to get response for qWasmStackValue"); + + WritableDataBufferSP buffer_sp( + new DataBufferHeap(response.GetStringRef().size() / 2, 0)); + response.GetHexBytes(buffer_sp->GetData(), '\xcc'); + return buffer_sp; +} diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h new file mode 100644 index 0000000000000..81682eac27997 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h @@ -0,0 +1,106 @@ +//===----------------------------------------------------------------------===// +// +// 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" + +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. +enum WasmAddressType : uint8_t { Memory = 0x00, Object = 0x01, Invalid = 0xff }; + +/// For the purpose of debugging, we can represent all these separated 32-bit +/// address spaces with a single virtual 64-bit address space. The +/// wasm_addr_t provides this encoding using bitfields. +struct wasm_addr_t { + uint64_t offset : 32; + uint64_t module_id : 30; + uint64_t type : 2; + + wasm_addr_t(lldb::addr_t addr) + : offset(addr & 0x00000000ffffffff), + module_id((addr & 0x00ffffff00000000) >> 32), type(addr >> 62) {} + + wasm_addr_t(WasmAddressType type, uint32_t module_id, uint32_t offset) + : offset(offset), module_id(module_id), type(type) {} + + WasmAddressType GetType() { return static_cast<WasmAddressType>(type); } + + operator lldb::addr_t() { return *(uint64_t *)this; } +}; + +static_assert(sizeof(wasm_addr_t) == 8, ""); + +/// ProcessWasm provides the access to the Wasm program state +/// retrieved from the Wasm engine. +c... [truncated] `````````` </details> https://github.com/llvm/llvm-project/pull/151056 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits