diff --git a/lldb/bindings/CMakeLists.txt b/lldb/bindings/CMakeLists.txt
index 9759b069fdc4..25b427f8bcf2 100644
--- a/lldb/bindings/CMakeLists.txt
+++ b/lldb/bindings/CMakeLists.txt
@@ -26,8 +26,6 @@ set(SWIG_COMMON_FLAGS
   -features autodoc
   -I${LLDB_SOURCE_DIR}/include
   -I${CMAKE_CURRENT_SOURCE_DIR}
-  -D__STDC_LIMIT_MACROS
-  -D__STDC_CONSTANT_MACROS
   ${DARWIN_EXTRAS}
 )
 
diff --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig
index c9a6d0f06056..021c7683d170 100644
--- a/lldb/bindings/interfaces.swig
+++ b/lldb/bindings/interfaces.swig
@@ -1,8 +1,5 @@
 /* Various liblldb typedefs that SWIG needs to know about.  */
 #define __extension__ /* Undefine GCC keyword to make Swig happy when processing glibc's stdint.h. */
-/* The ISO C99 standard specifies that in C++ implementations limit macros such
-   as INT32_MAX should only be defined if __STDC_LIMIT_MACROS is. */
-#define __STDC_LIMIT_MACROS
 %include "stdint.i"
 
 %include "lldb/lldb-defines.h"
diff --git a/lldb/bindings/python/python-typemaps.swig b/lldb/bindings/python/python-typemaps.swig
index b1ace4ff3b1e..5f8f4aa678c4 100644
--- a/lldb/bindings/python/python-typemaps.swig
+++ b/lldb/bindings/python/python-typemaps.swig
@@ -439,7 +439,7 @@ bool SetNumberFromPyObject<double>(double &number, PyObject *obj) {
 
 %typemap(out) lldb::FileSP {
   $result = nullptr;
-  lldb::FileSP &sp = $1;
+  const lldb::FileSP &sp = $1;
   if (sp) {
     PythonFile pyfile = unwrapOrSetPythonException(PythonFile::FromFile(*sp));
     if (!pyfile.IsValid())
diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h
index f2e2a0d22784..426d1129bd10 100644
--- a/lldb/include/lldb/Breakpoint/Breakpoint.h
+++ b/lldb/include/lldb/Breakpoint/Breakpoint.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_BREAKPOINT_BREAKPOINT_H
 #define LLDB_BREAKPOINT_BREAKPOINT_H
 
+#include <limits>
 #include <memory>
 #include <string>
 #include <unordered_set>
diff --git a/lldb/include/lldb/Core/Module.h b/lldb/include/lldb/Core/Module.h
index dd7100c4616c..97d70daadbdc 100644
--- a/lldb/include/lldb/Core/Module.h
+++ b/lldb/include/lldb/Core/Module.h
@@ -41,6 +41,7 @@
 
 namespace lldb_private {
 class CompilerDeclContext;
+class DWARFEvaluatorFactory;
 class Function;
 class Log;
 class ObjectFile;
@@ -859,6 +860,8 @@ public:
   /// Update the ArchSpec to a more specific variant.
   bool MergeArchitecture(const ArchSpec &arch_spec);
 
+  DWARFEvaluatorFactory *GetDWARFExpressionEvaluatorFactory();
+
   /// \class LookupInfo Module.h "lldb/Core/Module.h"
   /// A class that encapsulates name lookup information.
   ///
@@ -985,6 +988,8 @@ protected:
       m_first_file_changed_log : 1; /// See if the module was modified after it
                                     /// was initially opened.
 
+  std::unique_ptr<DWARFEvaluatorFactory> m_dwarf_evaluator_factory;
+
   /// Resolve a file or load virtual address.
   ///
   /// Tries to resolve \a vm_addr as a file address (if \a
diff --git a/lldb/include/lldb/Core/PluginManager.h b/lldb/include/lldb/Core/PluginManager.h
index be91929c62e1..8d876fc1fa2f 100644
--- a/lldb/include/lldb/Core/PluginManager.h
+++ b/lldb/include/lldb/Core/PluginManager.h
@@ -508,6 +508,17 @@ public:
   static bool CreateSettingForStructuredDataPlugin(
       Debugger &debugger, const lldb::OptionValuePropertiesSP &properties_sp,
       ConstString description, bool is_global_property);
+
+  // DWARFEvaluatorFactory
+  static bool
+  RegisterPlugin(ConstString name, const char *description,
+                 DWARFEvaluatorFactoryCreateInstance create_callback);
+
+  static bool
+  UnregisterPlugin(DWARFEvaluatorFactoryCreateInstance create_callback);
+
+  static DWARFEvaluatorFactoryCreateInstance
+  GetDWARFEvaluatorFactoryCreateCallbackAtIndex(uint32_t idx);
 };
 
 } // namespace lldb_private
diff --git a/lldb/include/lldb/Expression/DWARFEvaluator.h b/lldb/include/lldb/Expression/DWARFEvaluator.h
new file mode 100644
index 000000000000..6811cbeae3d3
--- /dev/null
+++ b/lldb/include/lldb/Expression/DWARFEvaluator.h
@@ -0,0 +1,110 @@
+//===-- DWARFEvaluator.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_EXPRESSION_DWARFEVALUATOR_H
+#define LLDB_EXPRESSION_DWARFEVALUATOR_H
+
+#include "lldb/lldb-private.h"
+#include <vector>
+
+namespace lldb_private {
+
+class DWARFExpression;
+
+/// \class DWARFEvaluator DWARFEvaluator.h
+/// "lldb/Expression/DWARFEvaluator.h" Evaluates DWARF opcodes.
+///
+class DWARFEvaluator {
+public:
+  /// Crates a DWARF location expression evaluator
+  ///
+  /// \param[in] dwarf_expression
+  ///     The DWARF expression to evaluate.
+  ///
+  /// \param[in] exe_ctx
+  ///     The execution context in which to evaluate the location
+  ///     expression.  The location expression may access the target's
+  ///     memory, especially if it comes from the expression parser.
+  ///
+  ///  \param[in] reg_ctx
+  ///     An optional parameter which provides a RegisterContext for use
+  ///     when evaluating the expression (i.e. for fetching register values).
+  ///     Normally this will come from the ExecutionContext's StackFrame but
+  ///     in the case where an expression needs to be evaluated while building
+  ///     the stack frame list, this short-cut is available.
+  ///
+  /// \param[in] initial_value_ptr
+  ///     A value to put on top of the interpreter stack before evaluating
+  ///     the expression, if the expression is parametrized.  Can be NULL.
+  ///
+  /// \param[in] object_address_ptr
+  ///
+  DWARFEvaluator(const DWARFExpression &dwarf_expression,
+                 ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
+                 const Value *initial_value_ptr,
+                 const Value *object_address_ptr);
+
+  /// DWARFEvaluator protocol.
+  /// \{
+
+  /// Evaluate the DWARF location expression
+  ///
+  /// \param[in] result
+  ///     A value into which the result of evaluating the expression is
+  ///     to be placed.
+  ///
+  /// \param[in] error_ptr
+  ///     If non-NULL, used to report errors in expression evaluation.
+  ///
+  /// \return
+  ///     True on success; false otherwise.  If error_ptr is non-NULL,
+  ///     details of the failure are provided through it.
+  virtual bool Evaluate(Value &result, Status *error_ptr);
+
+  /// Evaluate the DWARF location expression with the opcodes specified.
+  ///
+  /// \param[in] opcodes
+  ///     The DWARF opcodes to evaluate.
+  ///
+  /// \param[in] result
+  ///     A value into which the result of evaluating the expression is
+  ///     to be placed.
+  ///
+  /// \param[in] error_ptr
+  ///     If non-NULL, used to report errors in expression evaluation.
+  ///
+  /// \return
+  ///     True on success; false otherwise.  If error_ptr is non-NULL,
+  ///     details of the failure are provided through it.
+  virtual bool Evaluate(const DataExtractor &opcodes, Value &result,
+                        Status *error_ptr);
+
+  /// Evaluates a specific DWARF opcode in the context of a DWARF expression
+  virtual bool Evaluate(const uint8_t op, Process *process, StackFrame *frame,
+                        std::vector<Value> &stack, const DataExtractor &opcodes,
+                        lldb::offset_t &offset, Value &pieces,
+                        uint64_t &op_piece_offset, Log *log, Status *error_ptr);
+
+  /// \}
+
+protected:
+  const DWARFExpression &m_dwarf_expression;
+  ExecutionContext *m_exe_ctx;
+  RegisterContext *m_reg_ctx;
+  const Value *m_initial_value_ptr;
+  const Value *m_object_address_ptr;
+
+private:
+  DWARFEvaluator(const DWARFEvaluator &);
+  const DWARFEvaluator &operator=(const DWARFEvaluator &) = delete;
+
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_EXPRESSION_DWARFEVALUATOR_H
diff --git a/lldb/include/lldb/Expression/DWARFEvaluatorFactory.h b/lldb/include/lldb/Expression/DWARFEvaluatorFactory.h
new file mode 100644
index 000000000000..f3b496c580e4
--- /dev/null
+++ b/lldb/include/lldb/Expression/DWARFEvaluatorFactory.h
@@ -0,0 +1,56 @@
+//===-- DWARFEvaluatorFactory.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_EXPRESSION_DWARFEVALUATORFACTORY_H
+#define LLDB_EXPRESSION_DWARFEVALUATORFACTORY_H
+
+#include "lldb/Core/PluginInterface.h"
+#include "lldb/Utility/ConstString.h"
+#include "lldb/lldb-private.h"
+
+class DWARFUnit;
+
+namespace lldb_private {
+
+class DWARFEvaluator;
+class DWARFExpression;
+
+/// \class DWARFEvaluatorFactory DWARFEvaluatorFactory.h
+/// "lldb/Expression/DWARFEvaluatorFactory.h" Factory class that allows the
+/// registration of platform-specific DWARF expression evaluators, used to
+/// handle platform-specific DWARF opcodes.
+class DWARFEvaluatorFactory : public PluginInterface {
+public:
+  static std::unique_ptr<DWARFEvaluatorFactory> FindPlugin(Module *module);
+
+  /// PluginInterface protocol.
+  /// \{
+  ConstString GetPluginName() override;
+
+  uint32_t GetPluginVersion() override { return 1; }
+  /// \}
+
+  DWARFEvaluatorFactory() {}
+
+  /// DWARFEvaluatorFactory protocol.
+  /// \{
+  virtual std::unique_ptr<DWARFEvaluator>
+  CreateDWARFEvaluator(const DWARFExpression &dwarf_expression,
+                       ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
+                       const Value *initial_value_ptr,
+                       const Value *object_address_ptr);
+  /// \}
+
+private:
+  DWARFEvaluatorFactory(const DWARFEvaluatorFactory &);
+  const DWARFEvaluatorFactory &operator=(const DWARFEvaluatorFactory &) = delete;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_EXPRESSION_DWARFEVALUATORFACTORY_H
diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h
index 1490ac2d614a..35c741d4e6ba 100644
--- a/lldb/include/lldb/Expression/DWARFExpression.h
+++ b/lldb/include/lldb/Expression/DWARFExpression.h
@@ -120,6 +120,10 @@ public:
 
   void SetModule(const lldb::ModuleSP &module) { m_module_wp = module; }
 
+  lldb::ModuleSP GetModule() const { return m_module_wp.lock(); }
+
+  const DWARFUnit *GetDWARFCompileUnit() const { return m_dwarf_cu; }
+
   bool ContainsThreadLocalStorage() const;
 
   bool LinkThreadLocalStorage(
@@ -140,7 +144,7 @@ public:
                                 lldb::addr_t func_file_addr);
 
   /// Return the call-frame-info style register kind
-  int GetRegisterKind();
+  lldb::RegisterKind  GetRegisterKind() const;
 
   /// Set the call-frame-info style register kind
   ///
@@ -219,6 +223,9 @@ public:
 
   bool MatchesOperand(StackFrame &frame, const Instruction::Operand &op);
 
+  static lldb::addr_t ReadAddressFromDebugAddrSection(const DWARFUnit *dwarf_cu,
+                                                      uint32_t index);
+
   llvm::Optional<DataExtractor>
   GetLocationExpression(lldb::addr_t load_function_start,
                         lldb::addr_t addr) const;
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index aaa2470d2931..c15f2db52fbc 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1434,7 +1434,7 @@ public:
   ///     vm_addr, \a buf, and \a size updated appropriately. Zero is
   ///     returned in the case of an error.
   virtual size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
-                            Status &error);
+                            Status &error, ExecutionContext *exe_ctx = nullptr);
 
   /// Read of memory from a process.
   ///
diff --git a/lldb/include/lldb/Target/ProcessTrace.h b/lldb/include/lldb/Target/ProcessTrace.h
index 7b9d6b13dd6f..9525fc9750fd 100644
--- a/lldb/include/lldb/Target/ProcessTrace.h
+++ b/lldb/include/lldb/Target/ProcessTrace.h
@@ -59,7 +59,7 @@ public:
   bool WarnBeforeDetach() const override { return false; }
 
   size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
-                    Status &error) override;
+                    Status &error, ExecutionContext *exe_ctx = nullptr) override;
 
   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
                       Status &error) override;
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index ad5298151e4a..5a3c0b27a738 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -74,6 +74,7 @@ class Disassembler;
 class DumpValueObjectOptions;
 class DynamicCheckerFunctions;
 class DynamicLoader;
+class DWARFEvaluatorFactory;
 class Editline;
 class EmulateInstruction;
 class Environment;
diff --git a/lldb/include/lldb/lldb-private-interfaces.h b/lldb/include/lldb/lldb-private-interfaces.h
index 2ed083ec8ae9..f4d500d198e8 100644
--- a/lldb/include/lldb/lldb-private-interfaces.h
+++ b/lldb/include/lldb/lldb-private-interfaces.h
@@ -113,6 +113,8 @@ typedef lldb::REPLSP (*REPLCreateInstance)(Status &error,
                                            const char *repl_options);
 typedef int (*ComparisonFunction)(const void *, const void *);
 typedef void (*DebuggerInitializeCallback)(Debugger &debugger);
+typedef DWARFEvaluatorFactory *(*DWARFEvaluatorFactoryCreateInstance)(
+    Module *module);
 /// Trace
 /// \{
 typedef llvm::Expected<lldb::TraceSP> (*TraceCreateInstanceForSessionFile)(
diff --git a/lldb/source/Core/Module.cpp b/lldb/source/Core/Module.cpp
index 19c97be15066..1647f93ec4f3 100644
--- a/lldb/source/Core/Module.cpp
+++ b/lldb/source/Core/Module.cpp
@@ -16,6 +16,7 @@
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/SearchFilter.h"
 #include "lldb/Core/Section.h"
+#include "lldb/Expression/DWARFEvaluatorFactory.h"
 #include "lldb/Host/FileSystem.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/HostInfo.h"
@@ -1659,3 +1660,9 @@ bool Module::GetIsDynamicLinkEditor() {
 
   return false;
 }
+
+DWARFEvaluatorFactory *Module::GetDWARFExpressionEvaluatorFactory() {
+  if (!m_dwarf_evaluator_factory)
+    m_dwarf_evaluator_factory = DWARFEvaluatorFactory::FindPlugin(this);
+  return m_dwarf_evaluator_factory.get();
+}
diff --git a/lldb/source/Core/PluginManager.cpp b/lldb/source/Core/PluginManager.cpp
index fcaa868b083e..59a404d4a7e1 100644
--- a/lldb/source/Core/PluginManager.cpp
+++ b/lldb/source/Core/PluginManager.cpp
@@ -1597,3 +1597,32 @@ bool PluginManager::CreateSettingForStructuredDataPlugin(
       ConstString("Settings for structured data plug-ins"), properties_sp,
       description, is_global_property);
 }
+
+#pragma mark DWARFEvaluator
+
+typedef PluginInstance<DWARFEvaluatorFactoryCreateInstance>
+    DWARFEvaluatorFactoryInstance;
+typedef PluginInstances<DWARFEvaluatorFactoryInstance>
+    DWARFEvaluatorFactoryInstances;
+
+static DWARFEvaluatorFactoryInstances &GetDWARFEvaluatorFactoryInstances() {
+  static DWARFEvaluatorFactoryInstances g_instances;
+  return g_instances;
+}
+
+bool PluginManager::RegisterPlugin(
+    ConstString name, const char *description,
+    DWARFEvaluatorFactoryCreateInstance create_callback) {
+  return GetDWARFEvaluatorFactoryInstances().RegisterPlugin(name, description,
+                                                            create_callback);
+}
+
+bool PluginManager::UnregisterPlugin(
+    DWARFEvaluatorFactoryCreateInstance create_callback) {
+  return GetDWARFEvaluatorFactoryInstances().UnregisterPlugin(create_callback);
+}
+
+DWARFEvaluatorFactoryCreateInstance
+PluginManager::GetDWARFEvaluatorFactoryCreateCallbackAtIndex(uint32_t idx) {
+  return GetDWARFEvaluatorFactoryInstances().GetCallbackAtIndex(idx);
+}
diff --git a/lldb/source/Core/Value.cpp b/lldb/source/Core/Value.cpp
index fb57c0fedf04..f92d6a54de94 100644
--- a/lldb/source/Core/Value.cpp
+++ b/lldb/source/Core/Value.cpp
@@ -538,7 +538,7 @@ Status Value::GetValueAsData(ExecutionContext *exe_ctx, DataExtractor &data,
 
         if (process) {
           const size_t bytes_read =
-              process->ReadMemory(address, dst, byte_size, error);
+              process->ReadMemory(address, dst, byte_size, error, exe_ctx);
           if (bytes_read != byte_size)
             error.SetErrorStringWithFormat(
                 "read memory from 0x%" PRIx64 " failed (%u of %u bytes read)",
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index 9c1ba99da1d0..b15b214b2a2f 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -735,7 +735,7 @@ size_t ValueObject::GetPointeeData(DataExtractor &data, uint32_t item_idx,
       if (process) {
         heap_buf_ptr->SetByteSize(bytes);
         size_t bytes_read = process->ReadMemory(
-            addr + offset, heap_buf_ptr->GetBytes(), bytes, error);
+            addr + offset, heap_buf_ptr->GetBytes(), bytes, error, &exe_ctx);
         if (error.Success() || bytes_read > 0) {
           data.SetData(data_sp);
           return bytes_read;
diff --git a/lldb/source/Expression/CMakeLists.txt b/lldb/source/Expression/CMakeLists.txt
index bf94361dd6c1..4e76d547aeaf 100644
--- a/lldb/source/Expression/CMakeLists.txt
+++ b/lldb/source/Expression/CMakeLists.txt
@@ -1,5 +1,7 @@
 add_lldb_library(lldbExpression
   DiagnosticManager.cpp
+  DWARFEvaluator.cpp
+  DWARFEvaluatorFactory.cpp
   DWARFExpression.cpp
   Expression.cpp
   ExpressionVariable.cpp
diff --git a/lldb/source/Expression/DWARFEvaluator.cpp b/lldb/source/Expression/DWARFEvaluator.cpp
new file mode 100644
index 000000000000..06107e136197
--- /dev/null
+++ b/lldb/source/Expression/DWARFEvaluator.cpp
@@ -0,0 +1,1952 @@
+//===-- DWARFEvaluator.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/Expression/DWARFEvaluator.h"
+#include "lldb/Expression/DWARFExpression.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/dwarf.h"
+
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/RegisterValue.h"
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+
+#include "Plugins/SymbolFile/DWARF/DWARFUnit.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+DWARFEvaluator::DWARFEvaluator(const DWARFExpression &dwarf_expression,
+                               ExecutionContext *exe_ctx,
+                               RegisterContext *reg_ctx,
+                               const Value *initial_value_ptr,
+                               const Value *object_address_ptr)
+    : m_dwarf_expression(dwarf_expression), m_exe_ctx(exe_ctx),
+      m_reg_ctx(reg_ctx), m_initial_value_ptr(initial_value_ptr),
+      m_object_address_ptr(object_address_ptr) {}
+
+static bool 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->SetErrorStringWithFormat("No register context in frame.\n");
+  } else {
+    uint32_t native_reg =
+        reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num);
+    if (native_reg == LLDB_INVALID_REGNUM) {
+      if (error_ptr)
+        error_ptr->SetErrorStringWithFormat("Unable to convert register "
+                                            "kind=%u reg_num=%u to a native "
+                                            "register number.\n",
+                                            reg_kind, reg_num);
+    } else {
+      const RegisterInfo *reg_info =
+          reg_ctx->GetRegisterInfoAtIndex(native_reg);
+      RegisterValue reg_value;
+      if (reg_ctx->ReadRegister(reg_info, reg_value)) {
+        if (reg_value.GetScalarValue(value.GetScalar())) {
+          value.SetValueType(Value::ValueType::Scalar);
+          value.SetContext(Value::ContextType::RegisterInfo,
+                           const_cast<RegisterInfo *>(reg_info));
+          if (error_ptr)
+            error_ptr->Clear();
+          return true;
+        } else {
+          // If we get this error, then we need to implement a value buffer in
+          // the dwarf expression evaluation function...
+          if (error_ptr)
+            error_ptr->SetErrorStringWithFormat(
+                "register %s can't be converted to a scalar value",
+                reg_info->name);
+        }
+      } else {
+        if (error_ptr)
+          error_ptr->SetErrorStringWithFormat("register %s is not available",
+                                              reg_info->name);
+      }
+    }
+  }
+  return false;
+}
+
+static bool Evaluate_DW_OP_entry_value(std::vector<Value> &stack,
+                                       ExecutionContext *exe_ctx,
+                                       RegisterContext *reg_ctx,
+                                       const DataExtractor &opcodes,
+                                       lldb::offset_t &opcode_offset,
+                                       Status *error_ptr, Log *log) {
+  // DW_OP_entry_value(sub-expr) describes the location a variable had upon
+  // function entry: this variable location is presumed to be optimized out at
+  // the current PC value.  The caller of the function may have call site
+  // information that describes an alternate location for the variable (e.g. a
+  // constant literal, or a spilled stack value) in the parent frame.
+  //
+  // Example (this is pseudo-code & pseudo-DWARF, but hopefully illustrative):
+  //
+  //     void child(int &sink, int x) {
+  //       ...
+  //       /* "x" gets optimized out. */
+  //
+  //       /* The location of "x" here is: DW_OP_entry_value($reg2). */
+  //       ++sink;
+  //     }
+  //
+  //     void parent() {
+  //       int sink;
+  //
+  //       /*
+  //        * The callsite information emitted here is:
+  //        *
+  //        * DW_TAG_call_site
+  //        *   DW_AT_return_pc ... (for "child(sink, 123);")
+  //        *   DW_TAG_call_site_parameter (for "sink")
+  //        *     DW_AT_location   ($reg1)
+  //        *     DW_AT_call_value ($SP - 8)
+  //        *   DW_TAG_call_site_parameter (for "x")
+  //        *     DW_AT_location   ($reg2)
+  //        *     DW_AT_call_value ($literal 123)
+  //        *
+  //        * DW_TAG_call_site
+  //        *   DW_AT_return_pc ... (for "child(sink, 456);")
+  //        *   ...
+  //        */
+  //       child(sink, 123);
+  //       child(sink, 456);
+  //     }
+  //
+  // When the program stops at "++sink" within `child`, the debugger determines
+  // the call site by analyzing the return address. Once the call site is found,
+  // the debugger determines which parameter is referenced by DW_OP_entry_value
+  // and evaluates the corresponding location for that parameter in `parent`.
+
+  // 1. Find the function which pushed the current frame onto the stack.
+  if ((!exe_ctx || !exe_ctx->HasTargetScope()) || !reg_ctx) {
+    LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no exe/reg context");
+    return false;
+  }
+
+  StackFrame *current_frame = exe_ctx->GetFramePtr();
+  Thread *thread = exe_ctx->GetThreadPtr();
+  if (!current_frame || !thread) {
+    LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no current frame/thread");
+    return false;
+  }
+
+  Target &target = exe_ctx->GetTargetRef();
+  StackFrameSP parent_frame = nullptr;
+  addr_t return_pc = LLDB_INVALID_ADDRESS;
+  uint32_t current_frame_idx = current_frame->GetFrameIndex();
+  uint32_t num_frames = thread->GetStackFrameCount();
+  for (uint32_t parent_frame_idx = current_frame_idx + 1;
+       parent_frame_idx < num_frames; ++parent_frame_idx) {
+    parent_frame = thread->GetStackFrameAtIndex(parent_frame_idx);
+    // Require a valid sequence of frames.
+    if (!parent_frame)
+      break;
+
+    // Record the first valid return address, even if this is an inlined frame,
+    // in order to look up the associated call edge in the first non-inlined
+    // parent frame.
+    if (return_pc == LLDB_INVALID_ADDRESS) {
+      return_pc = parent_frame->GetFrameCodeAddress().GetLoadAddress(&target);
+      LLDB_LOG(log,
+               "Evaluate_DW_OP_entry_value: immediate ancestor with pc = {0:x}",
+               return_pc);
+    }
+
+    // If we've found an inlined frame, skip it (these have no call site
+    // parameters).
+    if (parent_frame->IsInlined())
+      continue;
+
+    // We've found the first non-inlined parent frame.
+    break;
+  }
+  if (!parent_frame || !parent_frame->GetRegisterContext()) {
+    LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no parent frame with reg ctx");
+    return false;
+  }
+
+  Function *parent_func =
+      parent_frame->GetSymbolContext(eSymbolContextFunction).function;
+  if (!parent_func) {
+    LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no parent function");
+    return false;
+  }
+
+  // 2. Find the call edge in the parent function responsible for creating the
+  //    current activation.
+  Function *current_func =
+      current_frame->GetSymbolContext(eSymbolContextFunction).function;
+  if (!current_func) {
+    LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no current function");
+    return false;
+  }
+
+  CallEdge *call_edge = nullptr;
+  ModuleList &modlist = target.GetImages();
+  ExecutionContext parent_exe_ctx = *exe_ctx;
+  parent_exe_ctx.SetFrameSP(parent_frame);
+  if (!parent_frame->IsArtificial()) {
+    // If the parent frame is not artificial, the current activation may be
+    // produced by an ambiguous tail call. In this case, refuse to proceed.
+    call_edge = parent_func->GetCallEdgeForReturnAddress(return_pc, target);
+    if (!call_edge) {
+      LLDB_LOG(log,
+               "Evaluate_DW_OP_entry_value: no call edge for retn-pc = {0:x} "
+               "in parent frame {1}",
+               return_pc, parent_func->GetName());
+      return false;
+    }
+    Function *callee_func = call_edge->GetCallee(modlist, parent_exe_ctx);
+    if (callee_func != current_func) {
+      LLDB_LOG(log, "Evaluate_DW_OP_entry_value: ambiguous call sequence, "
+                    "can't find real parent frame");
+      return false;
+    }
+  } else {
+    // The StackFrameList solver machinery has deduced that an unambiguous tail
+    // call sequence that produced the current activation.  The first edge in
+    // the parent that points to the current function must be valid.
+    for (auto &edge : parent_func->GetTailCallingEdges()) {
+      if (edge->GetCallee(modlist, parent_exe_ctx) == current_func) {
+        call_edge = edge.get();
+        break;
+      }
+    }
+  }
+  if (!call_edge) {
+    LLDB_LOG(log, "Evaluate_DW_OP_entry_value: no unambiguous edge from parent "
+                  "to current function");
+    return false;
+  }
+
+  // 3. Attempt to locate the DW_OP_entry_value expression in the set of
+  //    available call site parameters. If found, evaluate the corresponding
+  //    parameter in the context of the parent frame.
+  const uint32_t subexpr_len = opcodes.GetULEB128(&opcode_offset);
+  const void *subexpr_data = opcodes.GetData(&opcode_offset, subexpr_len);
+  if (!subexpr_data) {
+    LLDB_LOG(log, "Evaluate_DW_OP_entry_value: subexpr could not be read");
+    return false;
+  }
+
+  const CallSiteParameter *matched_param = nullptr;
+  for (const CallSiteParameter &param : call_edge->GetCallSiteParameters()) {
+    DataExtractor param_subexpr_extractor;
+    if (!param.LocationInCallee.GetExpressionData(param_subexpr_extractor))
+      continue;
+    lldb::offset_t param_subexpr_offset = 0;
+    const void *param_subexpr_data =
+        param_subexpr_extractor.GetData(&param_subexpr_offset, subexpr_len);
+    if (!param_subexpr_data ||
+        param_subexpr_extractor.BytesLeft(param_subexpr_offset) != 0)
+      continue;
+
+    // At this point, the DW_OP_entry_value sub-expression and the callee-side
+    // expression in the call site parameter are known to have the same length.
+    // Check whether they are equal.
+    //
+    // Note that an equality check is sufficient: the contents of the
+    // DW_OP_entry_value subexpression are only used to identify the right call
+    // site parameter in the parent, and do not require any special handling.
+    if (memcmp(subexpr_data, param_subexpr_data, subexpr_len) == 0) {
+      matched_param = &param;
+      break;
+    }
+  }
+  if (!matched_param) {
+    LLDB_LOG(log,
+             "Evaluate_DW_OP_entry_value: no matching call site param found");
+    return false;
+  }
+
+  // TODO: Add support for DW_OP_push_object_address within a DW_OP_entry_value
+  // subexpresion whenever llvm does.
+  Value result;
+  const DWARFExpression &param_expr = matched_param->LocationInCaller;
+  if (!param_expr.Evaluate(&parent_exe_ctx,
+                           parent_frame->GetRegisterContext().get(),
+                           /*loclist_base_addr=*/LLDB_INVALID_ADDRESS,
+                           /*initial_value_ptr=*/nullptr,
+                           /*object_address_ptr=*/nullptr, result, error_ptr)) {
+    LLDB_LOG(log,
+             "Evaluate_DW_OP_entry_value: call site param evaluation failed");
+    return false;
+  }
+
+  stack.push_back(result);
+  return true;
+}
+
+bool DWARFEvaluator::Evaluate(Value &result, Status *error_ptr) {
+  DataExtractor opcodes;
+  if (!m_dwarf_expression.GetExpressionData(opcodes)) {
+    if (error_ptr)
+      error_ptr->SetErrorString(
+          "no location, value may have been optimized out");
+    return false;
+  }
+  return Evaluate(opcodes, result, error_ptr);
+}
+
+bool DWARFEvaluator::Evaluate(const DataExtractor &opcodes, Value &result,
+                              Status *error_ptr) {
+  if (opcodes.GetByteSize() == 0) {
+    if (error_ptr)
+      error_ptr->SetErrorString(
+          "no location, value may have been optimized out");
+    return false;
+  }
+  std::vector<Value> stack;
+
+  Process *process = nullptr;
+  StackFrame *frame = nullptr;
+
+  if (m_exe_ctx) {
+    process = m_exe_ctx->GetProcessPtr();
+    frame = m_exe_ctx->GetFramePtr();
+  }
+  if (m_reg_ctx == nullptr && frame)
+    m_reg_ctx = frame->GetRegisterContext().get();
+
+  if (m_initial_value_ptr)
+    stack.push_back(*m_initial_value_ptr);
+
+  lldb::offset_t offset = 0;
+
+  /// Insertion point for evaluating multi-piece expression.
+  uint64_t op_piece_offset = 0;
+  Value pieces; // Used for DW_OP_piece
+
+  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
+
+  uint8_t _opcode = 0;
+
+  while (opcodes.ValidOffset(offset)) {
+    const lldb::offset_t op_offset = offset;
+    const uint8_t op = opcodes.GetU8(&offset);
+    _opcode = op;
+
+    if (log && log->GetVerbose()) {
+      size_t count = stack.size();
+      LLDB_LOGF(log, "Stack before operation has %" PRIu64 " values:",
+                (uint64_t)count);
+      for (size_t i = 0; i < count; ++i) {
+        StreamString new_value;
+        new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
+        stack[i].Dump(&new_value);
+        LLDB_LOGF(log, "  %s", new_value.GetData());
+      }
+      LLDB_LOGF(log, "0x%8.8" PRIx64 ": %s", op_offset,
+                DW_OP_value_to_name(op));
+    }
+
+    if (!Evaluate(op, process, frame, stack, opcodes, offset, pieces,
+                  op_piece_offset, log, error_ptr))
+      return false;
+  }
+
+  if (stack.empty()) {
+    // Nothing on the stack, check if we created a piece value from DW_OP_piece
+    // or DW_OP_bit_piece opcodes
+    if (pieces.GetBuffer().GetByteSize())
+      result = pieces;
+    else {
+      if (error_ptr)
+        error_ptr->SetErrorString("Stack empty after evaluation.");
+      return false;
+    }
+  } else {
+    if (log && log->GetVerbose()) {
+      size_t count = stack.size();
+      LLDB_LOGF(log, "Stack after operation has %" PRIu64 " values:",
+                (uint64_t)count);
+      for (size_t i = 0; i < count; ++i) {
+        StreamString new_value;
+        new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
+        stack[i].Dump(&new_value);
+        LLDB_LOGF(log, "  %s", new_value.GetData());
+      }
+    }
+    result = stack.back();
+  }
+  return true; // Return true on success
+}
+
+bool DWARFEvaluator::Evaluate(const uint8_t op, Process *process,
+                              StackFrame *frame, std::vector<Value> &stack,
+                              const DataExtractor &opcodes,
+                              lldb::offset_t &offset, Value &pieces,
+                              uint64_t &op_piece_offset, Log *log,
+                              Status *error_ptr) {
+  Value tmp;
+  uint32_t reg_num;
+
+  lldb::ModuleSP module_sp = m_dwarf_expression.GetModule();
+  const DWARFUnit *dwarf_cu = m_dwarf_expression.GetDWARFCompileUnit();
+  const lldb::RegisterKind reg_kind = m_dwarf_expression.GetRegisterKind();
+
+  switch (op) {
+  // The DW_OP_addr operation has a single operand that encodes a machine
+  // address and whose size is the size of an address on the target machine.
+  case DW_OP_addr:
+    stack.push_back(Scalar(opcodes.GetAddress(&offset)));
+    stack.back().SetValueType(Value::ValueType::FileAddress);
+    // Convert the file address to a load address, so subsequent
+    // DWARF operators can operate on it.
+    if (frame)
+      stack.back().ConvertToLoadAddress(module_sp.get(),
+                                        frame->CalculateTarget().get());
+    break;
+
+  // The DW_OP_addr_sect_offset4 is used for any location expressions in
+  // shared libraries that have a location like:
+  //  DW_OP_addr(0x1000)
+  // If this address resides in a shared library, then this virtual address
+  // won't make sense when it is evaluated in the context of a running
+  // process where shared libraries have been slid. To account for this, this
+  // new address type where we can store the section pointer and a 4 byte
+  // offset.
+  //      case DW_OP_addr_sect_offset4:
+  //          {
+  //              result_type = eResultTypeFileAddress;
+  //              lldb::Section *sect = (lldb::Section
+  //              *)opcodes.GetMaxU64(&offset, sizeof(void *));
+  //              lldb::addr_t sect_offset = opcodes.GetU32(&offset);
+  //
+  //              Address so_addr (sect, sect_offset);
+  //              lldb::addr_t load_addr = so_addr.GetLoadAddress();
+  //              if (load_addr != LLDB_INVALID_ADDRESS)
+  //              {
+  //                  // We successfully resolve a file address to a load
+  //                  // address.
+  //                  stack.push_back(load_addr);
+  //                  break;
+  //              }
+  //              else
+  //              {
+  //                  // We were able
+  //                  if (error_ptr)
+  //                      error_ptr->SetErrorStringWithFormat ("Section %s in
+  //                      %s is not currently loaded.\n",
+  //                      sect->GetName().AsCString(),
+  //                      sect->GetModule()->GetFileSpec().GetFilename().AsCString());
+  //                  return false;
+  //              }
+  //          }
+  //          break;
+
+  // OPCODE: DW_OP_deref
+  // OPERANDS: none
+  // DESCRIPTION: Pops the top stack entry and treats it as an address.
+  // The value retrieved from that address is pushed. The size of the data
+  // retrieved from the dereferenced address is the size of an address on the
+  // target machine.
+  case DW_OP_deref: {
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString("Expression stack empty for DW_OP_deref.");
+      return false;
+    }
+    Value::ValueType value_type = stack.back().GetValueType();
+    switch (value_type) {
+    case Value::ValueType::HostAddress: {
+      void *src = (void *)stack.back().GetScalar().ULongLong();
+      intptr_t ptr;
+      ::memcpy(&ptr, src, sizeof(void *));
+      stack.back().GetScalar() = ptr;
+      stack.back().ClearContext();
+    } break;
+    case Value::ValueType::FileAddress: {
+      auto file_addr = stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+      if (!module_sp) {
+        if (error_ptr)
+          error_ptr->SetErrorStringWithFormat(
+              "need module to resolve file address for DW_OP_deref");
+        return false;
+      }
+      Address so_addr;
+      if (!module_sp->ResolveFileAddress(file_addr, so_addr)) {
+        if (error_ptr)
+          error_ptr->SetErrorStringWithFormat(
+              "failed to resolve file address in module");
+        return false;
+      }
+      addr_t load_Addr = so_addr.GetLoadAddress(m_exe_ctx->GetTargetPtr());
+      if (load_Addr == LLDB_INVALID_ADDRESS) {
+        if (error_ptr)
+          error_ptr->SetErrorStringWithFormat("failed to resolve load address");
+        return false;
+      }
+      stack.back().GetScalar() = load_Addr;
+      stack.back().SetValueType(Value::ValueType::LoadAddress);
+      // Fall through to load address code below...
+    }
+      LLVM_FALLTHROUGH;
+    case Value::ValueType::LoadAddress:
+      if (m_exe_ctx) {
+        if (process) {
+          lldb::addr_t pointer_addr =
+              stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+          Status error;
+          lldb::addr_t pointer_value =
+              process->ReadPointerFromMemory(pointer_addr, error);
+          if (pointer_value != LLDB_INVALID_ADDRESS) {
+            stack.back().GetScalar() = pointer_value;
+            stack.back().ClearContext();
+          } else {
+            if (error_ptr)
+              error_ptr->SetErrorStringWithFormat(
+                  "Failed to dereference pointer from 0x%" PRIx64
+                  " for DW_OP_deref: %s\n",
+                  pointer_addr, error.AsCString());
+            return false;
+          }
+        } else {
+          if (error_ptr)
+            error_ptr->SetErrorStringWithFormat(
+                "NULL process for DW_OP_deref.\n");
+          return false;
+        }
+      } else {
+        if (error_ptr)
+          error_ptr->SetErrorStringWithFormat(
+              "NULL execution context for DW_OP_deref.\n");
+        return false;
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  } break;
+
+  // OPCODE: DW_OP_deref_size
+  // OPERANDS: 1
+  //  1 - uint8_t that specifies the size of the data to dereference.
+  // DESCRIPTION: Behaves like the DW_OP_deref operation: it pops the top
+  // stack entry and treats it as an address. The value retrieved from that
+  // address is pushed. In the DW_OP_deref_size operation, however, the size
+  // in bytes of the data retrieved from the dereferenced address is
+  // specified by the single operand. This operand is a 1-byte unsigned
+  // integral constant whose value may not be larger than the size of an
+  // address on the target machine. The data retrieved is zero extended to
+  // the size of an address on the target machine before being pushed on the
+  // expression stack.
+  case DW_OP_deref_size: {
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack empty for DW_OP_deref_size.");
+      return false;
+    }
+    uint8_t size = opcodes.GetU8(&offset);
+    Value::ValueType value_type = stack.back().GetValueType();
+    switch (value_type) {
+    case Value::ValueType::HostAddress: {
+      void *src = (void *)stack.back().GetScalar().ULongLong();
+      intptr_t ptr;
+      ::memcpy(&ptr, src, sizeof(void *));
+      // I can't decide whether the size operand should apply to the bytes in
+      // their
+      // lldb-host endianness or the target endianness.. I doubt this'll ever
+      // come up but I'll opt for assuming big endian regardless.
+      switch (size) {
+      case 1:
+        ptr = ptr & 0xff;
+        break;
+      case 2:
+        ptr = ptr & 0xffff;
+        break;
+      case 3:
+        ptr = ptr & 0xffffff;
+        break;
+      case 4:
+        ptr = ptr & 0xffffffff;
+        break;
+      // the casts are added to work around the case where intptr_t is a 32
+      // bit quantity;
+      // presumably we won't hit the 5..7 cases if (void*) is 32-bits in this
+      // program.
+      case 5:
+        ptr = (intptr_t)ptr & 0xffffffffffULL;
+        break;
+      case 6:
+        ptr = (intptr_t)ptr & 0xffffffffffffULL;
+        break;
+      case 7:
+        ptr = (intptr_t)ptr & 0xffffffffffffffULL;
+        break;
+      default:
+        break;
+      }
+      stack.back().GetScalar() = ptr;
+      stack.back().ClearContext();
+    } break;
+    case Value::ValueType::LoadAddress:
+      if (m_exe_ctx) {
+        if (process) {
+          lldb::addr_t pointer_addr =
+              stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+          uint8_t addr_bytes[sizeof(lldb::addr_t)];
+          Status error;
+          if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) ==
+              size) {
+            DataExtractor addr_data(addr_bytes, sizeof(addr_bytes),
+                                    process->GetByteOrder(), size);
+            lldb::offset_t addr_data_offset = 0;
+            switch (size) {
+            case 1:
+              stack.back().GetScalar() = addr_data.GetU8(&addr_data_offset);
+              break;
+            case 2:
+              stack.back().GetScalar() = addr_data.GetU16(&addr_data_offset);
+              break;
+            case 4:
+              stack.back().GetScalar() = addr_data.GetU32(&addr_data_offset);
+              break;
+            case 8:
+              stack.back().GetScalar() = addr_data.GetU64(&addr_data_offset);
+              break;
+            default:
+              stack.back().GetScalar() =
+                  addr_data.GetAddress(&addr_data_offset);
+            }
+            stack.back().ClearContext();
+          } else {
+            if (error_ptr)
+              error_ptr->SetErrorStringWithFormat(
+                  "Failed to dereference pointer from 0x%" PRIx64
+                  " for DW_OP_deref: %s\n",
+                  pointer_addr, error.AsCString());
+            return false;
+          }
+        } else {
+          if (error_ptr)
+            error_ptr->SetErrorStringWithFormat(
+                "NULL process for DW_OP_deref.\n");
+          return false;
+        }
+      } else {
+        if (error_ptr)
+          error_ptr->SetErrorStringWithFormat(
+              "NULL execution context for DW_OP_deref.\n");
+        return false;
+      }
+      break;
+
+    default:
+      break;
+    }
+
+  } break;
+
+  // OPCODE: DW_OP_xderef_size
+  // OPERANDS: 1
+  //  1 - uint8_t that specifies the size of the data to dereference.
+  // DESCRIPTION: Behaves like the DW_OP_xderef operation: the entry at
+  // the top of the stack is treated as an address. The second stack entry is
+  // treated as an "address space identifier" for those architectures that
+  // support multiple address spaces. The top two stack elements are popped,
+  // a data item is retrieved through an implementation-defined address
+  // calculation and pushed as the new stack top. In the DW_OP_xderef_size
+  // operation, however, the size in bytes of the data retrieved from the
+  // dereferenced address is specified by the single operand. This operand is
+  // a 1-byte unsigned integral constant whose value may not be larger than
+  // the size of an address on the target machine. The data retrieved is zero
+  // extended to the size of an address on the target machine before being
+  // pushed on the expression stack.
+  case DW_OP_xderef_size:
+    if (error_ptr)
+      error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef_size.");
+    return false;
+  // OPCODE: DW_OP_xderef
+  // OPERANDS: none
+  // DESCRIPTION: Provides an extended dereference mechanism. The entry at
+  // the top of the stack is treated as an address. The second stack entry is
+  // treated as an "address space identifier" for those architectures that
+  // support multiple address spaces. The top two stack elements are popped,
+  // a data item is retrieved through an implementation-defined address
+  // calculation and pushed as the new stack top. The size of the data
+  // retrieved from the dereferenced address is the size of an address on the
+  // target machine.
+  case DW_OP_xderef:
+    if (error_ptr)
+      error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef.");
+    return false;
+
+  // All DW_OP_constXXX opcodes have a single operand as noted below:
+  //
+  // Opcode           Operand 1
+  // DW_OP_const1u    1-byte unsigned integer constant DW_OP_const1s
+  // 1-byte signed integer constant DW_OP_const2u    2-byte unsigned integer
+  // constant DW_OP_const2s    2-byte signed integer constant DW_OP_const4u
+  // 4-byte unsigned integer constant DW_OP_const4s    4-byte signed integer
+  // constant DW_OP_const8u    8-byte unsigned integer constant DW_OP_const8s
+  // 8-byte signed integer constant DW_OP_constu     unsigned LEB128 integer
+  // constant DW_OP_consts     signed LEB128 integer constant
+  case DW_OP_const1u:
+    stack.push_back(Scalar((uint8_t)opcodes.GetU8(&offset)));
+    break;
+  case DW_OP_const1s:
+    stack.push_back(Scalar((int8_t)opcodes.GetU8(&offset)));
+    break;
+  case DW_OP_const2u:
+    stack.push_back(Scalar((uint16_t)opcodes.GetU16(&offset)));
+    break;
+  case DW_OP_const2s:
+    stack.push_back(Scalar((int16_t)opcodes.GetU16(&offset)));
+    break;
+  case DW_OP_const4u:
+    stack.push_back(Scalar((uint32_t)opcodes.GetU32(&offset)));
+    break;
+  case DW_OP_const4s:
+    stack.push_back(Scalar((int32_t)opcodes.GetU32(&offset)));
+    break;
+  case DW_OP_const8u:
+    stack.push_back(Scalar((uint64_t)opcodes.GetU64(&offset)));
+    break;
+  case DW_OP_const8s:
+    stack.push_back(Scalar((int64_t)opcodes.GetU64(&offset)));
+    break;
+  case DW_OP_constu:
+    stack.push_back(Scalar(opcodes.GetULEB128(&offset)));
+    break;
+  case DW_OP_consts:
+    stack.push_back(Scalar(opcodes.GetSLEB128(&offset)));
+    break;
+
+  // OPCODE: DW_OP_dup
+  // OPERANDS: none
+  // DESCRIPTION: duplicates the value at the top of the stack
+  case DW_OP_dup:
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString("Expression stack empty for DW_OP_dup.");
+      return false;
+    } else
+      stack.push_back(stack.back());
+    break;
+
+  // OPCODE: DW_OP_drop
+  // OPERANDS: none
+  // DESCRIPTION: pops the value at the top of the stack
+  case DW_OP_drop:
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString("Expression stack empty for DW_OP_drop.");
+      return false;
+    } else
+      stack.pop_back();
+    break;
+
+  // OPCODE: DW_OP_over
+  // OPERANDS: none
+  // DESCRIPTION: Duplicates the entry currently second in the stack at
+  // the top of the stack.
+  case DW_OP_over:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_over.");
+      return false;
+    } else
+      stack.push_back(stack[stack.size() - 2]);
+    break;
+
+  // OPCODE: DW_OP_pick
+  // OPERANDS: uint8_t index into the current stack
+  // DESCRIPTION: The stack entry with the specified index (0 through 255,
+  // inclusive) is pushed on the stack
+  case DW_OP_pick: {
+    uint8_t pick_idx = opcodes.GetU8(&offset);
+    if (pick_idx < stack.size())
+      stack.push_back(stack[stack.size() - 1 - pick_idx]);
+    else {
+      if (error_ptr)
+        error_ptr->SetErrorStringWithFormat(
+            "Index %u out of range for DW_OP_pick.\n", pick_idx);
+      return false;
+    }
+  } break;
+
+  // OPCODE: DW_OP_swap
+  // OPERANDS: none
+  // DESCRIPTION: swaps the top two stack entries. The entry at the top
+  // of the stack becomes the second stack entry, and the second entry
+  // becomes the top of the stack
+  case DW_OP_swap:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_swap.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.back() = stack[stack.size() - 2];
+      stack[stack.size() - 2] = tmp;
+    }
+    break;
+
+  // OPCODE: DW_OP_rot
+  // OPERANDS: none
+  // DESCRIPTION: Rotates the first three stack entries. The entry at
+  // the top of the stack becomes the third stack entry, the second entry
+  // becomes the top of the stack, and the third entry becomes the second
+  // entry.
+  case DW_OP_rot:
+    if (stack.size() < 3) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 3 items for DW_OP_rot.");
+      return false;
+    } else {
+      size_t last_idx = stack.size() - 1;
+      Value old_top = stack[last_idx];
+      stack[last_idx] = stack[last_idx - 1];
+      stack[last_idx - 1] = stack[last_idx - 2];
+      stack[last_idx - 2] = old_top;
+    }
+    break;
+
+  // OPCODE: DW_OP_abs
+  // OPERANDS: none
+  // DESCRIPTION: pops the top stack entry, interprets it as a signed
+  // value and pushes its absolute value. If the absolute value can not be
+  // represented, the result is undefined.
+  case DW_OP_abs:
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 1 item for DW_OP_abs.");
+      return false;
+    } else if (!stack.back().ResolveValue(m_exe_ctx).AbsoluteValue()) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Failed to take the absolute value of the first stack item.");
+      return false;
+    }
+    break;
+
+  // OPCODE: DW_OP_and
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, performs a bitwise and
+  // operation on the two, and pushes the result.
+  case DW_OP_and:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_and.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) & tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_div
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, divides the former second
+  // entry by the former top of the stack using signed division, and pushes
+  // the result.
+  case DW_OP_div:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_div.");
+      return false;
+    } else {
+      tmp = stack.back();
+      if (tmp.ResolveValue(m_exe_ctx).IsZero()) {
+        if (error_ptr)
+          error_ptr->SetErrorString("Divide by zero.");
+        return false;
+      } else {
+        stack.pop_back();
+        stack.back() =
+            stack.back().ResolveValue(m_exe_ctx) / tmp.ResolveValue(m_exe_ctx);
+        if (!stack.back().ResolveValue(m_exe_ctx).IsValid()) {
+          if (error_ptr)
+            error_ptr->SetErrorString("Divide failed.");
+          return false;
+        }
+      }
+    }
+    break;
+
+  // OPCODE: DW_OP_minus
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, subtracts the former top
+  // of the stack from the former second entry, and pushes the result.
+  case DW_OP_minus:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_minus.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) - tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_mod
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values and pushes the result of
+  // the calculation: former second stack entry modulo the former top of the
+  // stack.
+  case DW_OP_mod:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_mod.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) % tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_mul
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack entries, multiplies them
+  // together, and pushes the result.
+  case DW_OP_mul:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_mul.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) * tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_neg
+  // OPERANDS: none
+  // DESCRIPTION: pops the top stack entry, and pushes its negation.
+  case DW_OP_neg:
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 1 item for DW_OP_neg.");
+      return false;
+    } else {
+      if (!stack.back().ResolveValue(m_exe_ctx).UnaryNegate()) {
+        if (error_ptr)
+          error_ptr->SetErrorString("Unary negate failed.");
+        return false;
+      }
+    }
+    break;
+
+  // OPCODE: DW_OP_not
+  // OPERANDS: none
+  // DESCRIPTION: pops the top stack entry, and pushes its bitwise
+  // complement
+  case DW_OP_not:
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 1 item for DW_OP_not.");
+      return false;
+    } else {
+      if (!stack.back().ResolveValue(m_exe_ctx).OnesComplement()) {
+        if (error_ptr)
+          error_ptr->SetErrorString("Logical NOT failed.");
+        return false;
+      }
+    }
+    break;
+
+  // OPCODE: DW_OP_or
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack entries, performs a bitwise or
+  // operation on the two, and pushes the result.
+  case DW_OP_or:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_or.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) | tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_plus
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack entries, adds them together, and
+  // pushes the result.
+  case DW_OP_plus:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_plus.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().GetScalar() += tmp.GetScalar();
+    }
+    break;
+
+  // OPCODE: DW_OP_plus_uconst
+  // OPERANDS: none
+  // DESCRIPTION: pops the top stack entry, adds it to the unsigned LEB128
+  // constant operand and pushes the result.
+  case DW_OP_plus_uconst:
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 1 item for DW_OP_plus_uconst.");
+      return false;
+    } else {
+      const uint64_t uconst_value = opcodes.GetULEB128(&offset);
+      // Implicit conversion from a UINT to a Scalar...
+      stack.back().GetScalar() += uconst_value;
+      if (!stack.back().GetScalar().IsValid()) {
+        if (error_ptr)
+          error_ptr->SetErrorString("DW_OP_plus_uconst failed.");
+        return false;
+      }
+    }
+    break;
+
+  // OPCODE: DW_OP_shl
+  // OPERANDS: none
+  // DESCRIPTION:  pops the top two stack entries, shifts the former
+  // second entry left by the number of bits specified by the former top of
+  // the stack, and pushes the result.
+  case DW_OP_shl:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_shl.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) <<= tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_shr
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack entries, shifts the former second
+  // entry right logically (filling with zero bits) by the number of bits
+  // specified by the former top of the stack, and pushes the result.
+  case DW_OP_shr:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_shr.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      if (!stack.back().ResolveValue(m_exe_ctx).ShiftRightLogical(
+              tmp.ResolveValue(m_exe_ctx))) {
+        if (error_ptr)
+          error_ptr->SetErrorString("DW_OP_shr failed.");
+        return false;
+      }
+    }
+    break;
+
+  // OPCODE: DW_OP_shra
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack entries, shifts the former second
+  // entry right arithmetically (divide the magnitude by 2, keep the same
+  // sign for the result) by the number of bits specified by the former top
+  // of the stack, and pushes the result.
+  case DW_OP_shra:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_shra.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) >>= tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_xor
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack entries, performs the bitwise
+  // exclusive-or operation on the two, and pushes the result.
+  case DW_OP_xor:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_xor.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) ^ tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_skip
+  // OPERANDS: int16_t
+  // DESCRIPTION:  An unconditional branch. Its single operand is a 2-byte
+  // signed integer constant. The 2-byte constant is the number of bytes of
+  // the DWARF expression to skip forward or backward from the current
+  // operation, beginning after the 2-byte constant.
+  case DW_OP_skip: {
+    int16_t skip_offset = (int16_t)opcodes.GetU16(&offset);
+    lldb::offset_t new_offset = offset + skip_offset;
+    if (opcodes.ValidOffset(new_offset))
+      offset = new_offset;
+    else {
+      if (error_ptr)
+        error_ptr->SetErrorString("Invalid opcode offset in DW_OP_skip.");
+      return false;
+    }
+  } break;
+
+  // OPCODE: DW_OP_bra
+  // OPERANDS: int16_t
+  // DESCRIPTION: A conditional branch. Its single operand is a 2-byte
+  // signed integer constant. This operation pops the top of stack. If the
+  // value popped is not the constant 0, the 2-byte constant operand is the
+  // number of bytes of the DWARF expression to skip forward or backward from
+  // the current operation, beginning after the 2-byte constant.
+  case DW_OP_bra:
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 1 item for DW_OP_bra.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      int16_t bra_offset = (int16_t)opcodes.GetU16(&offset);
+      Scalar zero(0);
+      if (tmp.ResolveValue(m_exe_ctx) != zero) {
+        lldb::offset_t new_offset = offset + bra_offset;
+        if (opcodes.ValidOffset(new_offset))
+          offset = new_offset;
+        else {
+          if (error_ptr)
+            error_ptr->SetErrorString("Invalid opcode offset in DW_OP_bra.");
+          return false;
+        }
+      }
+    }
+    break;
+
+  // OPCODE: DW_OP_eq
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, compares using the
+  // equals (==) operator.
+  // STACK RESULT: push the constant value 1 onto the stack if the result
+  // of the operation is true or the constant value 0 if the result of the
+  // operation is false.
+  case DW_OP_eq:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_eq.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) == tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_ge
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, compares using the
+  // greater than or equal to (>=) operator.
+  // STACK RESULT: push the constant value 1 onto the stack if the result
+  // of the operation is true or the constant value 0 if the result of the
+  // operation is false.
+  case DW_OP_ge:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_ge.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) >= tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_gt
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, compares using the
+  // greater than (>) operator.
+  // STACK RESULT: push the constant value 1 onto the stack if the result
+  // of the operation is true or the constant value 0 if the result of the
+  // operation is false.
+  case DW_OP_gt:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_gt.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) > tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_le
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, compares using the
+  // less than or equal to (<=) operator.
+  // STACK RESULT: push the constant value 1 onto the stack if the result
+  // of the operation is true or the constant value 0 if the result of the
+  // operation is false.
+  case DW_OP_le:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_le.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) <= tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_lt
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, compares using the
+  // less than (<) operator.
+  // STACK RESULT: push the constant value 1 onto the stack if the result
+  // of the operation is true or the constant value 0 if the result of the
+  // operation is false.
+  case DW_OP_lt:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_lt.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) < tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_ne
+  // OPERANDS: none
+  // DESCRIPTION: pops the top two stack values, compares using the
+  // not equal (!=) operator.
+  // STACK RESULT: push the constant value 1 onto the stack if the result
+  // of the operation is true or the constant value 0 if the result of the
+  // operation is false.
+  case DW_OP_ne:
+    if (stack.size() < 2) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 2 items for DW_OP_ne.");
+      return false;
+    } else {
+      tmp = stack.back();
+      stack.pop_back();
+      stack.back().ResolveValue(m_exe_ctx) =
+          stack.back().ResolveValue(m_exe_ctx) != tmp.ResolveValue(m_exe_ctx);
+    }
+    break;
+
+  // OPCODE: DW_OP_litn
+  // OPERANDS: none
+  // DESCRIPTION: encode the unsigned literal values from 0 through 31.
+  // STACK RESULT: push the unsigned literal constant value onto the top
+  // of the stack.
+  case DW_OP_lit0:
+  case DW_OP_lit1:
+  case DW_OP_lit2:
+  case DW_OP_lit3:
+  case DW_OP_lit4:
+  case DW_OP_lit5:
+  case DW_OP_lit6:
+  case DW_OP_lit7:
+  case DW_OP_lit8:
+  case DW_OP_lit9:
+  case DW_OP_lit10:
+  case DW_OP_lit11:
+  case DW_OP_lit12:
+  case DW_OP_lit13:
+  case DW_OP_lit14:
+  case DW_OP_lit15:
+  case DW_OP_lit16:
+  case DW_OP_lit17:
+  case DW_OP_lit18:
+  case DW_OP_lit19:
+  case DW_OP_lit20:
+  case DW_OP_lit21:
+  case DW_OP_lit22:
+  case DW_OP_lit23:
+  case DW_OP_lit24:
+  case DW_OP_lit25:
+  case DW_OP_lit26:
+  case DW_OP_lit27:
+  case DW_OP_lit28:
+  case DW_OP_lit29:
+  case DW_OP_lit30:
+  case DW_OP_lit31:
+    stack.push_back(Scalar((uint64_t)(op - DW_OP_lit0)));
+    break;
+
+  // OPCODE: DW_OP_regN
+  // OPERANDS: none
+  // DESCRIPTION: Push the value in register n on the top of the stack.
+  case DW_OP_reg0:
+  case DW_OP_reg1:
+  case DW_OP_reg2:
+  case DW_OP_reg3:
+  case DW_OP_reg4:
+  case DW_OP_reg5:
+  case DW_OP_reg6:
+  case DW_OP_reg7:
+  case DW_OP_reg8:
+  case DW_OP_reg9:
+  case DW_OP_reg10:
+  case DW_OP_reg11:
+  case DW_OP_reg12:
+  case DW_OP_reg13:
+  case DW_OP_reg14:
+  case DW_OP_reg15:
+  case DW_OP_reg16:
+  case DW_OP_reg17:
+  case DW_OP_reg18:
+  case DW_OP_reg19:
+  case DW_OP_reg20:
+  case DW_OP_reg21:
+  case DW_OP_reg22:
+  case DW_OP_reg23:
+  case DW_OP_reg24:
+  case DW_OP_reg25:
+  case DW_OP_reg26:
+  case DW_OP_reg27:
+  case DW_OP_reg28:
+  case DW_OP_reg29:
+  case DW_OP_reg30:
+  case DW_OP_reg31: {
+    reg_num = op - DW_OP_reg0;
+
+    if (ReadRegisterValueAsScalar(m_reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+      stack.push_back(tmp);
+    else
+      return false;
+  } break;
+  // OPCODE: DW_OP_regx
+  // OPERANDS:
+  //      ULEB128 literal operand that encodes the register.
+  // DESCRIPTION: Push the value in register on the top of the stack.
+  case DW_OP_regx: {
+    reg_num = opcodes.GetULEB128(&offset);
+    if (ReadRegisterValueAsScalar(m_reg_ctx, reg_kind, reg_num, error_ptr, tmp))
+      stack.push_back(tmp);
+    else
+      return false;
+  } break;
+
+  // OPCODE: DW_OP_bregN
+  // OPERANDS:
+  //      SLEB128 offset from register N
+  // DESCRIPTION: Value is in memory at the address specified by register
+  // N plus an offset.
+  case DW_OP_breg0:
+  case DW_OP_breg1:
+  case DW_OP_breg2:
+  case DW_OP_breg3:
+  case DW_OP_breg4:
+  case DW_OP_breg5:
+  case DW_OP_breg6:
+  case DW_OP_breg7:
+  case DW_OP_breg8:
+  case DW_OP_breg9:
+  case DW_OP_breg10:
+  case DW_OP_breg11:
+  case DW_OP_breg12:
+  case DW_OP_breg13:
+  case DW_OP_breg14:
+  case DW_OP_breg15:
+  case DW_OP_breg16:
+  case DW_OP_breg17:
+  case DW_OP_breg18:
+  case DW_OP_breg19:
+  case DW_OP_breg20:
+  case DW_OP_breg21:
+  case DW_OP_breg22:
+  case DW_OP_breg23:
+  case DW_OP_breg24:
+  case DW_OP_breg25:
+  case DW_OP_breg26:
+  case DW_OP_breg27:
+  case DW_OP_breg28:
+  case DW_OP_breg29:
+  case DW_OP_breg30:
+  case DW_OP_breg31: {
+    reg_num = op - DW_OP_breg0;
+
+    if (ReadRegisterValueAsScalar(m_reg_ctx, reg_kind, reg_num, error_ptr,
+                                  tmp)) {
+      int64_t breg_offset = opcodes.GetSLEB128(&offset);
+      tmp.ResolveValue(m_exe_ctx) += (uint64_t)breg_offset;
+      tmp.ClearContext();
+      stack.push_back(tmp);
+      stack.back().SetValueType(Value::ValueType::LoadAddress);
+    } else
+      return false;
+  } break;
+  // OPCODE: DW_OP_bregx
+  // OPERANDS: 2
+  //      ULEB128 literal operand that encodes the register.
+  //      SLEB128 offset from register N
+  // DESCRIPTION: Value is in memory at the address specified by register
+  // N plus an offset.
+  case DW_OP_bregx: {
+    reg_num = opcodes.GetULEB128(&offset);
+
+    if (ReadRegisterValueAsScalar(m_reg_ctx, reg_kind, reg_num, error_ptr,
+                                  tmp)) {
+      int64_t breg_offset = opcodes.GetSLEB128(&offset);
+      tmp.ResolveValue(m_exe_ctx) += (uint64_t)breg_offset;
+      tmp.ClearContext();
+      stack.push_back(tmp);
+      stack.back().SetValueType(Value::ValueType::LoadAddress);
+    } else
+      return false;
+  } break;
+
+  case DW_OP_fbreg:
+    if (m_exe_ctx) {
+      if (frame) {
+        Scalar value;
+        if (frame->GetFrameBaseValue(value, error_ptr)) {
+          int64_t fbreg_offset = opcodes.GetSLEB128(&offset);
+          value += fbreg_offset;
+          stack.push_back(value);
+          stack.back().SetValueType(Value::ValueType::LoadAddress);
+        } else
+          return false;
+      } else {
+        if (error_ptr)
+          error_ptr->SetErrorString(
+              "Invalid stack frame in context for DW_OP_fbreg opcode.");
+        return false;
+      }
+    } else {
+      if (error_ptr)
+        error_ptr->SetErrorStringWithFormat(
+            "NULL execution context for DW_OP_fbreg.\n");
+      return false;
+    }
+
+    break;
+
+  // OPCODE: DW_OP_nop
+  // OPERANDS: none
+  // DESCRIPTION: A place holder. It has no effect on the location stack
+  // or any of its values.
+  case DW_OP_nop:
+    break;
+
+  // OPCODE: DW_OP_piece
+  // OPERANDS: 1
+  //      ULEB128: byte size of the piece
+  // DESCRIPTION: The operand describes the size in bytes of the piece of
+  // the object referenced by the DWARF expression whose result is at the top
+  // of the stack. If the piece is located in a register, but does not occupy
+  // the entire register, the placement of the piece within that register is
+  // defined by the ABI.
+  //
+  // Many compilers store a single variable in sets of registers, or store a
+  // variable partially in memory and partially in registers. DW_OP_piece
+  // provides a way of describing how large a part of a variable a particular
+  // DWARF expression refers to.
+  case DW_OP_piece: {
+    const uint64_t piece_byte_size = opcodes.GetULEB128(&offset);
+
+    if (piece_byte_size > 0) {
+      Value curr_piece;
+
+      if (stack.empty()) {
+        // In a multi-piece expression, this means that the current piece is
+        // not available. Fill with zeros for now by resizing the data and
+        // appending it
+        curr_piece.ResizeData(piece_byte_size);
+        // Note that "0" is not a correct value for the unknown bits.
+        // It would be better to also return a mask of valid bits together
+        // with the expression result, so the debugger can print missing
+        // members as "<optimized out>" or something.
+        ::memset(curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
+        pieces.AppendDataToHostBuffer(curr_piece);
+      } else {
+        Status error;
+        // Extract the current piece into "curr_piece"
+        Value curr_piece_source_value(stack.back());
+        stack.pop_back();
+
+        const Value::ValueType curr_piece_source_value_type =
+            curr_piece_source_value.GetValueType();
+        switch (curr_piece_source_value_type) {
+        case Value::ValueType::LoadAddress:
+          if (process) {
+            if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size) {
+              lldb::addr_t load_addr =
+                  curr_piece_source_value.GetScalar().ULongLong(
+                      LLDB_INVALID_ADDRESS);
+              if (process->ReadMemory(
+                      load_addr, curr_piece.GetBuffer().GetBytes(),
+                      piece_byte_size, error) != piece_byte_size) {
+                if (error_ptr)
+                  error_ptr->SetErrorStringWithFormat(
+                      "failed to read memory DW_OP_piece(%" PRIu64
+                      ") from 0x%" PRIx64,
+                      piece_byte_size, load_addr);
+                return false;
+              }
+            } else {
+              if (error_ptr)
+                error_ptr->SetErrorStringWithFormat(
+                    "failed to resize the piece memory buffer for "
+                    "DW_OP_piece(%" PRIu64 ")",
+                    piece_byte_size);
+              return false;
+            }
+          }
+          break;
+
+        case Value::ValueType::FileAddress:
+        case Value::ValueType::HostAddress:
+          if (error_ptr) {
+            lldb::addr_t addr = curr_piece_source_value.GetScalar().ULongLong(
+                LLDB_INVALID_ADDRESS);
+            error_ptr->SetErrorStringWithFormat(
+                "failed to read memory DW_OP_piece(%" PRIu64
+                ") from %s address 0x%" PRIx64,
+                piece_byte_size,
+                curr_piece_source_value.GetValueType() ==
+                        Value::ValueType::FileAddress
+                    ? "file"
+                    : "host",
+                addr);
+          }
+          return false;
+
+        case Value::ValueType::Scalar: {
+          uint32_t bit_size = piece_byte_size * 8;
+          uint32_t bit_offset = 0;
+          Scalar &scalar = curr_piece_source_value.GetScalar();
+          if (!scalar.ExtractBitfield(bit_size, bit_offset)) {
+            if (error_ptr)
+              error_ptr->SetErrorStringWithFormat(
+                  "unable to extract %" PRIu64 " bytes from a %" PRIu64
+                  " byte scalar value.",
+                  piece_byte_size,
+                  (uint64_t)curr_piece_source_value.GetScalar().GetByteSize());
+            return false;
+          }
+          // Create curr_piece with bit_size. By default Scalar
+          // grows to the nearest host integer type.
+          llvm::APInt fail_value(1, 0, false);
+          llvm::APInt ap_int = scalar.UInt128(fail_value);
+          assert(ap_int.getBitWidth() >= bit_size);
+          llvm::ArrayRef<uint64_t> buf{ap_int.getRawData(),
+                                       ap_int.getNumWords()};
+          curr_piece.GetScalar() = Scalar(llvm::APInt(bit_size, buf));
+        } break;
+        }
+
+        // Check if this is the first piece?
+        if (op_piece_offset == 0) {
+          // This is the first piece, we should push it back onto the stack
+          // so subsequent pieces will be able to access this piece and add
+          // to it.
+          if (pieces.AppendDataToHostBuffer(curr_piece) == 0) {
+            if (error_ptr)
+              error_ptr->SetErrorString("failed to append piece data");
+            return false;
+          }
+        } else {
+          // If this is the second or later piece there should be a value on
+          // the stack.
+          if (pieces.GetBuffer().GetByteSize() != op_piece_offset) {
+            if (error_ptr)
+              error_ptr->SetErrorStringWithFormat(
+                  "DW_OP_piece for offset %" PRIu64
+                  " but top of stack is of size %" PRIu64,
+                  op_piece_offset, pieces.GetBuffer().GetByteSize());
+            return false;
+          }
+
+          if (pieces.AppendDataToHostBuffer(curr_piece) == 0) {
+            if (error_ptr)
+              error_ptr->SetErrorString("failed to append piece data");
+            return false;
+          }
+        }
+      }
+      op_piece_offset += piece_byte_size;
+    }
+  } break;
+
+  case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
+    if (stack.size() < 1) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 1 item for DW_OP_bit_piece.");
+      return false;
+    } else {
+      const uint64_t piece_bit_size = opcodes.GetULEB128(&offset);
+      const uint64_t piece_bit_offset = opcodes.GetULEB128(&offset);
+      switch (stack.back().GetValueType()) {
+      case Value::ValueType::Scalar: {
+        if (!stack.back().GetScalar().ExtractBitfield(piece_bit_size,
+                                                      piece_bit_offset)) {
+          if (error_ptr)
+            error_ptr->SetErrorStringWithFormat(
+                "unable to extract %" PRIu64 " bit value with %" PRIu64
+                " bit offset from a %" PRIu64 " bit scalar value.",
+                piece_bit_size, piece_bit_offset,
+                (uint64_t)(stack.back().GetScalar().GetByteSize() * 8));
+          return false;
+        }
+      } break;
+
+      case Value::ValueType::FileAddress:
+      case Value::ValueType::LoadAddress:
+      case Value::ValueType::HostAddress:
+        if (error_ptr) {
+          error_ptr->SetErrorStringWithFormat(
+              "unable to extract DW_OP_bit_piece(bit_size = %" PRIu64
+              ", bit_offset = %" PRIu64 ") from an address value.",
+              piece_bit_size, piece_bit_offset);
+        }
+        return false;
+      }
+    }
+    break;
+
+  // OPCODE: DW_OP_push_object_address
+  // OPERANDS: none
+  // DESCRIPTION: Pushes the address of the object currently being
+  // evaluated as part of evaluation of a user presented expression. This
+  // object may correspond to an independent variable described by its own
+  // DIE or it may be a component of an array, structure, or class whose
+  // address has been dynamically determined by an earlier step during user
+  // expression evaluation.
+  case DW_OP_push_object_address:
+    if (m_object_address_ptr)
+      stack.push_back(*m_object_address_ptr);
+    else {
+      if (error_ptr)
+        error_ptr->SetErrorString("DW_OP_push_object_address used without "
+                                  "specifying an object address");
+      return false;
+    }
+    break;
+
+  // OPCODE: DW_OP_call2
+  // OPERANDS:
+  //      uint16_t compile unit relative offset of a DIE
+  // DESCRIPTION: Performs subroutine calls during evaluation
+  // of a DWARF expression. The operand is the 2-byte unsigned offset of a
+  // debugging information entry in the current compilation unit.
+  //
+  // Operand interpretation is exactly like that for DW_FORM_ref2.
+  //
+  // This operation transfers control of DWARF expression evaluation to the
+  // DW_AT_location attribute of the referenced DIE. If there is no such
+  // attribute, then there is no effect. Execution of the DWARF expression of
+  // a DW_AT_location attribute may add to and/or remove from values on the
+  // stack. Execution returns to the point following the call when the end of
+  // the attribute is reached. Values on the stack at the time of the call
+  // may be used as parameters by the called expression and values left on
+  // the stack by the called expression may be used as return values by prior
+  // agreement between the calling and called expressions.
+  case DW_OP_call2:
+    if (error_ptr)
+      error_ptr->SetErrorString("Unimplemented opcode DW_OP_call2.");
+    return false;
+  // OPCODE: DW_OP_call4
+  // OPERANDS: 1
+  //      uint32_t compile unit relative offset of a DIE
+  // DESCRIPTION: Performs a subroutine call during evaluation of a DWARF
+  // expression. For DW_OP_call4, the operand is a 4-byte unsigned offset of
+  // a debugging information entry in  the current compilation unit.
+  //
+  // Operand interpretation DW_OP_call4 is exactly like that for
+  // DW_FORM_ref4.
+  //
+  // This operation transfers control of DWARF expression evaluation to the
+  // DW_AT_location attribute of the referenced DIE. If there is no such
+  // attribute, then there is no effect. Execution of the DWARF expression of
+  // a DW_AT_location attribute may add to and/or remove from values on the
+  // stack. Execution returns to the point following the call when the end of
+  // the attribute is reached. Values on the stack at the time of the call
+  // may be used as parameters by the called expression and values left on
+  // the stack by the called expression may be used as return values by prior
+  // agreement between the calling and called expressions.
+  case DW_OP_call4:
+    if (error_ptr)
+      error_ptr->SetErrorString("Unimplemented opcode DW_OP_call4.");
+    return false;
+
+  // OPCODE: DW_OP_stack_value
+  // OPERANDS: None
+  // DESCRIPTION: Specifies that the object does not exist in memory but
+  // rather is a constant value.  The value from the top of the stack is the
+  // value to be used.  This is the actual object value and not the location.
+  case DW_OP_stack_value:
+    if (stack.empty()) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 1 item for DW_OP_stack_value.");
+      return false;
+    }
+    stack.back().SetValueType(Value::ValueType::Scalar);
+    break;
+
+  // OPCODE: DW_OP_convert
+  // OPERANDS: 1
+  //      A ULEB128 that is either a DIE offset of a
+  //      DW_TAG_base_type or 0 for the generic (pointer-sized) type.
+  //
+  // DESCRIPTION: Pop the top stack element, convert it to a
+  // different type, and push the result.
+  case DW_OP_convert: {
+    if (stack.size() < 1) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "Expression stack needs at least 1 item for DW_OP_convert.");
+      return false;
+    }
+    const uint64_t die_offset = opcodes.GetULEB128(&offset);
+    uint64_t bit_size;
+    bool sign;
+    if (die_offset == 0) {
+      // The generic type has the size of an address on the target
+      // machine and an unspecified signedness. Scalar has no
+      // "unspecified signedness", so we use unsigned types.
+      if (!module_sp) {
+        if (error_ptr)
+          error_ptr->SetErrorString("No module");
+        return false;
+      }
+      sign = false;
+      bit_size = module_sp->GetArchitecture().GetAddressByteSize() * 8;
+      if (!bit_size) {
+        if (error_ptr)
+          error_ptr->SetErrorString("unspecified architecture");
+        return false;
+      }
+    } else {
+      // Retrieve the type DIE that the value is being converted to.
+      // FIXME: the constness has annoying ripple effects.
+      DWARFDIE die = const_cast<DWARFUnit *>(dwarf_cu)->GetDIE(die_offset);
+      if (!die) {
+        if (error_ptr)
+          error_ptr->SetErrorString("Cannot resolve DW_OP_convert type DIE");
+        return false;
+      }
+      uint64_t encoding =
+          die.GetAttributeValueAsUnsigned(DW_AT_encoding, DW_ATE_hi_user);
+      bit_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8;
+      if (!bit_size)
+        bit_size = die.GetAttributeValueAsUnsigned(DW_AT_bit_size, 0);
+      if (!bit_size) {
+        if (error_ptr)
+          error_ptr->SetErrorString("Unsupported type size in DW_OP_convert");
+        return false;
+      }
+      switch (encoding) {
+      case DW_ATE_signed:
+      case DW_ATE_signed_char:
+        sign = true;
+        break;
+      case DW_ATE_unsigned:
+      case DW_ATE_unsigned_char:
+        sign = false;
+        break;
+      default:
+        if (error_ptr)
+          error_ptr->SetErrorString("Unsupported encoding in DW_OP_convert");
+        return false;
+      }
+    }
+    Scalar &top = stack.back().ResolveValue(m_exe_ctx);
+    top.TruncOrExtendTo(bit_size, sign);
+    break;
+  }
+
+  // OPCODE: DW_OP_call_frame_cfa
+  // OPERANDS: None
+  // DESCRIPTION: Specifies a DWARF expression that pushes the value of
+  // the canonical frame address consistent with the call frame information
+  // located in .debug_frame (or in the FDEs of the eh_frame section).
+  case DW_OP_call_frame_cfa:
+    if (frame) {
+      // Note that we don't have to parse FDEs because this DWARF expression
+      // is commonly evaluated with a valid stack frame.
+      StackID id = frame->GetStackID();
+      addr_t cfa = id.GetCallFrameAddress();
+      if (cfa != LLDB_INVALID_ADDRESS) {
+        stack.push_back(Scalar(cfa));
+        stack.back().SetValueType(Value::ValueType::LoadAddress);
+      } else if (error_ptr)
+        error_ptr->SetErrorString("Stack frame does not include a canonical "
+                                  "frame address for DW_OP_call_frame_cfa "
+                                  "opcode.");
+    } else {
+      if (error_ptr)
+        error_ptr->SetErrorString("Invalid stack frame in context for "
+                                  "DW_OP_call_frame_cfa opcode.");
+      return false;
+    }
+    break;
+
+  // OPCODE: DW_OP_form_tls_address (or the old pre-DWARFv3 vendor extension
+  // opcode, DW_OP_GNU_push_tls_address)
+  // OPERANDS: none
+  // DESCRIPTION: Pops a TLS offset from the stack, converts it to
+  // an address in the current thread's thread-local storage block, and
+  // pushes it on the stack.
+  case DW_OP_form_tls_address:
+  case DW_OP_GNU_push_tls_address: {
+    if (stack.size() < 1) {
+      if (error_ptr) {
+        if (op == DW_OP_form_tls_address)
+          error_ptr->SetErrorString(
+              "DW_OP_form_tls_address needs an argument.");
+        else
+          error_ptr->SetErrorString(
+              "DW_OP_GNU_push_tls_address needs an argument.");
+      }
+      return false;
+    }
+
+    if (!m_exe_ctx || !module_sp) {
+      if (error_ptr)
+        error_ptr->SetErrorString("No context to evaluate TLS within.");
+      return false;
+    }
+
+    Thread *thread = m_exe_ctx->GetThreadPtr();
+    if (!thread) {
+      if (error_ptr)
+        error_ptr->SetErrorString("No thread to evaluate TLS within.");
+      return false;
+    }
+
+    // Lookup the TLS block address for this thread and module.
+    const addr_t tls_file_addr =
+        stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
+    const addr_t tls_load_addr =
+        thread->GetThreadLocalData(module_sp, tls_file_addr);
+
+    if (tls_load_addr == LLDB_INVALID_ADDRESS) {
+      if (error_ptr)
+        error_ptr->SetErrorString(
+            "No TLS data currently exists for this thread.");
+      return false;
+    }
+
+    stack.back().GetScalar() = tls_load_addr;
+    stack.back().SetValueType(Value::ValueType::LoadAddress);
+  } break;
+
+  // OPCODE: DW_OP_addrx (DW_OP_GNU_addr_index is the legacy name.)
+  // OPERANDS: 1
+  //      ULEB128: index to the .debug_addr section
+  // DESCRIPTION: Pushes an address to the stack from the .debug_addr
+  // section with the base address specified by the DW_AT_addr_base attribute
+  // and the 0 based index is the ULEB128 encoded index.
+  case DW_OP_addrx:
+  case DW_OP_GNU_addr_index: {
+    if (!dwarf_cu) {
+      if (error_ptr)
+        error_ptr->SetErrorString("DW_OP_GNU_addr_index found without a "
+                                  "compile unit being specified");
+      return false;
+    }
+    uint64_t index = opcodes.GetULEB128(&offset);
+    lldb::addr_t value =
+        DWARFExpression::ReadAddressFromDebugAddrSection(dwarf_cu, index);
+    stack.push_back(Scalar(value));
+    stack.back().SetValueType(Value::ValueType::FileAddress);
+  } break;
+
+  // OPCODE: DW_OP_GNU_const_index
+  // OPERANDS: 1
+  //      ULEB128: index to the .debug_addr section
+  // DESCRIPTION: Pushes an constant with the size of a machine address to
+  // the stack from the .debug_addr section with the base address specified
+  // by the DW_AT_addr_base attribute and the 0 based index is the ULEB128
+  // encoded index.
+  case DW_OP_GNU_const_index: {
+    if (!dwarf_cu) {
+      if (error_ptr)
+        error_ptr->SetErrorString("DW_OP_GNU_const_index found without a "
+                                  "compile unit being specified");
+      return false;
+    }
+    uint64_t index = opcodes.GetULEB128(&offset);
+    lldb::addr_t value =
+        DWARFExpression::ReadAddressFromDebugAddrSection(dwarf_cu, index);
+    stack.push_back(Scalar(value));
+  } break;
+
+  case DW_OP_entry_value: {
+    if (!Evaluate_DW_OP_entry_value(stack, m_exe_ctx, m_reg_ctx, opcodes,
+                                    offset, error_ptr, log)) {
+      LLDB_ERRORF(error_ptr, "Could not evaluate %s.", DW_OP_value_to_name(op));
+      return false;
+    }
+    break;
+  }
+
+  default:
+    LLDB_LOGF(log, "Unhandled opcode %s in DWARFExpression.",
+              DW_OP_value_to_name(op));
+    break;
+  }
+
+  return true;
+}
diff --git a/lldb/source/Expression/DWARFEvaluatorFactory.cpp b/lldb/source/Expression/DWARFEvaluatorFactory.cpp
new file mode 100644
index 000000000000..c0612641204a
--- /dev/null
+++ b/lldb/source/Expression/DWARFEvaluatorFactory.cpp
@@ -0,0 +1,57 @@
+//===-- DWARFEvaluatorFactory.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/Expression/DWARFEvaluatorFactory.h"
+#include "lldb/Expression/DWARFEvaluator.h"
+
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Target/RegisterContext.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// PluginInterface protocol
+lldb_private::ConstString DWARFEvaluatorFactory::GetPluginName() {
+  static ConstString g_name("vendor-default");
+  return g_name;
+}
+
+// FindPlugin
+//
+// Platforms can register a callback to use when creating DWARF expression
+// evaluators to allow handling platform-specific DWARF codes.
+std::unique_ptr<DWARFEvaluatorFactory>
+DWARFEvaluatorFactory::FindPlugin(Module *module) {
+  std::unique_ptr<DWARFEvaluatorFactory> instance_up;
+  DWARFEvaluatorFactoryCreateInstance create_callback;
+
+  for (size_t idx = 0;
+       (create_callback =
+            PluginManager::GetDWARFEvaluatorFactoryCreateCallbackAtIndex(
+                idx)) != nullptr;
+       ++idx) {
+    instance_up.reset(create_callback(module));
+
+    if (instance_up) {
+      return instance_up;
+    }
+  }
+
+  instance_up.reset(new DWARFEvaluatorFactory());
+  return instance_up;
+}
+
+std::unique_ptr<DWARFEvaluator> DWARFEvaluatorFactory::CreateDWARFEvaluator(
+    const DWARFExpression &dwarf_expression, ExecutionContext *exe_ctx,
+    RegisterContext *reg_ctx, const Value *initial_value_ptr,
+    const Value *object_address_ptr) {
+  return std::make_unique<DWARFEvaluator>(dwarf_expression, exe_ctx, reg_ctx,
+                                          initial_value_ptr,
+                                          object_address_ptr);
+}
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index a10546c1deae..4d13e4642af3 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -15,6 +15,8 @@
 #include "lldb/Core/Module.h"
 #include "lldb/Core/Value.h"
 #include "lldb/Core/dwarf.h"
