https://github.com/MrEven132 updated https://github.com/llvm/llvm-project/pull/219372
>From a160b8f8bfc144f35c12616c77513714eda24c26 Mon Sep 17 00:00:00 2001 From: MrEven132 <[email protected]> Date: Fri, 28 Aug 2026 13:04:45 +0800 Subject: [PATCH 1/3] [lldb] Track location descriptions per DWARF stack entry --- lldb/source/Expression/DWARFExpression.cpp | 136 ++++++++++++------ .../Expression/DWARFExpressionTest.cpp | 25 ++++ 2 files changed, 121 insertions(+), 40 deletions(-) diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index d22634d63e875..268637c109f3b 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -64,6 +64,71 @@ enum LocationDescriptionKind { /* Composite*/ }; +/// Keeps the location description kind associated with each eagerly +/// materialized value on the DWARF expression stack. +class EvaluationStack { +public: + bool empty() const { return m_values.empty(); } + size_t size() const { return m_values.size(); } + + Value &back() { return m_values.back(); } + const Value &back() const { return m_values.back(); } + + Value &operator[](size_t index) { return m_values[index]; } + const Value &operator[](size_t index) const { return m_values[index]; } + + void push_back(Value value, LocationDescriptionKind loc_desc_kind = Memory) { + m_values.push_back(std::move(value)); + m_loc_desc_kinds.push_back(loc_desc_kind); + } + + void PushCopy(size_t index) { + push_back(m_values[index], m_loc_desc_kinds[index]); + } + + void pop_back() { + m_values.pop_back(); + m_loc_desc_kinds.pop_back(); + } + + LocationDescriptionKind GetLocationDescriptionKind() const { + return m_loc_desc_kinds.back(); + } + + void SetLocationDescriptionKind(LocationDescriptionKind loc_desc_kind) { + m_loc_desc_kinds.back() = loc_desc_kind; + } + + void SwapTopTwo() { + const size_t last = size() - 1; + std::swap(m_values[last], m_values[last - 1]); + std::swap(m_loc_desc_kinds[last], m_loc_desc_kinds[last - 1]); + } + + void RotateTopThree() { + const size_t last = size() - 1; + Value old_top = m_values[last]; + m_values[last] = m_values[last - 1]; + m_values[last - 1] = m_values[last - 2]; + m_values[last - 2] = std::move(old_top); + + LocationDescriptionKind old_top_kind = m_loc_desc_kinds[last]; + m_loc_desc_kinds[last] = m_loc_desc_kinds[last - 1]; + m_loc_desc_kinds[last - 1] = m_loc_desc_kinds[last - 2]; + m_loc_desc_kinds[last - 2] = old_top_kind; + } + + DWARFExpression::Stack &Values() { return m_values; } + + void SyncLocationDescriptionKinds() { + m_loc_desc_kinds.resize(m_values.size(), Memory); + } + +private: + DWARFExpression::Stack m_values; + std::vector<LocationDescriptionKind> m_loc_desc_kinds; +}; + /// Aggregates the inputs, derived pointers, and mutable evaluation state for /// a single DWARF expression evaluation. Passed by reference to every helper /// so they don't need to re-thread these individually. @@ -81,10 +146,9 @@ struct EvalContext { /// Mutable evaluation state. /// @{ - std::vector<Value> stack; + EvaluationStack stack; Value pieces; uint64_t op_piece_offset = 0; - LocationDescriptionKind loc_desc_kind = Memory; /// @} EvalContext(ExecutionContext *exe_ctx, RegisterContext *reg_ctx, @@ -974,10 +1038,11 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx, // Deref a register or implicit location and truncate the value to `size` // bytes. See the corresponding comment in DW_OP_deref for more details on // why we deref these locations this way. - if (eval_ctx.loc_desc_kind == Register || - eval_ctx.loc_desc_kind == Implicit) { + LocationDescriptionKind loc_desc_kind = + eval_ctx.stack.GetLocationDescriptionKind(); + if (loc_desc_kind == Register || loc_desc_kind == Implicit) { // Reset context to default values. - eval_ctx.loc_desc_kind = Memory; + eval_ctx.stack.SetLocationDescriptionKind(Memory); eval_ctx.stack.back().ClearContext(); // Truncate the value on top of the stack to *size* bytes then @@ -1108,12 +1173,15 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx, static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx, uint64_t piece_byte_size) { - LocationDescriptionKind piece_locdesc = eval_ctx.loc_desc_kind; - // Reset for the next piece. - eval_ctx.loc_desc_kind = Memory; + LocationDescriptionKind piece_locdesc = + eval_ctx.stack.empty() ? Memory + : eval_ctx.stack.GetLocationDescriptionKind(); - if (piece_byte_size == 0) + if (piece_byte_size == 0) { + if (!eval_ctx.stack.empty()) + eval_ctx.stack.SetLocationDescriptionKind(Memory); return llvm::Error::success(); + } Value curr_piece; @@ -1455,7 +1523,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( EvalContext eval_ctx(exe_ctx, reg_ctx, std::move(module_sp), dwarf_cu, reg_kind, initial_value_ptr, object_address_ptr); - Stack &stack = eval_ctx.stack; + EvaluationStack &stack = eval_ctx.stack; if (initial_value_ptr) stack.push_back(*initial_value_ptr); @@ -1557,7 +1625,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( if (stack.empty()) { return llvm::createStringError("expression stack empty for DW_OP_dup"); } else - stack.push_back(stack.back()); + stack.PushCopy(stack.size() - 1); break; case DW_OP_drop: @@ -1568,13 +1636,13 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_over: - stack.push_back(stack[stack.size() - 2]); + stack.PushCopy(stack.size() - 2); break; case DW_OP_pick: { uint8_t pick_idx = op->getRawOperand(0); if (pick_idx < stack.size()) - stack.push_back(stack[stack.size() - 1 - pick_idx]); + stack.PushCopy(stack.size() - 1 - pick_idx); else { return llvm::createStringError( "Index %u out of range for DW_OP_pick.\n", pick_idx); @@ -1582,18 +1650,12 @@ llvm::Expected<Value> DWARFExpression::Evaluate( } break; case DW_OP_swap: - tmp = stack.back(); - stack.back() = stack[stack.size() - 2]; - stack[stack.size() - 2] = tmp; + stack.SwapTopTwo(); break; - case DW_OP_rot: { - 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; + case DW_OP_rot: + stack.RotateTopThree(); + break; case DW_OP_abs: if (!stack.back().GetScalar().AbsoluteValue()) { @@ -1948,22 +2010,20 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_reg29: case DW_OP_reg30: case DW_OP_reg31: { - eval_ctx.loc_desc_kind = Register; reg_num = opcode - DW_OP_reg0; if (llvm::Error err = ReadRegisterValueAsScalar( eval_ctx.reg_ctx, eval_ctx.reg_kind, reg_num, tmp)) return err; - stack.push_back(tmp); + stack.push_back(tmp, Register); } break; case DW_OP_regx: { - eval_ctx.loc_desc_kind = Register; reg_num = op->getRawOperand(0); Status read_err; if (llvm::Error err = ReadRegisterValueAsScalar( eval_ctx.reg_ctx, eval_ctx.reg_kind, reg_num, tmp)) return err; - stack.push_back(tmp); + stack.push_back(tmp, Register); } break; case DW_OP_breg0: @@ -2045,15 +2105,13 @@ llvm::Expected<Value> DWARFExpression::Evaluate( if (stack.size() < 1) { UpdateValueTypeFromLocationDescription(eval_ctx, LocationDescriptionKind::Empty); - // Reset for the next piece. - eval_ctx.loc_desc_kind = Memory; return llvm::createStringError( "expression stack needs at least 1 item for DW_OP_bit_piece"); } else { - UpdateValueTypeFromLocationDescription(eval_ctx, eval_ctx.loc_desc_kind, - &stack.back()); + UpdateValueTypeFromLocationDescription( + eval_ctx, stack.GetLocationDescriptionKind(), &stack.back()); // Reset for the next piece. - eval_ctx.loc_desc_kind = Memory; + stack.SetLocationDescriptionKind(Memory); const uint64_t piece_bit_size = op->getRawOperand(0); const uint64_t piece_bit_offset = op->getRawOperand(1); switch (stack.back().GetValueType()) { @@ -2083,8 +2141,6 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_implicit_value: { - eval_ctx.loc_desc_kind = Implicit; - // The second operand is a sequence of bytes of the length specified by // the first operand. LLVM represents it as an offset to that sequence. const uint64_t block_size = op->getRawOperand(0); @@ -2098,12 +2154,11 @@ llvm::Expected<Value> DWARFExpression::Evaluate( return error; Value result(block_data.data(), block_data.size()); - stack.push_back(result); + stack.push_back(result, Implicit); break; } case DW_OP_implicit_pointer: { - eval_ctx.loc_desc_kind = Implicit; return llvm::createStringError("could not evaluate %s", DW_OP_value_to_name(opcode)); } @@ -2118,7 +2173,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_stack_value: - eval_ctx.loc_desc_kind = Implicit; + stack.SetLocationDescriptionKind(Implicit); stack.back().SetValueType(Value::ValueType::Scalar); break; @@ -2213,7 +2268,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate( uint64_t offset = operands_offset; // Updated by the callee. if (eval_ctx.dwarf_cu->ParseVendorDWARFOpcode( opcode, expr_data, offset, eval_ctx.reg_ctx, eval_ctx.reg_kind, - stack)) { + stack.Values())) { + stack.SyncLocationDescriptionKinds(); // This is a little tricky. If LLVM knows about this vendor-specific // operation, `getEndOffset()` points past its last operand. If LLVM // knows nothing about this operation, `getEndOffset()` points to its @@ -2242,8 +2298,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate( return llvm::createStringError("stack empty after evaluation"); } - UpdateValueTypeFromLocationDescription(eval_ctx, eval_ctx.loc_desc_kind, - &stack.back()); + UpdateValueTypeFromLocationDescription( + eval_ctx, stack.GetLocationDescriptionKind(), &stack.back()); if (log && log->GetVerbose()) { size_t count = stack.size(); diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index aa8e17a88cc34..29c9163c1f3f8 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -2373,6 +2373,31 @@ TEST_F(DWARFExpressionMockProcessTest, deref_register) { ExpectLoadAddress(0x08070605, Value::ContextType::Invalid)); } +TEST_F(DWARFExpressionMockProcessTest, DW_OP_drop_location_description) { + TestContext test_ctx; + MockMemory::Map memory = {{{0x4, 2}, {0x1, 0x2}}}; + ASSERT_TRUE(CreateTestContext(&test_ctx, "i386-pc-linux", + RegisterValue(uint32_t{0x504}), memory)); + + MockDwarfDelegate delegate = MockDwarfDelegate::Dwarf5(); + auto Eval = [&](llvm::ArrayRef<uint8_t> expr_data) { + ExecutionContext exe_ctx(test_ctx.process_sp); + return Evaluate(expr_data, {}, &delegate, &exe_ctx, + test_ctx.reg_ctx_sp.get()); + }; + + // Dropping a register location restores the memory location underneath it. + EXPECT_THAT_EXPECTED( + Eval({DW_OP_lit4, DW_OP_reg0, DW_OP_drop, DW_OP_deref_size, 2}), + ExpectLoadAddress(0x0201)); + + // Dropping the only implicit location clears its location state before the + // following memory location is pushed. + EXPECT_THAT_EXPECTED(Eval({DW_OP_implicit_value, 1, 0, DW_OP_drop, DW_OP_lit4, + DW_OP_deref_size, 2}), + ExpectLoadAddress(0x0201)); +} + TEST_F(DWARFExpressionMockProcessTest, deref_implicit_value) { TestContext test_ctx; MockMemory::Map memory = { >From 24ed31711716ff8c2ac1e99e6520ba82d0c21a8c Mon Sep 17 00:00:00 2001 From: MrEven132 <[email protected]> Date: Tue, 1 Sep 2026 13:26:30 +0800 Subject: [PATCH 2/3] [lldb] Track location descriptions per DWARF stack entry --- .../include/lldb/Expression/DWARFExpression.h | 76 +++++++++++- lldb/source/Expression/DWARFExpression.cpp | 115 +++++------------- .../Plugins/SymbolFile/DWARF/DWARFUnit.cpp | 2 +- .../Plugins/SymbolFile/DWARF/DWARFUnit.h | 11 +- .../SymbolFile/DWARF/SymbolFileDWARF.h | 2 +- .../SymbolFile/DWARF/SymbolFileDWARFDwo.cpp | 2 +- .../SymbolFile/DWARF/SymbolFileDWARFDwo.h | 2 +- .../SymbolFile/DWARF/SymbolFileWasm.cpp | 10 +- .../Plugins/SymbolFile/DWARF/SymbolFileWasm.h | 2 +- .../Expression/DWARFExpressionTest.cpp | 95 ++++++++++++++- 10 files changed, 207 insertions(+), 110 deletions(-) diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h index 1f9994815499a..f8710d555e6a7 100644 --- a/lldb/include/lldb/Expression/DWARFExpression.h +++ b/lldb/include/lldb/Expression/DWARFExpression.h @@ -11,6 +11,7 @@ #include "lldb/Core/Address.h" #include "lldb/Core/Disassembler.h" +#include "lldb/Core/Value.h" #include "lldb/Core/dwarf.h" #include "lldb/Utility/DataExtractor.h" #include "lldb/Utility/Scalar.h" @@ -18,7 +19,10 @@ #include "lldb/lldb-private.h" #include "llvm/DebugInfo/DWARF/DWARFLocationExpression.h" #include "llvm/Support/Error.h" +#include <cstddef> #include <functional> +#include <utility> +#include <vector> namespace lldb_private { @@ -35,7 +39,77 @@ namespace lldb_private { /// location expression or a location list and interprets it. class DWARFExpression { public: - using Stack = std::vector<Value>; + /// The stack used while evaluating a DWARF expression. Each eagerly + /// materialized value retains the kind of location description that + /// produced it. + class Stack { + public: + enum class LocationDescriptionKind { Empty, Memory, Register, Implicit }; + + bool empty() const { return m_entries.empty(); } + size_t size() const { return m_entries.size(); } + + Value &back() { return m_entries.back().value; } + const Value &back() const { return m_entries.back().value; } + + Value &operator[](size_t index) { return m_entries[index].value; } + const Value &operator[](size_t index) const { + return m_entries[index].value; + } + + void push_back(Value value, LocationDescriptionKind loc_desc_kind = + LocationDescriptionKind::Memory) { + m_entries.push_back({std::move(value), loc_desc_kind}); + } + + /// Push a copy of the entry at \p index, or return false if it is invalid. + [[nodiscard]] bool PushCopy(size_t index) { + if (index >= size()) + return false; + Entry entry = m_entries[index]; + m_entries.push_back(std::move(entry)); + return true; + } + + void pop_back() { m_entries.pop_back(); } + + LocationDescriptionKind GetLocationDescriptionKind() const { + return m_entries.back().loc_desc_kind; + } + + void SetLocationDescriptionKind(LocationDescriptionKind loc_desc_kind) { + m_entries.back().loc_desc_kind = loc_desc_kind; + } + + /// Swap the top two entries, or return false if fewer than two exist. + [[nodiscard]] bool SwapTopTwo() { + if (size() < 2) + return false; + const size_t last = size() - 1; + std::swap(m_entries[last], m_entries[last - 1]); + return true; + } + + /// Rotate the top three entries, or return false if fewer than three exist. + [[nodiscard]] bool RotateTopThree() { + if (size() < 3) + return false; + const size_t last = size() - 1; + Entry old_top = m_entries[last]; + m_entries[last] = m_entries[last - 1]; + m_entries[last - 1] = m_entries[last - 2]; + m_entries[last - 2] = std::move(old_top); + return true; + } + + private: + struct Entry { + Value value; + LocationDescriptionKind loc_desc_kind; + }; + + std::vector<Entry> m_entries; + }; class Delegate { public: diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 268637c109f3b..3ef1673f641b6 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -53,81 +53,14 @@ using namespace lldb_private::plugin::dwarf; using namespace llvm::dwarf; namespace { -/// The location description kinds described by the DWARF v5 -/// specification. Composite locations are handled out-of-band and -/// thus aren't part of the enum. -enum LocationDescriptionKind { - Empty, - Memory, - Register, - Implicit - /* Composite*/ -}; - -/// Keeps the location description kind associated with each eagerly -/// materialized value on the DWARF expression stack. -class EvaluationStack { -public: - bool empty() const { return m_values.empty(); } - size_t size() const { return m_values.size(); } - - Value &back() { return m_values.back(); } - const Value &back() const { return m_values.back(); } - - Value &operator[](size_t index) { return m_values[index]; } - const Value &operator[](size_t index) const { return m_values[index]; } - - void push_back(Value value, LocationDescriptionKind loc_desc_kind = Memory) { - m_values.push_back(std::move(value)); - m_loc_desc_kinds.push_back(loc_desc_kind); - } - - void PushCopy(size_t index) { - push_back(m_values[index], m_loc_desc_kinds[index]); - } - - void pop_back() { - m_values.pop_back(); - m_loc_desc_kinds.pop_back(); - } - - LocationDescriptionKind GetLocationDescriptionKind() const { - return m_loc_desc_kinds.back(); - } - - void SetLocationDescriptionKind(LocationDescriptionKind loc_desc_kind) { - m_loc_desc_kinds.back() = loc_desc_kind; - } - - void SwapTopTwo() { - const size_t last = size() - 1; - std::swap(m_values[last], m_values[last - 1]); - std::swap(m_loc_desc_kinds[last], m_loc_desc_kinds[last - 1]); - } - - void RotateTopThree() { - const size_t last = size() - 1; - Value old_top = m_values[last]; - m_values[last] = m_values[last - 1]; - m_values[last - 1] = m_values[last - 2]; - m_values[last - 2] = std::move(old_top); - - LocationDescriptionKind old_top_kind = m_loc_desc_kinds[last]; - m_loc_desc_kinds[last] = m_loc_desc_kinds[last - 1]; - m_loc_desc_kinds[last - 1] = m_loc_desc_kinds[last - 2]; - m_loc_desc_kinds[last - 2] = old_top_kind; - } - - DWARFExpression::Stack &Values() { return m_values; } - - void SyncLocationDescriptionKinds() { - m_loc_desc_kinds.resize(m_values.size(), Memory); - } - -private: - DWARFExpression::Stack m_values; - std::vector<LocationDescriptionKind> m_loc_desc_kinds; -}; +using LocationDescriptionKind = DWARFExpression::Stack::LocationDescriptionKind; +static constexpr LocationDescriptionKind Empty = LocationDescriptionKind::Empty; +static constexpr LocationDescriptionKind Memory = + LocationDescriptionKind::Memory; +static constexpr LocationDescriptionKind Register = + LocationDescriptionKind::Register; +static constexpr LocationDescriptionKind Implicit = + LocationDescriptionKind::Implicit; /// Aggregates the inputs, derived pointers, and mutable evaluation state for /// a single DWARF expression evaluation. Passed by reference to every helper @@ -146,7 +79,7 @@ struct EvalContext { /// Mutable evaluation state. /// @{ - EvaluationStack stack; + DWARFExpression::Stack stack; Value pieces; uint64_t op_piece_offset = 0; /// @} @@ -1523,7 +1456,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( EvalContext eval_ctx(exe_ctx, reg_ctx, std::move(module_sp), dwarf_cu, reg_kind, initial_value_ptr, object_address_ptr); - EvaluationStack &stack = eval_ctx.stack; + Stack &stack = eval_ctx.stack; if (initial_value_ptr) stack.push_back(*initial_value_ptr); @@ -1624,8 +1557,10 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_dup: if (stack.empty()) { return llvm::createStringError("expression stack empty for DW_OP_dup"); - } else - stack.PushCopy(stack.size() - 1); + } else if (!stack.PushCopy(stack.size() - 1)) { + return llvm::createStringError( + "unable to copy stack entry for DW_OP_dup"); + } break; case DW_OP_drop: @@ -1636,25 +1571,32 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_over: - stack.PushCopy(stack.size() - 2); + if (!stack.PushCopy(stack.size() - 2)) + return llvm::createStringError( + "unable to copy stack entry for DW_OP_over"); break; case DW_OP_pick: { uint8_t pick_idx = op->getRawOperand(0); - if (pick_idx < stack.size()) - stack.PushCopy(stack.size() - 1 - pick_idx); - else { + if (pick_idx >= stack.size()) { return llvm::createStringError( "Index %u out of range for DW_OP_pick.\n", pick_idx); } + if (!stack.PushCopy(stack.size() - 1 - pick_idx)) + return llvm::createStringError( + "unable to copy stack entry for DW_OP_pick"); } break; case DW_OP_swap: - stack.SwapTopTwo(); + if (!stack.SwapTopTwo()) + return llvm::createStringError( + "expression stack needs at least 2 items for DW_OP_swap"); break; case DW_OP_rot: - stack.RotateTopThree(); + if (!stack.RotateTopThree()) + return llvm::createStringError( + "expression stack needs at least 3 items for DW_OP_rot"); break; case DW_OP_abs: @@ -2268,8 +2210,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( uint64_t offset = operands_offset; // Updated by the callee. if (eval_ctx.dwarf_cu->ParseVendorDWARFOpcode( opcode, expr_data, offset, eval_ctx.reg_ctx, eval_ctx.reg_kind, - stack.Values())) { - stack.SyncLocationDescriptionKinds(); + stack)) { // This is a little tricky. If LLVM knows about this vendor-specific // operation, `getEndOffset()` points past its last operand. If LLVM // knows nothing about this operation, `getEndOffset()` points to its diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp index bb89ebd52f766..a966e4883af6a 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp @@ -759,7 +759,7 @@ bool DWARFUnit::ParseVendorDWARFOpcode(uint8_t op, lldb::offset_t &offset, RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, - std::vector<Value> &stack) const { + DWARFExpression::Stack &stack) const { return GetSymbolFileDWARF().ParseVendorDWARFOpcode(op, opcodes, offset, reg_ctx, reg_kind, stack); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h index bac64ea467238..0949f69d9b886 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.h @@ -164,12 +164,11 @@ class DWARFUnit : public DWARFExpression::Delegate, public UserID { const lldb::offset_t data_offset, const uint8_t op) const override; - virtual bool ParseVendorDWARFOpcode(uint8_t op, - const llvm::DataExtractor &opcodes, - lldb::offset_t &offset, - RegisterContext *reg_ctx, - lldb::RegisterKind reg_kind, - std::vector<Value> &stack) const override; + virtual bool + ParseVendorDWARFOpcode(uint8_t op, const llvm::DataExtractor &opcodes, + lldb::offset_t &offset, RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + DWARFExpression::Stack &stack) const override; bool ParseDWARFLocationList(const DataExtractor &data, DWARFExpressionList &loc_list) const; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index 9879fc4fe922c..dd2528d4918cf 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -339,7 +339,7 @@ class SymbolFileDWARF : public SymbolFileCommon { lldb::offset_t &offset, RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, - std::vector<Value> &stack) const { + DWARFExpression::Stack &stack) const { return false; } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp index 0ac035a32a3f4..b4483a80abc31 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.cpp @@ -99,7 +99,7 @@ uint64_t SymbolFileDWARFDwo::GetDebugInfoSize(bool load_all_debug_info) { bool SymbolFileDWARFDwo::ParseVendorDWARFOpcode( uint8_t op, const llvm::DataExtractor &opcodes, lldb::offset_t &offset, RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, - std::vector<Value> &stack) const { + DWARFExpression::Stack &stack) const { return GetBaseSymbolFile().ParseVendorDWARFOpcode(op, opcodes, offset, reg_ctx, reg_kind, stack); } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h index 42fb0e8a943c7..b177187884f5d 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -54,7 +54,7 @@ class SymbolFileDWARFDwo : public SymbolFileDWARF { bool ParseVendorDWARFOpcode(uint8_t op, const llvm::DataExtractor &opcodes, lldb::offset_t &offset, RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, - std::vector<Value> &stack) const override; + DWARFExpression::Stack &stack) const override; void FindGlobalVariables(ConstString name, const CompilerDeclContext &parent_decl_ctx, diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp index de660d58682cc..8d26e944b640c 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.cpp @@ -188,12 +188,10 @@ SymbolFileWasm::GetVendorDWARFOpcodeSize(const DataExtractor &data, return offset - data_offset; } -bool SymbolFileWasm::ParseVendorDWARFOpcode(uint8_t op, - const llvm::DataExtractor &opcodes, - lldb::offset_t &offset, - RegisterContext *reg_ctx, - lldb::RegisterKind reg_kind, - std::vector<Value> &stack) const { +bool SymbolFileWasm::ParseVendorDWARFOpcode( + uint8_t op, const llvm::DataExtractor &opcodes, lldb::offset_t &offset, + RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, + DWARFExpression::Stack &stack) const { if (op != llvm::dwarf::DW_OP_WASM_location) return false; diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h index 0d7f0c3b59373..87a1e1d9961d3 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileWasm.h @@ -31,7 +31,7 @@ class SymbolFileWasm : public SymbolFileDWARF { bool ParseVendorDWARFOpcode(uint8_t op, const llvm::DataExtractor &opcodes, lldb::offset_t &offset, RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, - std::vector<Value> &stack) const override; + DWARFExpression::Stack &stack) const override; }; } // namespace dwarf } // namespace lldb_private::plugin diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 29c9163c1f3f8..cf8c21e9b89f5 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -1897,11 +1897,11 @@ class CustomSymbolFileDWARF : public SymbolFileDWARF { return offset - data_offset; } - virtual bool ParseVendorDWARFOpcode( - uint8_t op, const llvm::DataExtractor &opcodes, lldb::offset_t &offset, - - RegisterContext *reg_ctx, lldb::RegisterKind reg_kind, - std::vector<lldb_private::Value> &stack) const override { + virtual bool + ParseVendorDWARFOpcode(uint8_t op, const llvm::DataExtractor &opcodes, + lldb::offset_t &offset, RegisterContext *reg_ctx, + lldb::RegisterKind reg_kind, + DWARFExpression::Stack &stack) const override { if (op != DW_OP_WASM_location) { return false; } @@ -2441,3 +2441,88 @@ TEST_F(DWARFExpressionMockProcessTest, deref_implicit_value) { EXPECT_THAT_EXPECTED(Eval({DW_OP_lit4, DW_OP_deref_size, 1}), ExpectLoadAddress(0x01)); } + +using DWARFStack = DWARFExpression::Stack; +using LocationDescriptionKind = DWARFStack::LocationDescriptionKind; + +static Value MakeStackValue(uint64_t value) { return Value(Scalar(value)); } + +static void ExpectStackTop(const DWARFStack &stack, uint64_t value, + LocationDescriptionKind loc_desc_kind) { + EXPECT_EQ(stack.back().GetScalar().ULongLong(), value); + EXPECT_EQ(stack.GetLocationDescriptionKind(), loc_desc_kind); +} + +TEST(DWARFExpressionStackTest, PushPopAndSetLocationDescriptionKind) { + DWARFStack stack; + EXPECT_TRUE(stack.empty()); + + stack.push_back(MakeStackValue(1)); + EXPECT_EQ(stack.size(), 1u); + ExpectStackTop(stack, 1, LocationDescriptionKind::Memory); + + stack.SetLocationDescriptionKind(LocationDescriptionKind::Implicit); + ExpectStackTop(stack, 1, LocationDescriptionKind::Implicit); + + stack.push_back(MakeStackValue(2), LocationDescriptionKind::Register); + EXPECT_EQ(stack.size(), 2u); + ExpectStackTop(stack, 2, LocationDescriptionKind::Register); + EXPECT_EQ(stack[0].GetScalar().ULongLong(), 1u); + + stack.pop_back(); + EXPECT_EQ(stack.size(), 1u); + ExpectStackTop(stack, 1, LocationDescriptionKind::Implicit); +} + +TEST(DWARFExpressionStackTest, PushCopy) { + DWARFStack stack; + EXPECT_FALSE(stack.PushCopy(0)); + + stack.push_back(MakeStackValue(7), LocationDescriptionKind::Register); + EXPECT_TRUE(stack.PushCopy(0)); + EXPECT_EQ(stack.size(), 2u); + ExpectStackTop(stack, 7, LocationDescriptionKind::Register); + + stack.back().GetScalar() = Scalar(8); + stack.pop_back(); + ExpectStackTop(stack, 7, LocationDescriptionKind::Register); + + EXPECT_FALSE(stack.PushCopy(1)); + EXPECT_EQ(stack.size(), 1u); +} + +TEST(DWARFExpressionStackTest, SwapTopTwo) { + DWARFStack stack; + EXPECT_FALSE(stack.SwapTopTwo()); + + stack.push_back(MakeStackValue(1)); + EXPECT_FALSE(stack.SwapTopTwo()); + ExpectStackTop(stack, 1, LocationDescriptionKind::Memory); + + stack.push_back(MakeStackValue(2), LocationDescriptionKind::Register); + EXPECT_TRUE(stack.SwapTopTwo()); + ExpectStackTop(stack, 1, LocationDescriptionKind::Memory); + + stack.pop_back(); + ExpectStackTop(stack, 2, LocationDescriptionKind::Register); +} + +TEST(DWARFExpressionStackTest, RotateTopThree) { + DWARFStack stack; + EXPECT_FALSE(stack.RotateTopThree()); + + stack.push_back(MakeStackValue(1)); + EXPECT_FALSE(stack.RotateTopThree()); + + stack.push_back(MakeStackValue(2), LocationDescriptionKind::Register); + EXPECT_FALSE(stack.RotateTopThree()); + + stack.push_back(MakeStackValue(3), LocationDescriptionKind::Implicit); + EXPECT_TRUE(stack.RotateTopThree()); + + ExpectStackTop(stack, 2, LocationDescriptionKind::Register); + stack.pop_back(); + ExpectStackTop(stack, 1, LocationDescriptionKind::Memory); + stack.pop_back(); + ExpectStackTop(stack, 3, LocationDescriptionKind::Implicit); +} >From 5b6302b1408bcee0f9ba7ea7271190d56ab6cb22 Mon Sep 17 00:00:00 2001 From: MrEven132 <[email protected]> Date: Wed, 16 Sep 2026 16:14:35 +0800 Subject: [PATCH 3/3] [lldb] Simplify the DWARF expression stack representation Represent the evaluation stack as a vector of StackEntry objects instead of a custom stack wrapper. Access values and location-description kinds through the same entry, while keeping opcode-specific copy and reorder logic in the evaluator. Take stack entry values by const reference and remove the metadata getter, setter, and opcode-specific stack methods. Replace their direct unit tests with evaluator-level coverage. --- .../include/lldb/Expression/DWARFExpression.h | 87 +---- lldb/source/Expression/DWARFExpression.cpp | 337 +++++++++--------- .../Expression/DWARFExpressionTest.cpp | 139 +++----- 3 files changed, 240 insertions(+), 323 deletions(-) diff --git a/lldb/include/lldb/Expression/DWARFExpression.h b/lldb/include/lldb/Expression/DWARFExpression.h index f8710d555e6a7..90ea94e6582bc 100644 --- a/lldb/include/lldb/Expression/DWARFExpression.h +++ b/lldb/include/lldb/Expression/DWARFExpression.h @@ -39,78 +39,25 @@ namespace lldb_private { /// location expression or a location list and interprets it. class DWARFExpression { public: - /// The stack used while evaluating a DWARF expression. Each eagerly - /// materialized value retains the kind of location description that - /// produced it. - class Stack { - public: - enum class LocationDescriptionKind { Empty, Memory, Register, Implicit }; - - bool empty() const { return m_entries.empty(); } - size_t size() const { return m_entries.size(); } - - Value &back() { return m_entries.back().value; } - const Value &back() const { return m_entries.back().value; } - - Value &operator[](size_t index) { return m_entries[index].value; } - const Value &operator[](size_t index) const { - return m_entries[index].value; - } - - void push_back(Value value, LocationDescriptionKind loc_desc_kind = - LocationDescriptionKind::Memory) { - m_entries.push_back({std::move(value), loc_desc_kind}); - } - - /// Push a copy of the entry at \p index, or return false if it is invalid. - [[nodiscard]] bool PushCopy(size_t index) { - if (index >= size()) - return false; - Entry entry = m_entries[index]; - m_entries.push_back(std::move(entry)); - return true; - } - - void pop_back() { m_entries.pop_back(); } - - LocationDescriptionKind GetLocationDescriptionKind() const { - return m_entries.back().loc_desc_kind; - } - - void SetLocationDescriptionKind(LocationDescriptionKind loc_desc_kind) { - m_entries.back().loc_desc_kind = loc_desc_kind; - } - - /// Swap the top two entries, or return false if fewer than two exist. - [[nodiscard]] bool SwapTopTwo() { - if (size() < 2) - return false; - const size_t last = size() - 1; - std::swap(m_entries[last], m_entries[last - 1]); - return true; - } - - /// Rotate the top three entries, or return false if fewer than three exist. - [[nodiscard]] bool RotateTopThree() { - if (size() < 3) - return false; - const size_t last = size() - 1; - Entry old_top = m_entries[last]; - m_entries[last] = m_entries[last - 1]; - m_entries[last - 1] = m_entries[last - 2]; - m_entries[last - 2] = std::move(old_top); - return true; - } - - private: - struct Entry { - Value value; - LocationDescriptionKind loc_desc_kind; - }; - - std::vector<Entry> m_entries; + enum class LocationDescriptionKind { Empty, Memory, Register, Implicit }; + + /// An eagerly materialized value on the DWARF expression stack together + /// with the kind of location description that produced it. + struct StackEntry { + StackEntry(const Value &value, LocationDescriptionKind loc_desc_kind = + LocationDescriptionKind::Memory) + : value(value), loc_desc_kind(loc_desc_kind) {} + + StackEntry(const Scalar &value, LocationDescriptionKind loc_desc_kind = + LocationDescriptionKind::Memory) + : value(value), loc_desc_kind(loc_desc_kind) {} + + Value value; + LocationDescriptionKind loc_desc_kind; }; + using Stack = std::vector<StackEntry>; + class Delegate { public: Delegate() = default; diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp index 685fbc847e908..ec86b56ae81a9 100644 --- a/lldb/source/Expression/DWARFExpression.cpp +++ b/lldb/source/Expression/DWARFExpression.cpp @@ -53,7 +53,7 @@ using namespace lldb_private::plugin::dwarf; using namespace llvm::dwarf; namespace { -using LocationDescriptionKind = DWARFExpression::Stack::LocationDescriptionKind; +using LocationDescriptionKind = DWARFExpression::LocationDescriptionKind; static constexpr LocationDescriptionKind Empty = LocationDescriptionKind::Empty; static constexpr LocationDescriptionKind Memory = LocationDescriptionKind::Memory; @@ -971,27 +971,26 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx, // Deref a register or implicit location and truncate the value to `size` // bytes. See the corresponding comment in DW_OP_deref for more details on // why we deref these locations this way. - LocationDescriptionKind loc_desc_kind = - eval_ctx.stack.GetLocationDescriptionKind(); + LocationDescriptionKind loc_desc_kind = eval_ctx.stack.back().loc_desc_kind; if (loc_desc_kind == Register || loc_desc_kind == Implicit) { // Reset context to default values. - eval_ctx.stack.SetLocationDescriptionKind(Memory); - eval_ctx.stack.back().ClearContext(); + eval_ctx.stack.back().loc_desc_kind = Memory; + eval_ctx.stack.back().value.ClearContext(); // Truncate the value on top of the stack to *size* bytes then // extend to the size of an address (e.g. generic type). - Scalar scalar = eval_ctx.stack.back().GetScalar(); + Scalar scalar = eval_ctx.stack.back().value.GetScalar(); scalar.TruncOrExtendTo(size * 8, /*sign=*/false); scalar.TruncOrExtendTo(size_addr_bytes * 8, /*sign=*/false); - eval_ctx.stack.back().GetScalar() = scalar; + eval_ctx.stack.back().value.GetScalar() = scalar; return llvm::Error::success(); } - Value::ValueType value_type = eval_ctx.stack.back().GetValueType(); + Value::ValueType value_type = eval_ctx.stack.back().value.GetValueType(); switch (value_type) { case Value::ValueType::HostAddress: { - void *src = (void *)eval_ctx.stack.back().GetScalar().ULongLong(); + void *src = (void *)eval_ctx.stack.back().value.GetScalar().ULongLong(); intptr_t ptr; ::memcpy(&ptr, src, sizeof(void *)); // I can't decide whether the size operand should apply to the bytes in @@ -1025,12 +1024,12 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx, default: break; } - eval_ctx.stack.back().GetScalar() = ptr; - eval_ctx.stack.back().ClearContext(); + eval_ctx.stack.back().value.GetScalar() = ptr; + eval_ctx.stack.back().value.ClearContext(); } break; case Value::ValueType::FileAddress: { auto file_addr = - eval_ctx.stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + eval_ctx.stack.back().value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); Address so_addr; auto maybe_load_addr = ResolveLoadAddress(eval_ctx, op_name, file_addr, so_addr, @@ -1054,19 +1053,19 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx, ObjectFile *objfile = eval_ctx.module_sp->GetObjectFile(); - eval_ctx.stack.back().GetScalar() = DerefSizeExtractDataHelper( + eval_ctx.stack.back().value.GetScalar() = DerefSizeExtractDataHelper( addr_bytes, size, objfile->GetByteOrder(), size); - eval_ctx.stack.back().ClearContext(); + eval_ctx.stack.back().value.ClearContext(); break; } - eval_ctx.stack.back().GetScalar() = load_addr; + eval_ctx.stack.back().value.GetScalar() = load_addr; // Fall through to load address promotion code below. } [[fallthrough]]; case Value::ValueType::Scalar: // Promote Scalar to LoadAddress and fall through. - eval_ctx.stack.back().SetValueType(Value::ValueType::LoadAddress); + eval_ctx.stack.back().value.SetValueType(Value::ValueType::LoadAddress); [[fallthrough]]; case Value::ValueType::LoadAddress: { if (!eval_ctx.exe_ctx) @@ -1075,7 +1074,7 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx, return llvm::createStringError("no process for %s", op_name); lldb::addr_t pointer_addr = - eval_ctx.stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + eval_ctx.stack.back().value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); uint8_t addr_bytes[sizeof(lldb::addr_t)]; Status error; @@ -1085,9 +1084,9 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx, "failed to dereference pointer from 0x%" PRIx64 " for %s: %s\n", pointer_addr, op_name, error.AsCString()); - eval_ctx.stack.back().GetScalar() = DerefSizeExtractDataHelper( + eval_ctx.stack.back().value.GetScalar() = DerefSizeExtractDataHelper( addr_bytes, sizeof(addr_bytes), eval_ctx.process->GetByteOrder(), size); - eval_ctx.stack.back().ClearContext(); + eval_ctx.stack.back().value.ClearContext(); } break; case Value::ValueType::Invalid: @@ -1098,21 +1097,21 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext &eval_ctx, // `size` bytes is unnecessary here because the branches above already limit // the value to `size` bytes; it is only done for consistency with the // Register/Implicit path above. - eval_ctx.stack.back().GetScalar().TruncOrExtendTo(size * 8, /*sign=*/false); - eval_ctx.stack.back().GetScalar().TruncOrExtendTo(size_addr_bytes * 8, - /*sign=*/false); + eval_ctx.stack.back().value.GetScalar().TruncOrExtendTo(size * 8, + /*sign=*/false); + eval_ctx.stack.back().value.GetScalar().TruncOrExtendTo(size_addr_bytes * 8, + /*sign=*/false); return llvm::Error::success(); } static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx, uint64_t piece_byte_size) { LocationDescriptionKind piece_locdesc = - eval_ctx.stack.empty() ? Memory - : eval_ctx.stack.GetLocationDescriptionKind(); + eval_ctx.stack.empty() ? Memory : eval_ctx.stack.back().loc_desc_kind; if (piece_byte_size == 0) { if (!eval_ctx.stack.empty()) - eval_ctx.stack.SetLocationDescriptionKind(Memory); + eval_ctx.stack.back().loc_desc_kind = Memory; return llvm::Error::success(); } @@ -1134,7 +1133,7 @@ static llvm::Error Evaluate_DW_OP_piece(EvalContext &eval_ctx, } else { Status error; // Extract the current piece into "curr_piece" - Value curr_piece_source_value(eval_ctx.stack.back()); + Value curr_piece_source_value(eval_ctx.stack.back().value); eval_ctx.stack.pop_back(); UpdateValueTypeFromLocationDescription(eval_ctx, piece_locdesc, &curr_piece_source_value); @@ -1273,7 +1272,7 @@ static llvm::Error Evaluate_DW_OP_convert(EvalContext &eval_ctx, encoding = bit_size_encoding_or_err->second; } - Scalar &scalar = eval_ctx.stack.back().GetScalar(); + Scalar &scalar = eval_ctx.stack.back().value.GetScalar(); if (encoding == llvm::dwarf::DW_ATE_float) { const llvm::fltSemantics *semantics; switch (bit_size) { @@ -1341,7 +1340,7 @@ static llvm::Error Evaluate_DW_OP_form_tls_address(EvalContext &eval_ctx, // Lookup the TLS block address for this thread and module. const addr_t tls_file_addr = - eval_ctx.stack.back().GetScalar().ULongLong(LLDB_INVALID_ADDRESS); + eval_ctx.stack.back().value.GetScalar().ULongLong(LLDB_INVALID_ADDRESS); const addr_t tls_load_addr = thread->GetThreadLocalData(eval_ctx.module_sp, tls_file_addr); @@ -1349,8 +1348,8 @@ static llvm::Error Evaluate_DW_OP_form_tls_address(EvalContext &eval_ctx, return llvm::createStringError( "no TLS data currently exists for this thread"); - eval_ctx.stack.back().GetScalar() = tls_load_addr; - eval_ctx.stack.back().SetValueType(Value::ValueType::LoadAddress); + eval_ctx.stack.back().value.GetScalar() = tls_load_addr; + eval_ctx.stack.back().value.SetValueType(Value::ValueType::LoadAddress); return llvm::Error::success(); } @@ -1367,7 +1366,7 @@ static llvm::Error Evaluate_DW_OP_fbreg(EvalContext &eval_ctx, return err; value += fbreg_offset; eval_ctx.stack.push_back(value); - eval_ctx.stack.back().SetValueType(Value::ValueType::LoadAddress); + eval_ctx.stack.back().value.SetValueType(Value::ValueType::LoadAddress); return llvm::Error::success(); } @@ -1386,7 +1385,7 @@ static llvm::Error Evaluate_DW_OP_call_frame_cfa(EvalContext &eval_ctx) { "opcode"); eval_ctx.stack.push_back(Scalar(cfa)); - eval_ctx.stack.back().SetValueType(Value::ValueType::LoadAddress); + eval_ctx.stack.back().value.SetValueType(Value::ValueType::LoadAddress); return llvm::Error::success(); } @@ -1499,7 +1498,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( for (size_t i = 0; i < count; ++i) { StreamString new_value; new_value.Printf("[%" PRIu64 "]", static_cast<uint64_t>(i)); - stack[i].Dump(&new_value); + stack[i].value.Dump(&new_value); LLDB_LOGF(log, " %s", new_value.GetData()); } LLDB_LOGF(log, "0x%8.8" PRIx64 ": %s", op_offset, @@ -1516,7 +1515,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( switch (opcode) { case DW_OP_addr: stack.push_back(to_generic(op->getRawOperand(0))); - stack.back().SetValueType(Value::ValueType::FileAddress); + stack.back().value.SetValueType(Value::ValueType::FileAddress); break; case DW_OP_deref: { @@ -1566,10 +1565,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_dup: if (stack.empty()) { return llvm::createStringError("expression stack empty for DW_OP_dup"); - } else if (!stack.PushCopy(stack.size() - 1)) { - return llvm::createStringError( - "unable to copy stack entry for DW_OP_dup"); - } + } else + stack.push_back(stack.back()); break; case DW_OP_drop: @@ -1580,36 +1577,33 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_over: - if (!stack.PushCopy(stack.size() - 2)) - return llvm::createStringError( - "unable to copy stack entry for DW_OP_over"); + stack.push_back(stack[stack.size() - 2]); break; case DW_OP_pick: { uint8_t pick_idx = op->getRawOperand(0); - if (pick_idx >= stack.size()) { + if (pick_idx < stack.size()) + stack.push_back(stack[stack.size() - 1 - pick_idx]); + else { return llvm::createStringError( "Index %u out of range for DW_OP_pick.\n", pick_idx); } - if (!stack.PushCopy(stack.size() - 1 - pick_idx)) - return llvm::createStringError( - "unable to copy stack entry for DW_OP_pick"); } break; case DW_OP_swap: - if (!stack.SwapTopTwo()) - return llvm::createStringError( - "expression stack needs at least 2 items for DW_OP_swap"); + std::swap(stack[stack.size() - 1], stack[stack.size() - 2]); break; - case DW_OP_rot: - if (!stack.RotateTopThree()) - return llvm::createStringError( - "expression stack needs at least 3 items for DW_OP_rot"); - break; + case DW_OP_rot: { + size_t last_idx = stack.size() - 1; + StackEntry 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; case DW_OP_abs: - if (!stack.back().GetScalar().AbsoluteValue()) { + if (!stack.back().value.GetScalar().AbsoluteValue()) { return llvm::createStringError( "failed to take the absolute value of the first stack item"); } @@ -1617,104 +1611,109 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_and: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() = stack.back().GetScalar() & tmp.GetScalar(); + stack.back().value.GetScalar() = + stack.back().value.GetScalar() & tmp.GetScalar(); break; case DW_OP_div: { if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; if (tmp.GetScalar().IsZero()) return llvm::createStringError("divide by zero"); stack.pop_back(); Scalar divisor, dividend; divisor = tmp.GetScalar(); - dividend = stack.back().GetScalar(); + dividend = stack.back().value.GetScalar(); divisor.MakeSigned(); dividend.MakeSigned(); - stack.back() = dividend / divisor; + stack.back().value = dividend / divisor; - if (!stack.back().GetScalar().IsValid()) + if (!stack.back().value.GetScalar().IsValid()) return llvm::createStringError("divide failed"); } break; case DW_OP_minus: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() = stack.back().GetScalar() - tmp.GetScalar(); + stack.back().value.GetScalar() = + stack.back().value.GetScalar() - tmp.GetScalar(); break; case DW_OP_mod: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); if (IsPotentiallyGenericIntegerOperand(tmp.GetScalar(), address_size) && - IsPotentiallyGenericIntegerOperand(stack.back().GetScalar(), + IsPotentiallyGenericIntegerOperand(stack.back().value.GetScalar(), address_size)) { tmp.GetScalar().MakeUnsigned(); - stack.back().GetScalar().MakeUnsigned(); + stack.back().value.GetScalar().MakeUnsigned(); } - stack.back().GetScalar() = stack.back().GetScalar() % tmp.GetScalar(); + stack.back().value.GetScalar() = + stack.back().value.GetScalar() % tmp.GetScalar(); break; case DW_OP_mul: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() = stack.back().GetScalar() * tmp.GetScalar(); + stack.back().value.GetScalar() = + stack.back().value.GetScalar() * tmp.GetScalar(); break; case DW_OP_neg: - if (!stack.back().GetScalar().UnaryNegate()) + if (!stack.back().value.GetScalar().UnaryNegate()) return llvm::createStringError("unary negate failed"); break; case DW_OP_not: - if (!stack.back().GetScalar().OnesComplement()) + if (!stack.back().value.GetScalar().OnesComplement()) return llvm::createStringError("logical NOT failed"); break; case DW_OP_or: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() = stack.back().GetScalar() | tmp.GetScalar(); + stack.back().value.GetScalar() = + stack.back().value.GetScalar() | tmp.GetScalar(); break; case DW_OP_plus: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() += tmp.GetScalar(); + stack.back().value.GetScalar() += tmp.GetScalar(); break; case DW_OP_plus_uconst: { const uint64_t uconst_value = op->getRawOperand(0); - Scalar &operand = stack.back().GetScalar(); + Scalar &operand = stack.back().value.GetScalar(); Scalar addend(uconst_value); // The addend is interpreted as the same type as the popped operand // (DWARF v5, 2.5.1.4). Give it the operand's exact integer type so @@ -1730,43 +1729,44 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_shl: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() <<= tmp.GetScalar(); + stack.back().value.GetScalar() <<= tmp.GetScalar(); break; case DW_OP_shr: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - if (!stack.back().GetScalar().ShiftRightLogical(tmp.GetScalar())) + if (!stack.back().value.GetScalar().ShiftRightLogical(tmp.GetScalar())) return llvm::createStringError("DW_OP_shr failed"); break; case DW_OP_shra: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() >>= tmp.GetScalar(); + stack.back().value.GetScalar() >>= tmp.GetScalar(); break; case DW_OP_xor: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() = stack.back().GetScalar() ^ tmp.GetScalar(); + stack.back().value.GetScalar() = + stack.back().value.GetScalar() ^ tmp.GetScalar(); break; case DW_OP_skip: { @@ -1785,7 +1785,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( } case DW_OP_bra: { - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); int16_t bra_offset = static_cast<int16_t>(op->getRawOperand(0)); Scalar zero(0); @@ -1806,92 +1806,92 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_eq: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() = - to_generic(stack.back().GetScalar() == tmp.GetScalar()); + stack.back().value.GetScalar() = + to_generic(stack.back().value.GetScalar() == tmp.GetScalar()); break; case DW_OP_ge: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); if (IsPotentiallyGenericIntegerOperand(tmp.GetScalar(), address_size) && - IsPotentiallyGenericIntegerOperand(stack.back().GetScalar(), + IsPotentiallyGenericIntegerOperand(stack.back().value.GetScalar(), address_size)) { tmp.GetScalar().MakeSigned(); - stack.back().GetScalar().MakeSigned(); + stack.back().value.GetScalar().MakeSigned(); } - stack.back().GetScalar() = - to_generic(stack.back().GetScalar() >= tmp.GetScalar()); + stack.back().value.GetScalar() = + to_generic(stack.back().value.GetScalar() >= tmp.GetScalar()); break; case DW_OP_gt: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); if (IsPotentiallyGenericIntegerOperand(tmp.GetScalar(), address_size) && - IsPotentiallyGenericIntegerOperand(stack.back().GetScalar(), + IsPotentiallyGenericIntegerOperand(stack.back().value.GetScalar(), address_size)) { tmp.GetScalar().MakeSigned(); - stack.back().GetScalar().MakeSigned(); + stack.back().value.GetScalar().MakeSigned(); } - stack.back().GetScalar() = - to_generic(stack.back().GetScalar() > tmp.GetScalar()); + stack.back().value.GetScalar() = + to_generic(stack.back().value.GetScalar() > tmp.GetScalar()); break; case DW_OP_le: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); if (IsPotentiallyGenericIntegerOperand(tmp.GetScalar(), address_size) && - IsPotentiallyGenericIntegerOperand(stack.back().GetScalar(), + IsPotentiallyGenericIntegerOperand(stack.back().value.GetScalar(), address_size)) { tmp.GetScalar().MakeSigned(); - stack.back().GetScalar().MakeSigned(); + stack.back().value.GetScalar().MakeSigned(); } - stack.back().GetScalar() = - to_generic(stack.back().GetScalar() <= tmp.GetScalar()); + stack.back().value.GetScalar() = + to_generic(stack.back().value.GetScalar() <= tmp.GetScalar()); break; case DW_OP_lt: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); if (IsPotentiallyGenericIntegerOperand(tmp.GetScalar(), address_size) && - IsPotentiallyGenericIntegerOperand(stack.back().GetScalar(), + IsPotentiallyGenericIntegerOperand(stack.back().value.GetScalar(), address_size)) { tmp.GetScalar().MakeSigned(); - stack.back().GetScalar().MakeSigned(); + stack.back().value.GetScalar().MakeSigned(); } - stack.back().GetScalar() = - to_generic(stack.back().GetScalar() < tmp.GetScalar()); + stack.back().value.GetScalar() = + to_generic(stack.back().value.GetScalar() < tmp.GetScalar()); break; case DW_OP_ne: if (llvm::Error err = CheckScalarOperandsHaveSameType( - stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(), - opcode, address_size)) + stack[stack.size() - 2].value.GetScalar(), + stack.back().value.GetScalar(), opcode, address_size)) return err; - tmp = stack.back(); + tmp = stack.back().value; stack.pop_back(); - stack.back().GetScalar() = - to_generic(stack.back().GetScalar() != tmp.GetScalar()); + stack.back().value.GetScalar() = + to_generic(stack.back().value.GetScalar() != tmp.GetScalar()); break; case DW_OP_lit0: @@ -1966,7 +1966,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( if (llvm::Error err = ReadRegisterValueAsScalar( eval_ctx.reg_ctx, eval_ctx.reg_kind, reg_num, tmp)) return err; - stack.push_back(tmp, Register); + stack.emplace_back(tmp, Register); } break; case DW_OP_regx: { reg_num = op->getRawOperand(0); @@ -1974,7 +1974,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( if (llvm::Error err = ReadRegisterValueAsScalar( eval_ctx.reg_ctx, eval_ctx.reg_kind, reg_num, tmp)) return err; - stack.push_back(tmp, Register); + stack.emplace_back(tmp, Register); } break; case DW_OP_breg0: @@ -2019,7 +2019,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( tmp.GetScalar() += to_generic(breg_offset); tmp.ClearContext(); stack.push_back(tmp); - stack.back().SetValueType(Value::ValueType::LoadAddress); + stack.back().value.SetValueType(Value::ValueType::LoadAddress); } break; case DW_OP_bregx: { reg_num = op->getRawOperand(0); @@ -2032,15 +2032,15 @@ llvm::Expected<Value> DWARFExpression::Evaluate( tmp.GetScalar() += to_generic(breg_offset); tmp.ClearContext(); stack.push_back(tmp); - stack.back().SetValueType(Value::ValueType::LoadAddress); + stack.back().value.SetValueType(Value::ValueType::LoadAddress); } break; case DW_OP_fbreg: if (llvm::Error err = Evaluate_DW_OP_fbreg(eval_ctx, op->getRawOperand(0))) return err; - stack.back().GetScalar() = - to_generic(stack.back().GetScalar().ULongLong()); + stack.back().value.GetScalar() = + to_generic(stack.back().value.GetScalar().ULongLong()); break; case DW_OP_nop: @@ -2060,25 +2060,25 @@ llvm::Expected<Value> DWARFExpression::Evaluate( "expression stack needs at least 1 item for DW_OP_bit_piece"); } else { const LocationDescriptionKind piece_locdesc = - stack.GetLocationDescriptionKind(); + stack.back().loc_desc_kind; UpdateValueTypeFromLocationDescription(eval_ctx, piece_locdesc, - &stack.back()); + &stack.back().value); // Reset for the next piece. - stack.SetLocationDescriptionKind(Memory); + stack.back().loc_desc_kind = Memory; const uint64_t piece_bit_size = op->getRawOperand(0); const uint64_t piece_bit_offset = op->getRawOperand(1); - switch (stack.back().GetValueType()) { + switch (stack.back().value.GetValueType()) { case Value::ValueType::Invalid: return llvm::createStringError( "unable to extract bit value from invalid value"); case Value::ValueType::Scalar: { - if (!stack.back().GetScalar().ExtractBitfield(piece_bit_size, - piece_bit_offset)) { + if (!stack.back().value.GetScalar().ExtractBitfield( + piece_bit_size, piece_bit_offset)) { return llvm::createStringError( "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)); + (uint64_t)(stack.back().value.GetScalar().GetByteSize() * 8)); } } break; @@ -2094,7 +2094,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate( // backing bytes, not the address of that backing storage. if (piece_locdesc == Implicit && piece_bit_offset == 0 && piece_bit_size % 8 == 0 && - stack.back().GetBuffer().GetByteSize() == piece_bit_size / 8) + stack.back().value.GetBuffer().GetByteSize() == + piece_bit_size / 8) break; return llvm::createStringError( "unable to extract DW_OP_bit_piece(bit_size = %" PRIu64 @@ -2118,7 +2119,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( return error; Value result(block_data.data(), block_data.size()); - stack.push_back(result, Implicit); + stack.emplace_back(result, Implicit); break; } @@ -2137,8 +2138,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate( break; case DW_OP_stack_value: - stack.SetLocationDescriptionKind(Implicit); - stack.back().SetValueType(Value::ValueType::Scalar); + stack.back().loc_desc_kind = Implicit; + stack.back().value.SetValueType(Value::ValueType::Scalar); break; case DW_OP_convert: @@ -2150,8 +2151,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate( case DW_OP_call_frame_cfa: if (llvm::Error err = Evaluate_DW_OP_call_frame_cfa(eval_ctx)) return err; - stack.back().GetScalar() = - to_generic(stack.back().GetScalar().ULongLong()); + stack.back().value.GetScalar() = + to_generic(stack.back().value.GetScalar().ULongLong()); break; case DW_OP_form_tls_address: @@ -2169,7 +2170,7 @@ llvm::Expected<Value> DWARFExpression::Evaluate( lldb::addr_t value = eval_ctx.dwarf_cu->ReadAddressFromDebugAddrSection(index); stack.push_back(to_generic(value)); - stack.back().SetValueType(Value::ValueType::FileAddress); + stack.back().value.SetValueType(Value::ValueType::FileAddress); } break; case DW_OP_GNU_const_index: { @@ -2261,8 +2262,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate( return llvm::createStringError("stack empty after evaluation"); } - UpdateValueTypeFromLocationDescription( - eval_ctx, stack.GetLocationDescriptionKind(), &stack.back()); + UpdateValueTypeFromLocationDescription(eval_ctx, stack.back().loc_desc_kind, + &stack.back().value); if (log && log->GetVerbose()) { size_t count = stack.size(); @@ -2271,11 +2272,11 @@ llvm::Expected<Value> DWARFExpression::Evaluate( for (size_t i = 0; i < count; ++i) { StreamString new_value; new_value.Printf("[%" PRIu64 "]", static_cast<uint64_t>(i)); - stack[i].Dump(&new_value); + stack[i].value.Dump(&new_value); LLDB_LOGF(log, " %s", new_value.GetData()); } } - return stack.back(); + return stack.back().value; } bool DWARFExpression::MatchesOperand( diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp index 7270a0f3c3811..1dfb8d8a41377 100644 --- a/lldb/unittests/Expression/DWARFExpressionTest.cpp +++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -2409,6 +2409,60 @@ TEST_F(DWARFExpressionMockProcessTest, DW_OP_drop_location_description) { ExpectLoadAddress(0x0201)); } +TEST_F(DWARFExpressionMockProcessTest, DW_OP_swap_rot_location_description) { + TestContext test_ctx; + MockMemory::Map memory = {{{0x4, 2}, {0x1, 0x2}}}; + ASSERT_TRUE(CreateTestContext(&test_ctx, "i386-pc-linux", + RegisterValue(uint32_t{0x504}), memory)); + + MockDwarfDelegate delegate = MockDwarfDelegate::Dwarf5(); + auto Eval = [&](llvm::ArrayRef<uint8_t> expr_data) { + ExecutionContext exe_ctx(test_ctx.process_sp); + return Evaluate(expr_data, {}, &delegate, &exe_ctx, + test_ctx.reg_ctx_sp.get()); + }; + + // Swapping a register location with the memory location underneath keeps + // each entry's location kind with its value: the new top is a memory + // location and is dereferenced as an address. + EXPECT_THAT_EXPECTED( + Eval({DW_OP_lit4, DW_OP_reg0, DW_OP_swap, DW_OP_deref_size, 2}), + ExpectLoadAddress(0x0201)); + + // Rotating the top three entries keeps each entry's location kind with its + // value: the new top (lit4) is a memory location. + EXPECT_THAT_EXPECTED(Eval({DW_OP_lit5, DW_OP_lit4, DW_OP_reg0, DW_OP_rot, + DW_OP_deref_size, 2}), + ExpectLoadAddress(0x0201)); +} + +TEST_F(DWARFExpressionMockProcessTest, DW_OP_copy_location_description) { + TestContext test_ctx; + MockMemory::Map memory = {{{0x4, 2}, {0x1, 0x2}}}; + ASSERT_TRUE(CreateTestContext(&test_ctx, "i386-pc-linux", + RegisterValue(uint32_t{0x504}), memory)); + + MockDwarfDelegate delegate = MockDwarfDelegate::Dwarf5(); + auto Eval = [&](llvm::ArrayRef<uint8_t> expr_data) { + ExecutionContext exe_ctx(test_ctx.process_sp); + return Evaluate(expr_data, {}, &delegate, &exe_ctx, + test_ctx.reg_ctx_sp.get()); + }; + + // Copying a register location keeps the copied entry's kind: dereferencing + // the new top truncates the register value instead of reading memory. + EXPECT_THAT_EXPECTED(Eval({DW_OP_reg0, DW_OP_dup, DW_OP_deref_size, 2}), + ExpectLoadAddress(0x0504)); + + EXPECT_THAT_EXPECTED( + Eval({DW_OP_reg0, DW_OP_lit4, DW_OP_over, DW_OP_deref_size, 2}), + ExpectLoadAddress(0x0504)); + + EXPECT_THAT_EXPECTED( + Eval({DW_OP_reg0, DW_OP_lit4, DW_OP_pick, 1, DW_OP_deref_size, 2}), + ExpectLoadAddress(0x0504)); +} + TEST_F(DWARFExpressionMockProcessTest, deref_implicit_value) { TestContext test_ctx; MockMemory::Map memory = { @@ -2452,88 +2506,3 @@ TEST_F(DWARFExpressionMockProcessTest, deref_implicit_value) { EXPECT_THAT_EXPECTED(Eval({DW_OP_lit4, DW_OP_deref_size, 1}), ExpectLoadAddress(0x01)); } - -using DWARFStack = DWARFExpression::Stack; -using LocationDescriptionKind = DWARFStack::LocationDescriptionKind; - -static Value MakeStackValue(uint64_t value) { return Value(Scalar(value)); } - -static void ExpectStackTop(const DWARFStack &stack, uint64_t value, - LocationDescriptionKind loc_desc_kind) { - EXPECT_EQ(stack.back().GetScalar().ULongLong(), value); - EXPECT_EQ(stack.GetLocationDescriptionKind(), loc_desc_kind); -} - -TEST(DWARFExpressionStackTest, PushPopAndSetLocationDescriptionKind) { - DWARFStack stack; - EXPECT_TRUE(stack.empty()); - - stack.push_back(MakeStackValue(1)); - EXPECT_EQ(stack.size(), 1u); - ExpectStackTop(stack, 1, LocationDescriptionKind::Memory); - - stack.SetLocationDescriptionKind(LocationDescriptionKind::Implicit); - ExpectStackTop(stack, 1, LocationDescriptionKind::Implicit); - - stack.push_back(MakeStackValue(2), LocationDescriptionKind::Register); - EXPECT_EQ(stack.size(), 2u); - ExpectStackTop(stack, 2, LocationDescriptionKind::Register); - EXPECT_EQ(stack[0].GetScalar().ULongLong(), 1u); - - stack.pop_back(); - EXPECT_EQ(stack.size(), 1u); - ExpectStackTop(stack, 1, LocationDescriptionKind::Implicit); -} - -TEST(DWARFExpressionStackTest, PushCopy) { - DWARFStack stack; - EXPECT_FALSE(stack.PushCopy(0)); - - stack.push_back(MakeStackValue(7), LocationDescriptionKind::Register); - EXPECT_TRUE(stack.PushCopy(0)); - EXPECT_EQ(stack.size(), 2u); - ExpectStackTop(stack, 7, LocationDescriptionKind::Register); - - stack.back().GetScalar() = Scalar(8); - stack.pop_back(); - ExpectStackTop(stack, 7, LocationDescriptionKind::Register); - - EXPECT_FALSE(stack.PushCopy(1)); - EXPECT_EQ(stack.size(), 1u); -} - -TEST(DWARFExpressionStackTest, SwapTopTwo) { - DWARFStack stack; - EXPECT_FALSE(stack.SwapTopTwo()); - - stack.push_back(MakeStackValue(1)); - EXPECT_FALSE(stack.SwapTopTwo()); - ExpectStackTop(stack, 1, LocationDescriptionKind::Memory); - - stack.push_back(MakeStackValue(2), LocationDescriptionKind::Register); - EXPECT_TRUE(stack.SwapTopTwo()); - ExpectStackTop(stack, 1, LocationDescriptionKind::Memory); - - stack.pop_back(); - ExpectStackTop(stack, 2, LocationDescriptionKind::Register); -} - -TEST(DWARFExpressionStackTest, RotateTopThree) { - DWARFStack stack; - EXPECT_FALSE(stack.RotateTopThree()); - - stack.push_back(MakeStackValue(1)); - EXPECT_FALSE(stack.RotateTopThree()); - - stack.push_back(MakeStackValue(2), LocationDescriptionKind::Register); - EXPECT_FALSE(stack.RotateTopThree()); - - stack.push_back(MakeStackValue(3), LocationDescriptionKind::Implicit); - EXPECT_TRUE(stack.RotateTopThree()); - - ExpectStackTop(stack, 2, LocationDescriptionKind::Register); - stack.pop_back(); - ExpectStackTop(stack, 1, LocationDescriptionKind::Memory); - stack.pop_back(); - ExpectStackTop(stack, 3, LocationDescriptionKind::Implicit); -} _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
