[Lldb-commits] [lldb] [lldb] Evaluate DW_OP_abs and DW_OP_shra with signed operand semantics (PR #225772)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Sep 23 18:55:39 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: firmiana (firmiana402)
<details>
<summary>Changes</summary>
`DW_OP_const*u` produces a generic value, but LLDB retains the constant's unsigned encoding in its internal `Scalar`. `DW_OP_abs` and `DW_OP_shra` then accidentally use that unsignedness, although both operations require signed interpretation ([DWARF v5](https://dwarfstd.org/doc/DWARF5.pdf), section 2.5.1.4). For example, on a 64-bit target, `DW_OP_abs` applied to `DW_OP_const8u 0xffffffffffffffff` yields all ones instead of 1, while `DW_OP_shra` by 63 yields 1 instead of all ones.
Interpret integer bits as signed for these two operations, then restore the original `Scalar` signedness so the result keeps the operand's type. Add 32- and 64-bit expression tests covering both cases.
Fixes #<!-- -->207497.
---
Full diff: https://github.com/llvm/llvm-project/pull/225772.diff
2 Files Affected:
- (modified) lldb/source/Expression/DWARFExpression.cpp (+21-6)
- (modified) lldb/unittests/Expression/DWARFExpressionTest.cpp (+27-2)
``````````diff
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index f884724766714..a04c498f22a9b 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -1604,12 +1604,20 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
stack[last_idx - 2] = old_top;
} break;
- case DW_OP_abs:
- if (!stack.back().GetScalar().AbsoluteValue()) {
+ case DW_OP_abs: {
+ Scalar &operand = stack.back().GetScalar();
+ const bool was_unsigned =
+ operand.GetType() == Scalar::e_int && !operand.IsSigned();
+ // DW_OP_abs interprets the bits as signed without changing the result
+ // type.
+ operand.MakeSigned();
+ if (!operand.AbsoluteValue()) {
return llvm::createStringError(
"failed to take the absolute value of the first stack item");
}
- break;
+ if (was_unsigned)
+ operand.MakeUnsigned();
+ } break;
case DW_OP_and:
if (llvm::Error err = CheckScalarOperandsHaveSameType(
@@ -1745,15 +1753,22 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
return llvm::createStringError("DW_OP_shr failed");
break;
- case DW_OP_shra:
+ case DW_OP_shra: {
if (llvm::Error err = CheckScalarOperandsHaveSameType(
stack[stack.size() - 2].GetScalar(), stack.back().GetScalar(),
opcode, address_size))
return err;
tmp = stack.back();
stack.pop_back();
- stack.back().GetScalar() >>= tmp.GetScalar();
- break;
+ Scalar &operand = stack.back().GetScalar();
+ const bool was_unsigned =
+ operand.GetType() == Scalar::e_int && !operand.IsSigned();
+ // DW_OP_shra shifts signed bits without changing the result type.
+ operand.MakeSigned();
+ operand >>= tmp.GetScalar();
+ if (was_unsigned)
+ operand.MakeUnsigned();
+ } break;
case DW_OP_xor:
if (llvm::Error err = CheckScalarOperandsHaveSameType(
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 31e629967c6a2..f5a0e89ebbbd0 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -261,10 +261,11 @@ static llvm::Expected<Value> Evaluate(llvm::ArrayRef<uint8_t> expr,
lldb::ModuleSP module_sp = {},
DWARFExpression::Delegate *unit = nullptr,
ExecutionContext *exe_ctx = nullptr,
- RegisterContext *reg_ctx = nullptr) {
+ RegisterContext *reg_ctx = nullptr,
+ uint8_t address_size = 4) {
DataExtractor extractor(
expr.data(), expr.size(), lldb::eByteOrderLittle,
- /*addr_size*/ exe_ctx ? exe_ctx->GetAddressByteSize() : 4);
+ /*addr_size*/ exe_ctx ? exe_ctx->GetAddressByteSize() : address_size);
return DWARFExpression::Evaluate(exe_ctx, reg_ctx, module_sp, extractor, unit,
lldb::eRegisterKindLLDB,
@@ -1089,6 +1090,18 @@ TEST(DWARFExpression, DW_OP_abs) {
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));
+
+ // Generic values have unspecified signedness, but DW_OP_abs interprets its
+ // operand as signed.
+ EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const4u, 0xff, 0xff, 0xff, 0xff,
+ DW_OP_abs, DW_OP_stack_value}),
+ ExpectScalar(32, 1, false));
+ EXPECT_THAT_EXPECTED(
+ Evaluate({DW_OP_const8u, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ DW_OP_abs, DW_OP_stack_value},
+ {}, nullptr, nullptr, nullptr,
+ /*address_size=*/8),
+ ExpectScalar(64, 1, false));
}
TEST(DWARFExpression, DW_OP_div_int_min_by_neg_one) {
@@ -1376,6 +1389,18 @@ TEST(DWARFExpression, DW_OP_shra) {
EXPECT_THAT_EXPECTED(Evaluate({DW_OP_const1s, static_cast<uint8_t>(-8),
DW_OP_lit1, DW_OP_shra}),
ExpectScalar(static_cast<int32_t>(-4)));
+
+ // Generic values have unspecified signedness, but DW_OP_shra performs a
+ // signed arithmetic right shift.
+ EXPECT_THAT_EXPECTED(
+ Evaluate({DW_OP_const4u, 0xff, 0xff, 0xff, 0xff, DW_OP_const1u, 31,
+ DW_OP_shra, DW_OP_stack_value}),
+ ExpectScalar(32, 0xffffffff, false));
+ EXPECT_THAT_EXPECTED(
+ Evaluate({DW_OP_const8u, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ DW_OP_const1u, 63, DW_OP_shra, DW_OP_stack_value},
+ {}, nullptr, nullptr, nullptr, /*address_size=*/8),
+ ExpectScalar(64, 0xffffffffffffffffULL, false));
}
TEST(DWARFExpression, DW_OP_shl_overflow_count) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/225772
More information about the lldb-commits
mailing list