+#include "lldb/Expression/DWARFEvaluator.h"
+#include "lldb/Expression/DWARFEvaluatorFactory.h"
 #include "lldb/Utility/DataEncoder.h"
 #include "lldb/Utility/Log.h"
 #include "lldb/Utility/RegisterValue.h"
@@ -41,8 +43,8 @@
 using namespace lldb;
 using namespace lldb_private;
 
-static lldb::addr_t
-ReadAddressFromDebugAddrSection(const DWARFUnit *dwarf_cu,
+lldb::addr_t
+DWARFExpression::ReadAddressFromDebugAddrSection(const DWARFUnit *dwarf_cu,
                                 uint32_t index) {
   uint32_t index_size = dwarf_cu->GetAddressByteSize();
   dw_offset_t addr_base = dwarf_cu->GetAddrBase();
@@ -96,7 +98,7 @@ void DWARFExpression::SetLocationListAddresses(addr_t cu_file_addr,
   m_loclist_addresses = LoclistAddresses{cu_file_addr, func_file_addr};
 }
 
-int DWARFExpression::GetRegisterKind() { return m_reg_kind; }
+RegisterKind DWARFExpression::GetRegisterKind() const { return m_reg_kind; }
 
 void DWARFExpression::SetRegisterKind(RegisterKind reg_kind) {
   m_reg_kind = reg_kind;
@@ -150,52 +152,6 @@ void DWARFExpression::GetDescription(Stream *s, lldb::DescriptionLevel level,
   }
 }
 
-static bool 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");
-  } else {
-    uint32_t native_reg =
-        reg_ctx->ConvertRegisterKindToRegisterNumber(reg_kind, reg_num);
-    if (native_reg == LLDB_INVALID_REGNUM) {
-      if (error_ptr)
-        error_ptr->SetErrorStringWithFormat("Unable to convert register "
-                                            "kind=%u reg_num=%u to a native "
-                                            "register number.\n",
-                                            reg_kind, reg_num);
-    } else {
-      const RegisterInfo *reg_info =
-          reg_ctx->GetRegisterInfoAtIndex(native_reg);
-      RegisterValue reg_value;
-      if (reg_ctx->ReadRegister(reg_info, reg_value)) {
-        if (reg_value.GetScalarValue(value.GetScalar())) {
-          value.SetValueType(Value::ValueType::Scalar);
-          value.SetContext(Value::ContextType::RegisterInfo,
-                           const_cast<RegisterInfo *>(reg_info));
-          if (error_ptr)
-            error_ptr->Clear();
-          return true;
-        } else {
-          // If we get this error, then we need to implement a value buffer in
-          // the dwarf expression evaluation function...
-          if (error_ptr)
-            error_ptr->SetErrorStringWithFormat(
-                "register %s can't be converted to a scalar value",
-                reg_info->name);
-        }
-      } else {
-        if (error_ptr)
-          error_ptr->SetErrorStringWithFormat("register %s is not available",
-                                              reg_info->name);
-      }
-    }
-  }
-  return false;
-}
-
 /// Return the length in bytes of the set of operands for \p op. No guarantees
 /// are made on the state of \p data after this call.
 static offset_t GetOpcodeDataSize(const DataExtractor &data,
@@ -955,1719 +911,17 @@ bool DWARFExpression::Evaluate(
     const Value *initial_value_ptr, const Value *object_address_ptr,
     Value &result, Status *error_ptr) {
 
-  if (opcodes.GetByteSize() == 0) {
-    if (error_ptr)
-      error_ptr->SetErrorString(
-          "no location, value may have been optimized out");
-    return false;
-  }
-  std::vector<Value> stack;
-
-  Process *process = nullptr;
-  StackFrame *frame = nullptr;
-
-  if (exe_ctx) {
-    process = exe_ctx->GetProcessPtr();
-    frame = exe_ctx->GetFramePtr();
-  }
-  if (reg_ctx == nullptr && frame)
-    reg_ctx = frame->GetRegisterContext().get();
-
-  if (initial_value_ptr)
-    stack.push_back(*initial_value_ptr);
-
-  lldb::offset_t offset = 0;
-  Value tmp;
-  uint32_t reg_num;
-
-  /// Insertion point for evaluating multi-piece expression.
-  uint64_t op_piece_offset = 0;
-  Value pieces; // Used for DW_OP_piece
-
-  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
-  // A generic type is "an integral type that has the size of an address and an
-  // unspecified signedness". For now, just use the signedness of the operand.
-  // TODO: Implement a real typed stack, and store the genericness of the value
-  // there.
-  auto to_generic = [&](auto v) {
-    bool is_signed = std::is_signed<decltype(v)>::value;
-    return Scalar(llvm::APSInt(
-        llvm::APInt(8 * opcodes.GetAddressByteSize(), v, is_signed),
-        !is_signed));
-  };
-
-  // The default kind is a memory location. This is updated by any
-  // operation that changes this, such as DW_OP_stack_value, and reset
-  // by composition operations like DW_OP_piece.
-  LocationDescriptionKind dwarf4_location_description_kind = Memory;
-
-  while (opcodes.ValidOffset(offset)) {
-    const lldb::offset_t op_offset = offset;
-    const uint8_t op = opcodes.GetU8(&offset);
-
-    if (log && log->GetVerbose()) {
-      size_t count = stack.size();
-      LLDB_LOGF(log, "Stack before operation has %" PRIu64 " values:",
-                (uint64_t)count);
-      for (size_t i = 0; i < count; ++i) {
-        StreamString new_value;
-        new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
-        stack[i].Dump(&new_value);
-        LLDB_LOGF(log, "  %s", new_value.GetData());
-      }
-      LLDB_LOGF(log, "0x%8.8" PRIx64 ": %s", op_offset,
-                DW_OP_value_to_name(op));
-    }
-
-    switch (op) {
-    // The DW_OP_addr operation has a single operand that encodes a machine
-    // address and whose size is the size of an address on the target machine.
-    case DW_OP_addr:
-      stack.push_back(Scalar(opcodes.GetAddress(&offset)));
-      stack.back().SetValueType(Value::ValueType::FileAddress);
-      // Convert the file address to a load address, so subsequent
-      // DWARF operators can operate on it.
-      if (frame)
-        stack.back().ConvertToLoadAddress(module_sp.get(),
-                                          frame->CalculateTarget().get());
-      break;
-
-    // The DW_OP_addr_sect_offset4 is used for any location expressions in
-    // shared libraries that have a location like:
-    //  DW_OP_addr(0x1000)
-    // If this address resides in a shared library, then this virtual address
-    // won't make sense when it is evaluated in the context of a running
-    // process where shared libraries have been slid. To account for this, this
-    // new address type where we can store the section pointer and a 4 byte
-    // offset.
-    //      case DW_OP_addr_sect_offset4:
-    //          {
-    //              result_type = eResultTypeFileAddress;
-    //              lldb::Section *sect = (lldb::Section
-    //              *)opcodes.GetMaxU64(&offset, sizeof(void *));
-    //              lldb::addr_t sect_offset = opcodes.GetU32(&offset);
-    //
-    //              Address so_addr (sect, sect_offset);
-    //              lldb::addr_t load_addr = so_addr.GetLoadAddress();
-    //              if (load_addr != LLDB_INVALID_ADDRESS)
-    //              {
-    //                  // We successfully resolve a file address to a load
-    //                  // address.
-    //                  stack.push_back(load_addr);
-    //                  break;
-    //              }
-    //              else
-    //              {
-    //                  // We were able
-    //                  if (error_ptr)
-    //                      error_ptr->SetErrorStringWithFormat ("Section %s in
-    //                      %s is not currently loaded.\n",
-    //                      sect->GetName().AsCString(),
-    //                      sect->GetModule()->GetFileSpec().GetFilename().AsCString());
-    //                  return false;
-    //              }
-    //          }
-    //          break;
-
-    // OPCODE: DW_OP_deref
-    // OPERANDS: none
-    // DESCRIPTION: Pops the top stack entry and treats it as an address.
-    // The value retrieved from that address is pushed. The size of the data
-    // retrieved from the dereferenced address is the size of an address on the
-    // target machine.
-    case DW_OP_deref: {
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString("Expression stack empty for DW_OP_deref.");
-        return false;
-      }
-      Value::ValueType value_type = stack.back().GetValueType();
-      switch (value_type) {
-      case Value::ValueType::HostAddress: {
-        void *src = (void *)stack.back().GetScalar().ULongLong();
-        intptr_t ptr;
-        ::memcpy(&ptr, src, sizeof(void *));
-        stack.back().GetScalar() = ptr;
-        stack.back().ClearContext();
-      } break;
-      case Value::ValueType::FileAddress: {
-        auto file_addr = stack.back().GetScalar().ULongLong(
-            LLDB_INVALID_ADDRESS);
-        if (!module_sp) {
-          if (error_ptr)
-            error_ptr->SetErrorString(
-                "need module to resolve file address for DW_OP_deref");
-          return false;
-        }
-        Address so_addr;
-        if (!module_sp->ResolveFileAddress(file_addr, so_addr)) {
-          if (error_ptr)
-            error_ptr->SetErrorString(
-                "failed to resolve file address in module");
-          return false;
-        }
-        addr_t load_Addr = so_addr.GetLoadAddress(exe_ctx->GetTargetPtr());
-        if (load_Addr == LLDB_INVALID_ADDRESS) {
-          if (error_ptr)
-            error_ptr->SetErrorString("failed to resolve load address");
-          return false;
-        }
-        stack.back().GetScalar() = load_Addr;
-        // Fall through to load address promotion code below.
-      } LLVM_FALLTHROUGH;
-      case Value::ValueType::Scalar:
-        // Promote Scalar to LoadAddress and fall through.
-        stack.back().SetValueType(Value::ValueType::LoadAddress);
-        LLVM_FALLTHROUGH;
-      case Value::ValueType::LoadAddress:
-        if (exe_ctx) {
-          if (process) {
-            lldb::addr_t pointer_addr =
-                stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
-            Status error;
-            lldb::addr_t pointer_value =
-                process->ReadPointerFromMemory(pointer_addr, error);
-            if (pointer_value != LLDB_INVALID_ADDRESS) {
-              if (ABISP abi_sp = process->GetABI())
-                pointer_value = abi_sp->FixCodeAddress(pointer_value);
-              stack.back().GetScalar() = pointer_value;
-              stack.back().ClearContext();
-            } else {
-              if (error_ptr)
-                error_ptr->SetErrorStringWithFormat(
-                    "Failed to dereference pointer from 0x%" PRIx64
-                    " for DW_OP_deref: %s\n",
-                    pointer_addr, error.AsCString());
-              return false;
-            }
-          } else {
-            if (error_ptr)
-              error_ptr->SetErrorString("NULL process for DW_OP_deref.\n");
-            return false;
-          }
-        } else {
-          if (error_ptr)
-            error_ptr->SetErrorString(
-                "NULL execution context for DW_OP_deref.\n");
-          return false;
-        }
-        break;
-
-      case Value::ValueType::Invalid:
-        if (error_ptr)
-          error_ptr->SetErrorString("Invalid value type for DW_OP_deref.\n");
-        return false;
-      }
-
-    } break;
-
-    // OPCODE: DW_OP_deref_size
-    // OPERANDS: 1
-    //  1 - uint8_t that specifies the size of the data to dereference.
-    // DESCRIPTION: Behaves like the DW_OP_deref operation: it pops the top
-    // stack entry and treats it as an address. The value retrieved from that
-    // address is pushed. In the DW_OP_deref_size operation, however, the size
-    // in bytes of the data retrieved from the dereferenced address is
-    // specified by the single operand. This operand is a 1-byte unsigned
-    // integral constant whose value may not be larger than the size of an
-    // address on the target machine. The data retrieved is zero extended to
-    // the size of an address on the target machine before being pushed on the
-    // expression stack.
-    case DW_OP_deref_size: {
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack empty for DW_OP_deref_size.");
-        return false;
-      }
-      uint8_t size = opcodes.GetU8(&offset);
-      Value::ValueType value_type = stack.back().GetValueType();
-      switch (value_type) {
-      case Value::ValueType::HostAddress: {
-        void *src = (void *)stack.back().GetScalar().ULongLong();
-        intptr_t ptr;
-        ::memcpy(&ptr, src, sizeof(void *));
-        // I can't decide whether the size operand should apply to the bytes in
-        // their
-        // lldb-host endianness or the target endianness.. I doubt this'll ever
-        // come up but I'll opt for assuming big endian regardless.
-        switch (size) {
-        case 1:
-          ptr = ptr & 0xff;
-          break;
-        case 2:
-          ptr = ptr & 0xffff;
-          break;
-        case 3:
-          ptr = ptr & 0xffffff;
-          break;
-        case 4:
-          ptr = ptr & 0xffffffff;
-          break;
-        // the casts are added to work around the case where intptr_t is a 32
-        // bit quantity;
-        // presumably we won't hit the 5..7 cases if (void*) is 32-bits in this
-        // program.
-        case 5:
-          ptr = (intptr_t)ptr & 0xffffffffffULL;
-          break;
-        case 6:
-          ptr = (intptr_t)ptr & 0xffffffffffffULL;
-          break;
-        case 7:
-          ptr = (intptr_t)ptr & 0xffffffffffffffULL;
-          break;
-        default:
-          break;
-        }
-        stack.back().GetScalar() = ptr;
-        stack.back().ClearContext();
-      } break;
-      case Value::ValueType::Scalar:
-      case Value::ValueType::LoadAddress:
-        if (exe_ctx) {
-          if (process) {
-            lldb::addr_t pointer_addr =
-                stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
-            uint8_t addr_bytes[sizeof(lldb::addr_t)];
-            Status error;
-            if (process->ReadMemory(pointer_addr, &addr_bytes, size, error) ==
-                size) {
-              DataExtractor addr_data(addr_bytes, sizeof(addr_bytes),
-                                      process->GetByteOrder(), size);
-              lldb::offset_t addr_data_offset = 0;
-              switch (size) {
-              case 1:
-                stack.back().GetScalar() = addr_data.GetU8(&addr_data_offset);
-                break;
-              case 2:
-                stack.back().GetScalar() = addr_data.GetU16(&addr_data_offset);
-                break;
-              case 4:
-                stack.back().GetScalar() = addr_data.GetU32(&addr_data_offset);
-                break;
-              case 8:
-                stack.back().GetScalar() = addr_data.GetU64(&addr_data_offset);
-                break;
-              default:
-                stack.back().GetScalar() =
-                    addr_data.GetAddress(&addr_data_offset);
-              }
-              stack.back().ClearContext();
-            } else {
-              if (error_ptr)
-                error_ptr->SetErrorStringWithFormat(
-                    "Failed to dereference pointer from 0x%" PRIx64
-                    " for DW_OP_deref: %s\n",
-                    pointer_addr, error.AsCString());
-              return false;
-            }
-          } else {
-            if (error_ptr)
-              error_ptr->SetErrorString("NULL process for DW_OP_deref_size.\n");
-            return false;
-          }
-        } else {
-          if (error_ptr)
-            error_ptr->SetErrorString(
-                "NULL execution context for DW_OP_deref_size.\n");
-          return false;
-        }
-        break;
-
-      case Value::ValueType::FileAddress:
-      case Value::ValueType::Invalid:
-        if (error_ptr)
-          error_ptr->SetErrorString("Invalid value for DW_OP_deref_size.\n");
-        return false;
-      }
-
-    } break;
-
-    // OPCODE: DW_OP_xderef_size
-    // OPERANDS: 1
-    //  1 - uint8_t that specifies the size of the data to dereference.
-    // DESCRIPTION: Behaves like the DW_OP_xderef operation: the entry at
-    // the top of the stack is treated as an address. The second stack entry is
-    // treated as an "address space identifier" for those architectures that
-    // support multiple address spaces. The top two stack elements are popped,
-    // a data item is retrieved through an implementation-defined address
-    // calculation and pushed as the new stack top. In the DW_OP_xderef_size
-    // operation, however, the size in bytes of the data retrieved from the
-    // dereferenced address is specified by the single operand. This operand is
-    // a 1-byte unsigned integral constant whose value may not be larger than
-    // the size of an address on the target machine. The data retrieved is zero
-    // extended to the size of an address on the target machine before being
-    // pushed on the expression stack.
-    case DW_OP_xderef_size:
-      if (error_ptr)
-        error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef_size.");
-      return false;
-    // OPCODE: DW_OP_xderef
-    // OPERANDS: none
-    // DESCRIPTION: Provides an extended dereference mechanism. The entry at
-    // the top of the stack is treated as an address. The second stack entry is
-    // treated as an "address space identifier" for those architectures that
-    // support multiple address spaces. The top two stack elements are popped,
-    // a data item is retrieved through an implementation-defined address
-    // calculation and pushed as the new stack top. The size of the data
-    // retrieved from the dereferenced address is the size of an address on the
-    // target machine.
-    case DW_OP_xderef:
-      if (error_ptr)
-        error_ptr->SetErrorString("Unimplemented opcode: DW_OP_xderef.");
-      return false;
-
-    // All DW_OP_constXXX opcodes have a single operand as noted below:
-    //
-    // Opcode           Operand 1
-    // DW_OP_const1u    1-byte unsigned integer constant
-    // DW_OP_const1s    1-byte signed integer constant
-    // DW_OP_const2u    2-byte unsigned integer constant
-    // DW_OP_const2s    2-byte signed integer constant
-    // DW_OP_const4u    4-byte unsigned integer constant
-    // DW_OP_const4s    4-byte signed integer constant
-    // DW_OP_const8u    8-byte unsigned integer constant
-    // DW_OP_const8s    8-byte signed integer constant
-    // DW_OP_constu     unsigned LEB128 integer constant
-    // DW_OP_consts     signed LEB128 integer constant
-    case DW_OP_const1u:
-      stack.push_back(to_generic(opcodes.GetU8(&offset)));
-      break;
-    case DW_OP_const1s:
-      stack.push_back(to_generic((int8_t)opcodes.GetU8(&offset)));
-      break;
-    case DW_OP_const2u:
-      stack.push_back(to_generic(opcodes.GetU16(&offset)));
-      break;
-    case DW_OP_const2s:
-      stack.push_back(to_generic((int16_t)opcodes.GetU16(&offset)));
-      break;
-    case DW_OP_const4u:
-      stack.push_back(to_generic(opcodes.GetU32(&offset)));
-      break;
-    case DW_OP_const4s:
-      stack.push_back(to_generic((int32_t)opcodes.GetU32(&offset)));
-      break;
-    case DW_OP_const8u:
-      stack.push_back(to_generic(opcodes.GetU64(&offset)));
-      break;
-    case DW_OP_const8s:
-      stack.push_back(to_generic((int64_t)opcodes.GetU64(&offset)));
-      break;
-    // These should also use to_generic, but we can't do that due to a
-    // producer-side bug in llvm. See llvm.org/pr48087.
-    case DW_OP_constu:
-      stack.push_back(Scalar(opcodes.GetULEB128(&offset)));
-      break;
-    case DW_OP_consts:
-      stack.push_back(Scalar(opcodes.GetSLEB128(&offset)));
-      break;
-
-    // OPCODE: DW_OP_dup
-    // OPERANDS: none
-    // DESCRIPTION: duplicates the value at the top of the stack
-    case DW_OP_dup:
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString("Expression stack empty for DW_OP_dup.");
-        return false;
-      } else
-        stack.push_back(stack.back());
-      break;
-
-    // OPCODE: DW_OP_drop
-    // OPERANDS: none
-    // DESCRIPTION: pops the value at the top of the stack
-    case DW_OP_drop:
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString("Expression stack empty for DW_OP_drop.");
-        return false;
-      } else
-        stack.pop_back();
-      break;
-
-    // OPCODE: DW_OP_over
-    // OPERANDS: none
-    // DESCRIPTION: Duplicates the entry currently second in the stack at
-    // the top of the stack.
-    case DW_OP_over:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_over.");
-        return false;
-      } else
-        stack.push_back(stack[stack.size() - 2]);
-      break;
-
-    // OPCODE: DW_OP_pick
-    // OPERANDS: uint8_t index into the current stack
-    // DESCRIPTION: The stack entry with the specified index (0 through 255,
-    // inclusive) is pushed on the stack
-    case DW_OP_pick: {
-      uint8_t pick_idx = opcodes.GetU8(&offset);
-      if (pick_idx < stack.size())
-        stack.push_back(stack[stack.size() - 1 - pick_idx]);
-      else {
-        if (error_ptr)
-          error_ptr->SetErrorStringWithFormat(
-              "Index %u out of range for DW_OP_pick.\n", pick_idx);
-        return false;
-      }
-    } break;
-
-    // OPCODE: DW_OP_swap
-    // OPERANDS: none
-    // DESCRIPTION: swaps the top two stack entries. The entry at the top
-    // of the stack becomes the second stack entry, and the second entry
-    // becomes the top of the stack
-    case DW_OP_swap:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_swap.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.back() = stack[stack.size() - 2];
-        stack[stack.size() - 2] = tmp;
-      }
-      break;
-
-    // OPCODE: DW_OP_rot
-    // OPERANDS: none
-    // DESCRIPTION: Rotates the first three stack entries. The entry at
-    // the top of the stack becomes the third stack entry, the second entry
-    // becomes the top of the stack, and the third entry becomes the second
-    // entry.
-    case DW_OP_rot:
-      if (stack.size() < 3) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 3 items for DW_OP_rot.");
-        return false;
-      } else {
-        size_t last_idx = stack.size() - 1;
-        Value old_top = stack[last_idx];
-        stack[last_idx] = stack[last_idx - 1];
-        stack[last_idx - 1] = stack[last_idx - 2];
-        stack[last_idx - 2] = old_top;
-      }
-      break;
-
-    // OPCODE: DW_OP_abs
-    // OPERANDS: none
-    // DESCRIPTION: pops the top stack entry, interprets it as a signed
-    // value and pushes its absolute value. If the absolute value can not be
-    // represented, the result is undefined.
-    case DW_OP_abs:
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 1 item for DW_OP_abs.");
-        return false;
-      } else if (!stack.back().ResolveValue(exe_ctx).AbsoluteValue()) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Failed to take the absolute value of the first stack item.");
-        return false;
-      }
-      break;
-
-    // OPCODE: DW_OP_and
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, performs a bitwise and
-    // operation on the two, and pushes the result.
-    case DW_OP_and:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_and.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) & tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_div
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, divides the former second
-    // entry by the former top of the stack using signed division, and pushes
-    // the result.
-    case DW_OP_div:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_div.");
-        return false;
-      } else {
-        tmp = stack.back();
-        if (tmp.ResolveValue(exe_ctx).IsZero()) {
-          if (error_ptr)
-            error_ptr->SetErrorString("Divide by zero.");
-          return false;
-        } else {
-          stack.pop_back();
-          stack.back() =
-              stack.back().ResolveValue(exe_ctx) / tmp.ResolveValue(exe_ctx);
-          if (!stack.back().ResolveValue(exe_ctx).IsValid()) {
-            if (error_ptr)
-              error_ptr->SetErrorString("Divide failed.");
-            return false;
-          }
-        }
-      }
-      break;
-
-    // OPCODE: DW_OP_minus
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, subtracts the former top
-    // of the stack from the former second entry, and pushes the result.
-    case DW_OP_minus:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_minus.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) - tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_mod
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values and pushes the result of
-    // the calculation: former second stack entry modulo the former top of the
-    // stack.
-    case DW_OP_mod:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_mod.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) % tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_mul
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack entries, multiplies them
-    // together, and pushes the result.
-    case DW_OP_mul:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_mul.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) * tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_neg
-    // OPERANDS: none
-    // DESCRIPTION: pops the top stack entry, and pushes its negation.
-    case DW_OP_neg:
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 1 item for DW_OP_neg.");
-        return false;
-      } else {
-        if (!stack.back().ResolveValue(exe_ctx).UnaryNegate()) {
-          if (error_ptr)
-            error_ptr->SetErrorString("Unary negate failed.");
-          return false;
-        }
-      }
-      break;
-
-    // OPCODE: DW_OP_not
-    // OPERANDS: none
-    // DESCRIPTION: pops the top stack entry, and pushes its bitwise
-    // complement
-    case DW_OP_not:
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 1 item for DW_OP_not.");
-        return false;
-      } else {
-        if (!stack.back().ResolveValue(exe_ctx).OnesComplement()) {
-          if (error_ptr)
-            error_ptr->SetErrorString("Logical NOT failed.");
-          return false;
-        }
-      }
-      break;
-
-    // OPCODE: DW_OP_or
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack entries, performs a bitwise or
-    // operation on the two, and pushes the result.
-    case DW_OP_or:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_or.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) | tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_plus
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack entries, adds them together, and
-    // pushes the result.
-    case DW_OP_plus:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_plus.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().GetScalar() += tmp.GetScalar();
-      }
-      break;
-
-    // OPCODE: DW_OP_plus_uconst
-    // OPERANDS: none
-    // DESCRIPTION: pops the top stack entry, adds it to the unsigned LEB128
-    // constant operand and pushes the result.
-    case DW_OP_plus_uconst:
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 1 item for DW_OP_plus_uconst.");
-        return false;
-      } else {
-        const uint64_t uconst_value = opcodes.GetULEB128(&offset);
-        // Implicit conversion from a UINT to a Scalar...
-        stack.back().GetScalar() += uconst_value;
-        if (!stack.back().GetScalar().IsValid()) {
-          if (error_ptr)
-            error_ptr->SetErrorString("DW_OP_plus_uconst failed.");
-          return false;
-        }
-      }
-      break;
-
-    // OPCODE: DW_OP_shl
-    // OPERANDS: none
-    // DESCRIPTION:  pops the top two stack entries, shifts the former
-    // second entry left by the number of bits specified by the former top of
-    // the stack, and pushes the result.
-    case DW_OP_shl:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_shl.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) <<= tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_shr
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack entries, shifts the former second
-    // entry right logically (filling with zero bits) by the number of bits
-    // specified by the former top of the stack, and pushes the result.
-    case DW_OP_shr:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_shr.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        if (!stack.back().ResolveValue(exe_ctx).ShiftRightLogical(
-                tmp.ResolveValue(exe_ctx))) {
-          if (error_ptr)
-            error_ptr->SetErrorString("DW_OP_shr failed.");
-          return false;
-        }
-      }
-      break;
-
-    // OPCODE: DW_OP_shra
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack entries, shifts the former second
-    // entry right arithmetically (divide the magnitude by 2, keep the same
-    // sign for the result) by the number of bits specified by the former top
-    // of the stack, and pushes the result.
-    case DW_OP_shra:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_shra.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) >>= tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_xor
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack entries, performs the bitwise
-    // exclusive-or operation on the two, and pushes the result.
-    case DW_OP_xor:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_xor.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) ^ tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_skip
-    // OPERANDS: int16_t
-    // DESCRIPTION:  An unconditional branch. Its single operand is a 2-byte
-    // signed integer constant. The 2-byte constant is the number of bytes of
-    // the DWARF expression to skip forward or backward from the current
-    // operation, beginning after the 2-byte constant.
-    case DW_OP_skip: {
-      int16_t skip_offset = (int16_t)opcodes.GetU16(&offset);
-      lldb::offset_t new_offset = offset + skip_offset;
-      if (opcodes.ValidOffset(new_offset))
-        offset = new_offset;
-      else {
-        if (error_ptr)
-          error_ptr->SetErrorString("Invalid opcode offset in DW_OP_skip.");
-        return false;
-      }
-    } break;
-
-    // OPCODE: DW_OP_bra
-    // OPERANDS: int16_t
-    // DESCRIPTION: A conditional branch. Its single operand is a 2-byte
-    // signed integer constant. This operation pops the top of stack. If the
-    // value popped is not the constant 0, the 2-byte constant operand is the
-    // number of bytes of the DWARF expression to skip forward or backward from
-    // the current operation, beginning after the 2-byte constant.
-    case DW_OP_bra:
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 1 item for DW_OP_bra.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        int16_t bra_offset = (int16_t)opcodes.GetU16(&offset);
-        Scalar zero(0);
-        if (tmp.ResolveValue(exe_ctx) != zero) {
-          lldb::offset_t new_offset = offset + bra_offset;
-          if (opcodes.ValidOffset(new_offset))
-            offset = new_offset;
-          else {
-            if (error_ptr)
-              error_ptr->SetErrorString("Invalid opcode offset in DW_OP_bra.");
-            return false;
-          }
-        }
-      }
-      break;
-
-    // OPCODE: DW_OP_eq
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, compares using the
-    // equals (==) operator.
-    // STACK RESULT: push the constant value 1 onto the stack if the result
-    // of the operation is true or the constant value 0 if the result of the
-    // operation is false.
-    case DW_OP_eq:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_eq.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) == tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_ge
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, compares using the
-    // greater than or equal to (>=) operator.
-    // STACK RESULT: push the constant value 1 onto the stack if the result
-    // of the operation is true or the constant value 0 if the result of the
-    // operation is false.
-    case DW_OP_ge:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_ge.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) >= tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_gt
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, compares using the
-    // greater than (>) operator.
-    // STACK RESULT: push the constant value 1 onto the stack if the result
-    // of the operation is true or the constant value 0 if the result of the
-    // operation is false.
-    case DW_OP_gt:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_gt.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) > tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_le
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, compares using the
-    // less than or equal to (<=) operator.
-    // STACK RESULT: push the constant value 1 onto the stack if the result
-    // of the operation is true or the constant value 0 if the result of the
-    // operation is false.
-    case DW_OP_le:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_le.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) <= tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_lt
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, compares using the
-    // less than (<) operator.
-    // STACK RESULT: push the constant value 1 onto the stack if the result
-    // of the operation is true or the constant value 0 if the result of the
-    // operation is false.
-    case DW_OP_lt:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_lt.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) < tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_ne
-    // OPERANDS: none
-    // DESCRIPTION: pops the top two stack values, compares using the
-    // not equal (!=) operator.
-    // STACK RESULT: push the constant value 1 onto the stack if the result
-    // of the operation is true or the constant value 0 if the result of the
-    // operation is false.
-    case DW_OP_ne:
-      if (stack.size() < 2) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 2 items for DW_OP_ne.");
-        return false;
-      } else {
-        tmp = stack.back();
-        stack.pop_back();
-        stack.back().ResolveValue(exe_ctx) =
-            stack.back().ResolveValue(exe_ctx) != tmp.ResolveValue(exe_ctx);
-      }
-      break;
-
-    // OPCODE: DW_OP_litn
-    // OPERANDS: none
-    // DESCRIPTION: encode the unsigned literal values from 0 through 31.
-    // STACK RESULT: push the unsigned literal constant value onto the top
-    // of the stack.
-    case DW_OP_lit0:
-    case DW_OP_lit1:
-    case DW_OP_lit2:
-    case DW_OP_lit3:
-    case DW_OP_lit4:
-    case DW_OP_lit5:
-    case DW_OP_lit6:
-    case DW_OP_lit7:
-    case DW_OP_lit8:
-    case DW_OP_lit9:
-    case DW_OP_lit10:
-    case DW_OP_lit11:
-    case DW_OP_lit12:
-    case DW_OP_lit13:
-    case DW_OP_lit14:
-    case DW_OP_lit15:
-    case DW_OP_lit16:
-    case DW_OP_lit17:
-    case DW_OP_lit18:
-    case DW_OP_lit19:
-    case DW_OP_lit20:
-    case DW_OP_lit21:
-    case DW_OP_lit22:
-    case DW_OP_lit23:
-    case DW_OP_lit24:
-    case DW_OP_lit25:
-    case DW_OP_lit26:
-    case DW_OP_lit27:
-    case DW_OP_lit28:
-    case DW_OP_lit29:
-    case DW_OP_lit30:
-    case DW_OP_lit31:
-      stack.push_back(to_generic(op - DW_OP_lit0));
-      break;
-
-    // OPCODE: DW_OP_regN
-    // OPERANDS: none
-    // DESCRIPTION: Push the value in register n on the top of the stack.
-    case DW_OP_reg0:
-    case DW_OP_reg1:
-    case DW_OP_reg2:
-    case DW_OP_reg3:
-    case DW_OP_reg4:
-    case DW_OP_reg5:
-    case DW_OP_reg6:
-    case DW_OP_reg7:
-    case DW_OP_reg8:
-    case DW_OP_reg9:
-    case DW_OP_reg10:
-    case DW_OP_reg11:
-    case DW_OP_reg12:
-    case DW_OP_reg13:
-    case DW_OP_reg14:
-    case DW_OP_reg15:
-    case DW_OP_reg16:
-    case DW_OP_reg17:
-    case DW_OP_reg18:
-    case DW_OP_reg19:
-    case DW_OP_reg20:
-    case DW_OP_reg21:
-    case DW_OP_reg22:
-    case DW_OP_reg23:
-    case DW_OP_reg24:
-    case DW_OP_reg25:
-    case DW_OP_reg26:
-    case DW_OP_reg27:
-    case DW_OP_reg28:
-    case DW_OP_reg29:
-    case DW_OP_reg30:
-    case DW_OP_reg31: {
-      dwarf4_location_description_kind = Register;
-      reg_num = op - DW_OP_reg0;
-
-      if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp))
-        stack.push_back(tmp);
-      else
-        return false;
-    } break;
-    // OPCODE: DW_OP_regx
-    // OPERANDS:
-    //      ULEB128 literal operand that encodes the register.
-    // DESCRIPTION: Push the value in register on the top of the stack.
-    case DW_OP_regx: {
-      dwarf4_location_description_kind = Register;
-      reg_num = opcodes.GetULEB128(&offset);
-      if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr, tmp))
-        stack.push_back(tmp);
-      else
-        return false;
-    } break;
-
-    // OPCODE: DW_OP_bregN
-    // OPERANDS:
-    //      SLEB128 offset from register N
-    // DESCRIPTION: Value is in memory at the address specified by register
-    // N plus an offset.
-    case DW_OP_breg0:
-    case DW_OP_breg1:
-    case DW_OP_breg2:
-    case DW_OP_breg3:
-    case DW_OP_breg4:
-    case DW_OP_breg5:
-    case DW_OP_breg6:
-    case DW_OP_breg7:
-    case DW_OP_breg8:
-    case DW_OP_breg9:
-    case DW_OP_breg10:
-    case DW_OP_breg11:
-    case DW_OP_breg12:
-    case DW_OP_breg13:
-    case DW_OP_breg14:
-    case DW_OP_breg15:
-    case DW_OP_breg16:
-    case DW_OP_breg17:
-    case DW_OP_breg18:
-    case DW_OP_breg19:
-    case DW_OP_breg20:
-    case DW_OP_breg21:
-    case DW_OP_breg22:
-    case DW_OP_breg23:
-    case DW_OP_breg24:
-    case DW_OP_breg25:
-    case DW_OP_breg26:
-    case DW_OP_breg27:
-    case DW_OP_breg28:
-    case DW_OP_breg29:
-    case DW_OP_breg30:
-    case DW_OP_breg31: {
-      reg_num = op - DW_OP_breg0;
-
-      if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr,
-                                    tmp)) {
-        int64_t breg_offset = opcodes.GetSLEB128(&offset);
-        tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset;
-        tmp.ClearContext();
-        stack.push_back(tmp);
-        stack.back().SetValueType(Value::ValueType::LoadAddress);
-      } else
-        return false;
-    } break;
-    // OPCODE: DW_OP_bregx
-    // OPERANDS: 2
-    //      ULEB128 literal operand that encodes the register.
-    //      SLEB128 offset from register N
-    // DESCRIPTION: Value is in memory at the address specified by register
-    // N plus an offset.
-    case DW_OP_bregx: {
-      reg_num = opcodes.GetULEB128(&offset);
-
-      if (ReadRegisterValueAsScalar(reg_ctx, reg_kind, reg_num, error_ptr,
-                                    tmp)) {
-        int64_t breg_offset = opcodes.GetSLEB128(&offset);
-        tmp.ResolveValue(exe_ctx) += (uint64_t)breg_offset;
-        tmp.ClearContext();
-        stack.push_back(tmp);
-        stack.back().SetValueType(Value::ValueType::LoadAddress);
-      } else
-        return false;
-    } break;
-
-    case DW_OP_fbreg:
-      if (exe_ctx) {
-        if (frame) {
-          Scalar value;
-          if (frame->GetFrameBaseValue(value, error_ptr)) {
-            int64_t fbreg_offset = opcodes.GetSLEB128(&offset);
-            value += fbreg_offset;
-            stack.push_back(value);
-            stack.back().SetValueType(Value::ValueType::LoadAddress);
-          } else
-            return false;
-        } else {
-          if (error_ptr)
-            error_ptr->SetErrorString(
-                "Invalid stack frame in context for DW_OP_fbreg opcode.");
-          return false;
-        }
-      } else {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "NULL execution context for DW_OP_fbreg.\n");
-        return false;
-      }
-
-      break;
-
-    // OPCODE: DW_OP_nop
-    // OPERANDS: none
-    // DESCRIPTION: A place holder. It has no effect on the location stack
-    // or any of its values.
-    case DW_OP_nop:
-      break;
-
-    // OPCODE: DW_OP_piece
-    // OPERANDS: 1
-    //      ULEB128: byte size of the piece
-    // DESCRIPTION: The operand describes the size in bytes of the piece of
-    // the object referenced by the DWARF expression whose result is at the top
-    // of the stack. If the piece is located in a register, but does not occupy
-    // the entire register, the placement of the piece within that register is
-    // defined by the ABI.
-    //
-    // Many compilers store a single variable in sets of registers, or store a
-    // variable partially in memory and partially in registers. DW_OP_piece
-    // provides a way of describing how large a part of a variable a particular
-    // DWARF expression refers to.
-    case DW_OP_piece: {
-      LocationDescriptionKind piece_locdesc = dwarf4_location_description_kind;
-      // Reset for the next piece.
-      dwarf4_location_description_kind = Memory;
-
-      const uint64_t piece_byte_size = opcodes.GetULEB128(&offset);
-
-      if (piece_byte_size > 0) {
-        Value curr_piece;
-
-        if (stack.empty()) {
-          UpdateValueTypeFromLocationDescription(
-              log, dwarf_cu, LocationDescriptionKind::Empty);
-          // In a multi-piece expression, this means that the current piece is
-          // not available. Fill with zeros for now by resizing the data and
-          // appending it
-          curr_piece.ResizeData(piece_byte_size);
-          // Note that "0" is not a correct value for the unknown bits.
-          // It would be better to also return a mask of valid bits together
-          // with the expression result, so the debugger can print missing
-          // members as "<optimized out>" or something.
-          ::memset(curr_piece.GetBuffer().GetBytes(), 0, piece_byte_size);
-          pieces.AppendDataToHostBuffer(curr_piece);
-        } else {
-          Status error;
-          // Extract the current piece into "curr_piece"
-          Value curr_piece_source_value(stack.back());
-          stack.pop_back();
-          UpdateValueTypeFromLocationDescription(log, dwarf_cu, piece_locdesc,
-                                                 &curr_piece_source_value);
-
-          const Value::ValueType curr_piece_source_value_type =
-              curr_piece_source_value.GetValueType();
-          switch (curr_piece_source_value_type) {
-          case Value::ValueType::Invalid:
-            return false;
-          case Value::ValueType::LoadAddress:
-            if (process) {
-              if (curr_piece.ResizeData(piece_byte_size) == piece_byte_size) {
-                lldb::addr_t load_addr =
-                    curr_piece_source_value.GetScalar().ULongLong(
-                        LLDB_INVALID_ADDRESS);
-                if (process->ReadMemory(
-                        load_addr, curr_piece.GetBuffer().GetBytes(),
-                        piece_byte_size, error) != piece_byte_size) {
-                  if (error_ptr)
-                    error_ptr->SetErrorStringWithFormat(
-                        "failed to read memory DW_OP_piece(%" PRIu64
-                        ") from 0x%" PRIx64,
-                        piece_byte_size, load_addr);
-                  return false;
-                }
-              } else {
-                if (error_ptr)
-                  error_ptr->SetErrorStringWithFormat(
-                      "failed to resize the piece memory buffer for "
-                      "DW_OP_piece(%" PRIu64 ")",
-                      piece_byte_size);
-                return false;
-              }
-            }
-            break;
-
-          case Value::ValueType::FileAddress:
-          case Value::ValueType::HostAddress:
-            if (error_ptr) {
-              lldb::addr_t addr = curr_piece_source_value.GetScalar().ULongLong(
-                  LLDB_INVALID_ADDRESS);
-              error_ptr->SetErrorStringWithFormat(
-                  "failed to read memory DW_OP_piece(%" PRIu64
-                  ") from %s address 0x%" PRIx64,
-                  piece_byte_size, curr_piece_source_value.GetValueType() ==
-                                           Value::ValueType::FileAddress
-                                       ? "file"
-                                       : "host",
-                  addr);
-            }
-            return false;
-
-          case Value::ValueType::Scalar: {
-            uint32_t bit_size = piece_byte_size * 8;
-            uint32_t bit_offset = 0;
-            Scalar &scalar = curr_piece_source_value.GetScalar();
-            if (!scalar.ExtractBitfield(
-                    bit_size, bit_offset)) {
-              if (error_ptr)
-                error_ptr->SetErrorStringWithFormat(
-                    "unable to extract %" PRIu64 " bytes from a %" PRIu64
-                    " byte scalar value.",
-                    piece_byte_size,
-                    (uint64_t)curr_piece_source_value.GetScalar()
-                        .GetByteSize());
-              return false;
-            }
-            // Create curr_piece with bit_size. By default Scalar
-            // grows to the nearest host integer type.
-            llvm::APInt fail_value(1, 0, false);
-            llvm::APInt ap_int = scalar.UInt128(fail_value);
-            assert(ap_int.getBitWidth() >= bit_size);
-            llvm::ArrayRef<uint64_t> buf{ap_int.getRawData(),
-                                         ap_int.getNumWords()};
-            curr_piece.GetScalar() = Scalar(llvm::APInt(bit_size, buf));
-          } break;
-          }
-
-          // Check if this is the first piece?
-          if (op_piece_offset == 0) {
-            // This is the first piece, we should push it back onto the stack
-            // so subsequent pieces will be able to access this piece and add
-            // to it.
-            if (pieces.AppendDataToHostBuffer(curr_piece) == 0) {
-              if (error_ptr)
-                error_ptr->SetErrorString("failed to append piece data");
-              return false;
-            }
-          } else {
-            // If this is the second or later piece there should be a value on
-            // the stack.
-            if (pieces.GetBuffer().GetByteSize() != op_piece_offset) {
-              if (error_ptr)
-                error_ptr->SetErrorStringWithFormat(
-                    "DW_OP_piece for offset %" PRIu64
-                    " but top of stack is of size %" PRIu64,
-                    op_piece_offset, pieces.GetBuffer().GetByteSize());
-              return false;
-            }
-
-            if (pieces.AppendDataToHostBuffer(curr_piece) == 0) {
-              if (error_ptr)
-                error_ptr->SetErrorString("failed to append piece data");
-              return false;
-            }
-          }
-        }
-        op_piece_offset += piece_byte_size;
-      }
-    } break;
-
-    case DW_OP_bit_piece: // 0x9d ULEB128 bit size, ULEB128 bit offset (DWARF3);
-      if (stack.size() < 1) {
-        UpdateValueTypeFromLocationDescription(log, dwarf_cu,
-                                               LocationDescriptionKind::Empty);
-        // Reset for the next piece.
-        dwarf4_location_description_kind = Memory;
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 1 item for DW_OP_bit_piece.");
-        return false;
-      } else {
-        UpdateValueTypeFromLocationDescription(
-            log, dwarf_cu, dwarf4_location_description_kind, &stack.back());
-        // Reset for the next piece.
-        dwarf4_location_description_kind = Memory;
-        const uint64_t piece_bit_size = opcodes.GetULEB128(&offset);
-        const uint64_t piece_bit_offset = opcodes.GetULEB128(&offset);
-        switch (stack.back().GetValueType()) {
-        case Value::ValueType::Invalid:
-          return false;
-        case Value::ValueType::Scalar: {
-          if (!stack.back().GetScalar().ExtractBitfield(piece_bit_size,
-                                                        piece_bit_offset)) {
-            if (error_ptr)
-              error_ptr->SetErrorStringWithFormat(
-                  "unable to extract %" PRIu64 " bit value with %" PRIu64
-                  " bit offset from a %" PRIu64 " bit scalar value.",
-                  piece_bit_size, piece_bit_offset,
-                  (uint64_t)(stack.back().GetScalar().GetByteSize() * 8));
-            return false;
-          }
-        } break;
-
-        case Value::ValueType::FileAddress:
-        case Value::ValueType::LoadAddress:
-        case Value::ValueType::HostAddress:
-          if (error_ptr) {
-            error_ptr->SetErrorStringWithFormat(
-                "unable to extract DW_OP_bit_piece(bit_size = %" PRIu64
-                ", bit_offset = %" PRIu64 ") from an address value.",
-                piece_bit_size, piece_bit_offset);
-          }
-          return false;
-        }
-      }
-      break;
-
-    // OPCODE: DW_OP_implicit_value
-    // OPERANDS: 2
-    //      ULEB128  size of the value block in bytes
-    //      uint8_t* block bytes encoding value in target's memory
-    //      representation
-    // DESCRIPTION: Value is immediately stored in block in the debug info with
-    // the memory representation of the target.
-    case DW_OP_implicit_value: {
-      dwarf4_location_description_kind = Implicit;
-
-      const uint32_t len = opcodes.GetULEB128(&offset);
-      const void *data = opcodes.GetData(&offset, len);
-
-      if (!data) {
-        LLDB_LOG(log, "Evaluate_DW_OP_implicit_value: could not be read data");
-        LLDB_ERRORF(error_ptr, "Could not evaluate %s.",
-                    DW_OP_value_to_name(op));
-        return false;
-      }
-
-      Value result(data, len);
-      stack.push_back(result);
-      break;
-    }
-
-    case DW_OP_implicit_pointer: {
-      dwarf4_location_description_kind = Implicit;
-      LLDB_ERRORF(error_ptr, "Could not evaluate %s.", DW_OP_value_to_name(op));
-      return false;
-    }
-
-    // OPCODE: DW_OP_push_object_address
-    // OPERANDS: none
-    // DESCRIPTION: Pushes the address of the object currently being
-    // evaluated as part of evaluation of a user presented expression. This
-    // object may correspond to an independent variable described by its own
-    // DIE or it may be a component of an array, structure, or class whose
-    // address has been dynamically determined by an earlier step during user
-    // expression evaluation.
-    case DW_OP_push_object_address:
-      if (object_address_ptr)
-        stack.push_back(*object_address_ptr);
-      else {
-        if (error_ptr)
-          error_ptr->SetErrorString("DW_OP_push_object_address used without "
-                                    "specifying an object address");
-        return false;
-      }
-      break;
-
-    // OPCODE: DW_OP_call2
-    // OPERANDS:
-    //      uint16_t compile unit relative offset of a DIE
-    // DESCRIPTION: Performs subroutine calls during evaluation
-    // of a DWARF expression. The operand is the 2-byte unsigned offset of a
-    // debugging information entry in the current compilation unit.
-    //
-    // Operand interpretation is exactly like that for DW_FORM_ref2.
-    //
-    // This operation transfers control of DWARF expression evaluation to the
-    // DW_AT_location attribute of the referenced DIE. If there is no such
-    // attribute, then there is no effect. Execution of the DWARF expression of
-    // a DW_AT_location attribute may add to and/or remove from values on the
-    // stack. Execution returns to the point following the call when the end of
-    // the attribute is reached. Values on the stack at the time of the call
-    // may be used as parameters by the called expression and values left on
-    // the stack by the called expression may be used as return values by prior
-    // agreement between the calling and called expressions.
-    case DW_OP_call2:
-      if (error_ptr)
-        error_ptr->SetErrorString("Unimplemented opcode DW_OP_call2.");
-      return false;
-    // OPCODE: DW_OP_call4
-    // OPERANDS: 1
-    //      uint32_t compile unit relative offset of a DIE
-    // DESCRIPTION: Performs a subroutine call during evaluation of a DWARF
-    // expression. For DW_OP_call4, the operand is a 4-byte unsigned offset of
-    // a debugging information entry in  the current compilation unit.
-    //
-    // Operand interpretation DW_OP_call4 is exactly like that for
-    // DW_FORM_ref4.
-    //
-    // This operation transfers control of DWARF expression evaluation to the
-    // DW_AT_location attribute of the referenced DIE. If there is no such
-    // attribute, then there is no effect. Execution of the DWARF expression of
-    // a DW_AT_location attribute may add to and/or remove from values on the
-    // stack. Execution returns to the point following the call when the end of
-    // the attribute is reached. Values on the stack at the time of the call
-    // may be used as parameters by the called expression and values left on
-    // the stack by the called expression may be used as return values by prior
-    // agreement between the calling and called expressions.
-    case DW_OP_call4:
-      if (error_ptr)
-        error_ptr->SetErrorString("Unimplemented opcode DW_OP_call4.");
-      return false;
-
-    // OPCODE: DW_OP_stack_value
-    // OPERANDS: None
-    // DESCRIPTION: Specifies that the object does not exist in memory but
-    // rather is a constant value.  The value from the top of the stack is the
-    // value to be used.  This is the actual object value and not the location.
-    case DW_OP_stack_value:
-      dwarf4_location_description_kind = Implicit;
-      if (stack.empty()) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 1 item for DW_OP_stack_value.");
-        return false;
-      }
-      stack.back().SetValueType(Value::ValueType::Scalar);
-      break;
-
-    // OPCODE: DW_OP_convert
-    // OPERANDS: 1
-    //      A ULEB128 that is either a DIE offset of a
-    //      DW_TAG_base_type or 0 for the generic (pointer-sized) type.
-    //
-    // DESCRIPTION: Pop the top stack element, convert it to a
-    // different type, and push the result.
-    case DW_OP_convert: {
-      if (stack.size() < 1) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "Expression stack needs at least 1 item for DW_OP_convert.");
-        return false;
-      }
-      const uint64_t die_offset = opcodes.GetULEB128(&offset);
-      uint64_t bit_size;
-      bool sign;
-      if (die_offset == 0) {
-        // The generic type has the size of an address on the target
-        // machine and an unspecified signedness. Scalar has no
-        // "unspecified signedness", so we use unsigned types.
-        if (!module_sp) {
-          if (error_ptr)
-            error_ptr->SetErrorString("No module");
-          return false;
-        }
-        sign = false;
-        bit_size = module_sp->GetArchitecture().GetAddressByteSize() * 8;
-        if (!bit_size) {
-          if (error_ptr)
-            error_ptr->SetErrorString("unspecified architecture");
-          return false;
-        }
-      } else {
-        // Retrieve the type DIE that the value is being converted to.
-        // FIXME: the constness has annoying ripple effects.
-        DWARFDIE die = const_cast<DWARFUnit *>(dwarf_cu)->GetDIE(die_offset);
-        if (!die) {
-          if (error_ptr)
-            error_ptr->SetErrorString("Cannot resolve DW_OP_convert type DIE");
-          return false;
-        }
-        uint64_t encoding =
-            die.GetAttributeValueAsUnsigned(DW_AT_encoding, DW_ATE_hi_user);
-        bit_size = die.GetAttributeValueAsUnsigned(DW_AT_byte_size, 0) * 8;
-        if (!bit_size)
-          bit_size = die.GetAttributeValueAsUnsigned(DW_AT_bit_size, 0);
-        if (!bit_size) {
-          if (error_ptr)
-            error_ptr->SetErrorString("Unsupported type size in DW_OP_convert");
-          return false;
-        }
-        switch (encoding) {
-        case DW_ATE_signed:
-        case DW_ATE_signed_char:
-          sign = true;
-          break;
-        case DW_ATE_unsigned:
-        case DW_ATE_unsigned_char:
-          sign = false;
-          break;
-        default:
-          if (error_ptr)
-            error_ptr->SetErrorString("Unsupported encoding in DW_OP_convert");
-          return false;
-        }
-      }
-      Scalar &top = stack.back().ResolveValue(exe_ctx);
-      top.TruncOrExtendTo(bit_size, sign);
-      break;
-    }
-
-    // OPCODE: DW_OP_call_frame_cfa
-    // OPERANDS: None
-    // DESCRIPTION: Specifies a DWARF expression that pushes the value of
-    // the canonical frame address consistent with the call frame information
-    // located in .debug_frame (or in the FDEs of the eh_frame section).
-    case DW_OP_call_frame_cfa:
-      if (frame) {
-        // Note that we don't have to parse FDEs because this DWARF expression
-        // is commonly evaluated with a valid stack frame.
-        StackID id = frame->GetStackID();
-        addr_t cfa = id.GetCallFrameAddress();
-        if (cfa != LLDB_INVALID_ADDRESS) {
-          stack.push_back(Scalar(cfa));
-          stack.back().SetValueType(Value::ValueType::LoadAddress);
-        } else if (error_ptr)
-          error_ptr->SetErrorString("Stack frame does not include a canonical "
-                                    "frame address for DW_OP_call_frame_cfa "
-                                    "opcode.");
-      } else {
-        if (error_ptr)
-          error_ptr->SetErrorString("Invalid stack frame in context for "
-                                    "DW_OP_call_frame_cfa opcode.");
-        return false;
-      }
-      break;
-
-    // OPCODE: DW_OP_form_tls_address (or the old pre-DWARFv3 vendor extension
-    // opcode, DW_OP_GNU_push_tls_address)
-    // OPERANDS: none
-    // DESCRIPTION: Pops a TLS offset from the stack, converts it to
-    // an address in the current thread's thread-local storage block, and
-    // pushes it on the stack.
-    case DW_OP_form_tls_address:
-    case DW_OP_GNU_push_tls_address: {
-      if (stack.size() < 1) {
-        if (error_ptr) {
-          if (op == DW_OP_form_tls_address)
-            error_ptr->SetErrorString(
-                "DW_OP_form_tls_address needs an argument.");
-          else
-            error_ptr->SetErrorString(
-                "DW_OP_GNU_push_tls_address needs an argument.");
-        }
-        return false;
-      }
-
-      if (!exe_ctx || !module_sp) {
-        if (error_ptr)
-          error_ptr->SetErrorString("No context to evaluate TLS within.");
-        return false;
-      }
-
-      Thread *thread = exe_ctx->GetThreadPtr();
-      if (!thread) {
-        if (error_ptr)
-          error_ptr->SetErrorString("No thread to evaluate TLS within.");
-        return false;
-      }
-
-      // Lookup the TLS block address for this thread and module.
-      const addr_t tls_file_addr =
-          stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS);
-      const addr_t tls_load_addr =
-          thread->GetThreadLocalData(module_sp, tls_file_addr);
-
-      if (tls_load_addr == LLDB_INVALID_ADDRESS) {
-        if (error_ptr)
-          error_ptr->SetErrorString(
-              "No TLS data currently exists for this thread.");
-        return false;
-      }
-
-      stack.back().GetScalar() = tls_load_addr;
-      stack.back().SetValueType(Value::ValueType::LoadAddress);
-    } break;
-
-    // OPCODE: DW_OP_addrx (DW_OP_GNU_addr_index is the legacy name.)
-    // OPERANDS: 1
-    //      ULEB128: index to the .debug_addr section
-    // DESCRIPTION: Pushes an address to the stack from the .debug_addr
-    // section with the base address specified by the DW_AT_addr_base attribute
-    // and the 0 based index is the ULEB128 encoded index.
-    case DW_OP_addrx:
-    case DW_OP_GNU_addr_index: {
-      if (!dwarf_cu) {
-        if (error_ptr)
-          error_ptr->SetErrorString("DW_OP_GNU_addr_index found without a "
-                                    "compile unit being specified");
-        return false;
-      }
-      uint64_t index = opcodes.GetULEB128(&offset);
-      lldb::addr_t value = ReadAddressFromDebugAddrSection(dwarf_cu, index);
-      stack.push_back(Scalar(value));
-      stack.back().SetValueType(Value::ValueType::FileAddress);
-    } break;
-
-    // OPCODE: DW_OP_GNU_const_index
-    // OPERANDS: 1
-    //      ULEB128: index to the .debug_addr section
-    // DESCRIPTION: Pushes an constant with the size of a machine address to
-    // the stack from the .debug_addr section with the base address specified
-    // by the DW_AT_addr_base attribute and the 0 based index is the ULEB128
-    // encoded index.
-    case DW_OP_GNU_const_index: {
-      if (!dwarf_cu) {
-        if (error_ptr)
-          error_ptr->SetErrorString("DW_OP_GNU_const_index found without a "
-                                    "compile unit being specified");
-        return false;
-      }
-      uint64_t index = opcodes.GetULEB128(&offset);
-      lldb::addr_t value = ReadAddressFromDebugAddrSection(dwarf_cu, index);
-      stack.push_back(Scalar(value));
-    } break;
-
-    case DW_OP_GNU_entry_value:
-    case DW_OP_entry_value: {
-      if (!Evaluate_DW_OP_entry_value(stack, exe_ctx, reg_ctx, opcodes, offset,
-                                      error_ptr, log)) {
-        LLDB_ERRORF(error_ptr, "Could not evaluate %s.",
-                    DW_OP_value_to_name(op));
-        return false;
-      }
-      break;
-    }
-
-    default:
-      if (error_ptr)
-        error_ptr->SetErrorStringWithFormatv(
-            "Unhandled opcode {0} in DWARFExpression", LocationAtom(op));
-      return false;
-    }
-  }
-
-  if (stack.empty()) {
-    // Nothing on the stack, check if we created a piece value from DW_OP_piece
-    // or DW_OP_bit_piece opcodes
-    if (pieces.GetBuffer().GetByteSize()) {
-      result = pieces;
-      return true;
-    }
-    if (error_ptr)
-      error_ptr->SetErrorString("Stack empty after evaluation.");
-    return false;
-  }
-
-  UpdateValueTypeFromLocationDescription(
-      log, dwarf_cu, dwarf4_location_description_kind, &stack.back());
-
-  if (log && log->GetVerbose()) {
-    size_t count = stack.size();
-    LLDB_LOGF(log,
-              "Stack after operation has %" PRIu64 " values:", (uint64_t)count);
-    for (size_t i = 0; i < count; ++i) {
-      StreamString new_value;
-      new_value.Printf("[%" PRIu64 "]", (uint64_t)i);
-      stack[i].Dump(&new_value);
-      LLDB_LOGF(log, "  %s", new_value.GetData());
-    }
-  }
-  result = stack.back();
-  return true; // Return true on success
+  DWARFExpression expr(module_sp, opcodes, dwarf_cu);
+  expr.SetRegisterKind(reg_kind);
+
+  // Use the DWARF expression evaluator registered for this module (or
+  // DWARFEvaluator by default).
+  DWARFEvaluatorFactory *evaluator_factory =
+      module_sp->GetDWARFExpressionEvaluatorFactory();
+  std::unique_ptr<DWARFEvaluator> evaluator =
+      evaluator_factory->CreateDWARFEvaluator(
+          expr, exe_ctx, reg_ctx, initial_value_ptr, object_address_ptr);
+  return evaluator->Evaluate(result, error_ptr);
 }
 
 static DataExtractor ToDataExtractor(const llvm::DWARFLocationExpression &loc,
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index 00e9ccb762c3..2137a1ac8324 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -759,6 +759,24 @@ void CommandInterpreter::LoadCommandDictionary() {
     }
   }
 
