paolosev created this revision.
paolosev added reviewers: labath, clayborg.
paolosev added a project: LLDB.
Herald added subscribers: lldb-commits, sunfish, aheejin, jgravelle-google, 
sbc100, aprantl, mgorny, dschuff.
paolosev edited the summary of this revision.

This patch is a refactoring of  https://reviews.llvm.org/D78801. As suggested, 
I have created a separate patch to more easily compare the implementations.
Even here, the goal is to use the GDB-remote protocol to connect to a Wasm 
engine that implements a GDB-remote stub that offers the ability to access the 
engine runtime internal state.

Here I am removing the interface IWasmProcess and the new class 
WasmProcessGDBRemote and moving most of the Wasm logic in `ProcessGDBRemote`.
I am still adding the new Unwind class `UnwindWasm`, which now however is in 
core and not in plugins code.  Having a Unwind-derived class for Wasm unwinding 
seems to be the cleanest solution.

The advantage with this new design is that the required changes are smaller and 
isolated in a few places.
The drawback is that three 'core' classes (UnwindWasm, Value and 
DWARFExpression) have now a dependency on ProcessGDBRemote and/or 
ThreadGDBRemote. This could be avoided re-introducing a core interface like 
IWasmProcess. We could add a couple of virtual method  `bool IsWasmProcess()` 
and `IWasmProcess* AsWasmProcess()` to Process, which would be overridden by 
ProcessGDBRemote. Then these classes could just query this interface, removing 
direct dependencies on GDBRemote.

I am also adding a new `qSupported` flag named "wasm" that should tell LLDB 
whether the remote supports Wasm debugging.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D78978

Files:
  lldb/include/lldb/Target/UnwindWasm.h
  lldb/source/Core/Value.cpp
  lldb/source/Expression/DWARFExpression.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
  lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
  lldb/source/Target/CMakeLists.txt
  lldb/source/Target/Thread.cpp
  lldb/source/Target/UnwindWasm.cpp

Index: lldb/source/Target/UnwindWasm.cpp
===================================================================
--- /dev/null
+++ lldb/source/Target/UnwindWasm.cpp
@@ -0,0 +1,75 @@
+//===-- 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 "lldb/Target/UnwindWasm.h"
+#include "lldb/Target/Thread.h"
+
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace process_gdb_remote;
+
+class WasmGDBRemoteRegisterContext : public GDBRemoteRegisterContext {
+public:
+  WasmGDBRemoteRegisterContext(ThreadGDBRemote &thread,
+                               uint32_t concrete_frame_idx,
+                               GDBRemoteDynamicRegisterInfo &reg_info,
+                               uint64_t pc)
+      : GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info, 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();
+  ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread.get());
+  ProcessGDBRemote *gdb_process =
+      static_cast<ProcessGDBRemote *>(thread->GetProcess().get());
+  std::shared_ptr<GDBRemoteRegisterContext> reg_ctx_sp =
+      std::make_shared<WasmGDBRemoteRegisterContext>(
+          *gdb_thread, frame->GetConcreteFrameIndex(),
+          gdb_process->m_register_info, m_frames[frame->GetFrameIndex()]);
+  return reg_ctx_sp;
+}
+
+uint32_t UnwindWasm::DoGetFrameCount() {
+  if (!m_unwind_complete) {
+    m_unwind_complete = true;
+    m_frames.clear();
+
+    ProcessGDBRemote *gdb_process =
+        static_cast<ProcessGDBRemote *>(GetThread().GetProcess().get());
+    if (!gdb_process->GetWasmCallStack(m_frames))
+      return 0;
+  }
+  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
Index: lldb/source/Target/Thread.cpp
===================================================================
--- lldb/source/Target/Thread.cpp
+++ lldb/source/Target/Thread.cpp
@@ -43,6 +43,7 @@
 #include "lldb/Target/ThreadPlanStepUntil.h"
 #include "lldb/Target/ThreadSpec.h"
 #include "lldb/Target/UnwindLLDB.h"
+#include "lldb/Target/UnwindWasm.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/RegularExpression.h"
 #include "lldb/Utility/State.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 UnwindWasm(*this));
+    else
+      m_unwinder_up.reset(new UnwindLLDB(*this));
+  }
   return *m_unwinder_up;
 }
 
