[llvm] Reapply "[Dexter] Add rewriting for aggregate variables (#202800)" (PR #206535)
Stephen Tozer via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 30 08:38:27 PDT 2026
https://github.com/SLTozer updated https://github.com/llvm/llvm-project/pull/206535
>From a02f4e94a720f48309b8df0677706e762914f516 Mon Sep 17 00:00:00 2001
From: Stephen Tozer <stephen.tozer at sony.com>
Date: Mon, 29 Jun 2026 15:01:59 +0100
Subject: [PATCH] Reapply "[Dexter] Add rewriting for aggregate variables
(#202800)"
This reverts commit 5bf495456b9898c45c437b8dadae21417d04a9a5.
---
.../dexter/dex/debugger/lldb/LLDB.py | 1 +
.../dexter/dex/evaluation/ExpectRewriter.py | 26 ++++++-
.../Inputs/rewrite_aggregates_expected.cpp | 70 +++++++++++++++++++
.../rewrite_list_aggregates_expected.cpp | 58 +++++++++++++++
.../scripts/rewriting/rewrite_aggregates.cpp | 53 ++++++++++++++
.../rewriting/rewrite_list_aggregates.cpp | 48 +++++++++++++
6 files changed, 253 insertions(+), 3 deletions(-)
create mode 100644 cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/Inputs/rewrite_aggregates_expected.cpp
create mode 100644 cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/Inputs/rewrite_list_aggregates_expected.cpp
create mode 100644 cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/rewrite_aggregates.cpp
create mode 100644 cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/rewrite_list_aggregates.cpp
diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py b/cross-project-tests/debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py
index 8f90981f67e4c..4b92da9e0f38c 100644
--- a/cross-project-tests/debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py
+++ b/cross-project-tests/debuginfo-tests/dexter/dex/debugger/lldb/LLDB.py
@@ -510,6 +510,7 @@ def _evaluate_result_value(
"couldn't read from memory",
"Cannot access memory at address",
"invalid address (fault address:",
+ "error: parent is NULL",
]
)
diff --git a/cross-project-tests/debuginfo-tests/dexter/dex/evaluation/ExpectRewriter.py b/cross-project-tests/debuginfo-tests/dexter/dex/evaluation/ExpectRewriter.py
index 7519d96a02a6d..5f8829287efe4 100644
--- a/cross-project-tests/debuginfo-tests/dexter/dex/evaluation/ExpectRewriter.py
+++ b/cross-project-tests/debuginfo-tests/dexter/dex/evaluation/ExpectRewriter.py
@@ -25,7 +25,20 @@ class ExpectedValueRewriter:
def __init__(self, expect: Expect, value: ValueIR):
self.expect = expect
self.root_value = value
- self.expected_value = expect.get_variable_result(value)
+ self.expected_value: Union[Dict, str, None] = None
+ if sub_values := self.root_value.sub_values:
+ self.expected_value = {
+ sub_value.expression: expected_value
+ for sub_value in sub_values
+ if (
+ expected_value := ExpectedValueRewriter(
+ expect, sub_value
+ ).expected_value
+ )
+ is not None
+ }
+ if not self.expected_value:
+ self.expected_value = expect.get_variable_result(value)
def unique_expected_values(elements: List[ExpectedValueRewriter]):
@@ -33,14 +46,21 @@ def unique_expected_values(elements: List[ExpectedValueRewriter]):
values, or a single item if there is only one non-duplicated expected value in the list, or None if there are no
valid expected values."""
+ def freeze(input):
+ assert input is not None, "Unexpected 'None' in an expected_value"
+ if isinstance(input, dict):
+ return tuple(sorted((str(k), freeze(v)) for k, v in input.items()))
+ return input
+
unique_set = set()
result = []
for element in elements:
expected_value = element.expected_value
if expected_value is None:
continue
- if expected_value not in unique_set:
- unique_set.add(expected_value)
+ frozen_value = freeze(expected_value)
+ if frozen_value not in unique_set:
+ unique_set.add(frozen_value)
result.append(expected_value)
if not result:
return None
diff --git a/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/Inputs/rewrite_aggregates_expected.cpp b/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/Inputs/rewrite_aggregates_expected.cpp
new file mode 100644
index 0000000000000..8f9c5206e6480
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/Inputs/rewrite_aggregates_expected.cpp
@@ -0,0 +1,70 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %dexter_regression_test_cxx_build %s -o %t/test
+// RUN: %dexter_regression_test_run --use-script --binary %t/test \
+// RUN: --results-directory %t/results -- %s 2>&1 | FileCheck %s
+// RUN: diff %t/results/%{s:basename} %S/Inputs/rewrite_aggregates_expected.cpp
+
+/// Test that Dexter can write disaggregated expected values for aggregates,
+/// including falling back to the parent value if sub_values contain errors,
+/// e.g. for pointers that are not dereferencable.
+
+/// NB: The exact contents of this file are compared against the expect file in
+/// the Inputs/ directory; any changes to this file, including comments,
+/// will require updating the corresponding expected file.
+
+// CHECK: Rewrote script to add 5 expected values.
+
+// CHECK: total_watched_steps: 5
+// CHECK: correct_steps: 5
+// CHECK: incorrect_steps: 0
+// CHECK: seen_values: 16
+// CHECK: missing_values: 0
+
+struct Point {
+ int X;
+ int Y;
+ int Z;
+};
+
+struct Rect {
+ Point TopLeft;
+ Point BottomRight;
+};
+
+int main() {
+ Point P{1, 2, 3};
+ int *I = &P.X;
+ Rect R{{1, 1, 1}, {2, 2, 2}};
+ int L[] = {0, 1, 2, 3, 4};
+ int *InvalidPtr = nullptr;
+ return 0; // !dex_label ret
+}
+
+/*
+---
+? !where {lines: !label 'ret'}
+: !value 'P':
+ X: '1'
+ Y: '2'
+ Z: '3'
+ !value 'I':
+ '*I': '1'
+ !value 'R':
+ BottomRight:
+ X: '2'
+ Y: '2'
+ Z: '2'
+ TopLeft:
+ X: '1'
+ Y: '1'
+ Z: '1'
+ !value 'L':
+ '[0]': '0'
+ '[1]': '1'
+ '[2]': '2'
+ '[3]': '3'
+ '[4]': '4'
+ !value 'InvalidPtr': '0x0000000000000000'
+...
+*/
diff --git a/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/Inputs/rewrite_list_aggregates_expected.cpp b/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/Inputs/rewrite_list_aggregates_expected.cpp
new file mode 100644
index 0000000000000..630ed6e887413
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/Inputs/rewrite_list_aggregates_expected.cpp
@@ -0,0 +1,58 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %dexter_regression_test_cxx_build %s -o %t/test
+// RUN: %dexter_regression_test_run --use-script --binary %t/test \
+// RUN: --results-directory %t/results -- %s 2>&1 | FileCheck %s
+// RUN: diff %t/results/%{s:basename} \
+// RUN: %S/Inputs/rewrite_list_aggregates_expected.cpp
+
+/// Test that Dexter can write expects for variables that are aggregates and
+/// have more than one value, without writing any duplicate expected values.
+
+/// NB: The exact contents of this file are compared against the expect file in
+/// the Inputs/ directory; any changes to this file, including comments,
+/// will require updating the corresponding expected file.
+
+// CHECK: Rewrote script to add 1 expected values.
+
+struct Point {
+ int X;
+ int Y;
+};
+
+int main() {
+ Point P{1, 2};
+ P.X = 3; // !dex_label start
+ P.Y = 0;
+ P.X = 1;
+ P.Y = 2;
+ P = {0, 0};
+ return 0; // !dex_label end
+}
+
+// CHECK: total_watched_steps: 6
+// CHECK: correct_steps: 6
+// CHECK: incorrect_steps: 0
+// CHECK: partial_step_correctness: 6.0
+// CHECK: missing_var_steps: 0
+// CHECK: unexpected_value_steps: 0
+// CHECK: correct_step_coverage: 100.0% (6/6)
+// CHECK: seen_values: 10
+// CHECK: missing_values: 0
+
+/*
+---
+? !where {lines: !range [!label 'start', !label 'end']}
+: !value 'P':
+ - X: '1'
+ Y: '2'
+ - X: '3'
+ Y: '2'
+ - X: '3'
+ Y: '0'
+ - X: '1'
+ Y: '0'
+ - X: '0'
+ Y: '0'
+...
+*/
diff --git a/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/rewrite_aggregates.cpp b/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/rewrite_aggregates.cpp
new file mode 100644
index 0000000000000..da55a3345093c
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/rewrite_aggregates.cpp
@@ -0,0 +1,53 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %dexter_regression_test_cxx_build %s -o %t/test
+// RUN: %dexter_regression_test_run --use-script --binary %t/test \
+// RUN: --results-directory %t/results -- %s 2>&1 | FileCheck %s
+// RUN: diff %t/results/%{s:basename} %S/Inputs/rewrite_aggregates_expected.cpp
+
+/// Test that Dexter can write disaggregated expected values for aggregates,
+/// including falling back to the parent value if sub_values contain errors,
+/// e.g. for pointers that are not dereferencable.
+
+/// NB: The exact contents of this file are compared against the expect file in
+/// the Inputs/ directory; any changes to this file, including comments,
+/// will require updating the corresponding expected file.
+
+// CHECK: Rewrote script to add 5 expected values.
+
+// CHECK: total_watched_steps: 5
+// CHECK: correct_steps: 5
+// CHECK: incorrect_steps: 0
+// CHECK: seen_values: 16
+// CHECK: missing_values: 0
+
+struct Point {
+ int X;
+ int Y;
+ int Z;
+};
+
+struct Rect {
+ Point TopLeft;
+ Point BottomRight;
+};
+
+int main() {
+ Point P{1, 2, 3};
+ int *I = &P.X;
+ Rect R{{1, 1, 1}, {2, 2, 2}};
+ int L[] = {0, 1, 2, 3, 4};
+ int *InvalidPtr = nullptr;
+ return 0; // !dex_label ret
+}
+
+/*
+---
+!where {lines: !label ret}:
+ ? !value P
+ ? !value I
+ ? !value R
+ ? !value L
+ ? !value InvalidPtr
+...
+*/
diff --git a/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/rewrite_list_aggregates.cpp b/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/rewrite_list_aggregates.cpp
new file mode 100644
index 0000000000000..ab517d1342b2f
--- /dev/null
+++ b/cross-project-tests/debuginfo-tests/dexter/feature_tests/scripts/rewriting/rewrite_list_aggregates.cpp
@@ -0,0 +1,48 @@
+// RUN: rm -rf %t
+// RUN: mkdir %t
+// RUN: %dexter_regression_test_cxx_build %s -o %t/test
+// RUN: %dexter_regression_test_run --use-script --binary %t/test \
+// RUN: --results-directory %t/results -- %s 2>&1 | FileCheck %s
+// RUN: diff %t/results/%{s:basename} \
+// RUN: %S/Inputs/rewrite_list_aggregates_expected.cpp
+
+/// Test that Dexter can write expects for variables that are aggregates and
+/// have more than one value, without writing any duplicate expected values.
+
+/// NB: The exact contents of this file are compared against the expect file in
+/// the Inputs/ directory; any changes to this file, including comments,
+/// will require updating the corresponding expected file.
+
+// CHECK: Rewrote script to add 1 expected values.
+
+struct Point {
+ int X;
+ int Y;
+};
+
+int main() {
+ Point P{1, 2};
+ P.X = 3; // !dex_label start
+ P.Y = 0;
+ P.X = 1;
+ P.Y = 2;
+ P = {0, 0};
+ return 0; // !dex_label end
+}
+
+// CHECK: total_watched_steps: 6
+// CHECK: correct_steps: 6
+// CHECK: incorrect_steps: 0
+// CHECK: partial_step_correctness: 6.0
+// CHECK: missing_var_steps: 0
+// CHECK: unexpected_value_steps: 0
+// CHECK: correct_step_coverage: 100.0% (6/6)
+// CHECK: seen_values: 10
+// CHECK: missing_values: 0
+
+/*
+---
+!where {lines: !range [!label start, !label end]}:
+ ? !value P
+...
+*/
More information about the llvm-commits
mailing list