+  std::unique_ptr<CommandObjectRegexCommand> connect_wasm_cmd_up(
+      new CommandObjectRegexCommand(
+          *this, "wasm",
+          "Connect to a WebAssembly process via remote GDB server.  "
+          "If no host is specifed, localhost is assumed.",
+          "wasm [<hostname>:]<portnum>", 2, 0, false));
+  if (connect_wasm_cmd_up) {
+    if (connect_wasm_cmd_up->AddRegexCommand(
+            "^([^:]+|\\[[0-9a-fA-F:]+.*\\]):([0-9]+)$",
+            "process connect --plugin wasm connect://%1:%2") &&
+        connect_wasm_cmd_up->AddRegexCommand(
+            "^([[:digit:]]+)$",
+            "process connect --plugin wasm connect://localhost:%1")) {
+      CommandObjectSP command_sp(connect_wasm_cmd_up.release());
+      m_command_dict[std::string(command_sp->GetCommandName())] = command_sp;
+    }
+  }
+
   std::unique_ptr<CommandObjectRegexCommand> connect_kdp_remote_cmd_up(
       new CommandObjectRegexCommand(
           *this, "kdp-remote",
diff --git a/lldb/source/Plugins/CMakeLists.txt b/lldb/source/Plugins/CMakeLists.txt
index 9181a4e47675..2be6ec3657c0 100644
--- a/lldb/source/Plugins/CMakeLists.txt
+++ b/lldb/source/Plugins/CMakeLists.txt
@@ -2,6 +2,7 @@ add_subdirectory(ABI)
 add_subdirectory(Architecture)
 add_subdirectory(Disassembler)
 add_subdirectory(DynamicLoader)
+add_subdirectory(DWARFEvaluator)
 add_subdirectory(ExpressionParser)
 add_subdirectory(Instruction)
 add_subdirectory(InstrumentationRuntime)
@@ -32,6 +33,7 @@ set(LLDB_ENUM_PLUGINS "")
 # 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})
@@ -43,6 +45,8 @@ foreach(p ${LLDB_ALL_PLUGINS})
     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(${pStripped})\n")
   else()
     set(LLDB_ENUM_PLUGINS "${LLDB_ENUM_PLUGINS}LLDB_PLUGIN(${pStripped})\n")
   endif()
diff --git a/lldb/source/Plugins/DWARFEvaluator/CMakeLists.txt b/lldb/source/Plugins/DWARFEvaluator/CMakeLists.txt
new file mode 100644
index 000000000000..73fad41e1a72
--- /dev/null
+++ b/lldb/source/Plugins/DWARFEvaluator/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(wasm)
diff --git a/lldb/source/Plugins/DWARFEvaluator/wasm/CMakeLists.txt b/lldb/source/Plugins/DWARFEvaluator/wasm/CMakeLists.txt
new file mode 100644
index 000000000000..e50b1bef7e69
--- /dev/null
+++ b/lldb/source/Plugins/DWARFEvaluator/wasm/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginWasmDWARFEvaluatorFactory PLUGIN
+  WasmDWARFEvaluator.cpp
+  WasmDWARFEvaluatorFactory.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbHost
+    lldbSymbol
+    lldbPluginObjectFileWasm
+  )
diff --git a/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluator.cpp b/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluator.cpp
new file mode 100644
index 000000000000..fdda1991d19f
--- /dev/null
+++ b/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluator.cpp
@@ -0,0 +1,126 @@
+//===-- WasmDWARFEvaluator.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 "WasmDWARFEvaluator.h"
+
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
+#include "Plugins/Process/wasm/ProcessWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Expression/DWARFExpression.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+bool WasmDWARFEvaluator::Evaluate(const uint8_t op, Process *process,
+                                  StackFrame *frame, std::vector<Value> &stack,
+                                  const DataExtractor &opcodes,
+                                  lldb::offset_t &offset, Value &pieces,
+                                  uint64_t &op_piece_offset, Log *log,
+                                  Status *error_ptr) {
+  lldb::ModuleSP module_sp = m_dwarf_expression.GetModule();
+
+  switch (op) {
+  case DW_OP_WASM_location: {
+    if (frame) {
+      const llvm::Triple::ArchType machine =
+          frame->CalculateTarget()->GetArchitecture().GetMachine();
+      if (machine != llvm::Triple::wasm32) {
+        if (error_ptr)
+          error_ptr->SetErrorString("Invalid target architecture for "
+                                    "DW_OP_WASM_location opcode.");
+        return false;
+      }
+
+      ProcessWasm *wasm_process =
+          static_cast<wasm::ProcessWasm *>(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 stack frame in context for "
+                                  "DW_OP_WASM_location opcode.");
+      return false;
+    }
+  } break;
+
+  case DW_OP_addr: {
+    /// {addr} is an offset in the module Data section.
+    lldb::addr_t addr = opcodes.GetAddress(&offset);
+    stack.push_back(Scalar(addr));
+    stack.back().SetValueType(Value::ValueType::LoadAddress);
+  } break;
+
+  case DW_OP_fbreg:
+    if (m_exe_ctx) {
+      if (frame) {
+        Scalar value;
+        if (frame->GetFrameBaseValue(value, error_ptr)) {
+          // The value is an address in the Wasm Memory space.
+          int64_t fbreg_offset = opcodes.GetSLEB128(&offset);
+          stack.push_back(Scalar(value.ULong() + fbreg_offset));
+          stack.back().SetValueType(Value::ValueType::LoadAddress);
+        } else
+          return false;
+      } else {
+        if (error_ptr)
+          error_ptr->SetErrorString(
+              "Invalid stack frame in context for DW_OP_fbreg opcode.");
+        return false;
+      }
+    } else {
+      if (error_ptr)
+        error_ptr->SetErrorStringWithFormat(
+            "NULL execution context for DW_OP_fbreg.\n");
+      return false;
+    }
+    break;
+
+  default:
+    return DWARFEvaluator::Evaluate(op, process, frame, stack, opcodes, offset,
+                                    pieces, op_piece_offset, log, error_ptr);
+  }
+  return true;
+}
diff --git a/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluator.h b/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluator.h
new file mode 100644
index 000000000000..a01159064a39
--- /dev/null
+++ b/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluator.h
@@ -0,0 +1,47 @@
+//===-- WasmDWARFEvaluator.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_DWARFEVALUATOR_WASM_WASMDWARFEVALUATOR_H
+#define LLDB_SOURCE_PLUGINS_DWARFEVALUATOR_WASM_WASMDWARFEVALUATOR_H
+
+#include "lldb/Expression/DWARFEvaluator.h"
+#include "lldb/lldb-private.h"
+
+namespace lldb_private {
+namespace wasm {
+
+/// \class WasmDWARFEvaluator evaluates DWARF expressions in the context of a
+///  WebAssembly process.
+///
+class WasmDWARFEvaluator : public DWARFEvaluator {
+public:
+  WasmDWARFEvaluator(const DWARFExpression &dwarf_expression,
+                     ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
+                     const Value *initial_value_ptr,
+                     const Value *object_address_ptr)
+      : DWARFEvaluator(dwarf_expression, exe_ctx, reg_ctx, initial_value_ptr,
+                       object_address_ptr) {}
+
+  /// DWARFEvaluator protocol.
+  /// \{
+  bool Evaluate(const uint8_t op, Process *process, StackFrame *frame,
+                std::vector<Value> &stack, const DataExtractor &opcodes,
+                lldb::offset_t &offset, Value &pieces,
+                uint64_t &op_piece_offset, Log *log,
+                Status *error_ptr) override;
+  /// \}
+
+private:
+  WasmDWARFEvaluator(const WasmDWARFEvaluator &);
+  const WasmDWARFEvaluator &operator=(const WasmDWARFEvaluator &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_DWARFEVALUATOR_WASM_WASMDWARFEVALUATOR_H
diff --git a/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluatorFactory.cpp b/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluatorFactory.cpp
new file mode 100644
index 000000000000..d43e96a34d37
--- /dev/null
+++ b/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluatorFactory.cpp
@@ -0,0 +1,64 @@
+//===-- WasmDWARFEvaluatorFactory.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 "WasmDWARFEvaluatorFactory.h"
+#include "WasmDWARFEvaluator.h"
+
+#include "Plugins/ObjectFile/wasm/ObjectFileWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+LLDB_PLUGIN_DEFINE(WasmDWARFEvaluatorFactory)
+
+void WasmDWARFEvaluatorFactory::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void WasmDWARFEvaluatorFactory::Terminate() {
+  PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString WasmDWARFEvaluatorFactory::GetPluginNameStatic() {
+  static ConstString g_name("WASM");
+  return g_name;
+}
+
+const char *WasmDWARFEvaluatorFactory::GetPluginDescriptionStatic() {
+  return "DWARF expression evaluator factory for WASM.";
+}
+
+// CreateInstance
+//
+// Platforms can register a callback to use when creating DWARF expression
+// evaluators to allow handling platform-specific DWARF codes.
+DWARFEvaluatorFactory *
+WasmDWARFEvaluatorFactory::CreateInstance(Module *module) {
+  if (!module)
+    return nullptr;
+
+  ObjectFileWasm *obj_file =
+      llvm::dyn_cast_or_null<ObjectFileWasm>(module->GetObjectFile());
+  if (!obj_file)
+    return nullptr;
+
+  return new WasmDWARFEvaluatorFactory();
+}
+
+std::unique_ptr<DWARFEvaluator> WasmDWARFEvaluatorFactory::CreateDWARFEvaluator(
+    const DWARFExpression &dwarf_expression, ExecutionContext *exe_ctx,
+    RegisterContext *reg_ctx, const Value *initial_value_ptr,
+    const Value *object_address_ptr) {
+  return std::make_unique<WasmDWARFEvaluator>(dwarf_expression, exe_ctx,
+                                              reg_ctx, initial_value_ptr,
+                                              object_address_ptr);
+}
diff --git a/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluatorFactory.h b/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluatorFactory.h
new file mode 100644
index 000000000000..8a946592a09a
--- /dev/null
+++ b/lldb/source/Plugins/DWARFEvaluator/wasm/WasmDWARFEvaluatorFactory.h
@@ -0,0 +1,55 @@
+//===-- WasmDWARFEvaluatorFactory.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_DWARFEVALUATOR_WASM_WASMDWARFEVALUATORFACTORY_H
+#define LLDB_SOURCE_PLUGINS_DWARFEVALUATOR_WASM_WASMDWARFEVALUATORFACTORY_H
+
+#include "lldb/Expression/DWARFEvaluatorFactory.h"
+
+namespace lldb_private {
+namespace wasm {
+
+/// \class WasmDWARFEvaluatorFactory creates DWARF evaluators specialized to
+///  manage DWARF-specific opcodes.
+class WasmDWARFEvaluatorFactory : public DWARFEvaluatorFactory {
+public:
+  static void Initialize();
+  static void Terminate();
+  static lldb_private::ConstString GetPluginNameStatic();
+  static const char *GetPluginDescriptionStatic();
+
+  static lldb_private::DWARFEvaluatorFactory *CreateInstance(Module *module);
+
+  /// PluginInterface protocol.
+  /// \{
+  lldb_private::ConstString GetPluginName() override {
+    return GetPluginNameStatic();
+  }
+  uint32_t GetPluginVersion() override { return 1; }
+  /// \}
+
+  WasmDWARFEvaluatorFactory() {}
+
+  /// DWARFEvaluatorFactory protocol.
+  /// \{
+  std::unique_ptr<DWARFEvaluator>
+  CreateDWARFEvaluator(const DWARFExpression &dwarf_expression,
+                       ExecutionContext *exe_ctx, RegisterContext *reg_ctx,
+                       const Value *initial_value_ptr,
+                       const Value *object_address_ptr) override;
+  /// \}
+
+private:
+  WasmDWARFEvaluatorFactory(const WasmDWARFEvaluatorFactory &);
+  const WasmDWARFEvaluatorFactory &operator=(const WasmDWARFEvaluatorFactory &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_DWARFEVALUATOR_WASM_WASMDWARFEVALUATORFACTORY_H
diff --git a/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp b/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp
index ae7e011eaa52..24ea75d1971c 100644
--- a/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/wasm-DYLD/DynamicLoaderWasmDYLD.cpp
@@ -62,6 +62,15 @@ void DynamicLoaderWasmDYLD::DidAttach() {
   // Ask the process for the list of loaded WebAssembly modules.
   auto error = m_process->LoadModules();
   LLDB_LOG_ERROR(log, std::move(error), "Couldn't load modules: {0}");
+
+  // TODO: multi-modules support ?
+  Target &target = m_process->GetTarget();
+  const ModuleList &modules = target.GetImages();
+  ModuleSP module_sp(modules.GetModuleAtIndex(0));
+  // module_sp is nullptr if without libxml2
+  if(module_sp) {
+    module_sp->PreloadSymbols();
+  }
 }
 
 ThreadPlanSP DynamicLoaderWasmDYLD::GetStepThroughTrampolinePlan(Thread &thread,
diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
index 5272da9ab33a..abc5523bfd70 100644
--- a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
+++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp
@@ -23,6 +23,7 @@
 #include "llvm/BinaryFormat/Wasm.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/Format.h"
+#include "Plugins/Process/wasm/ProcessWasm.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -341,6 +342,8 @@ void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
                     0,              // Alignment of the section
                     0,              // Flags for this section.
                     1));            // Number of host bytes per target byte
+    if (section_type == eSectionTypeCode)
+      section_sp->SetPermissions(ePermissionsReadable|ePermissionsExecutable);
     m_sections_up->AddSection(section_sp);
     unified_section_list.AddSection(section_sp);
   }
@@ -367,6 +370,7 @@ bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
   assert(m_memory_addr == LLDB_INVALID_ADDRESS ||
          m_memory_addr == load_address);
 
+  lldb::addr_t adjust_addr;
   ModuleSP module_sp = GetModule();
   if (!module_sp)
     return false;
@@ -381,8 +385,9 @@ bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
   const size_t num_sections = section_list->GetSize();
   for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
     SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
+    adjust_addr = load_address;
     if (target.SetSectionLoadAddress(
-            section_sp, load_address | section_sp->GetFileOffset())) {
+            section_sp, adjust_addr | section_sp->GetFileOffset())) {
       ++num_loaded_sections;
     }
   }
diff --git a/lldb/source/Plugins/Platform/CMakeLists.txt b/lldb/source/Plugins/Platform/CMakeLists.txt
index 5f284e517dca..6084cbc9378d 100644
--- a/lldb/source/Plugins/Platform/CMakeLists.txt
+++ b/lldb/source/Plugins/Platform/CMakeLists.txt
@@ -15,3 +15,4 @@
 add_subdirectory(POSIX)
 add_subdirectory(gdb-server)
 add_subdirectory(Android)
+add_subdirectory(wasm-remote)
diff --git a/lldb/source/Plugins/Platform/wasm-remote/CMakeLists.txt b/lldb/source/Plugins/Platform/wasm-remote/CMakeLists.txt
new file mode 100644
index 000000000000..4a65765a5659
--- /dev/null
+++ b/lldb/source/Plugins/Platform/wasm-remote/CMakeLists.txt
@@ -0,0 +1,10 @@
+add_lldb_library(lldbPluginPlatformWasm PLUGIN
+  PlatformRemoteWasmServer.cpp
+
+   LINK_LIBS
+    lldbBreakpoint
+    lldbCore
+    lldbHost
+    lldbTarget
+    lldbPluginProcessUtility
+  )
diff --git a/lldb/source/Plugins/Platform/wasm-remote/PlatformRemoteWasmServer.cpp b/lldb/source/Plugins/Platform/wasm-remote/PlatformRemoteWasmServer.cpp
new file mode 100644
index 000000000000..f26d11f00e5c
--- /dev/null
+++ b/lldb/source/Plugins/Platform/wasm-remote/PlatformRemoteWasmServer.cpp
@@ -0,0 +1,139 @@
+#include "PlatformRemoteWasmServer.h"
+#include "lldb/Host/Config.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
+#include "lldb/Host/PosixApi.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/Log.h"
+#include "lldb/Utility/ProcessInfo.h"
+#include "lldb/Utility/Status.h"
+#include "lldb/Utility/StreamString.h"
+#include "lldb/Utility/UriParser.h"
+
+#include "Plugins/Process/Utility/GDBRemoteSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::platform_wasm_server;
+
+LLDB_PLUGIN_DEFINE_ADV(PlatformRemoteWASMServer, PlatformWasm)
+
+static bool g_initialized = false;
+
+void PlatformRemoteWASMServer::Initialize() {
+  Platform::Initialize();
+
+  if (!g_initialized) {
+    g_initialized = true;
+    PluginManager::RegisterPlugin(
+        PlatformRemoteWASMServer::GetPluginNameStatic(),
+        PlatformRemoteWASMServer::GetDescriptionStatic(),
+        PlatformRemoteWASMServer::CreateInstance);
+  }
+}
+
+void PlatformRemoteWASMServer::Terminate() {
+  if (g_initialized) {
+    g_initialized = false;
+    PluginManager::UnregisterPlugin(PlatformRemoteWASMServer::CreateInstance);
+  }
+
+  Platform::Terminate();
+}
+
+PlatformSP PlatformRemoteWASMServer::CreateInstance(bool force,
+                                                    const ArchSpec *arch) {
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM));
+  if (log) {
+    const char *arch_name;
+    if (arch && arch->GetArchitectureName())
+      arch_name = arch->GetArchitectureName();
+    else
+      arch_name = "<null>";
+
+    const char *triple_cstr =
+        arch ? arch->GetTriple().getTriple().c_str() : "<null>";
+
+    LLDB_LOGF(log, "PlatformRemoteWASMServer::%s(force=%s, arch={%s,%s})",
+              __FUNCTION__, force ? "true" : "false", arch_name, triple_cstr);
+  }
+
+  bool create = force;
+  if (!create && arch && arch->IsValid()) {
+    const llvm::Triple &triple = arch->GetTriple();
+    if (arch->GetMachine() == llvm::Triple::wasm32 &&
+        triple.getOS() == llvm::Triple::WASI) {
+      create = true;
+    }
+  }
+
+  if (create) {
+    if (log)
+      LLDB_LOGF(log, "PlatformRemoteWASMServer::%s() creating platform",
+                __FUNCTION__);
+    return PlatformSP(new PlatformRemoteWASMServer());
+  }
+
+  if (log)
+    LLDB_LOGF(log,
+              "PlatformRemoteWASMServer::%s() aborting creation of platform",
+              __FUNCTION__);
+  return PlatformSP();
+}
+
+ConstString PlatformRemoteWASMServer::GetPluginNameStatic() {
+  static ConstString g_name("remote-wasm-server");
+  return g_name;
+}
+
+ConstString PlatformRemoteWASMServer::GetPluginName() {
+  return GetPluginNameStatic();
+}
+
+const char *PlatformRemoteWASMServer::GetDescriptionStatic() {
+  return "A platform that uses the GDB remote protocol as the communication "
+         "transport for Wasm Runtime";
+}
+
+size_t PlatformRemoteWASMServer::ConnectToWaitingProcesses(Debugger &debugger,
+                                                          Status &error) {
+  std::vector<std::string> connection_urls;
+  GetPendingGdbServerList(connection_urls);
+
+  for (size_t i = 0; i < connection_urls.size(); ++i) {
+    ConnectProcess(connection_urls[i].c_str(), "wasm", debugger, nullptr, error);
+    if (error.Fail())
+      return i; // We already connected to i process succsessfully
+  }
+  return connection_urls.size();
+}
+
+bool PlatformRemoteWASMServer::GetSupportedArchitectureAtIndex(uint32_t idx,
+                                                              ArchSpec &arch) {
+  ArchSpec remote_arch = m_gdb_client.GetSystemArchitecture();
+  if (idx == 0) {
+    arch = remote_arch;
+    return arch.IsValid();
+  } else if (idx == 1 && remote_arch.IsValid() &&
+             remote_arch.GetTriple().getOS() == llvm::Triple::WASI) {
+    return arch.IsValid();
+  }
+  return false;
+}
+
+/// Default Constructor
+PlatformRemoteWASMServer::PlatformRemoteWASMServer()
+    : PlatformRemoteGDBServer()
+    {
+    }
\ No newline at end of file
diff --git a/lldb/source/Plugins/Platform/wasm-remote/PlatformRemoteWasmServer.h b/lldb/source/Plugins/Platform/wasm-remote/PlatformRemoteWasmServer.h
new file mode 100644
index 000000000000..f306a79d3f4f
--- /dev/null
+++ b/lldb/source/Plugins/Platform/wasm-remote/PlatformRemoteWasmServer.h
@@ -0,0 +1,37 @@
+#ifndef LLDB_SOURCE_PLUGINS_PLATFORM_GDB_SERVER_PLATFORMREMOTEWASMSERVER_H
+#define LLDB_SOURCE_PLUGINS_PLATFORM_GDB_SERVER_PLATFORMREMOTEWASMSERVER_H
+
+#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
+#include "lldb/Target/Platform.h"
+
+namespace lldb_private {
+namespace platform_wasm_server {
+
+class PlatformRemoteWASMServer : public lldb_private::platform_gdb_server::PlatformRemoteGDBServer{
+
+public:
+  static void Initialize();
+
+  static void Terminate();
+
+  static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);
+
+  static ConstString GetPluginNameStatic();
+
+  static const char *GetDescriptionStatic();
+
+  size_t ConnectToWaitingProcesses(lldb_private::Debugger &debugger,
+                                   lldb_private::Status &error) override;
+  
+  bool GetSupportedArchitectureAtIndex(uint32_t idx, ArchSpec &arch) override;
+
+  ConstString GetPluginName() override;
+
+  PlatformRemoteWASMServer();
+
+};
+
+} // namespace platform_wasm_server
+} // namespace lldb_private
+
+#endif
\ No newline at end of file
diff --git a/lldb/source/Plugins/Plugins.def.in b/lldb/source/Plugins/Plugins.def.in
index bf54598fb2f3..b0bd7b9965fe 100644
--- 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
index bea5bac9eb21..7a0855e02ca2 100644
--- a/lldb/source/Plugins/Process/CMakeLists.txt
+++ b/lldb/source/Plugins/Process/CMakeLists.txt
@@ -18,3 +18,4 @@ add_subdirectory(Utility)
 add_subdirectory(elf-core)
 add_subdirectory(mach-core)
 add_subdirectory(minidump)
+add_subdirectory(wasm)
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
index 12bc7390c729..707ab85e5615 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -285,7 +285,7 @@ bool ProcessElfCore::IsAlive() { return true; }
 
 // Process Memory
 size_t ProcessElfCore::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
-                                  Status &error) {
+                                  Status &error, ExecutionContext *exe_ctx) {
   // Don't allow the caching that lldb_private::Process::ReadMemory does since
   // in core files we have it all cached our our core file anyway.
   return DoReadMemory(addr, buf, size, error);
diff --git a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
index d8e3cc9ae3e1..f0bf9c4d3b00 100644
--- a/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
+++ b/lldb/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -84,7 +84,8 @@ public:
 
   // Process Memory
   size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
-                    lldb_private::Status &error) override;
+                    lldb_private::Status &error,
+                    lldb_private::ExecutionContext *exe_ctx = nullptr) override;
 
   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
                       lldb_private::Status &error) override;
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 6914b37348ea..bb8a056049f3 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -334,6 +334,11 @@ ConstString ProcessGDBRemote::GetPluginName() { return GetPluginNameStatic(); }
 
 uint32_t ProcessGDBRemote::GetPluginVersion() { return 1; }
 
