paolosev created this revision.
paolosev added reviewers: clayborg, labath.
paolosev added a project: LLDB.
Herald added subscribers: lldb-commits, sunfish, aheejin, jgravelle-google, 
sbc100, aprantl, mgorny.
paolosev marked 2 inline comments as done.
paolosev added a comment.

What is the best way to test classes WasmProcessGDBRemote and UnwindWasm?



================
Comment at: lldb/source/Plugins/Process/wasm/ProcessWasm.cpp:92
+                                        size_t buffer_size, size_t &size) {
+  // TODO(paolosev): Implement in GDBRemoteComunicationClient
+  return false;
----------------
This will be implemented as:
```
  return GetGDBRemote().GetWasmLocal(frame_index, index, buf, buffer_size, 
size);
```
as soon as `GetWasmLocal` can be added to GDBRemoteCommunicationClient.


================
Comment at: lldb/source/Plugins/Process/wasm/UnwindWasm.cpp:34-35
+
+    IWasmProcess *wasm_process =
+        static_cast<WasmProcessGDBRemote *>(GetThread().GetProcess().get());
+    if (wasm_process)
----------------
This cast works but it is ugly. Is there a better coding pattern I could use 
here?


This is the fourth in a series of patches to enable LLDB debugging of 
WebAssembly code that runs in a WebAssembly engine. Previous patches added 
ObjectFile, SymbolVendor and DynamicLoader plugin classes for Wasm, see:  
D71575 <https://reviews.llvm.org/D71575>, D72751 
<https://reviews.llvm.org/D72751>, D72650 <https://reviews.llvm.org/D72650>.

The idea 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. This patch introduce a new Process plugin //wasm//, 
with:

- class `IWasmProcess` that defines the interface with functions to access the 
Wasm engine state.
- class `WasmProcessGDBRemote` that inherits from `ProcessGDBRemote` and that 
will implement `IWasmProcess` by forwarding requests to the Wasm engine through 
a GDBRemote connection.
- class `UnwindWasm` that manages stack unwinding for Wasm.

Note that the GDB-remote protocol needs to be extended with a few Wasm-specific 
custom query commands, used to access Wasm-specific constructs like the Wasm 
memory, Wasm locals and globals. A patch for this with changes to 
`GDBRemoteCommunicationClient` will be proposed separately, like also a patch 
to `DWARFExpression` to handle Wasm-specific DWARF location expression 
operators, like `DW_OP_WASM_location`.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D78801

Files:
  lldb/source/Plugins/CMakeLists.txt
  lldb/source/Plugins/Plugins.def.in
  lldb/source/Plugins/Process/CMakeLists.txt
  lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
  lldb/source/Plugins/Process/wasm/CMakeLists.txt
  lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
  lldb/source/Plugins/Process/wasm/ProcessWasm.h
  lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
  lldb/source/Plugins/Process/wasm/UnwindWasm.h
  lldb/source/Target/Thread.cpp

Index: lldb/source/Target/Thread.cpp
===================================================================
--- lldb/source/Target/Thread.cpp
+++ 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;
 }
 
Index: lldb/source/Plugins/Process/wasm/UnwindWasm.h
===================================================================
--- /dev/null
+++ 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 <vector>
+
+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<lldb::addr_t> m_frames;
+  bool m_unwind_complete;
+
+  DISALLOW_COPY_AND_ASSIGN(UnwindWasm);
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // lldb_UnwindWasm_h_
Index: lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
===================================================================
--- /dev/null
+++ 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<WasmProcessGDBRemote *>(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<WasmProcessGDBRemote *>(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
Index: lldb/source/Plugins/Process/wasm/ProcessWasm.h
===================================================================
--- /dev/null
+++ 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<lldb::addr_t> &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<lldb::addr_t> &call_stack_pcs) override;
+
+private:
+  DISALLOW_COPY_AND_ASSIGN(WasmProcessGDBRemote);
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H
Index: lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
===================================================================
--- /dev/null
+++ lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
@@ -0,0 +1,119 @@
+//===-- 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<WasmProcessGDBRemote>(target_sp, listener_sp);
+  return process_sp;
+}
+
+size_t WasmProcessGDBRemote::ReadMemory(lldb::addr_t vm_addr, void *buf,
+                                        size_t size, Status &error) {
+  // TODO(paolosev): Implement in GDBRemoteComunicationClient
+  return false;
+}
+
+lldb::RegisterContextSP
+WasmProcessGDBRemote::CreateRegisterContextForFrame(StackFrame *frame,
+                                                    lldb::addr_t pc) {
+  ThreadGDBRemote *gdb_thread =
+      static_cast<ThreadGDBRemote *>(frame->CalculateThread().get());
+  std::shared_ptr<GDBRemoteRegisterContext> reg_ctx_sp =
+      std::make_shared<GDBRemoteRegisterContext>(
+          *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) {
+  // TODO(paolosev): Implement in GDBRemoteComunicationClient
+  return false;
+}
+
+bool WasmProcessGDBRemote::GetWasmGlobal(int frame_index, int index, void *buf,
+                                         size_t buffer_size, size_t &size) {
+  // TODO(paolosev): Implement in GDBRemoteComunicationClient
+  return false;
+}
+
+bool WasmProcessGDBRemote::GetWasmStackValue(int frame_index, int index,
+                                             void *buf, size_t buffer_size,
+                                             size_t &size) {
+  // TODO(paolosev): Implement in GDBRemoteComunicationClient
+  return false;
+}
+
+bool WasmProcessGDBRemote::WasmReadMemory(int frame_index, lldb::addr_t addr,
+                                          void *buf, size_t buffer_size) {
+  // TODO(paolosev): Implement in GDBRemoteComunicationClient
+  return false;
+}
+
+bool WasmProcessGDBRemote::GetWasmCallStack(
+    std::vector<lldb::addr_t> &call_stack_pcs) {
+  // TODO(paolosev): Implement in GDBRemoteComunicationClient
+  return false;
+}
Index: lldb/source/Plugins/Process/wasm/CMakeLists.txt
===================================================================
--- /dev/null
+++ 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
+  )
Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
===================================================================
--- lldb/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
+++ 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);
 
Index: lldb/source/Plugins/Process/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/Process/CMakeLists.txt
+++ lldb/source/Plugins/Process/CMakeLists.txt
@@ -17,3 +17,4 @@
 add_subdirectory(elf-core)
 add_subdirectory(mach-core)
 add_subdirectory(minidump)
+add_subdirectory(wasm)
Index: lldb/source/Plugins/Plugins.def.in
===================================================================
--- lldb/source/Plugins/Plugins.def.in
+++ 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
Index: lldb/source/Plugins/CMakeLists.txt
===================================================================
--- lldb/source/Plugins/CMakeLists.txt
+++ 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()
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to