[llvm] [clang] [lldb] [clang-tools-extra] [lldb] Support DW_OP_WASM_location in DWARFExpression (PR #78977)

Paolo Severini via cfe-commits cfe-commits at lists.llvm.org
Mon Feb 5 07:48:48 PST 2024


https://github.com/paolosevMSFT updated https://github.com/llvm/llvm-project/pull/78977

>From 4bcf2b50123b18752108aad163a059577e360aa6 Mon Sep 17 00:00:00 2001
From: Paolo Severini <paolosev at microsoft.com>
Date: Mon, 22 Jan 2024 06:06:56 -0800
Subject: [PATCH 1/3] Add support for DW_OP_WASM_location to DWARFExpression

---
 lldb/source/Expression/DWARFExpression.cpp | 41 ++++++++++++++++++++++
 1 file changed, 41 insertions(+)

diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index fe4928d4f43a4..95033db5ed8f5 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -346,6 +346,16 @@ 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 +2605,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 = 2; // Global
+      } 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(

>From 639295de7bdd4a2e710b62337a511ded92eb702a Mon Sep 17 00:00:00 2001
From: Paolo Severini <paolosev at microsoft.com>
Date: Mon, 29 Jan 2024 06:25:58 -0800
Subject: [PATCH 2/3] Add unite tests

---
 .../include/lldb/Expression/DWARFExpression.h |   5 +
 lldb/source/Expression/DWARFExpression.cpp    |  53 +-
 .../ObjectFile/wasm/ObjectFileWasm.cpp        |   6 +-
 .../SymbolFile/DWARF/SymbolFileDWARF.cpp      |  66 ++
 .../SymbolFile/DWARF/SymbolFileDWARF.h        |  27 +-
 .../SymbolFile/DWARF/SymbolFileDWARFDwo.cpp   |   8 +-
 .../SymbolFile/DWARF/SymbolFileDWARFDwo.h     |   8 +-
 lldb/unittests/Expression/CMakeLists.txt      |   2 +
 .../Expression/DWARFExpressionTest.cpp        | 562 ++++++++++++++----
 9 files changed, 580 insertions(+), 157 deletions(-)

diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h
index 1d85308d1caa7..73143399ff147 100644
--- a/lldb/include/lldb/Expression/DWARFExpression.h
+++ b/lldb/include/lldb/Expression/DWARFExpression.h
@@ -153,6 +153,11 @@ class DWARFExpression {
 
   bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op) const;
 
+  static bool ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
+                                        lldb::RegisterKind reg_kind,
+                                        uint32_t reg_num, Status *error_ptr,
+                                        Value &value);
+
 private:
   /// A data extractor capable of reading opcode bytes
   DataExtractor m_data;
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 95033db5ed8f5..7298ccbf998d4 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -95,10 +95,12 @@ void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) {
 }
 
 
-static bool ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
-                                      lldb::RegisterKind reg_kind,
-                                      uint32_t reg_num, Status *error_ptr,
-                                      Value &value) {
+// static
+bool DWARFExpression::ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
+                                                lldb::RegisterKind reg_kind,
+                                                uint32_t reg_num,
+                                                Status *error_ptr,
+                                                Value &value) {
   if (reg_ctx == nullptr) {
     if (error_ptr)
       error_ptr->SetErrorString("No register context in frame.\n");
@@ -346,16 +348,6 @@ 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;
@@ -2605,41 +2597,10 @@ 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 = 2; // Global
-      } 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(
-                op, opcodes, offset, stack)) {
+                op, reg_ctx, opcodes, reg_kind, offset, stack, error_ptr)) {
           break;
         }
       }
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index 06eb6ff9cafb5..cf643ba51280d 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -406,9 +406,13 @@ DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
         DataBufferSP buffer_sp(data_up.release());
         data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
       }
+    } else if (offset < m_data.GetByteSize()) {
+      size =
+          std::min(static_cast<uint64_t>(size), m_data.GetByteSize() - offset);
+      return DataExtractor(m_data.GetDataStart() + offset, size, GetByteOrder(),
+                           GetAddressByteSize());
     }
   }
-
   data.SetByteOrder(GetByteOrder());
   return data;
 }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index fed97858c83f8..72a831a8ab411 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -31,6 +31,7 @@
 
 #include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h"
 #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h"
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
 
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/Host.h"
@@ -327,6 +328,9 @@ llvm::StringRef SymbolFileDWARF::GetPluginDescriptionStatic() {
 }
 
 SymbolFile *SymbolFileDWARF::CreateInstance(ObjectFileSP objfile_sp) {
+  if (llvm::isa<lldb_private::wasm::ObjectFileWasm>(*objfile_sp))
+    return new wasm::SymbolFileWasm(std::move(objfile_sp),
+                              /*dwo_section_list*/ nullptr);
   return new SymbolFileDWARF(std::move(objfile_sp),
                              /*dwo_section_list*/ nullptr);
 }
@@ -4476,3 +4480,65 @@ void SymbolFileDWARF::GetCompileOptions(
     args.insert({comp_unit, Args(flags)});
   }
 }
+
+using namespace lldb_private::plugin::dwarf::wasm;
+
+SymbolFileWasm::SymbolFileWasm(ObjectFileSP objfile_sp,
+                               SectionList *dwo_section_list)
+    : SymbolFileDWARF(objfile_sp, dwo_section_list) {}
+
+SymbolFileWasm::~SymbolFileWasm() = default;
+
+lldb::offset_t
+SymbolFileWasm::GetVendorDWARFOpcodeSize(const DataExtractor &data,
+                                         const lldb::offset_t data_offset,
+                                         const uint8_t op) const {
+  if (op != DW_OP_WASM_location) {
+    return LLDB_INVALID_OFFSET;
+  }
+
+  lldb::offset_t offset = data_offset;
+  uint8_t wasm_op = data.GetU8(&offset);
+  if (wasm_op == 3) {
+    data.GetU32(&offset);
+  } else {
+    data.GetULEB128(&offset);
+  }
+  return offset - data_offset;
+}
+
+bool SymbolFileWasm::ParseVendorDWARFOpcode(
+    uint8_t op, RegisterContext *reg_ctx, const DataExtractor &opcodes,
+    const lldb::RegisterKind reg_kind, lldb::offset_t &offset,
+    std::vector<Value> &stack, Status *error_ptr) const {
+  uint8_t wasm_op = opcodes.GetU8(&offset);
+
+  /* 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
+   */
+  uint32_t index;
+  if (wasm_op == 3) {
+    index = opcodes.GetU32(&offset);
+    wasm_op = 2; // Global
+  } else {
+    index = opcodes.GetULEB128(&offset);
+  }
+
+  uint32_t reg_num = (((wasm_op + 1) & 0x03) << 30) | (index & 0x3fffffff);
+
+  Value tmp;
+  if (DWARFExpression::ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num,
+                                                 error_ptr, tmp)) {
+    stack.push_back(tmp);
+    return true;
+  }
+  else
+    return false;
+}
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
index 26a9502f90aa0..daacad8af46d5 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -305,9 +305,12 @@ class SymbolFileDWARF : public SymbolFileCommon {
     return LLDB_INVALID_OFFSET;
   }
 
-  virtual bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
+  virtual bool ParseVendorDWARFOpcode(uint8_t op, RegisterContext *reg_ctx,
+                                      const DataExtractor &opcodes,
+                                      const lldb::RegisterKind reg_kind,
                                       lldb::offset_t &offset,
-                                      std::vector<Value> &stack) const {
+                                      std::vector<Value> &stack,
+                                      Status *error_ptr) const {
     return false;
   }
 
@@ -547,6 +550,26 @@ class SymbolFileDWARF : public SymbolFileCommon {
   /// an index that identifies the .DWO or .o file.
   std::optional<uint64_t> m_file_index;
 };