Index: lldb/source/Target/CMakeLists.txt
===================================================================
--- lldb/source/Target/CMakeLists.txt
+++ lldb/source/Target/CMakeLists.txt
@@ -68,6 +68,7 @@
   UnixSignals.cpp
   UnwindAssembly.cpp
   UnwindLLDB.cpp
+  UnwindWasm.cpp
 
   LINK_LIBS
     lldbBreakpoint
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -231,7 +231,26 @@
   std::string HarmonizeThreadIdsForProfileData(
       StringExtractorGDBRemote &inputStringExtractor);
 
+  // Query remote GDBServer for Wasm information
+
+  bool IsWasmProcess() const;
+
+  bool GetWasmLocal(int frame_index, int index, void *buf, size_t buffer_size,
+                    size_t &size);
+
+  bool GetWasmGlobal(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 addr, void *buf,
+                      size_t buffer_size);
+
+  bool GetWasmCallStack(std::vector<lldb::addr_t> &call_stack_pcs);
+
 protected:
+  friend class UnwindWasm;
   friend class ThreadGDBRemote;
   friend class GDBRemoteCommunicationClient;
   friend class GDBRemoteRegisterContext;
Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -2689,9 +2689,61 @@
   }
 }
 
+// WebAssembly features
+
+bool ProcessGDBRemote::IsWasmProcess() const {
+  return GetTarget().GetArchitecture().GetMachine() == llvm::Triple::wasm32;
+}
+
+bool ProcessGDBRemote::GetWasmLocal(int frame_index, int index, void *buf,
+                                    size_t buffer_size, size_t &size) {
+  if (!m_gdb_comm.GetWasmFeaturesSupported())
+    return false;
+  return GetGDBRemote().GetWasmLocal(frame_index, index, buf, buffer_size,
+                                     size);
+}
+
+bool ProcessGDBRemote::GetWasmGlobal(int frame_index, int index, void *buf,
+                                     size_t buffer_size, size_t &size) {
+  if (!m_gdb_comm.GetWasmFeaturesSupported())
+    return false;
+  return GetGDBRemote().GetWasmGlobal(frame_index, index, buf, buffer_size,
+                                      size);
+}
+
+bool ProcessGDBRemote::GetWasmStackValue(int frame_index, int index, void *buf,
+                                         size_t buffer_size, size_t &size) {
+  if (!m_gdb_comm.GetWasmFeaturesSupported())
+    return false;
+  return GetGDBRemote().GetWasmStackValue(frame_index, index, buf, buffer_size,
+                                          size);
+}
+
+bool ProcessGDBRemote::WasmReadMemory(int frame_index, lldb::addr_t addr,
+                                      void *buf, size_t buffer_size) {
+  if (!m_gdb_comm.GetWasmFeaturesSupported())
+    return false;
+  return GetGDBRemote().WasmReadMemory(frame_index, addr, buf, buffer_size);
+}
+
+bool ProcessGDBRemote::GetWasmCallStack(
+    std::vector<lldb::addr_t> &call_stack_pcs) {
+  if (!m_gdb_comm.GetWasmFeaturesSupported())
+    return false;
+  return GetGDBRemote().GetWasmCallStack(call_stack_pcs);
+}
+
 // Process Memory
 size_t ProcessGDBRemote::DoReadMemory(addr_t addr, void *buf, size_t size,
                                       Status &error) {
+  if (addr < 0x100000000 && IsWasmProcess() &&
+      m_gdb_comm.GetWasmFeaturesSupported()) {
+    if (WasmReadMemory(0 /*frame_index*/, addr, buf, size)) {
+      return size;
+    }
+    return 0;
+  }
+
   GetMaxMemorySize();
   bool binary_memory_read = m_gdb_comm.GetxPacketSupported();
   // M and m packets take 2 bytes for 1 byte of memory
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
+++ 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<lldb::addr_t> &call_stack_pcs);
+
   bool SupportsGDBStoppointPacket(GDBStoppointType type) {
     switch (type) {
     case eBreakpointSoftware:
@@ -357,6 +368,8 @@
 
   bool GetQXferMemoryMapReadSupported();
 
+  bool GetWasmFeaturesSupported();
+
   LazyBool SupportsAllocDeallocMemory() // const
   {
     // Uncomment this to have lldb pretend the debug server doesn't respond to
@@ -552,6 +565,7 @@
   LazyBool m_supports_jGetSharedCacheInfo;
   LazyBool m_supports_QPassSignals;
   LazyBool m_supports_error_string_reply;
+  LazyBool m_supports_wasm;
 
   bool m_supports_qProcessInfoPID : 1, m_supports_qfProcessInfo : 1,
       m_supports_qUserName : 1, m_supports_qGroupName : 1,
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -199,6 +199,13 @@
   return m_supports_qXfer_memory_map_read == eLazyBoolYes;
 }
 
+bool GDBRemoteCommunicationClient::GetWasmFeaturesSupported() {
+  if (m_supports_wasm == eLazyBoolCalculate) {
+    GetRemoteQSupported();
+  }
+  return m_supports_wasm == eLazyBoolYes;
+}
+
 uint64_t GDBRemoteCommunicationClient::GetRemoteMaxPacketSize() {
   if (m_max_packet_size == 0) {
     GetRemoteQSupported();
@@ -342,6 +349,7 @@
   m_supports_augmented_libraries_svr4_read = eLazyBoolNo;
   m_supports_qXfer_features_read = eLazyBoolNo;
   m_supports_qXfer_memory_map_read = eLazyBoolNo;
+  m_supports_wasm = eLazyBoolNo;
   m_max_packet_size = UINT64_MAX; // It's supposed to always be there, but if
                                   // not, we assume no limit
 
@@ -433,6 +441,11 @@
     else
       m_supports_QPassSignals = eLazyBoolNo;
 
+    if (::strstr(response_cstr, "wasm+"))
+      m_supports_wasm = eLazyBoolYes;
+    else
+      m_supports_wasm = eLazyBoolNo;
+
     const char *packet_size_str = ::strstr(response_cstr, "PacketSize=");
     if (packet_size_str) {
       StringExtractorGDBRemote packet_response(packet_size_str +
@@ -2694,6 +2707,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<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 (SendPacketAndWaitForResponse(packet, response, true) ==
+      PacketResult::Success) {
+    if (response.IsNormalResponse()) {
+      return buffer_size ==
+             response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
+                                      static_cast<uint8_t *>(buf), buffer_size),
+                                  '\xdd');
+    }
+  }
+  return false;
+}
+
+bool GDBRemoteCommunicationClient::GetWasmCallStack(
+    std::vector<lldb::addr_t> &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>((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));
Index: lldb/source/Expression/DWARFExpression.cpp
===================================================================
--- lldb/source/Expression/DWARFExpression.cpp
+++ lldb/source/Expression/DWARFExpression.cpp
@@ -36,6 +36,7 @@
 #include "lldb/Target/Target.h"
 #include "lldb/Target/Thread.h"
 
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.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) {
+          process_gdb_remote::ProcessGDBRemote *wasm_process =
+              static_cast<process_gdb_remote::ProcessGDBRemote *>(
+                  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
Index: lldb/source/Core/Value.cpp
===================================================================
--- lldb/source/Core/Value.cpp
+++ lldb/source/Core/Value.cpp
@@ -30,6 +30,8 @@
 #include "lldb/lldb-forward.h"
 #include "lldb/lldb-types.h"
 
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+
 #include <memory>
 #include <string>
 
@@ -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();
+            process_gdb_remote::ProcessGDBRemote *wasm_process =
+                static_cast<process_gdb_remote::ProcessGDBRemote *>(
+                    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)",
Index: lldb/include/lldb/Target/UnwindWasm.h
===================================================================
--- /dev/null
+++ 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
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to