diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp --- a/lldb/source/Core/Value.cpp +++ b/lldb/source/Core/Value.cpp @@ -30,6 +30,8 @@ #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" +#include "Plugins/Process/wasm/ProcessWasm.h" + #include #include @@ -563,8 +565,27 @@ Process *process = exe_ctx->GetProcessPtr(); if (process) { - const size_t bytes_read = - process->ReadMemory(address, dst, byte_size, error); + StackFrame *frame = exe_ctx->GetFramePtr(); + size_t bytes_read = 0; + + bool isWasm = + frame + ? (frame->CalculateTarget()->GetArchitecture().GetMachine() == + llvm::Triple::wasm32) + : false; + if (isWasm) { + int frame_index = frame->GetConcreteFrameIndex(); + wasm::IWasmProcess *wasm_process = + static_cast( + frame->CalculateProcess().get()); + if (wasm_process->WasmReadMemory(frame_index, address, dst, + byte_size)) { + bytes_read = byte_size; + } + } else { + bytes_read = process->ReadMemory(address, dst, byte_size, 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 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -36,6 +36,7 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "Plugins/Process/wasm/ProcessWasm.h" #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" using namespace lldb; @@ -2483,6 +2484,66 @@ stack.back().SetValueType(Value::eValueTypeLoadAddress); } break; + case DW_OP_WASM_location: { + if (frame) { + const llvm::Triple::ArchType machine = + frame->CalculateTarget()->GetArchitecture().GetMachine(); + if (machine == llvm::Triple::wasm32) { + wasm::IWasmProcess *wasm_process = + static_cast( + frame->CalculateProcess().get()); + int frame_index = frame->GetConcreteFrameIndex(); + uint64_t wasm_op = opcodes.GetULEB128(&offset); + uint64_t index = opcodes.GetULEB128(&offset); + uint8_t buf[16]; + size_t size = 0; + switch (wasm_op) { + case 0: // Local + if (!wasm_process->GetWasmLocal(frame_index, index, buf, 16, + size)) { + return false; + } + break; + case 1: // Global + if (!wasm_process->GetWasmGlobal(frame_index, index, buf, 16, + size)) { + return false; + } + break; + case 2: // Operand Stack + if (!wasm_process->GetWasmStackValue(frame_index, index, buf, 16, + size)) { + return false; + } + break; + default: + return false; + } + + if (size == sizeof(uint32_t)) { + uint32_t value; + memcpy(&value, buf, size); + stack.push_back(Scalar(value)); + } else if (size == sizeof(uint64_t)) { + uint64_t value; + memcpy(&value, buf, size); + stack.push_back(Scalar(value)); + } else + return false; + } else { + if (error_ptr) + error_ptr->SetErrorString("Invalid target architecture for " + "DW_OP_WASM_location opcode."); + return false; + } + } else { + if (error_ptr) + error_ptr->SetErrorString("Invalid stack frame in context for " + "DW_OP_WASM_location opcode."); + return false; + } + } break; + // OPCODE: DW_OP_addrx (DW_OP_GNU_addr_index is the legacy name.) // OPERANDS: 1 // ULEB128: index to the .debug_addr section diff --git a/lldb/source/Plugins/CMakeLists.txt b/lldb/source/Plugins/CMakeLists.txt --- a/lldb/source/Plugins/CMakeLists.txt +++ b/lldb/source/Plugins/CMakeLists.txt @@ -30,6 +30,7 @@ # FIXME: ProcessWindowsCommon needs to be initialized after all other process # plugins but before ProcessGDBRemote. set(LLDB_PROCESS_WINDOWS_PLUGIN "") +set(LLDB_PROCESS_WASM_PLUGIN "") set(LLDB_PROCESS_GDB_PLUGIN "") foreach(p ${LLDB_ALL_PLUGINS}) @@ -41,6 +42,8 @@ set(LLDB_PROCESS_WINDOWS_PLUGIN "LLDB_PLUGIN(${pStripped})\n") elseif(${pStripped} STREQUAL "ProcessGDBRemote") set(LLDB_PROCESS_GDB_PLUGIN "LLDB_PLUGIN(${pStripped})\n") + elseif(${pStripped} STREQUAL "ProcessWasm") + set(LLDB_PROCESS_WASM_PLUGIN "LLDB_PLUGIN(WasmProcessGDBRemote)\n") else() set(LLDB_ENUM_PLUGINS "${LLDB_ENUM_PLUGINS}LLDB_PLUGIN(${pStripped})\n") endif() diff --git a/lldb/source/Plugins/Plugins.def.in b/lldb/source/Plugins/Plugins.def.in --- a/lldb/source/Plugins/Plugins.def.in +++ b/lldb/source/Plugins/Plugins.def.in @@ -31,6 +31,7 @@ @LLDB_ENUM_PLUGINS@ @LLDB_PROCESS_WINDOWS_PLUGIN@ +@LLDB_PROCESS_WASM_PLUGIN@ @LLDB_PROCESS_GDB_PLUGIN@ #undef LLDB_PLUGIN diff --git a/lldb/source/Plugins/Process/CMakeLists.txt b/lldb/source/Plugins/Process/CMakeLists.txt --- a/lldb/source/Plugins/Process/CMakeLists.txt +++ b/lldb/source/Plugins/Process/CMakeLists.txt @@ -17,3 +17,4 @@ add_subdirectory(elf-core) add_subdirectory(mach-core) add_subdirectory(minidump) +add_subdirectory(wasm) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -297,6 +297,17 @@ bool GetThreadStopInfo(lldb::tid_t tid, StringExtractorGDBRemote &response); + // WebAssembly-specific commands + bool GetWasmGlobal(int frame_index, int index, void *buf, size_t buffer_size, + size_t &size); + bool GetWasmLocal(int frame_index, int index, void *buf, size_t buffer_size, + size_t &size); + bool GetWasmStackValue(int frame_index, int index, void *buf, + size_t buffer_size, size_t &size); + bool WasmReadMemory(int frame_index, lldb::addr_t vm_addr, void *buf, + size_t buffer_size); + bool GetWasmCallStack(std::vector &call_stack_pcs); + bool SupportsGDBStoppointPacket(GDBStoppointType type) { switch (type) { case eBreakpointSoftware: diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -2694,6 +2694,141 @@ return false; } +bool GDBRemoteCommunicationClient::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 (SendPacketAndWaitForResponse(packet.GetString(), response, false) != + PacketResult::Success) { + return false; + } + + if (!response.IsNormalResponse()) { + return false; + } + + DataBufferSP 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 GDBRemoteCommunicationClient::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 (SendPacketAndWaitForResponse(packet.GetString(), response, false) != + PacketResult::Success) { + return false; + } + + if (!response.IsNormalResponse()) { + return false; + } + + DataBufferSP 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 GDBRemoteCommunicationClient::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 (SendPacketAndWaitForResponse(packet.GetString(), response, false) != + PacketResult::Success) { + return false; + } + + if (!response.IsNormalResponse()) { + return false; + } + + DataBufferSP 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 GDBRemoteCommunicationClient::WasmReadMemory(int frame_index, + lldb::addr_t addr, void *buf, + size_t buffer_size) { + char packet[64]; + int packet_len = ::snprintf( + packet, sizeof(packet), "qWasmMem:%d;%" PRIx64 ";%" PRIx64, frame_index, + static_cast(addr), static_cast(buffer_size)); + assert(packet_len + 1 < (int)sizeof(packet)); + UNUSED_IF_ASSERT_DISABLED(packet_len); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet, response, true) == + PacketResult::Success) { + if (response.IsNormalResponse()) { + return buffer_size == + response.GetHexBytes(llvm::MutableArrayRef( + static_cast(buf), buffer_size), + '\xdd'); + } + } + return false; +} + +bool GDBRemoteCommunicationClient::GetWasmCallStack( + std::vector &call_stack_pcs) { + call_stack_pcs.clear(); + StreamString packet; + packet.Printf("qWasmCallStack"); + StringExtractorGDBRemote response; + if (SendPacketAndWaitForResponse(packet.GetString(), response, false) != + 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 *)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; +} + uint8_t GDBRemoteCommunicationClient::SendGDBStoppointTypePacket( GDBStoppointType type, bool insert, addr_t addr, uint32_t length) { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h @@ -23,6 +23,11 @@ class StringExtractor; namespace lldb_private { + +namespace wasm { +class WasmProcessGDBRemote; +} + namespace process_gdb_remote { class ThreadGDBRemote; @@ -75,6 +80,7 @@ protected: friend class ThreadGDBRemote; + friend class wasm::WasmProcessGDBRemote; bool ReadRegisterBytes(const RegisterInfo *reg_info, DataExtractor &data); diff --git a/lldb/source/Plugins/Process/wasm/CMakeLists.txt b/lldb/source/Plugins/Process/wasm/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/CMakeLists.txt @@ -0,0 +1,11 @@ + +add_lldb_library(lldbPluginProcessWasm PLUGIN + ProcessWasm.cpp + UnwindWasm.cpp + + LINK_LIBS + lldbCore + ${LLDB_PLUGINS} + LINK_COMPONENTS + Support + ) diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h @@ -0,0 +1,97 @@ +//===-- 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 { + +// Interface IWasmProcess provides the access to the Wasm program state +// retrieved from the Wasm engine. +struct IWasmProcess { + ~IWasmProcess() = default; + + virtual lldb::RegisterContextSP + CreateRegisterContextForFrame(StackFrame *frame, lldb::addr_t pc) = 0; + + virtual bool GetWasmLocal(int frame_index, int index, void *buf, + size_t buffer_size, size_t &size) = 0; + + virtual bool GetWasmGlobal(int frame_index, int index, void *buf, + size_t buffer_size, size_t &size) = 0; + + virtual bool GetWasmStackValue(int frame_index, int index, void *buf, + size_t buffer_size, size_t &size) = 0; + + virtual bool WasmReadMemory(int frame_index, lldb::addr_t addr, void *buf, + size_t buffer_size) = 0; + + virtual bool GetWasmCallStack(std::vector &call_stack_pcs) = 0; +}; + +class WasmProcessGDBRemote : public process_gdb_remote::ProcessGDBRemote, + public IWasmProcess { +public: + WasmProcessGDBRemote(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp); + + ~WasmProcessGDBRemote() override; + + static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp, + lldb::ListenerSP listener_sp, + const FileSpec *crash_file_path); + + static void Initialize(); + + static void DebuggerInitialize(Debugger &debugger); + + static void Terminate(); + + static ConstString GetPluginNameStatic(); + + static const char *GetPluginDescriptionStatic(); + + // PluginInterface protocol + ConstString GetPluginName() override; + + uint32_t GetPluginVersion() override; + + // Process + size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, + Status &error) override; + + // IWasmProcess + lldb::RegisterContextSP + CreateRegisterContextForFrame(StackFrame *frame, + lldb::addr_t address) override; + + bool GetWasmLocal(int frame_index, int index, void *buf, size_t buffer_size, + size_t &size) override; + + bool GetWasmGlobal(int frame_index, int index, void *buf, size_t buffer_size, + size_t &size) override; + + bool GetWasmStackValue(int frame_index, int index, void *buf, + size_t buffer_size, size_t &size) override; + + bool WasmReadMemory(int frame_index, lldb::addr_t addr, void *buf, + size_t buffer_size) override; + + bool GetWasmCallStack(std::vector &call_stack_pcs) override; + +private: + DISALLOW_COPY_AND_ASSIGN(WasmProcessGDBRemote); +}; + +} // namespace wasm +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp @@ -0,0 +1,122 @@ +//===-- 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 "Plugins/Process/gdb-remote/ThreadGDBRemote.h" +#include "lldb/Core/PluginManager.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_gdb_remote; +using namespace lldb_private::wasm; + +LLDB_PLUGIN_DEFINE(WasmProcessGDBRemote) + +// ProcessGDBRemote constructor +WasmProcessGDBRemote::WasmProcessGDBRemote(lldb::TargetSP target_sp, + ListenerSP listener_sp) + : ProcessGDBRemote(target_sp, listener_sp) {} + +// Destructor +WasmProcessGDBRemote::~WasmProcessGDBRemote() {} + +void WasmProcessGDBRemote::Initialize() { + static llvm::once_flag g_once_flag; + + llvm::call_once(g_once_flag, []() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + DebuggerInitialize); + }); +} + +void WasmProcessGDBRemote::DebuggerInitialize(Debugger &debugger) { + ProcessGDBRemote::DebuggerInitialize(debugger); +} + +// PluginInterface +ConstString WasmProcessGDBRemote::GetPluginName() { + return GetPluginNameStatic(); +} + +uint32_t WasmProcessGDBRemote::GetPluginVersion() { return 1; } + +ConstString WasmProcessGDBRemote::GetPluginNameStatic() { + static ConstString g_name("wasm"); + return g_name; +} + +const char *WasmProcessGDBRemote::GetPluginDescriptionStatic() { + return "GDB Remote protocol based WebAssembly debugging plug-in."; +} + +void WasmProcessGDBRemote::Terminate() { + PluginManager::UnregisterPlugin(WasmProcessGDBRemote::CreateInstance); +} + +lldb::ProcessSP +WasmProcessGDBRemote::CreateInstance(lldb::TargetSP target_sp, + ListenerSP listener_sp, + const FileSpec *crash_file_path) { + lldb::ProcessSP process_sp; + if (crash_file_path == nullptr) + process_sp = std::make_shared(target_sp, listener_sp); + return process_sp; +} + +size_t WasmProcessGDBRemote::ReadMemory(lldb::addr_t vm_addr, void *buf, + size_t size, Status &error) { + if (vm_addr < 0x100000000) { + if (GetGDBRemote().WasmReadMemory(0 /*frame_index*/, vm_addr, buf, size)) { + return size; + } + return 0; + } else + return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error); +} + +lldb::RegisterContextSP +WasmProcessGDBRemote::CreateRegisterContextForFrame(StackFrame *frame, + lldb::addr_t pc) { + ThreadGDBRemote *gdb_thread = + static_cast(frame->CalculateThread().get()); + std::shared_ptr reg_ctx_sp = + std::make_shared( + *gdb_thread, frame->GetFrameIndex(), m_register_info, false, false); + reg_ctx_sp->PrivateSetRegisterValue(0, pc); + return reg_ctx_sp; +} + +bool WasmProcessGDBRemote::GetWasmLocal(int frame_index, int index, void *buf, + size_t buffer_size, size_t &size) { + return GetGDBRemote().GetWasmLocal(frame_index, index, buf, buffer_size, + size); +} + +bool WasmProcessGDBRemote::GetWasmGlobal(int frame_index, int index, void *buf, + size_t buffer_size, size_t &size) { + return GetGDBRemote().GetWasmGlobal(frame_index, index, buf, buffer_size, + size); +} + +bool WasmProcessGDBRemote::GetWasmStackValue(int frame_index, int index, + void *buf, size_t buffer_size, + size_t &size) { + return GetGDBRemote().GetWasmStackValue(frame_index, index, buf, buffer_size, + size); +} + +bool WasmProcessGDBRemote::WasmReadMemory(int frame_index, lldb::addr_t addr, + void *buf, size_t buffer_size) { + return GetGDBRemote().WasmReadMemory(frame_index, addr, buf, buffer_size); +} + +bool WasmProcessGDBRemote::GetWasmCallStack( + std::vector &call_stack_pcs) { + return GetGDBRemote().GetWasmCallStack(call_stack_pcs); +} diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.h b/lldb/source/Plugins/Process/wasm/UnwindWasm.h new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.h @@ -0,0 +1,49 @@ +//===-- 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 + +namespace lldb_private { +namespace wasm { + +class UnwindWasm : public lldb_private::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 m_frames; + bool m_unwind_complete; + + DISALLOW_COPY_AND_ASSIGN(UnwindWasm); +}; + +} // namespace wasm +} // namespace lldb_private + +#endif // lldb_UnwindWasm_h_ diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp new file mode 100644 --- /dev/null +++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp @@ -0,0 +1,57 @@ +//===-- 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/wasm/ProcessWasm.h" + +using namespace lldb; +using namespace lldb_private; +using namespace process_gdb_remote; +using namespace wasm; + +lldb::RegisterContextSP +UnwindWasm::DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) { + if (m_frames.size() <= frame->GetFrameIndex()) { + return lldb::RegisterContextSP(); + } + + IWasmProcess *wasm_process = + static_cast(frame->CalculateProcess().get()); + return wasm_process->CreateRegisterContextForFrame( + frame, m_frames[frame->GetFrameIndex()]); +} + +uint32_t UnwindWasm::DoGetFrameCount() { + if (!m_unwind_complete) { + m_unwind_complete = true; + m_frames.clear(); + + IWasmProcess *wasm_process = + static_cast(GetThread().GetProcess().get()); + if (wasm_process) + if (!wasm_process->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/Target/Thread.cpp b/lldb/source/Target/Thread.cpp --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Target/Thread.h" +#include "Plugins/Process/wasm/UnwindWasm.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/FormatEntity.h" @@ -1853,8 +1854,13 @@ } Unwind &Thread::GetUnwinder() { - if (!m_unwinder_up) - m_unwinder_up.reset(new UnwindLLDB(*this)); + if (!m_unwinder_up) { + if (CalculateTarget()->GetArchitecture().GetMachine() == + llvm::Triple::wasm32) + m_unwinder_up.reset(new wasm::UnwindWasm(*this)); + else + m_unwinder_up.reset(new UnwindLLDB(*this)); + } return *m_unwinder_up; }