+
+namespace wasm {
+class SymbolFileWasm : public SymbolFileDWARF {
+public:
+  SymbolFileWasm(lldb::ObjectFileSP objfile_sp, SectionList *dwo_section_list);
+
+  ~SymbolFileWasm() override;
+
+  lldb::offset_t GetVendorDWARFOpcodeSize(const DataExtractor &data,
+                                          const lldb::offset_t data_offset,
+                                          const uint8_t op) const override;
+
+  bool ParseVendorDWARFOpcode(uint8_t op, RegisterContext *reg_ctx,
+                              const DataExtractor &opcodes,
+                              const lldb::RegisterKind reg_kind,
+                              lldb::offset_t &offset, std::vector<Value> &stack,
+                              Status *error_ptr) const override;
+};
+} // namespace wasm
+
 } // namespace dwarf
 } // namespace lldb_private::plugin
 
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
index ca698a84a9146..379b98ff9b561 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp
@@ -86,9 +86,11 @@ lldb::offset_t SymbolFileDWARFDwo::GetVendorDWARFOpcodeSize(
 }
 
 bool SymbolFileDWARFDwo::ParseVendorDWARFOpcode(
-    uint8_t op, const lldb_private::DataExtractor &opcodes,
-    lldb::offset_t &offset, std::vector<lldb_private::Value> &stack) const {
-  return GetBaseSymbolFile().ParseVendorDWARFOpcode(op, opcodes, offset, stack);
+    uint8_t op, RegisterContext *reg_ctx, const DataExtractor &opcodes,
+    const lldb::RegisterKind reg_kind, lldb::offset_t &offset,
+    std::vector<Value> &stack, Status *error_ptr) const {
+  return GetBaseSymbolFile().ParseVendorDWARFOpcode(
+      op, reg_ctx, opcodes, reg_kind, offset, stack, error_ptr);
 }
 
 SymbolFileDWARF::DIEToTypePtr &SymbolFileDWARFDwo::GetDIEToType() {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
index 9f5950e51b0c1..1025fc47c28ff 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h
@@ -47,9 +47,11 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF {
                                           const lldb::offset_t data_offset,
                                           const uint8_t op) const override;
 
-  bool ParseVendorDWARFOpcode(uint8_t op, const DataExtractor &opcodes,
-                              lldb::offset_t &offset,
-                              std::vector<Value> &stack) const override;
+  bool ParseVendorDWARFOpcode(uint8_t op, RegisterContext *reg_ctx,
+                              const DataExtractor &opcodes,
+                              const lldb::RegisterKind reg_kind,
+                              lldb::offset_t &offset, std::vector<Value> &stack,
+                              Status *error_ptr) const override;
 
   void FindGlobalVariables(ConstString name,
                            const CompilerDeclContext &parent_decl_ctx,
diff --git a/lldb/unittests/Expression/CMakeLists.txt b/lldb/unittests/Expression/CMakeLists.txt
index 185b19f84cae7..533cdc673e6d1 100644
--- a/lldb/unittests/Expression/CMakeLists.txt
+++ b/lldb/unittests/Expression/CMakeLists.txt
@@ -8,6 +8,8 @@ add_lldb_unittest(ExpressionTests
   LINK_LIBS
     lldbCore
     lldbPluginObjectFileELF
+    lldbPluginObjectFileWasm
+    lldbPluginSymbolVendorWasm
     lldbPluginPlatformLinux
     lldbPluginExpressionParserClang
     lldbPluginTypeSystemClang
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 8d77d6b2585f1..82bcf9695a176 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -7,9 +7,11 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Expression/DWARFExpression.h"
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
 #include "Plugins/Platform/Linux/PlatformLinux.h"
 #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h"
 #include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h"
+#include "Plugins/SymbolVendor/wasm/SymbolVendorWasm.h"
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "TestingSupport/Symbol/YAMLModuleTester.h"
 #include "lldb/Core/Debugger.h"
@@ -18,6 +20,8 @@
 #include "lldb/Core/dwarf.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/RegisterValue.h"
 #include "lldb/Utility/StreamString.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/Testing/Support/Error.h"
@@ -26,20 +30,22 @@
 using namespace lldb_private;
 using namespace lldb_private::dwarf;
 using namespace lldb_private::plugin::dwarf;
+using namespace lldb_private::plugin::dwarf::wasm;
+using namespace lldb_private::wasm;
 
 static llvm::Expected<Scalar> Evaluate(llvm::ArrayRef<uint8_t> expr,
                                        lldb::ModuleSP module_sp = {},
                                        DWARFUnit *unit = nullptr,
-                                       ExecutionContext *exe_ctx = nullptr) {
+                                       ExecutionContext *exe_ctx = nullptr,
+                                       RegisterContext *reg_ctx = nullptr) {
   DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
                           /*addr_size*/ 4);
   Value result;
   Status status;
-  if (!DWARFExpression::Evaluate(exe_ctx, /*reg_ctx*/ nullptr, module_sp,
-                                 extractor, unit, lldb::eRegisterKindLLDB,
-                                 /*initial_value_ptr*/ nullptr,
-                                 /*object_address_ptr*/ nullptr, result,
-                                 &status))
+  if (!DWARFExpression::Evaluate(
+          exe_ctx, reg_ctx, module_sp, extractor, unit, lldb::eRegisterKindLLDB,
+          /*initial_value_ptr*/ nullptr,
+          /*object_address_ptr*/ nullptr, result, &status))
     return status.ToError();
 
   switch (result.GetValueType()) {
@@ -341,32 +347,33 @@ TEST(DWARFExpression, DW_OP_unknown) {
           "Unhandled opcode DW_OP_unknown_ff in DWARFExpression"));
 }
 
-TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
-  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());
+namespace {
+struct MockProcess : Process {
+  MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
+      : Process(target_sp, listener_sp) {}
 
-  struct MockProcess : Process {
-    MockProcess(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp)
-        : Process(target_sp, listener_sp) {}
-
-    llvm::StringRef GetPluginName() override { return "mock process"; }
-    bool CanDebug(lldb::TargetSP target,
-                  bool plugin_specified_by_name) override {
-      return false;
-    };
-    Status DoDestroy() override { return {}; }
-    void RefreshStateAfterStop() override {}
-    bool DoUpdateThreadList(ThreadList &old_thread_list,
-                            ThreadList &new_thread_list) override {
-      return false;
-    };
-    size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
-                        Status &error) override {
-      for (size_t i = 0; i < size; ++i)
-        ((char *)buf)[i] = (vm_addr + i) & 0xff;
-      error.Clear();
-      return size;
-    }
+  llvm::StringRef GetPluginName() override { return "mock process"; }
+  bool CanDebug(lldb::TargetSP target, bool plugin_specified_by_name) override {
+    return false;
+  };
+  Status DoDestroy() override { return {}; }
+  void RefreshStateAfterStop() override {}
+  bool DoUpdateThreadList(ThreadList &old_thread_list,
+                          ThreadList &new_thread_list) override {
+    return false;
   };
+  size_t DoReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+                      Status &error) override {
+    for (size_t i = 0; i < size; ++i)
+      ((char *)buf)[i] = (vm_addr + i) & 0xff;
+    error.Clear();
+    return size;
+  }
+};
+} // namespace
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());
 
   // Set up a mock process.
   ArchSpec arch("i386-pc-linux");
@@ -529,7 +536,7 @@ TEST_F(DWARFExpressionMockProcessTest, WASM_DW_OP_addr_index) {
   ASSERT_EQ(result.GetValueType(), Value::ValueType::LoadAddress);
   ASSERT_EQ(result.GetScalar().UInt(), 0xdeadbeefu);
 }
-
+/*
 class CustomSymbolFileDWARF : public SymbolFileDWARF {
   static char ID;
 
@@ -557,82 +564,12 @@ class CustomSymbolFileDWARF : public SymbolFileDWARF {
 
   static lldb_private::SymbolFile *
   CreateInstance(lldb::ObjectFileSP objfile_sp) {
-    return new CustomSymbolFileDWARF(std::move(objfile_sp),
-                                     /*dwo_section_list*/ nullptr);
-  }
-
-  lldb::offset_t
-  GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data,
-                           const lldb::offset_t data_offset,
-                           const uint8_t op) const final {
-    auto offset = data_offset;
-    if (op != DW_OP_WASM_location) {
-      return LLDB_INVALID_OFFSET;
-    }
-
-    // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32
-    // Called with "arguments" 0x03 and 0x04
-    // Location type:
-    if (data.GetU8(&offset) != /* global */ 0x03) {
-      return LLDB_INVALID_OFFSET;
-    }
-
-    // Index
-    if (data.GetU32(&offset) != 0x04) {
-      return LLDB_INVALID_OFFSET;
-    }
-
-    // Report the skipped distance:
-    return offset - data_offset;
-  }
-
-  bool
-  ParseVendorDWARFOpcode(uint8_t op, const lldb_private::DataExtractor &opcodes,
-                         lldb::offset_t &offset,
-                         std::vector<lldb_private::Value> &stack) const final {
-    if (op != DW_OP_WASM_location) {
-      return false;
-    }
-
-    // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32
-    // Called with "arguments" 0x03 and  0x04
-    // Location type:
-    if (opcodes.GetU8(&offset) != /* global */ 0x03) {
-      return false;
-    }
-
-    // Index:
-    if (opcodes.GetU32(&offset) != 0x04) {
-      return false;
-    }
-
-    // Return some value:
-    stack.push_back({GetScalar(32, 42, false)});
-    return true;
+    return new CustomSymbolFileDWARF(std::move(objfile_sp), nullptr);
   }
 };
 
 char CustomSymbolFileDWARF::ID;
 
-static auto testExpressionVendorExtensions(lldb::ModuleSP module_sp,
-                                           DWARFUnit &dwarf_unit) {
-  // Test that expression extensions can be evaluated, for example
-  // DW_OP_WASM_location which is not currently handled by DWARFExpression:
-  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_WASM_location, 0x03, // WASM_GLOBAL:0x03
-                                 0x04, 0x00, 0x00,          // index:u32
-                                 0x00, DW_OP_stack_value},
-                                module_sp, &dwarf_unit),
-                       llvm::HasValue(GetScalar(32, 42, false)));
-
-  // Test that searches for opcodes work in the presence of extensions:
-  uint8_t expr[] = {DW_OP_WASM_location,   0x03, 0x04, 0x00, 0x00, 0x00,
-                    DW_OP_form_tls_address};
-  DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
-                          /*addr_size*/ 4);
-  DWARFExpression dwarf_expr(extractor);
-  ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(&dwarf_unit));
-}
-
 TEST(DWARFExpression, Extensions) {
   const char *yamldata = R"(
 --- !ELF
@@ -768,3 +705,424 @@ TEST(DWARFExpression, ExtensionsDWO) {
 
   testExpressionVendorExtensions(dwo_module_sp, *dwo_dwarf_unit);
 }
+*/
+namespace {
+class MockThread : public Thread {
+public:
+  MockThread(Process &process) : Thread(process, 1 /* tid */), m_reg_ctx_sp() {}
+  ~MockThread() override { DestroyThread(); }
+
+  void RefreshStateAfterStop() override {}
+  lldb::RegisterContextSP GetRegisterContext() override { return m_reg_ctx_sp; }
+  lldb::RegisterContextSP
+  CreateRegisterContextForFrame(StackFrame *frame) override {
+    return m_reg_ctx_sp;
+  }
+  bool CalculateStopInfo() override { return false; }
+
+  void SetRegisterContext(lldb::RegisterContextSP reg_ctx_sp) {
+    m_reg_ctx_sp = reg_ctx_sp;
+  }
+
+private:
+  lldb::RegisterContextSP m_reg_ctx_sp;
+};
+
+class MockRegisterContext : public RegisterContext {
+public:
+  MockRegisterContext(Thread &thread, const RegisterValue &reg_value)
+      : RegisterContext(thread, 0 /*concrete_frame_idx*/),
+        m_reg_value(reg_value) {}
+
+  void InvalidateAllRegisters() override {}
+  size_t GetRegisterCount() override { return 0; }
+  const RegisterInfo *GetRegisterInfoAtIndex(size_t reg) override {
+    if (reg == 0x4000002a) {
+      return &m_reg_info;
+    }
+    return &m_reg_info; /* nullptr; */
+  }
+  size_t GetRegisterSetCount() override { return 0; }
+  const RegisterSet *GetRegisterSet(size_t reg_set) override { return nullptr; }
+  lldb::ByteOrder GetByteOrder() override {
+    return lldb::ByteOrder::eByteOrderLittle;
+  }
+  bool ReadRegister(const RegisterInfo *reg_info,
+                    RegisterValue &reg_value) override {
+    reg_value = m_reg_value;
+    return true;
+  }
+  bool WriteRegister(const RegisterInfo *reg_info,
+                     const RegisterValue &reg_value) override {
+    return false;
+  }
+  uint32_t ConvertRegisterKindToRegisterNumber(lldb::RegisterKind kind,
+                                               uint32_t num) override {
+    return num;
+  }
+
+private:
+  RegisterInfo m_reg_info;
+  RegisterValue m_reg_value;
+};
+
+static auto testExpressionVendorExtensions(lldb::ModuleSP module_sp,
+                                           DWARFUnit &dwarf_unit,
+                                           RegisterContext *reg_ctx) {
+  // Test that expression extensions can be evaluated, for example
+  // DW_OP_WASM_location which is not currently handled by DWARFExpression:
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_WASM_location, 0x03, // WASM_GLOBAL:0x03
+                                 0x04, 0x00, 0x00,          // index:u32
+                                 0x00, DW_OP_stack_value},
+                                module_sp, &dwarf_unit, nullptr, reg_ctx),
+                       llvm::HasValue(GetScalar(32, 42, false)));
+
+  // Test that searches for opcodes work in the presence of extensions:
+  uint8_t expr[] = {DW_OP_WASM_location,   0x03, 0x04, 0x00, 0x00, 0x00,
+                    DW_OP_form_tls_address};
+  DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle,
+                          /*addr_size*/ 4);
+  DWARFExpression dwarf_expr(extractor);
+  ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(&dwarf_unit));
+}
+} // namespace;
+
+TEST(DWARFExpression, Extensions) {
+  const char *yamldata = R"(
+--- !WASM
+FileHeader:
+  Version:         0x1
+Sections:
+  - Type:            TYPE
+    Signatures:
+      - Index:           0
+        ParamTypes:
+          - I32
+        ReturnTypes:
+          - I32
+  - Type:            FUNCTION
+    FunctionTypes:   [ 0 ]
+  - Type:            TABLE
+    Tables:
+      - Index:           0
+        ElemType:        FUNCREF
+        Limits:
+          Flags:           [ HAS_MAX ]
+          Minimum:         0x1
+          Maximum:         0x1
+  - Type:            MEMORY
+    Memories:
+      - Flags:           [ HAS_MAX ]
+        Minimum:         0x100
+        Maximum:         0x100
+  - Type:            GLOBAL
+    Globals:
+      - Index:           0
+        Type:            I32
+        Mutable:         true
+        InitExpr:
+          Opcode:          I32_CONST
+          Value:           65536
+  - Type:            EXPORT
+    Exports:
+      - Name:            memory
+        Kind:            MEMORY
+        Index:           0
+      - Name:            square
+        Kind:            FUNCTION
+        Index:           0
+      - Name:            __indirect_function_table
+        Kind:            TABLE
+        Index:           0
+  - Type:            CODE
+    Functions:
+      - Index:           0
+        Locals:
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+        Body:            2300210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B
+  - Type:            CUSTOM
+    Name:            name
+    FunctionNames:
+      - Index:           0
+        Name:            square
+    GlobalNames:
+      - Index:           0
+        Name:            __stack_pointer
+  - Type:            CUSTOM
+    Name:            .debug_abbrev
+    Payload:         011101250E1305030E10171B0E110112060000022E01110112064018030E3A0B3B0B271949133F1900000305000218030E3A0B3B0B49130000042400030E3E0B0B0B000000
+  - Type:            CUSTOM
+    Name:            .debug_info
+    Payload:         510000000400000000000401670000001D005E000000000000000A000000020000003C00000002020000003C00000004ED00039F5700000001014D0000000302910C0400000001014D000000000400000000050400
+  - Type:            CUSTOM
+    Name:            .debug_str
+    Payload:         696E740076616C756500513A5C70616F6C6F7365764D5346545C6C6C766D2D70726F6A6563745C6C6C64625C746573745C4150495C66756E6374696F6E616C69746965735C6764625F72656D6F74655F636C69656E745C737175617265007371756172652E6300636C616E672076657273696F6E2031382E302E30202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A65637420373535303166353336323464653932616166636532663164613639386232343961373239336463372900
+  - Type:            CUSTOM
+    Name:            .debug_line
+    Payload:         64000000040020000000010101FB0E0D000101010100000001000001007371756172652E6300000000000005020200000001000502250000000301050A0A010005022C00000005120601000502330000000510010005023A0000000503010005023E000000000101
+)";
+
+  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> mem_fs =
+      new llvm::vfs::InMemoryFileSystem();
+  FileSystem::Initialize(mem_fs);
+  {
+    SubsystemRAII<HostInfo, ObjectFileWasm, SymbolVendorWasm> subsystems;
+
+    // Set up a wasm target
+    ArchSpec arch("wasm32-unknown-unknown-wasm");
+    lldb::PlatformSP host_platform_sp =
+        platform_linux::PlatformLinux::CreateInstance(true, &arch);
+    ASSERT_TRUE(host_platform_sp);
+    Platform::SetHostPlatform(host_platform_sp);
+    lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
+    ASSERT_TRUE(debugger_sp);
+    lldb::TargetSP target_sp;
+    lldb::PlatformSP platform_sp;
+    debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch,
+                                              lldb_private::eLoadDependentsNo,
+                                              platform_sp, target_sp);
+    // Set up a mock process and thread.
+    lldb::ListenerSP listener_sp(Listener::MakeListener("dummy"));
+    lldb::ProcessSP process_sp =
+        std::make_shared<MockProcess>(target_sp, listener_sp);
+    ASSERT_TRUE(process_sp);
+    MockThread thread(*process_sp);
+    const uint32_t kExpectedValue = 42;
+    lldb::RegisterContextSP reg_ctx_sp = std::make_shared<MockRegisterContext>(
+        thread, RegisterValue(kExpectedValue));
+    thread.SetRegisterContext(reg_ctx_sp);
+
+    llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata);
+    EXPECT_THAT_EXPECTED(file, llvm::Succeeded());
+    auto module_sp = std::make_shared<Module>(file->moduleSpec());
+    auto obj_file_sp = module_sp->GetObjectFile()->shared_from_this();
+    SymbolFileWasm sym_file_wasm(obj_file_sp, nullptr);
+    auto *dwarf_unit = sym_file_wasm.DebugInfo().GetUnitAtIndex(0);
+
+    testExpressionVendorExtensions(module_sp, *dwarf_unit, reg_ctx_sp.get());
+  }
+  FileSystem::Terminate();
+}
+
+TEST(DWARFExpression, ExtensionsSplitSymbols) {
+  const char *skeleton_yamldata = R"(
+--- !WASM
+FileHeader:
+  Version:         0x1
+Sections:
+  - Type:            TYPE
+    Signatures:
+      - Index:           0
+        ParamTypes:
+          - I32
+        ReturnTypes:
+          - I32
+  - Type:            FUNCTION
+    FunctionTypes:   [ 0 ]
+  - Type:            TABLE
+    Tables:
+      - Index:           0
+        ElemType:        FUNCREF
+        Limits:
+          Flags:           [ HAS_MAX ]
+          Minimum:         0x1
+          Maximum:         0x1
+  - Type:            MEMORY
+    Memories:
+      - Flags:           [ HAS_MAX ]
+        Minimum:         0x100
+        Maximum:         0x100
+  - Type:            GLOBAL
+    Globals:
+      - Index:           0
+        Type:            I32
+        Mutable:         true
+        InitExpr:
+          Opcode:          I32_CONST
+          Value:           65536
+  - Type:            EXPORT
+    Exports:
+      - Name:            memory
+        Kind:            MEMORY
+        Index:           0
+      - Name:            square
+        Kind:            FUNCTION
+        Index:           0
+      - Name:            __indirect_function_table
+        Kind:            TABLE
+        Index:           0
+  - Type:            CODE
+    Functions:
+      - Index:           0
+        Locals:
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+        Body:            2300210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B
+  - Type:            CUSTOM
+    Name:            name
+    FunctionNames:
+      - Index:           0
+        Name:            square
+    GlobalNames:
+      - Index:           0
+        Name:            __stack_pointer
+  - Type:            CUSTOM
+    Name:            external_debug_info
+    Payload:         167371756172652E7761736D2E64656275672E7761736D
+)";
+
+  const char *sym_yamldata = R"(
+--- !WASM
+FileHeader:
+  Version:         0x1
+Sections:
+  - Type:            TYPE
+    Signatures:
+      - Index:           0
+        ParamTypes:
+          - I32
+        ReturnTypes:
+          - I32
+  - Type:            FUNCTION
+    FunctionTypes:   [ 0 ]
+  - Type:            TABLE
+    Tables:
+      - Index:           0
+        ElemType:        FUNCREF
+        Limits:
+          Flags:           [ HAS_MAX ]
+          Minimum:         0x1
+          Maximum:         0x1
+  - Type:            MEMORY
+    Memories:
+      - Flags:           [ HAS_MAX ]
+        Minimum:         0x100
+        Maximum:         0x100
+  - Type:            GLOBAL
+    Globals:
+      - Index:           0
+        Type:            I32
+        Mutable:         true
+        InitExpr:
+          Opcode:          I32_CONST
+          Value:           65536
+  - Type:            EXPORT
+    Exports:
+      - Name:            memory
+        Kind:            MEMORY
+        Index:           0
+      - Name:            square
+        Kind:            FUNCTION
+        Index:           0
+      - Name:            __indirect_function_table
+        Kind:            TABLE
+        Index:           0
+  - Type:            CODE
+    Functions:
+      - Index:           0
+        Locals:
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+          - Type:            I32
+            Count:           1
+        Body:            2300210141102102200120026B21032003200036020C200328020C2104200328020C2105200420056C210620060F0B
+  - Type:            CUSTOM
+    Name:            name
+    FunctionNames:
+      - Index:           0
+        Name:            square
+    GlobalNames:
+      - Index:           0
+        Name:            __stack_pointer
+  - Type:            CUSTOM
+    Name:            .debug_abbrev
+    Payload:         011101250E1305030E10171B0E110112060000022E01110112064018030E3A0B3B0B271949133F1900000305000218030E3A0B3B0B49130000042400030E3E0B0B0B000000
+  - Type:            CUSTOM
+    Name:            .debug_info
+    Payload:         510000000400000000000401670000001D005E0000000000000004000000020000003C00000002020000003C00000004ED00039F5700000001014D0000000302910C5100000001014D000000000400000000050400
+  - Type:            CUSTOM
+    Name:            .debug_str
+    Payload:         696E7400513A5C70616F6C6F7365764D5346545C6C6C766D2D70726F6A6563745C6C6C64625C746573745C4150495C66756E6374696F6E616C69746965735C6764625F72656D6F74655F636C69656E740076616C756500737175617265007371756172652E6300636C616E672076657273696F6E2031382E302E30202868747470733A2F2F6769746875622E636F6D2F6C6C766D2F6C6C766D2D70726F6A65637420373535303166353336323464653932616166636532663164613639386232343961373239336463372900
+  - Type:            CUSTOM
+    Name:            .debug_line
+    Payload:         64000000040020000000010101FB0E0D000101010100000001000001007371756172652E6300000000000005020200000001000502250000000301050A0A010005022C00000005120601000502330000000510010005023A0000000503010005023E000000000101
+)";
+
+  llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> mem_fs =
+      new llvm::vfs::InMemoryFileSystem();
+  FileSystem::Initialize(mem_fs);
+  {
+    SubsystemRAII<HostInfo, ObjectFileWasm, SymbolVendorWasm> subsystems;
+
+    // Set up a wasm target
+    ArchSpec arch("wasm32-unknown-unknown-wasm");
+    lldb::PlatformSP host_platform_sp =
+        platform_linux::PlatformLinux::CreateInstance(true, &arch);
+    ASSERT_TRUE(host_platform_sp);
+    Platform::SetHostPlatform(host_platform_sp);
+    lldb::DebuggerSP debugger_sp = Debugger::CreateInstance();
+    ASSERT_TRUE(debugger_sp);
+    lldb::TargetSP target_sp;
+    lldb::PlatformSP platform_sp;
+    debugger_sp->GetTargetList().CreateTarget(*debugger_sp, "", arch,
+                                              lldb_private::eLoadDependentsNo,
+                                              platform_sp, target_sp);
+    // Set up a mock process and thread.
+    lldb::ListenerSP listener_sp(Listener::MakeListener("dummy"));
+    lldb::ProcessSP process_sp =
+        std::make_shared<MockProcess>(target_sp, listener_sp);
+    ASSERT_TRUE(process_sp);
+    MockThread thread(*process_sp);
+    const uint32_t kExpectedValue = 42;
+    lldb::RegisterContextSP reg_ctx_sp = std::make_shared<MockRegisterContext>(
+        thread, RegisterValue(kExpectedValue));
+    thread.SetRegisterContext(reg_ctx_sp);
+
+    llvm::Expected<TestFile> skeleton_file =
+        TestFile::fromYaml(skeleton_yamldata);
+    EXPECT_THAT_EXPECTED(skeleton_file, llvm::Succeeded());
+    auto skeleton_module_sp =
+        std::make_shared<Module>(skeleton_file->moduleSpec());
+
+    llvm::Expected<TestFile> sym_file = TestFile::fromYaml(sym_yamldata);
+    EXPECT_THAT_EXPECTED(sym_file, llvm::Succeeded());
+    auto sym_module_sp = std::make_shared<Module>(sym_file->moduleSpec());
+
+    auto obj_file_sp = sym_module_sp->GetObjectFile()->shared_from_this();
+    SymbolFileWasm sym_file_wasm(obj_file_sp, nullptr);
+    auto *dwarf_unit = sym_file_wasm.DebugInfo().GetUnitAtIndex(0);
+
+    testExpressionVendorExtensions(sym_module_sp, *dwarf_unit,
+                                   reg_ctx_sp.get());
+  }
+  FileSystem::Terminate();
+}

>From 47f7d53fb008e7e0ed686afd68b3561703610237 Mon Sep 17 00:00:00 2001
From: Paolo Severini <paolosev at microsoft.com>
Date: Mon, 29 Jan 2024 06:50:25 -0800
Subject: [PATCH 3/3] Fix typo and formatting

---
 lldb/source/Expression/DWARFExpression.cpp               | 1 -
 lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp | 9 ++++++---
 lldb/unittests/Expression/DWARFExpressionTest.cpp        | 2 +-
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 7298ccbf998d4..f2c39fe991598 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -94,7 +94,6 @@ void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) {
   m_reg_kind = reg_kind;
 }
 
-
 // static
 bool DWARFExpression::ReadRegisterValueAsScalar(RegisterContext *reg_ctx,
                                                 lldb::RegisterKind reg_kind,
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index 72a831a8ab411..c52bc14970e74 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -330,7 +330,7 @@ llvm::StringRef SymbolFileDWARF::GetPluginDescriptionStatic() {
 SymbolFile *SymbolFileDWARF::CreateInstance(ObjectFileSP objfile_sp) {
   if (llvm::isa<lldb_private::wasm::ObjectFileWasm>(*objfile_sp))
     return new wasm::SymbolFileWasm(std::move(objfile_sp),
-                              /*dwo_section_list*/ nullptr);
+                                    /*dwo_section_list*/ nullptr);
   return new SymbolFileDWARF(std::move(objfile_sp),
                              /*dwo_section_list*/ nullptr);
 }
@@ -4511,6 +4511,10 @@ bool SymbolFileWasm::ParseVendorDWARFOpcode(
     uint8_t op, RegisterContext *reg_ctx, const DataExtractor &opcodes,
     const lldb::RegisterKind reg_kind, lldb::offset_t &offset,
     std::vector<Value> &stack, Status *error_ptr) const {
+  if (op != DW_OP_WASM_location) {
+    return false;
+  }
+
   uint8_t wasm_op = opcodes.GetU8(&offset);
 
   /* LLDB doesn't have an address space to represents WebAssembly locals,
@@ -4538,7 +4542,6 @@ bool SymbolFileWasm::ParseVendorDWARFOpcode(
                                                  error_ptr, tmp)) {
     stack.push_back(tmp);
     return true;
-  }
-  else
+  } else
     return false;
 }
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 82bcf9695a176..065492bf41d8b 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -785,7 +785,7 @@ static auto testExpressionVendorExtensions(lldb::ModuleSP module_sp,
   DWARFExpression dwarf_expr(extractor);
   ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(&dwarf_unit));
 }
-} // namespace;
+} // namespace
 
 TEST(DWARFExpression, Extensions) {
   const char *yamldata = R"(



More information about the cfe-commits mailing list