[Lldb-commits] [lldb] [lldb] Track location descriptions per DWARF stack entry (PR #219372)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 16 01:15:57 PDT 2026
https://github.com/MrEven132 updated https://github.com/llvm/llvm-project/pull/219372
>From a160b8f8bfc144f35c12616c77513714eda24c26 Mon Sep 17 00:00:00 2001
From: MrEven132 <13554966229 at 163.com>
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 <13554966229 at 163.com>
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 <13554966229 at 163.com>
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);
-}
More information about the lldb-commits
mailing list