+std::shared_ptr<ThreadGDBRemote>
+ProcessGDBRemote::CreateThread(lldb::tid_t tid) {
+  return std::make_shared<ThreadGDBRemote>(*this, tid);
+}
+
 bool ProcessGDBRemote::ParsePythonTargetDefinition(
     const FileSpec &target_definition_fspec) {
   ScriptInterpreter *interpreter =
@@ -1626,7 +1631,7 @@ bool ProcessGDBRemote::DoUpdateThreadList(ThreadList &old_thread_list,
       ThreadSP thread_sp(
           old_thread_list_copy.RemoveThreadByProtocolID(tid, false));
       if (!thread_sp) {
-        thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid);
+        thread_sp = CreateThread(tid);
         LLDB_LOGV(log, "Making new thread: {0} for thread ID: {1:x}.",
                   thread_sp.get(), thread_sp->GetID());
       } else {
@@ -1742,7 +1747,7 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
 
       if (!thread_sp) {
         // Create the thread if we need to
-        thread_sp = std::make_shared<ThreadGDBRemote>(*this, tid);
+        thread_sp = CreateThread(tid);
         m_thread_list_real.AddThread(thread_sp);
       }
     }
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index fe04cdddd0f5..e4a14c64579a 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -237,6 +237,8 @@ protected:
 
   bool SupportsMemoryTagging() override;
 
+  virtual std::shared_ptr<ThreadGDBRemote> CreateThread(lldb::tid_t tid);
+
   /// Broadcaster event bits definitions.
   enum {
     eBroadcastBitAsyncContinue = (1 << 0),
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
index 84548edb5caa..0ae6f7e4a177 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.cpp
@@ -596,7 +596,7 @@ bool ProcessMachCore::WarnBeforeDetach() const { return false; }
 
 // Process Memory
 size_t ProcessMachCore::ReadMemory(addr_t addr, void *buf, size_t size,
-                                   Status &error) {
+                                   Status &error, ExecutionContext *exe_ctx) {
   // Don't allow the caching that lldb_private::Process::ReadMemory does since
   // in core files we have it all cached our our core file anyway.
   return DoReadMemory(addr, buf, size, error);
diff --git a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.h b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.h
index db77e96f1072..1c930896c743 100644
--- a/lldb/source/Plugins/Process/mach-core/ProcessMachCore.h
+++ b/lldb/source/Plugins/Process/mach-core/ProcessMachCore.h
@@ -65,7 +65,8 @@ public:
 
   // Process Memory
   size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
-                    lldb_private::Status &error) override;
+                    lldb_private::Status &error,
+                    lldb_private::ExecutionContext *exe_ctx = nullptr) override;
 
   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
                       lldb_private::Status &error) override;
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index 385557422758..d8bb21581086 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -374,7 +374,7 @@ bool ProcessMinidump::IsAlive() { return true; }
 bool ProcessMinidump::WarnBeforeDetach() const { return false; }
 
 size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
