summaryrefslogtreecommitdiffstats
path: root/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch
diff options
context:
space:
mode:
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch')
-rw-r--r--fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch5867
1 files changed, 5867 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch
new file mode 100644
index 000000000..d6044e3a3
--- /dev/null
+++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/build-scripts/lldb-wasm.patch
@@ -0,0 +1,5867 @@
+diff --git a/lldb/include/lldb/Breakpoint/Breakpoint.h b/lldb/include/lldb/Breakpoint/Breakpoint.h
+index f2e2a0d22..426d1129b 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 dd7100c46..97d70daad 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 be91929c6..8d876fc1f 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 000000000..6811cbeae
+--- /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 000000000..f3b496c58
+--- /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 1490ac2d6..35c741d4e 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 aaa2470d2..c15f2db52 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 7b9d6b13d..9525fc975 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 ad5298151..5a3c0b27a 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 2ed083ec8..f4d500d19 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 19c97be15..1647f93ec 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 fcaa868b0..59a404d4a 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 fb57c0fed..f92d6a54d 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 9c1ba99da..b15b214b2 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 bf94361dd..4e76d547a 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 000000000..06107e136
+--- /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 000000000..c06126412
+--- /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 a10546c1d..4d13e4642 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 00e9ccb76..2137a1ac8 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 9181a4e47..2be6ec365 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 000000000..73fad41e1
+--- /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 000000000..e50b1bef7
+--- /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 000000000..fdda1991d
+--- /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 000000000..a01159064
+--- /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 000000000..d43e96a34
+--- /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 000000000..8a946592a
+--- /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 ae7e011ea..24ea75d19 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 5272da9ab..abc5523bf 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 5f284e517..6084cbc93 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 000000000..4a65765a5
+--- /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 000000000..f26d11f00
+--- /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 000000000..f306a79d3
+--- /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 bf54598fb..b0bd7b996 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 bea5bac9e..7a0855e02 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 12bc7390c..707ab85e5 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 d8e3cc9ae..f0bf9c4d3 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 6914b3734..bb8a05604 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 fe04cdddd..e4a14c645 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 84548edb5..0ae6f7e4a 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 db77e96f1..1c930896c 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 385557422..d8bb21581 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 27b0da004..e94ecab43 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 000000000..61efb933f
+--- /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 000000000..9c0fc7b7f
+--- /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 000000000..d3aece7a6
+--- /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 000000000..fa02073e7
+--- /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 000000000..0a33c07de
+--- /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 000000000..1a195cb93
+--- /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 000000000..9bd1dac9a
+--- /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 ccaf31317..c3ef5aebd 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 b660c310e..cd76421ce 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 a77ecddfb..e257f9350 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 8ecc66b59..f14898791 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 c878a2ac4..ad5945b0a 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 896e647bb..f76307016 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 4ec2e25c7..24c88fe9a 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 4310ba9ce..297b33879 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 753b1998c..27370c62d 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>