https://github.com/JDevlieghere created 
https://github.com/llvm/llvm-project/pull/196218

Add a dedicated unit test for every standard DWARF 5 expression operator (plus 
the GNU extensions in use), so each opcode in the evaluator's switch has 
explicit coverage. Tests for opcodes that require execution context not 
available in a standalone evaluation (process, frame, compile unit, object 
address) assert that evaluation fails cleanly rather than crashing.

This PR fixes one bug surfaced by the audit: DW_OP_deref_size only rejected 
sizes greater than 8, not sizes greater than the target's address size. The 
DWARF 5 spec requires the operand to be no larger than the generic type. The 
new check returns a clean diagnostic instead of silently dereferencing beyond 
the address-sized window on 32-bit targets.

Assisted-by: Claude

>From af6bbd5f9edf3aa14681372138811ceda3443113 Mon Sep 17 00:00:00 2001
From: Jonas Devlieghere <[email protected]>
Date: Wed, 6 May 2026 19:12:35 -0700
Subject: [PATCH] [lldb] Audit DWARF 5 expression evaluator and add per-opcode
 tests

Add a dedicated unit test for every standard DWARF 5 expression operator
(plus the GNU extensions in use), so each opcode in the evaluator's switch
has explicit coverage. Tests for opcodes that require execution context
not available in a standalone evaluation (process, frame, compile unit,
object address) assert that evaluation fails cleanly rather than crashing.

This PR fixes one bug surfaced by the audit: DW_OP_deref_size only
rejected sizes greater than 8, not sizes greater than the target's
address size. The DWARF 5 spec requires the operand to be no larger than
the generic type. The new check returns a clean diagnostic instead of
silently dereferencing beyond the address-sized window on 32-bit
targets.

Assisted-by: Claude
---
 lldb/source/Expression/DWARFExpression.cpp    |   5 +
 .../Expression/DWARFExpressionTest.cpp        | 455 ++++++++++++++++++
 2 files changed, 460 insertions(+)

diff --git a/lldb/source/Expression/DWARFExpression.cpp 
b/lldb/source/Expression/DWARFExpression.cpp
index 038e13f8e8c6a..d14b2c610a8b9 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -935,6 +935,11 @@ static llvm::Error Evaluate_DW_OP_deref(EvalContext 
&eval_ctx,
     return llvm::createStringError("Invalid address size for %s: %d\n", 
op_name,
                                    size);
 
+  if (opcode == DW_OP_deref_size && size > size_addr_bytes)
+    return llvm::createStringError(
+        "DW_OP_deref_size size (%u) exceeds address size (%zu)", size,
+        size_addr_bytes);
+
   // 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.
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp 
b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 77d6ddd21dc44..7be3203a21ce5 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -632,6 +632,461 @@ TEST(DWARFExpression, DW_OP_unknown) {
           "unhandled opcode DW_OP_unknown_ff in DWARFExpression"));
 }
 
+TEST(DWARFExpression, DW_OP_addr) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_addr, 0x10, 0x20, 0x30, 0x40, DW_OP_stack_value}),
+      ExpectScalar(uint32_t{0x40302010}));
+}
+
+TEST(DWARFExpression, DW_OP_nop) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_nop}), ExpectScalar(5));
+}
+
+TEST(DWARFExpression, DW_OP_neg) {
+  // neg interprets the operand as signed.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_neg}),
+                       ExpectScalar(static_cast<int32_t>(-5)));
+}
+
+TEST(DWARFExpression, DW_OP_abs) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_const1s, static_cast<uint8_t>(-5), DW_OP_abs}),
+      ExpectScalar(5));
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_abs}), ExpectScalar(5));
+}
+
+TEST(DWARFExpression, DW_OP_div_int_min_by_neg_one) {
+  // INT32_MIN / -1 is C++ UB; the evaluator must not crash.
+  auto result = Evaluate({DW_OP_const4s, 0x00, 0x00, 0x00, 0x80, DW_OP_const1s,
+                          static_cast<uint8_t>(-1), DW_OP_div});
+  if (!result)
+    llvm::consumeError(result.takeError());
+  SUCCEED();
+}
+
+TEST(DWARFExpression, DW_OP_div) {
+  // Signed division: -10 / 3 = -3 (truncation toward zero).
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, static_cast<uint8_t>(-10),
+                                 DW_OP_const1s, 3, DW_OP_div}),
+                       ExpectScalar(static_cast<int32_t>(-3)));
+}
+
+TEST(DWARFExpression, DW_OP_mod) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, static_cast<uint8_t>(-7),
+                                 DW_OP_const1s, 3, DW_OP_mod}),
+                       ExpectScalar(static_cast<int32_t>(-1)));
+}
+
+TEST(DWARFExpression, DW_OP_minus) {
+  // Generic arithmetic wraps modulo address-size: 0 - 1 = 0xFFFFFFFF.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_lit1, DW_OP_minus}),
+                       ExpectScalar(uint32_t{0xFFFFFFFF}));
+}
+
+TEST(DWARFExpression, DW_OP_plus) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_lit3, DW_OP_plus}),
+                       ExpectScalar(8));
+}
+
+TEST(DWARFExpression, DW_OP_mul) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_lit3, DW_OP_mul}),
+                       ExpectScalar(15));
+}
+
+TEST(DWARFExpression, DW_OP_plus_uconst) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, static_cast<uint8_t>(-10),
+                                 DW_OP_plus_uconst, 5}),
+                       ExpectScalar(static_cast<int32_t>(-5)));
+}
+
+TEST(DWARFExpression, DW_OP_and) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_const1u, 0x0F, DW_OP_const1u, 0x33, DW_OP_and}),
+      ExpectScalar(0x03));
+}
+
+TEST(DWARFExpression, DW_OP_or) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_const1u, 0x0F, DW_OP_const1u, 0x30, DW_OP_or}),
+      ExpectScalar(0x3F));
+}
+
+TEST(DWARFExpression, DW_OP_xor) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_const1u, 0x0F, DW_OP_const1u, 0x33, DW_OP_xor}),
+      ExpectScalar(0x3C));
+}
+
+TEST(DWARFExpression, DW_OP_not) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_not}),
+                       ExpectScalar(uint32_t{0xFFFFFFFF}));
+}
+
+TEST(DWARFExpression, DW_OP_lt) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_const1s, static_cast<uint8_t>(-1), DW_OP_lit0, 
DW_OP_lt}),
+      ExpectScalar(1));
+}
+
+TEST(DWARFExpression, DW_OP_gt) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_const1s, static_cast<uint8_t>(-1), 
DW_OP_gt}),
+      ExpectScalar(1));
+}
+
+TEST(DWARFExpression, DW_OP_le) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_const1s, static_cast<uint8_t>(-1), DW_OP_lit0, 
DW_OP_le}),
+      ExpectScalar(1));
+}
+
+TEST(DWARFExpression, DW_OP_ge) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_const1s, static_cast<uint8_t>(-1), 
DW_OP_ge}),
+      ExpectScalar(1));
+}
+
+TEST(DWARFExpression, DW_OP_eq) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_lit5, DW_OP_eq}),
+                       ExpectScalar(1));
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_lit3, DW_OP_eq}),
+                       ExpectScalar(0));
+}
+
+TEST(DWARFExpression, DW_OP_ne) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_lit3, DW_OP_ne}),
+                       ExpectScalar(1));
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_lit5, DW_OP_ne}),
+                       ExpectScalar(0));
+}
+
+TEST(DWARFExpression, DW_OP_swap) {
+  // After swap, top is the value pushed first (lit1).
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit2, DW_OP_swap}),
+                       ExpectScalar(1));
+}
+
+TEST(DWARFExpression, DW_OP_rot) {
+  // Stack pre-rot (top last): [1, 2, 3]. Post-rot: [2, 3, 1]. Top = 2.
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit1, DW_OP_lit2, DW_OP_lit3, DW_OP_rot}),
+      ExpectScalar(2));
+}
+
+TEST(DWARFExpression, DW_OP_over) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit1, DW_OP_lit2, DW_OP_over}),
+                       ExpectScalar(1));
+}
+
+TEST(DWARFExpression, DW_OP_dup) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_dup}), ExpectScalar(5));
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_dup}), llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_drop) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit3, DW_OP_lit5, DW_OP_drop}),
+                       ExpectScalar(3));
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_drop}), llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_skip_backward) {
+  // Layout (offsets):
+  //   0: skip +5  → end_offset=3, target=8
+  //   3: const1u 0x42  ← target of backward branch
+  //   5: skip +3  → end_offset=8, target=11 (== expr.size, exits)
+  //   8: skip -8  → end_offset=11, target=3
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_skip, 0x05, 0x00, DW_OP_const1u, 0x42, DW_OP_skip, 0x03,
+                0x00, DW_OP_skip, 0xF8, 0xFF}),
+      ExpectScalar(0x42));
+}
+
+TEST(DWARFExpression, DW_OP_skip_to_end) {
+  // skip 0 from end-of-skip lands at end-of-expression and terminates cleanly.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_skip, 0x00, 0x00}),
+                       ExpectScalar(5));
+}
+
+TEST(DWARFExpression, DW_OP_bra_false) {
+  // Top is 0 → no branch, fall through to next opcode.
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit5, DW_OP_lit0, DW_OP_bra, 0x63, 0x00}),
+      ExpectScalar(5));
+}
+
+TEST(DWARFExpression, DW_OP_lit_all) {
+  for (uint8_t n = 0; n <= 31; ++n) {
+    uint8_t opcode = DW_OP_lit0 + n;
+    EXPECT_THAT_EXPECTED(Evaluate({opcode}), ExpectScalar(n))
+        << "DW_OP_lit" << static_cast<int>(n) << " failed";
+  }
+}
+
+TEST(DWARFExpression, DW_OP_shl) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit5, DW_OP_lit1, DW_OP_shl}),
+                       ExpectScalar(10));
+}
+
+TEST(DWARFExpression, DW_OP_shr) {
+  // Logical right shift: -1 >> 1 = 0x7FFFFFFF on 32-bit.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, static_cast<uint8_t>(-1),
+                                 DW_OP_lit1, DW_OP_shr}),
+                       ExpectScalar(0x7FFFFFFF));
+}
+
+TEST(DWARFExpression, DW_OP_shra) {
+  // Arithmetic right shift sign-fills: -8 >> 1 = -4.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, static_cast<uint8_t>(-8),
+                                 DW_OP_lit1, DW_OP_shra}),
+                       ExpectScalar(static_cast<int32_t>(-4)));
+}
+
+TEST(DWARFExpression, DW_OP_shl_overflow_count) {
+  // Shift count exceeding scalar bit width must not crash.
+  auto result = Evaluate({DW_OP_lit1, DW_OP_const1u, 99, DW_OP_shl});
+  if (!result)
+    llvm::consumeError(result.takeError());
+  SUCCEED();
+}
+
+TEST(DWARFExpression, DW_OP_push_object_address_no_object) {
+  // Without an object_address_ptr, must fail cleanly.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_push_object_address}), llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_fbreg_no_frame) {
+  // Without a stack frame, fbreg fails cleanly.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_fbreg, 0x00}), llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_call_frame_cfa_no_frame) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_call_frame_cfa}), llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_form_tls_address_no_process) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_form_tls_address}),
+                       llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_GNU_push_tls_address_no_process) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_GNU_push_tls_address}),
+                       llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_entry_value_no_context) {
+  // entry_value with empty sub-expression and no execution context.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_entry_value, 0x00}), llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_GNU_entry_value_no_context) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_GNU_entry_value, 0x00}), 
llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_addrx_no_unit) {
+  // addrx requires a compile unit delegate.
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_addrx, 0x00}), llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_GNU_addr_index_no_unit) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_GNU_addr_index, 0x00}), llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_GNU_const_index_no_unit) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_GNU_const_index, 0x00}), 
llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_bit_piece_overflow) {
+  // bit_piece extracting more bits than the underlying scalar holds: the
+  // implementation silently zero-extends-then-truncates back to the scalar's
+  // original width. This locks in the current behavior.
+  // ULEB128(99) = 0x63 (single byte; 99 < 128).
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit5, DW_OP_stack_value, DW_OP_bit_piece, 0x63, 0x00}),
+      ExpectScalar(5));
+}
+
+TEST(DWARFExpression, DW_OP_bit_piece_empty_stack) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_bit_piece, 0x08, 0x00}), 
llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_deref_size_exceeds_address_size) {
+  // DWARF 5: deref_size operand may not be larger than the address size.
+  // address_size = 4 (default Evaluate). size operand = 8 (> addr_size).
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_deref_size, 0x08}),
+      llvm::FailedWithMessage(
+          "DW_OP_deref_size size (8) exceeds address size (4)"));
+}
+
+TEST(DWARFExpression, DW_OP_deref_size_too_large) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref_size, 0x09}),
+                       llvm::Failed());
+}
+
+// Status-locking tests for opcodes that today return a clean error. These
+// catch any change in implemented/unimplemented status.
+
+TEST(DWARFExpression, DW_OP_xderef_unimplemented) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_lit0, DW_OP_xderef}),
+      llvm::FailedWithMessage("unimplemented opcode: DW_OP_xderef"));
+}
+
+TEST(DWARFExpression, DW_OP_xderef_size_unimplemented) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_lit0, DW_OP_xderef_size, 4}),
+      llvm::FailedWithMessage("unimplemented opcode: DW_OP_xderef_size"));
+}
+
+TEST(DWARFExpression, DW_OP_call2_unimplemented) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_call2, 0x00, 0x00}),
+      llvm::FailedWithMessage("unimplemented opcode DW_OP_call2"));
+}
+
+TEST(DWARFExpression, DW_OP_call4_unimplemented) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_call4, 0x00, 0x00, 0x00, 0x00}),
+      llvm::FailedWithMessage("unimplemented opcode DW_OP_call4"));
+}
+
+TEST(DWARFExpression, DW_OP_call_ref_unhandled) {
+  // call_ref has stack arity 1 in LLVM's table, so push a value first.
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_call_ref, 0x00, 0x00, 0x00, 0x00}),
+      llvm::FailedWithMessage(
+          "unhandled opcode DW_OP_call_ref in DWARFExpression"));
+}
+
+TEST(DWARFExpression, DW_OP_implicit_pointer_unimplemented) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_implicit_pointer, 0x00, 0x00, 0x00, 0x00, 0x00}),
+      llvm::Failed());
+}
+
+TEST(DWARFExpression, DW_OP_GNU_implicit_pointer_unhandled) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_GNU_implicit_pointer, 0x00, 0x00, 0x00, 0x00, 0x00}),
+      llvm::FailedWithMessage(
+          "unhandled opcode DW_OP_GNU_implicit_pointer in DWARFExpression"));
+}
+
+TEST(DWARFExpression, DW_OP_const_type_unhandled) {
+  // const_type: ULEB128 type DIE offset, 1-byte size, N-byte value block.
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_const_type, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00}),
+      llvm::FailedWithMessage(
+          "unhandled opcode DW_OP_const_type in DWARFExpression"));
+}
+
+TEST(DWARFExpression, DW_OP_regval_type_unhandled) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_regval_type, 0x00, 0x00}),
+      llvm::FailedWithMessage(
+          "unhandled opcode DW_OP_regval_type in DWARFExpression"));
+}
+
+TEST(DWARFExpression, DW_OP_deref_type_unhandled) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_deref_type, 0x04, 0x00}),
+      llvm::FailedWithMessage(
+          "unhandled opcode DW_OP_deref_type in DWARFExpression"));
+}
+
+TEST(DWARFExpression, DW_OP_xderef_type_unhandled) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_lit0, DW_OP_xderef_type, 0x04, 0x00}),
+      llvm::FailedWithMessage(
+          "unhandled opcode DW_OP_xderef_type in DWARFExpression"));
+}
+
+TEST(DWARFExpression, DW_OP_constx_unhandled) {
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_constx, 0x00}),
+                       llvm::FailedWithMessage(
+                           "unhandled opcode DW_OP_constx in 
DWARFExpression"));
+}
+
+TEST(DWARFExpression, DW_OP_reinterpret_unhandled) {
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_lit0, DW_OP_reinterpret, 0x00}),
+      llvm::FailedWithMessage(
+          "unhandled opcode DW_OP_reinterpret in DWARFExpression"));
+}
+
+// Register-based tests need a register context. MockRegisterContext returns 
the
+// same value for every register query.
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_reg0) {
+  TestContext ctx;
+  ASSERT_TRUE(CreateTestContext(&ctx, "i386-pc-linux",
+                                RegisterValue(uint32_t{0xCAFE})));
+  ExecutionContext exe_ctx(ctx.process_sp);
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_reg0}, {}, {}, &exe_ctx, ctx.reg_ctx_sp.get()),
+      ExpectScalar(0xCAFE, Value::ContextType::RegisterInfo));
+}
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_reg_all) {
+  TestContext ctx;
+  ASSERT_TRUE(CreateTestContext(&ctx, "i386-pc-linux",
+                                RegisterValue(uint32_t{0xABCD})));
+  ExecutionContext exe_ctx(ctx.process_sp);
+  for (uint8_t n = 0; n <= 31; ++n) {
+    uint8_t opcode = DW_OP_reg0 + n;
+    EXPECT_THAT_EXPECTED(
+        Evaluate({opcode}, {}, {}, &exe_ctx, ctx.reg_ctx_sp.get()),
+        ExpectScalar(0xABCD, Value::ContextType::RegisterInfo))
+        << "DW_OP_reg" << static_cast<int>(n) << " failed";
+  }
+}
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_regx) {
+  TestContext ctx;
+  ASSERT_TRUE(CreateTestContext(&ctx, "i386-pc-linux",
+                                RegisterValue(uint32_t{0xBEEF})));
+  ExecutionContext exe_ctx(ctx.process_sp);
+  // ULEB128(64) for register 64.
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_regx, 0x40}, {}, {}, &exe_ctx, ctx.reg_ctx_sp.get()),
+      ExpectScalar(0xBEEF, Value::ContextType::RegisterInfo));
+}
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_breg0) {
+  TestContext ctx;
+  ASSERT_TRUE(CreateTestContext(&ctx, "i386-pc-linux",
+                                RegisterValue(uint32_t{0x1000})));
+  ExecutionContext exe_ctx(ctx.process_sp);
+  // breg0 + 0x10 = 0x1010 (load address).
+  EXPECT_THAT_EXPECTED(
+      Evaluate({DW_OP_breg0, 0x10}, {}, {}, &exe_ctx, ctx.reg_ctx_sp.get()),
+      ExpectLoadAddress(0x1010));
+}
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_breg_all) {
+  TestContext ctx;
+  ASSERT_TRUE(
+      CreateTestContext(&ctx, "i386-pc-linux", 
RegisterValue(uint32_t{0x100})));
+  ExecutionContext exe_ctx(ctx.process_sp);
+  for (uint8_t n = 0; n <= 31; ++n) {
+    uint8_t opcode = DW_OP_breg0 + n;
+    EXPECT_THAT_EXPECTED(
+        Evaluate({opcode, 0x05}, {}, {}, &exe_ctx, ctx.reg_ctx_sp.get()),
+        ExpectLoadAddress(0x105))
+        << "DW_OP_breg" << static_cast<int>(n) << " failed";
+  }
+}
+
+TEST_F(DWARFExpressionMockProcessTest, DW_OP_bregx) {
+  TestContext ctx;
+  ASSERT_TRUE(CreateTestContext(&ctx, "i386-pc-linux",
+                                RegisterValue(uint32_t{0x2000})));
+  ExecutionContext exe_ctx(ctx.process_sp);
+  // bregx reg=64 (ULEB128 0x40), offset=+16 (SLEB128 0x10).
+  EXPECT_THAT_EXPECTED(Evaluate({DW_OP_bregx, 0x40, 0x10}, {}, {}, &exe_ctx,
+                                ctx.reg_ctx_sp.get()),
+                       ExpectLoadAddress(0x2010));
+}
+
 TEST_F(DWARFExpressionMockProcessTest, DW_OP_deref) {
   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_lit0, DW_OP_deref}), llvm::Failed());
 

_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to