-                                   Status &error) {
+                                   Status &error, ExecutionContext *exe_ctx) {
   // Don't allow the caching that lldb_private::Process::ReadMemory does since
   // we have it all cached in our dump file anyway.
   return DoReadMemory(addr, buf, size, error);
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
index 27b0da0047a5..e94ecab430c1 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.h
@@ -69,8 +69,8 @@ public:
 
   bool WarnBeforeDetach() const override;
 
-  size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
-                    Status &error) override;
+  size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size, Status &error,
+                    ExecutionContext *exe_ctx = nullptr) override;
 
   size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
                       Status &error) override;
diff --git a/lldb/source/Plugins/Process/wasm/CMakeLists.txt b/lldb/source/Plugins/Process/wasm/CMakeLists.txt
new file mode 100644
index 000000000000..61efb933fa62
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/CMakeLists.txt
@@ -0,0 +1,12 @@
+
+add_lldb_library(lldbPluginProcessWasm PLUGIN
+  ProcessWasm.cpp
+  ThreadWasm.cpp
+  UnwindWasm.cpp
+
+  LINK_LIBS
+    lldbCore
+    ${LLDB_PLUGINS}
+  LINK_COMPONENTS
+    Support
+  )
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
new file mode 100644
index 000000000000..9c0fc7b7f270
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.cpp
@@ -0,0 +1,261 @@
+//===-- ProcessWasm.cpp ---------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessWasm.h"
+#include "ThreadWasm.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Utility/DataBufferHeap.h"
+
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::process_gdb_remote;
+using namespace lldb_private::wasm;
+
+LLDB_PLUGIN_DEFINE(ProcessWasm)
+
+// ProcessGDBRemote constructor
+ProcessWasm::ProcessWasm(lldb::TargetSP target_sp, ListenerSP listener_sp)
+    : ProcessGDBRemote(target_sp, listener_sp) {
+  /* always use linux signals for wasm process */
+  m_unix_signals_sp = UnixSignals::Create(ArchSpec{"wasm32-Ant-wasi-wasm"});
+}
+
+void ProcessWasm::Initialize() {
+  static llvm::once_flag g_once_flag;
+
+  llvm::call_once(g_once_flag, []() {
+    PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                  GetPluginDescriptionStatic(), CreateInstance,
+                                  DebuggerInitialize);
+  });
+}
+
+void ProcessWasm::DebuggerInitialize(Debugger &debugger) {
+  ProcessGDBRemote::DebuggerInitialize(debugger);
+}
+
+// PluginInterface
+ConstString ProcessWasm::GetPluginName() { return GetPluginNameStatic(); }
+
+uint32_t ProcessWasm::GetPluginVersion() { return 1; }
+
+ConstString ProcessWasm::GetPluginNameStatic() {
+  static ConstString g_name("wasm");
+  return g_name;
+}
+
+const char *ProcessWasm::GetPluginDescriptionStatic() {
+  return "GDB Remote protocol based WebAssembly debugging plug-in.";
+}
+
+void ProcessWasm::Terminate() {
+  PluginManager::UnregisterPlugin(ProcessWasm::CreateInstance);
+}
+
+lldb::ProcessSP ProcessWasm::CreateInstance(lldb::TargetSP target_sp,
+                                            ListenerSP listener_sp,
+                                            const FileSpec *crash_file_path,
+                                            bool can_connect) {
+  lldb::ProcessSP process_sp;
+  if (crash_file_path == nullptr)
+    process_sp = std::make_shared<ProcessWasm>(target_sp, listener_sp);
+  return process_sp;
+}
+
+bool ProcessWasm::CanDebug(lldb::TargetSP target_sp,
+                                bool plugin_specified_by_name) {
+  if (plugin_specified_by_name)
+    return true;
+
+  Module *exe_module = target_sp->GetExecutableModulePointer();
+  if (exe_module) {
+    ObjectFile *exe_objfile = exe_module->GetObjectFile();
+    return exe_objfile->GetArchitecture().GetMachine() == llvm::Triple::wasm32;
+  }
+  // However, if there is no wasm module, we return false, otherwise,
+  // we might use ProcessWasm to attach gdb remote.
+  return false;
+}
+
+
+
+std::shared_ptr<ThreadGDBRemote> ProcessWasm::CreateThread(lldb::tid_t tid) {
+  return std::make_shared<ThreadWasm>(*this, tid);
+}
+
+size_t ProcessWasm::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+                               Status &error, ExecutionContext *exe_ctx) {
+  wasm_addr_t wasm_addr(vm_addr);
+  size_t nread = 0;
+
+  switch (wasm_addr.GetType()) {
+  case WasmAddressType::Memory:
+  case WasmAddressType::Object:
+    return ProcessGDBRemote::ReadMemory(vm_addr, buf, size, error);
+  case WasmAddressType::Invalid:
+  default:
+    error.SetErrorStringWithFormat(
+        "Wasm read failed for invalid address 0x%" PRIx64, vm_addr);
+    return 0;
+  }
+}
+
+size_t ProcessWasm::WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr,
+                                 void *buf, size_t buffer_size) {
+  char packet[64];
+  int packet_len =
+      ::snprintf(packet, sizeof(packet), "qWasmMem:%d;%" PRIx64 ";%" PRIx64,
+                 wasm_module_id, static_cast<uint64_t>(addr),
+                 static_cast<uint64_t>(buffer_size));
+  assert(packet_len + 1 < (int)sizeof(packet));
+  UNUSED_IF_ASSERT_DISABLED(packet_len);
+  StringExtractorGDBRemote response;
+  if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) ==
+      GDBRemoteCommunication::PacketResult::Success) {
+    if (response.IsNormalResponse()) {
+      return response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
+                                      static_cast<uint8_t *>(buf), buffer_size),
+                                  '\xdd');
+    }
+  }
+  return 0;
+}
+
+size_t ProcessWasm::WasmReadData(uint32_t wasm_module_id, lldb::addr_t addr,
+                               void *buf, size_t buffer_size) {
+  char packet[64];
+  int packet_len =
+      ::snprintf(packet, sizeof(packet), "qWasmData:%d;%" PRIx64 ";%" PRIx64,
+                 wasm_module_id, static_cast<uint64_t>(addr),
+                 static_cast<uint64_t>(buffer_size));
+  assert(packet_len + 1 < (int)sizeof(packet));
+  UNUSED_IF_ASSERT_DISABLED(packet_len);
+  StringExtractorGDBRemote response;
+  if (m_gdb_comm.SendPacketAndWaitForResponse(packet, response, GetInterruptTimeout()) ==
+      GDBRemoteCommunication::PacketResult::Success) {
+    if (response.IsNormalResponse()) {
+      return response.GetHexBytes(llvm::MutableArrayRef<uint8_t>(
+                                      static_cast<uint8_t *>(buf), buffer_size),
+                                  '\xdd');
+    }
+  }
+  return 0;
+}
+
+bool ProcessWasm::GetWasmLocal(int frame_index, int index, void *buf,
+                               size_t buffer_size, size_t &size) {
+  StreamString packet;
+  packet.Printf("qWasmLocal:");
+  packet.Printf("%d;%d", frame_index, index);
+  StringExtractorGDBRemote response;
+  if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+      GDBRemoteCommunication::PacketResult::Success) {
+    return false;
+  }
+
+  if (!response.IsNormalResponse()) {
+    return false;
+  }
+
+  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 ProcessWasm::GetWasmGlobal(int frame_index, int index, void *buf,
+                                size_t buffer_size, size_t &size) {
+  StreamString packet;
+  packet.PutCString("qWasmGlobal:");
+  packet.Printf("%d;%d", frame_index, index);
+  StringExtractorGDBRemote response;
+  if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+      GDBRemoteCommunication::PacketResult::Success) {
+    return false;
+  }
+
+  if (!response.IsNormalResponse()) {
+    return false;
+  }
+
+  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 ProcessWasm::GetWasmStackValue(int frame_index, int index, void *buf,
+                                    size_t buffer_size, size_t &size) {
+  StreamString packet;
+  packet.PutCString("qWasmStackValue:");
+  packet.Printf("%d;%d", frame_index, index);
+  StringExtractorGDBRemote response;
+  if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+      GDBRemoteCommunication::PacketResult::Success) {
+    return false;
+  }
+
+  if (!response.IsNormalResponse()) {
+    return false;
+  }
+
+  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 ProcessWasm::GetWasmCallStack(lldb::tid_t tid,
+                                   std::vector<lldb::addr_t> &call_stack_pcs) {
+  call_stack_pcs.clear();
+  StreamString packet;
+  packet.Printf("qWasmCallStack:");
+  packet.Printf("%llx", tid);
+  StringExtractorGDBRemote response;
+  if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetString(), response) !=
+      GDBRemoteCommunication::PacketResult::Success) {
+    return false;
+  }
+
+  if (!response.IsNormalResponse()) {
+    return false;
+  }
+
+  addr_t buf[1024 / sizeof(addr_t)];
+  size_t bytes = response.GetHexBytes(
+      llvm::MutableArrayRef<uint8_t>((uint8_t *)buf, sizeof(buf)), '\xdd');
+  if (bytes == 0) {
+    return false;
+  }
+
+  for (size_t i = 0; i < bytes / sizeof(addr_t); i++) {
+    call_stack_pcs.push_back(buf[i]);
+  }
+  return true;
+}
diff --git a/lldb/source/Plugins/Process/wasm/ProcessWasm.h b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
new file mode 100644
index 000000000000..d3aece7a6554
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ProcessWasm.h
@@ -0,0 +1,128 @@
+//===-- ProcessWasm.h -------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H
+
+#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
+#include "lldb/Target/RegisterContext.h"
+
+namespace lldb_private {
+namespace wasm {
+
+// Each WebAssembly module has separated address spaces for Code and Memory.
+// A WebAssembly module also has a Data section which, when the module is
+// loaded, gets mapped into a region in the module Memory.
+// For the purpose of debugging, we can represent all these separated 32-bit
+// address spaces with a single virtual 64-bit address space.
+//
+// Struct wasm_addr_t provides this encoding using bitfields
+//
+enum WasmAddressType {
+  Memory = 0x00,
+  Object = 0x01,
+  Invalid = 0x03
+};
+struct wasm_addr_t {
+  uint64_t offset : 32;
+  uint64_t module_id : 30;
+  uint64_t type : 2;
+
+  wasm_addr_t(lldb::addr_t addr)
+      : type(addr >> 62), module_id((addr & 0x00ffffff00000000) >> 32),
+        offset(addr & 0x00000000ffffffff) {}
+
+  wasm_addr_t(WasmAddressType type_, uint32_t module_id_, uint32_t offset_)
+      : type(type_), module_id(module_id_), offset(offset_) {}
+
+  WasmAddressType GetType() { return static_cast<WasmAddressType>(type); }
+  operator lldb::addr_t() { return *(uint64_t *)this; }
+};
+
+/// ProcessWasm provides the access to the Wasm program state
+///  retrieved from the Wasm engine.
+class ProcessWasm : public process_gdb_remote::ProcessGDBRemote {
+public:
+  ProcessWasm(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp);
+  ~ProcessWasm() override = default;
+
+  static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
+                                        lldb::ListenerSP listener_sp,
+                                        const FileSpec *crash_file_path,
+                                        bool can_connect);
+
+  static void Initialize();
+  static void DebuggerInitialize(Debugger &debugger);
+  static void Terminate();
+  static ConstString GetPluginNameStatic();
+  static const char *GetPluginDescriptionStatic();
+
+  /// PluginInterface protocol.
+  /// \{
+  ConstString GetPluginName() override;
+  uint32_t GetPluginVersion() override;
+  /// \}
+
+  /// Process protocol.
+  /// \{
+  size_t ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size, Status &error,
+                    ExecutionContext *exe_ctx = nullptr) override;
+  /// \}
+
+  /// Query the value of a WebAssembly local variable from the WebAssembly
+  /// remote process.
+  bool GetWasmLocal(int frame_index, int index, void *buf, size_t buffer_size,
+                    size_t &size);
+
+  /// Query the value of a WebAssembly global variable from the WebAssembly
+  /// remote process.
+  bool GetWasmGlobal(int frame_index, int index, void *buf, size_t buffer_size,
+                     size_t &size);
+
+  /// Query the value of an item in the WebAssembly operand stack from the
+  /// WebAssembly remote process.
+  bool GetWasmStackValue(int frame_index, int index, void *buf,
+                         size_t buffer_size, size_t &size);
+
+  /// Read from the WebAssembly Memory space.
+  size_t WasmReadMemory(uint32_t wasm_module_id, lldb::addr_t addr, void *buf,
+                      size_t buffer_size);
+
+  /// Read from the WebAssembly Data space.
+  size_t WasmReadData(uint32_t wasm_module_id, lldb::addr_t addr, void *buf,
+                    size_t buffer_size);
+
+  /// Retrieve the current call stack from the WebAssembly remote process.
+  bool GetWasmCallStack(lldb::tid_t tid,
+                        std::vector<lldb::addr_t> &call_stack_pcs);
+
+  // Check if a given Process
+  bool CanDebug(lldb::TargetSP target_sp,
+                bool plugin_specified_by_name) override;
+
+protected:
+  /// ProcessGDBRemote protocol.
+  /// \{
+  std::shared_ptr<process_gdb_remote::ThreadGDBRemote>
+  CreateThread(lldb::tid_t tid) override;
+  /// \}
+
+private:
+  friend class UnwindWasm;
+  process_gdb_remote::GDBRemoteDynamicRegisterInfoSP &GetRegisterInfo() {
+    return m_register_info_sp;
+  }
+
+  ProcessWasm(const ProcessWasm &);
+  const ProcessWasm &operator=(const ProcessWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_PROCESSWASM_H
diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
new file mode 100644
index 000000000000..fa02073e7a52
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.cpp
@@ -0,0 +1,35 @@
+//===-- ThreadWasm.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "ThreadWasm.h"
+
+#include "ProcessWasm.h"
+#include "UnwindWasm.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace lldb_private::wasm;
+
+Unwind &ThreadWasm::GetUnwinder() {
+  if (!m_unwinder_up) {
+    assert(CalculateTarget()->GetArchitecture().GetMachine() ==
+           llvm::Triple::wasm32);
+    m_unwinder_up.reset(new wasm::UnwindWasm(*this));
+  }
+  return *m_unwinder_up;
+}
+
+bool ThreadWasm::GetWasmCallStack(std::vector<lldb::addr_t> &call_stack_pcs) {
+  ProcessSP process_sp(GetProcess());
+  if (process_sp) {
+    ProcessWasm *wasm_process = static_cast<ProcessWasm *>(process_sp.get());
+    return wasm_process->GetWasmCallStack(GetID(), call_stack_pcs);
+  }
+  return false;
+}
diff --git a/lldb/source/Plugins/Process/wasm/ThreadWasm.h b/lldb/source/Plugins/Process/wasm/ThreadWasm.h
new file mode 100644
index 000000000000..0a33c07de994
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/ThreadWasm.h
@@ -0,0 +1,41 @@
+//===-- ThreadWasm.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H
+#define LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H
+
+#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h"
+
+namespace lldb_private {
+namespace wasm {
+
+/// ProcessWasm provides the access to the Wasm program state
+///  retrieved from the Wasm engine.
+class ThreadWasm : public process_gdb_remote::ThreadGDBRemote {
+public:
+  ThreadWasm(Process &process, lldb::tid_t tid)
+      : process_gdb_remote::ThreadGDBRemote(process, tid) {}
+  ~ThreadWasm() override = default;
+
+  /// Retrieve the current call stack from the WebAssembly remote process.
+  bool GetWasmCallStack(std::vector<lldb::addr_t> &call_stack_pcs);
+
+protected:
+  /// Thread protocol.
+  /// \{
+  Unwind &GetUnwinder() override;
+  /// \}
+
+  ThreadWasm(const ThreadWasm &);
+  const ThreadWasm &operator=(const ThreadWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_PROCESS_WASM_THREADWASM_H
diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
new file mode 100644
index 000000000000..1a195cb9361a
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.cpp
@@ -0,0 +1,74 @@
+//===-- UnwindWasm.cpp ----------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnwindWasm.h"
+#include "Plugins/Process/gdb-remote/ThreadGDBRemote.h"
+#include "Plugins/Process/wasm/ProcessWasm.h"
+#include "Plugins/Process/wasm/ThreadWasm.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace process_gdb_remote;
+using namespace wasm;
+
+class WasmGDBRemoteRegisterContext : public GDBRemoteRegisterContext {
+public:
+  WasmGDBRemoteRegisterContext(ThreadGDBRemote &thread,
+                               uint32_t concrete_frame_idx,
+                               GDBRemoteDynamicRegisterInfoSP &reg_info_sp,
+                               uint64_t pc)
+      : GDBRemoteRegisterContext(thread, concrete_frame_idx, reg_info_sp, false,
+                                 false) {
+    PrivateSetRegisterValue(0, pc);
+  }
+};
+
+lldb::RegisterContextSP
+UnwindWasm::DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) {
+  if (m_frames.size() <= frame->GetFrameIndex()) {
+    return lldb::RegisterContextSP();
+  }
+
+  ThreadSP thread = frame->GetThread();
+  ThreadGDBRemote *gdb_thread = static_cast<ThreadGDBRemote *>(thread.get());
+  ProcessWasm *wasm_process =
+      static_cast<ProcessWasm *>(thread->GetProcess().get());
+  std::shared_ptr<GDBRemoteRegisterContext> reg_ctx_sp =
+      std::make_shared<WasmGDBRemoteRegisterContext>(
+          *gdb_thread, frame->GetConcreteFrameIndex(),
+          wasm_process->GetRegisterInfo(), m_frames[frame->GetFrameIndex()]);
+  return reg_ctx_sp;
+}
+
+uint32_t UnwindWasm::DoGetFrameCount() {
+  if (!m_unwind_complete) {
+    m_unwind_complete = true;
+    m_frames.clear();
+
+    ThreadWasm &wasm_thread = static_cast<ThreadWasm &>(GetThread());
+    if (!wasm_thread.GetWasmCallStack(m_frames))
+      m_frames.clear();
+  }
+  return m_frames.size();
+}
+
+bool UnwindWasm::DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
+                                       lldb::addr_t &pc,
+                                       bool &behaves_like_zeroth_frame) {
+  if (m_frames.size() == 0) {
+    DoGetFrameCount();
+  }
+
+  if (frame_idx < m_frames.size()) {
+    behaves_like_zeroth_frame = (frame_idx == 0);
+    cfa = 0;
+    pc = m_frames[frame_idx];
+    return true;
+  }
+  return false;
+}
\ No newline at end of file
diff --git a/lldb/source/Plugins/Process/wasm/UnwindWasm.h b/lldb/source/Plugins/Process/wasm/UnwindWasm.h
new file mode 100644
index 000000000000..9bd1dac9a98a
--- /dev/null
+++ b/lldb/source/Plugins/Process/wasm/UnwindWasm.h
@@ -0,0 +1,55 @@
+//===-- UnwindWasm.h --------------------------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindWasm_h_
+#define lldb_UnwindWasm_h_
+
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Unwind.h"
+#include <vector>
+
+namespace lldb_private {
+namespace wasm {
+
+/// UnwindWasm manages stack unwinding for a WebAssembly process.
+class UnwindWasm : public lldb_private::Unwind {
+public:
+  UnwindWasm(lldb_private::Thread &thread)
+      : Unwind(thread), m_frames(), m_unwind_complete(false) {}
+  ~UnwindWasm() override = default;
+
+protected:
+  /// Unwind protocol.
+  /// \{
+  void DoClear() override {
+    m_frames.clear();
+    m_unwind_complete = false;
+  }
+
+  uint32_t DoGetFrameCount() override;
+
+  bool DoGetFrameInfoAtIndex(uint32_t frame_idx, lldb::addr_t &cfa,
+                             lldb::addr_t &pc,
+                             bool &behaves_like_zeroth_frame) override;
+
+  lldb::RegisterContextSP
+  DoCreateRegisterContextForFrame(lldb_private::StackFrame *frame) override;
+  /// \}
+
+private:
+  std::vector<lldb::addr_t> m_frames;
+  bool m_unwind_complete;
+
+  UnwindWasm(const UnwindWasm &);
+  const UnwindWasm &operator=(const UnwindWasm &) = delete;
+};
+
+} // namespace wasm
+} // namespace lldb_private
+
+#endif // lldb_UnwindWasm_h_
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
index ccaf31317d75..c3ef5aebd46d 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -3212,8 +3212,13 @@ VariableSP SymbolFileDWARF::ParseVariableDIE(const SymbolContext &sc,
           GetDWARFDeclContext(die).GetQualifiedNameAsConstString().GetCString();
   }
 
-  if (tag == DW_TAG_formal_parameter)
+  if (tag == DW_TAG_formal_parameter) {
     scope = eValueTypeVariableArgument;
+    // For Wasm dwarft, pamameter may don't have location attr, 
+    // so set module here
+    if (!location.GetModule())
+      location.SetModule(module);
+  }
   else {
     // DWARF doesn't specify if a DW_TAG_variable is a local, global
     // or static variable, so we have to do a little digging:
diff --git a/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp
index b660c310ef31..cd76421cec18 100644
--- a/lldb/source/Target/PathMappingList.cpp
+++ b/lldb/source/Target/PathMappingList.cpp
@@ -218,7 +218,12 @@ bool PathMappingList::ReverseRemapPath(const FileSpec &file, FileSpec &fixed) co
 }
 
 llvm::Optional<FileSpec> PathMappingList::FindFile(const FileSpec &orig_spec) const {
-  if (auto remapped = RemapPath(orig_spec.GetPath(), /*only_if_exists=*/true))
+  // We must normalize the orig_spec again using the host's path style,
+  // otherwise there will be mismatch between the host and remote platform
+  // if they use different path styles.
+  if (auto remapped = RemapPath(
+          NormalizePath(ConstString(orig_spec.GetCString())).GetStringRef(),
+          /*only_if_exists=*/true))
     return remapped;
 
   return {};
diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp
index a77ecddfbab6..e257f93508f6 100644
--- a/lldb/source/Target/Platform.cpp
+++ b/lldb/source/Target/Platform.cpp
@@ -1970,6 +1970,12 @@ size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target,
     trap_opcode_size = sizeof(g_i386_opcode);
   } break;
 
+  case llvm::Triple::wasm32: {
+    static const uint8_t g_wasm_opcode[] = {0x00}; // unreachable
+    trap_opcode = g_wasm_opcode;
+    trap_opcode_size = sizeof(g_wasm_opcode);
+  } break;
+
   default:
     return 0;
   }
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 8ecc66b592ea..f148987915de 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -1892,7 +1892,8 @@ Status Process::DisableSoftwareBreakpoint(BreakpointSite *bp_site) {
 // code
 //#define VERIFY_MEMORY_READS
 
-size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error) {
+size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Status &error,
+                           ExecutionContext *exe_ctx) {
   error.Clear();
   if (!GetDisableMemoryCache()) {
 #if defined(VERIFY_MEMORY_READS)
diff --git a/lldb/source/Target/ProcessTrace.cpp b/lldb/source/Target/ProcessTrace.cpp
index c878a2ac4eb9..ad5945b0ad1f 100644
--- a/lldb/source/Target/ProcessTrace.cpp
+++ b/lldb/source/Target/ProcessTrace.cpp
@@ -88,7 +88,7 @@ void ProcessTrace::RefreshStateAfterStop() {}
 Status ProcessTrace::DoDestroy() { return Status(); }
 
 size_t ProcessTrace::ReadMemory(addr_t addr, void *buf, size_t size,
-                                Status &error) {
+                                Status &error, ExecutionContext *exe_ctx) {
   // Don't allow the caching that lldb_private::Process::ReadMemory does since
   // we have it all cached in the trace files.
   return DoReadMemory(addr, buf, size, error);
diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp
index 896e647bbb52..f76307016102 100644
--- a/lldb/source/Target/ThreadPlanStepRange.cpp
+++ b/lldb/source/Target/ThreadPlanStepRange.cpp
@@ -334,7 +334,10 @@ bool ThreadPlanStepRange::SetNextBranchBreakpoint() {
     // If we didn't find a branch, run to the end of the range.
     if (branch_index == UINT32_MAX) {
       uint32_t last_index = instructions->GetSize() - 1;
-      if (last_index - pc_index > 1) {
+      /* This line causes the "step over was treated as step in" issue, we
+       * modify it as a workaround */
+      /* The origin line is: if (last_index - pc_index > 1) { */
+      if (last_index - pc_index >= 1) {
         InstructionSP last_inst =
             instructions->GetInstructionAtIndex(last_index);
         size_t last_inst_size = last_inst->GetOpcode().GetByteSize();
diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp
index 4ec2e25c7e3b..24c88fe9ae4f 100644
--- a/lldb/source/Target/UnixSignals.cpp
+++ b/lldb/source/Target/UnixSignals.cpp
@@ -46,6 +46,8 @@ lldb::UnixSignalsSP UnixSignals::Create(const ArchSpec &arch) {
     return std::make_shared<FreeBSDSignals>();
   case llvm::Triple::NetBSD:
     return std::make_shared<NetBSDSignals>();
+  case llvm::Triple::WASI:
+    return std::make_shared<LinuxSignals>();
   default:
     return std::make_shared<UnixSignals>();
   }
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h
index 4310ba9ce9e0..297b3387999d 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/OrcRPCExecutorProcessControl.h
@@ -13,6 +13,7 @@
 #ifndef LLVM_EXECUTIONENGINE_ORC_ORCRPCEXECUTORPROCESSCONTROL_H
 #define LLVM_EXECUTIONENGINE_ORC_ORCRPCEXECUTORPROCESSCONTROL_H
 
+#include "llvm/ExecutionEngine/Orc/Core.h"
 #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
 #include "llvm/ExecutionEngine/Orc/Shared/RPCUtils.h"
 #include "llvm/ExecutionEngine/Orc/Shared/RawByteChannel.h"
diff --git a/llvm/include/llvm/Support/MathExtras.h b/llvm/include/llvm/Support/MathExtras.h
index 753b1998c40c..27370c62dd6e 100644
--- a/llvm/include/llvm/Support/MathExtras.h
+++ b/llvm/include/llvm/Support/MathExtras.h
@@ -16,6 +16,7 @@
 #include "llvm/Support/Compiler.h"
 #include <cassert>
 #include <climits>
+#include <limits>
 #include <cmath>
 #include <cstdint>
 #include <cstring>
