https://github.com/paolosevMSFT updated https://github.com/llvm/llvm-project/pull/76683
>From 739b26b03fd3661d1c22b975e241cbbe60ca6531 Mon Sep 17 00:00:00 2001 From: Paolo Severini <paolo...@microsoft.com> Date: Mon, 1 Jan 2024 06:55:40 -0800 Subject: [PATCH 1/3] [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; } >From 78574d642070387dfa21ba53aab8b8a192311448 Mon Sep 17 00:00:00 2001 From: Paolo Severini <paolo...@microsoft.com> Date: Thu, 4 Jan 2024 13:03:30 -0800 Subject: [PATCH 2/3] Minor refactoring --- .../Windows/Common/TargetThreadWindows.cpp | 3 +- .../Plugins/Process/wasm/ProcessWasm.cpp | 5 ++-- .../Process/wasm/wasmRegisterContext.cpp | 30 +++++++++++++++++-- .../Process/wasm/wasmRegisterContext.h | 1 + lldb/source/Target/Platform.cpp | 14 ++++----- 5 files changed, 39 insertions(+), 14 deletions(-) diff --git a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp index ad67e764fe10f2..50d0bd37bb0a49 100644 --- a/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp +++ b/lldb/source/Plugins/Process/Windows/Common/TargetThreadWindows.cpp @@ -29,8 +29,7 @@ using namespace lldb; using namespace lldb_private; -using GetThreadDescriptionFunctionPtr = HRESULT -WINAPI (*)(HANDLE hThread, PWSTR *ppszThreadDescription); +using GetThreadDescriptionFunctionPtr = HRESULT (*)(HANDLE hThread, PWSTR *ppszThreadDescription); TargetThreadWindows::TargetThreadWindows(ProcessWindows &process, const HostThread &thread) diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp index 1c1f9885b6395f..d8ab6d645884c3 100644 --- a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp @@ -29,7 +29,7 @@ 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"}); + m_unix_signals_sp = UnixSignals::Create(ArchSpec{"wasm32-unknown-unknown-wasm"}); } void ProcessWasm::Initialize() { @@ -97,10 +97,9 @@ size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, 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 + // TODO ? return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error); case WasmAddressType::Invalid: default: diff --git a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp index 2f8e24df14e7fb..0d3d84afb6bef4 100644 --- a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp +++ b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp @@ -40,8 +40,34 @@ const RegisterInfo *WasmRegisterContext::GetRegisterInfoAtIndex(size_t reg) { return m_reg_info_sp->GetRegisterInfoAtIndex(reg); } - WasmVirtualRegisterKinds kind = static_cast<WasmVirtualRegisterKinds>(tag - 1); - return new WasmVirtualRegisterInfo(kind, reg & 0x3fffffff); + reg &= 0x3fffffff; + + static const uint32_t kMaxVirtualRegisters = 2048; + if (reg > kMaxVirtualRegisters) { + // Only kMaxVirtualRegisters supported. + return nullptr; + // return m_reg_info_sp->GetRegisterInfoAtIndex(reg); // ??? + } + + static WasmVirtualRegisterInfo g_register_infos[kNumWasmVirtualRegisterKinds] + [kMaxVirtualRegisters]; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, [&]() { + for (int i_kind = WasmVirtualRegisterKinds::eLocal; + i_kind < WasmVirtualRegisterKinds::kNumWasmVirtualRegisterKinds; + i_kind++) { + WasmVirtualRegisterKinds kind = + static_cast<WasmVirtualRegisterKinds>(i_kind); + for (uint32_t i_reg = 0; i_reg < kMaxVirtualRegisters; i_reg++) { + g_register_infos[static_cast<WasmVirtualRegisterKinds>(kind)][i_reg] = { + kind, i_reg}; + } + } + }); + + WasmVirtualRegisterKinds kind = + static_cast<WasmVirtualRegisterKinds>(tag - 1); + return &g_register_infos[kind][reg]; } size_t WasmRegisterContext::GetRegisterSetCount() { return 0; } diff --git a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h index 61fb95cef632c9..8b198774ad163c 100644 --- a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h +++ b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h @@ -31,6 +31,7 @@ struct WasmVirtualRegisterInfo : public RegisterInfo { WasmVirtualRegisterKinds kind; uint32_t index; + WasmVirtualRegisterInfo() : RegisterInfo(), kind(eLocal), index(0) {} WasmVirtualRegisterInfo(WasmVirtualRegisterKinds kind, uint32_t index) : RegisterInfo(), kind(kind), index(index) {} }; diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 5e1579b3b63fa9..5236cb7b5e5b55 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -2112,13 +2112,13 @@ 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; + //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; >From 5d08fbe0205234000517202bd896ab65ede681a3 Mon Sep 17 00:00:00 2001 From: Paolo Severini <paolo...@microsoft.com> Date: Wed, 10 Jan 2024 07:31:49 -0800 Subject: [PATCH 3/3] Refactor class WasmVirtualRegisterInfo --- .../Process/wasm/wasmRegisterContext.cpp | 43 +++++-------------- .../Process/wasm/wasmRegisterContext.h | 6 ++- 2 files changed, 16 insertions(+), 33 deletions(-) diff --git a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp index 0d3d84afb6bef4..470a0fb6a43cb3 100644 --- a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp +++ b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.cpp @@ -8,9 +8,9 @@ #include "wasmRegisterContext.h" #include "Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h" -#include "lldb/Utility/RegisterValue.h" #include "ProcessWasm.h" #include "ThreadWasm.h" +#include "lldb/Utility/RegisterValue.h" #include <memory> using namespace lldb; @@ -27,9 +27,8 @@ WasmRegisterContext::WasmRegisterContext( WasmRegisterContext::~WasmRegisterContext() = default; uint32_t WasmRegisterContext::ConvertRegisterKindToRegisterNumber( - lldb::RegisterKind kind, uint32_t num) -{ - return num; + lldb::RegisterKind kind, uint32_t num) { + return num; } size_t WasmRegisterContext::GetRegisterCount() { return 0; } @@ -40,34 +39,15 @@ const RegisterInfo *WasmRegisterContext::GetRegisterInfoAtIndex(size_t reg) { return m_reg_info_sp->GetRegisterInfoAtIndex(reg); } - reg &= 0x3fffffff; - - static const uint32_t kMaxVirtualRegisters = 2048; - if (reg > kMaxVirtualRegisters) { - // Only kMaxVirtualRegisters supported. - return nullptr; - // return m_reg_info_sp->GetRegisterInfoAtIndex(reg); // ??? + auto it = m_register_map.find(reg); + if (it == m_register_map.end()) { + WasmVirtualRegisterKinds kind = + static_cast<WasmVirtualRegisterKinds>(tag - 1); + std::tie(it, std::ignore) = m_register_map.insert( + {reg, + std::make_unique<WasmVirtualRegisterInfo>(kind, reg & 0x3fffffff)}); } - - static WasmVirtualRegisterInfo g_register_infos[kNumWasmVirtualRegisterKinds] - [kMaxVirtualRegisters]; - static std::once_flag g_once_flag; - std::call_once(g_once_flag, [&]() { - for (int i_kind = WasmVirtualRegisterKinds::eLocal; - i_kind < WasmVirtualRegisterKinds::kNumWasmVirtualRegisterKinds; - i_kind++) { - WasmVirtualRegisterKinds kind = - static_cast<WasmVirtualRegisterKinds>(i_kind); - for (uint32_t i_reg = 0; i_reg < kMaxVirtualRegisters; i_reg++) { - g_register_infos[static_cast<WasmVirtualRegisterKinds>(kind)][i_reg] = { - kind, i_reg}; - } - } - }); - - WasmVirtualRegisterKinds kind = - static_cast<WasmVirtualRegisterKinds>(tag - 1); - return &g_register_infos[kind][reg]; + return it->second.get(); } size_t WasmRegisterContext::GetRegisterSetCount() { return 0; } @@ -87,7 +67,6 @@ bool WasmRegisterContext::ReadRegister(const RegisterInfo *reg_info, 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 *>( diff --git a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h index 8b198774ad163c..62bdf66c050ad3 100644 --- a/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h +++ b/lldb/source/Plugins/Process/wasm/wasmRegisterContext.h @@ -12,6 +12,7 @@ #include "Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h" #include "ThreadWasm.h" #include "lldb/lldb-private-types.h" +#include <unordered_map> namespace lldb_private { namespace wasm { @@ -31,7 +32,6 @@ struct WasmVirtualRegisterInfo : public RegisterInfo { WasmVirtualRegisterKinds kind; uint32_t index; - WasmVirtualRegisterInfo() : RegisterInfo(), kind(eLocal), index(0) {} WasmVirtualRegisterInfo(WasmVirtualRegisterKinds kind, uint32_t index) : RegisterInfo(), kind(kind), index(index) {} }; @@ -63,6 +63,10 @@ class WasmRegisterContext bool WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value) override; + +private: + std::unordered_map<size_t, std::unique_ptr<WasmVirtualRegisterInfo>> + m_register_map; }; } // namespace wasm _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits