Skip to content

[lldb] Produce generic results for DWARF relational operations#210122

Merged
augusto2112 merged 1 commit into
llvm:mainfrom
firmiana402:fix-lldb-dwarf-relational-result-type
Jul 16, 2026
Merged

[lldb] Produce generic results for DWARF relational operations#210122
augusto2112 merged 1 commit into
llvm:mainfrom
firmiana402:fix-lldb-dwarf-relational-result-type

Conversation

@firmiana402

@firmiana402 firmiana402 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

DWARF relational operations produce a generic result, whose width is the target address size. LLDB currently assigns the C++ bool comparison result directly to Scalar; because Scalar has no bool constructor, this creates a 32-bit integer even on 64-bit targets.

The stricter binary operand checks added in #201288 exposed this in x86-64 _sigtramp CFI. A later DW_OP_plus combines a 64-bit generic address with the 32-bit relational result, so evaluation fails and signal-frame unwinding stops. The generic-operand relaxation in #209641 does not cover this case because the relational result is narrower than the address size.

Convert the results of DW_OP_eq, DW_OP_ge, DW_OP_gt, DW_OP_le, DW_OP_lt, and DW_OP_ne through the existing to_generic helper.

Testing

Add a unit test that evaluates each relational opcode with an 8-byte address size and then consumes its result with DW_OP_plus.

@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-lldb

Author: firmiana (firmiana402)

Changes

DWARF relational operations produce a generic result, whose width is the target address size. LLDB currently assigns the C++ bool comparison result directly to Scalar; because Scalar has no bool constructor, this creates a 32-bit integer even on 64-bit targets.

The stricter binary operand checks added in #201288 exposed this in Apple's x86-64 _sigtramp CFI. A later DW_OP_plus combines a 64-bit generic address with the 32-bit relational result, so evaluation fails and signal-frame unwinding stops. The generic-operand relaxation in #209641 does not cover this case because the relational result is narrower than the address size.

Convert the results of DW_OP_eq, DW_OP_ge, DW_OP_gt, DW_OP_le, DW_OP_lt, and DW_OP_ne through the existing to_generic helper. This fixes the incorrect result producer without further relaxing binary type checking.

Testing

Add a unit test that evaluates each relational opcode with an 8-byte address size and then consumes its result with DW_OP_plus.


Full diff: https://github.com/llvm/llvm-project/pull/210122.diff

2 Files Affected:

  • (modified) lldb/source/Expression/DWARFExpression.cpp (+12-6)
  • (modified) lldb/unittests/Expression/DWARFExpressionTest.cpp (+33)
diff --git a/lldb/source/Expression/DWARFExpression.cpp b/lldb/source/Expression/DWARFExpression.cpp
index 5d5c03d81ef1f..299dbe97d6176 100644
--- a/lldb/source/Expression/DWARFExpression.cpp
+++ b/lldb/source/Expression/DWARFExpression.cpp
@@ -1724,7 +1724,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() = stack.back().GetScalar() == tmp.GetScalar();
+      stack.back().GetScalar() =
+          to_generic(stack.back().GetScalar() == tmp.GetScalar());
       break;
 
     case DW_OP_ge:
@@ -1734,7 +1735,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() = stack.back().GetScalar() >= tmp.GetScalar();
+      stack.back().GetScalar() =
+          to_generic(stack.back().GetScalar() >= tmp.GetScalar());
       break;
 
     case DW_OP_gt:
@@ -1744,7 +1746,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() = stack.back().GetScalar() > tmp.GetScalar();
+      stack.back().GetScalar() =
+          to_generic(stack.back().GetScalar() > tmp.GetScalar());
       break;
 
     case DW_OP_le:
@@ -1754,7 +1757,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() = stack.back().GetScalar() <= tmp.GetScalar();
+      stack.back().GetScalar() =
+          to_generic(stack.back().GetScalar() <= tmp.GetScalar());
       break;
 
     case DW_OP_lt:
@@ -1764,7 +1768,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() = stack.back().GetScalar() < tmp.GetScalar();
+      stack.back().GetScalar() =
+          to_generic(stack.back().GetScalar() < tmp.GetScalar());
       break;
 
     case DW_OP_ne:
@@ -1774,7 +1779,8 @@ llvm::Expected<Value> DWARFExpression::Evaluate(
         return err;
       tmp = stack.back();
       stack.pop_back();
-      stack.back().GetScalar() = stack.back().GetScalar() != tmp.GetScalar();
+      stack.back().GetScalar() =
+          to_generic(stack.back().GetScalar() != tmp.GetScalar());
       break;
 
     case DW_OP_lit0:
diff --git a/lldb/unittests/Expression/DWARFExpressionTest.cpp b/lldb/unittests/Expression/DWARFExpressionTest.cpp
index 7dc707ac29a70..6df4553757de4 100644
--- a/lldb/unittests/Expression/DWARFExpressionTest.cpp
+++ b/lldb/unittests/Expression/DWARFExpressionTest.cpp
@@ -708,6 +708,39 @@ TEST(DWARFExpression, GenericBinaryOpsAllowDifferentSignedness) {
       ExpectScalar(4));
 }
 
+TEST(DWARFExpression, RelationalOpsProduceGenericResult) {
+  struct TestCase {
+    uint8_t opcode;
+    uint8_t lhs;
+    uint8_t rhs;
+  };
+  constexpr TestCase test_cases[] = {
+      {DW_OP_eq, 3, 3}, {DW_OP_ge, 4, 3}, {DW_OP_gt, 4, 3},
+      {DW_OP_le, 3, 4}, {DW_OP_lt, 3, 4}, {DW_OP_ne, 3, 4},
+  };
+
+  for (const TestCase &test : test_cases) {
+    const std::vector<uint8_t> expr = {
+        DW_OP_lit8,
+        static_cast<uint8_t>(DW_OP_lit0 + test.lhs),
+        static_cast<uint8_t>(DW_OP_lit0 + test.rhs),
+        test.opcode,
+        DW_OP_plus,
+        DW_OP_stack_value,
+    };
+    DataExtractor extractor(expr.data(), expr.size(), lldb::eByteOrderLittle,
+                            /*addr_size=*/8);
+
+    EXPECT_THAT_EXPECTED(
+        DWARFExpression::Evaluate(
+            /*exe_ctx=*/nullptr, /*reg_ctx=*/nullptr, /*module_sp=*/{},
+            extractor, /*unit=*/nullptr, lldb::eRegisterKindLLDB,
+            /*initial_value_ptr=*/nullptr, /*object_address_ptr=*/nullptr),
+        ExpectScalar(64, 9, false))
+        << "opcode 0x" << llvm::utohexstr(test.opcode);
+  }
+}
+
 TEST(DWARFExpression, DW_OP_stack_value) {
   EXPECT_THAT_EXPECTED(Evaluate({DW_OP_stack_value}), llvm::Failed());
 }

@JDevlieghere JDevlieghere left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, this should unblock the x86 bots.

@augusto2112

Copy link
Copy Markdown
Contributor

The failing test is flaky and unrelated right?

2026-07-16T18:35:20.2830092Z Failed Tests (1):
2026-07-16T18:35:20.2830430Z   lldb-api :: functionalities/gdb_remote_client/TestGdbClientModuleLoad.py

Can we merge this?

@firmiana402

Copy link
Copy Markdown
Contributor Author

The failing test is flaky and unrelated right?

2026-07-16T18:35:20.2830092Z Failed Tests (1):
2026-07-16T18:35:20.2830430Z   lldb-api :: functionalities/gdb_remote_client/TestGdbClientModuleLoad.py

Can we merge this?

It looks like the Linux failure is in functionalities/gdb_remote_client/TestGdbClientModuleLoad.py. I reran this test locally, and it passed.

This test does not exercise the DWARF expression evaluator, so the failure appears unrelated to this patch.

Could you please rerun the Linux check?

DWARF relational operations produce a generic, address-sized result. Assigning their C++ bool results directly to Scalar instead created a 32-bit integer, causing later typed arithmetic to reject valid expressions on 64-bit targets, including Apple's x86-64 sigtramp CFI.

Convert all relational results through the existing to_generic helper and add coverage that consumes each result in address-sized arithmetic.
@firmiana402
firmiana402 force-pushed the fix-lldb-dwarf-relational-result-type branch from 7a1f18a to 211aea8 Compare July 16, 2026 19:06
@firmiana402

Copy link
Copy Markdown
Contributor Author

The failing test is flaky and unrelated right?

2026-07-16T18:35:20.2830092Z Failed Tests (1):
2026-07-16T18:35:20.2830430Z   lldb-api :: functionalities/gdb_remote_client/TestGdbClientModuleLoad.py

Can we merge this?

The tests have passed, and this is ready to merge. I don’t have write access yet, so could you please merge it for me?

@augusto2112
augusto2112 merged commit b74a97c into llvm:main Jul 16, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants