]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
gdb/aarch64: Test record/replay support for CSSC
authorEzra Sitorus <ezra.sitorus@arm.com>
Wed, 27 May 2026 16:59:16 +0000 (17:59 +0100)
committerEzra Sitorus <ezra.sitorus@arm.com>
Wed, 27 May 2026 16:59:16 +0000 (17:59 +0100)
GDB can handle AArch64's CSSC instructions but there were no tests
ensuring that and ensuring no regressions would creep in. This commit
adds some tests for these instructions. This was tested on
aarch64-none-linux-gnu on QEMU with CSSC support.

Approved-By: Guinevere Larsen <guinevere@redhat.com>
gdb/testsuite/gdb.reverse/aarch64-cssc.c [new file with mode: 0644]
gdb/testsuite/gdb.reverse/aarch64-cssc.exp [new file with mode: 0644]
gdb/testsuite/lib/gdb.exp

diff --git a/gdb/testsuite/gdb.reverse/aarch64-cssc.c b/gdb/testsuite/gdb.reverse/aarch64-cssc.c
new file mode 100644 (file)
index 0000000..67ccb68
--- /dev/null
@@ -0,0 +1,88 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2024-2026 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <stdint.h>
+
+#define PREPARE_REGS(X, Y, Z) \
+       __asm__ volatile ("mov x19, %0\n" : : "r"(X): "x19"); \
+       __asm__ volatile ("mov x20, %0\n" : : "r"(Y): "x20"); \
+       __asm__ volatile ("mov x21, %0\n" : : "r"(Z): "x21");
+
+int
+main (void)
+{
+  const uint64_t a = 0x0123456789abcdef;
+  const uint64_t b = 0xfedbca9876543210;
+  const uint64_t c = 0xdeadbeefc001face;
+
+  PREPARE_REGS (a, b, c);
+  /* Before abs.  */
+  __asm__ volatile ("abs x19, x21\n" ::: "x19");
+  /* After abs.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before cnt.  */
+  __asm__ volatile ("cnt x19, x20\n" : :: "x19");
+  /* After cnt.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before ctz.  */
+  __asm__ volatile ("ctz x19, x20\n" : :: "x19");
+  /* After ctz.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before smax-1.  */
+  __asm__ volatile ("smax x19, x20, #10\n" : :: "x19");
+  /* After smax-1.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before smax-2.  */
+  __asm__ volatile ("smax x19, x20, x21\n" : :: "x19");
+  /* After smax-2.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before smin-1.  */
+  __asm__ volatile ("smin x19, x20, #10\n" : :: "x19");
+  /* After smin-1.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before smin-2.  */
+  __asm__ volatile ("smin x19, x20, x21\n" : :: "x19");
+  /* After smin-2.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before umax-1.  */
+  __asm__ volatile ("umax x19, x20, #10\n" : :: "x19");
+  /* After umax-1.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before umax-2.  */
+  __asm__ volatile ("umax x19, x20, x21\n" : :: "x19");
+  /* After umax-2.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before umin-1.  */
+  __asm__ volatile ("umin x19, x20, #10\n" : :: "x19");
+  /* After umin-1.  */
+
+  PREPARE_REGS (a, b, c);
+  /* Before umin-2.  */
+  __asm__ volatile ("umin x19, x20, x21\n" : :: "x19");
+  /* After umin-2.  */
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.reverse/aarch64-cssc.exp b/gdb/testsuite/gdb.reverse/aarch64-cssc.exp
new file mode 100644 (file)
index 0000000..1e2980a
--- /dev/null
@@ -0,0 +1,139 @@
+# Copyright 2024-2026 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test instruction record for AArch64 FEAT_CSSC instructions.
+# Based on gdb.reverse/aarch64-mops.exp
+#
+# The basic flow of the record tests are:
+#    1) Stop before executing the instructions of interest.  Record
+#       the initial value of the registers that the instruction will
+#       change, i.e. the destination register.
+#    2) Execute the instructions.  Record the new value of the
+#       registers that changed.
+#    3) Reverse the direction of the execution and execute back to
+#       just before the instructions of interest.  Record the final
+#       value of the registers of interest.
+#    4) Check that the initial and new values of the registers are
+#       different, i.e. the instruction changed the registers as expected.
+#    5) Check that the initial and final values of the registers are
+#       the same, i.e. GDB record restored the registers to their
+#       original values.
+
+require allow_aarch64_cssc_tests
+standard_testfile
+
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \
+       [list debug additional_flags=-march=armv8-a+cssc]] } {
+    return
+}
+
+if {![runto_main]} {
+    return
+}
+
+gdb_test_no_output "record full"
+
+proc test_single_asm { name } {
+    with_test_prefix $name {
+       set before_seq [gdb_get_line_number "Before ${name}"]
+       set after_seq [gdb_get_line_number "After ${name}"]
+       set regs { x19 x20 x21 }
+
+       set insn [lindex [split $name "-"] 0]
+
+       gdb_test "break $before_seq" \
+           "Breakpoint ${::decimal} at ${::hex}: file .*/aarch64-cssc.c, line ${::decimal}\\." \
+           "$insn: break before instruction sequence"
+       gdb_continue_to_breakpoint "$insn: about to execute instruction sequence" \
+           [multi_line ".*/aarch64-cssc.c:${::decimal}" \
+               "${::decimal}\[ \t\]+__asm__ volatile \\(\"${insn} .*\".*"]
+
+       # Depending on the compiler, the line number information may put GDB a few
+       # instructions before the beginning of the asm statement.
+       arrive_at_instruction $insn
+       # Add a breakpoint that we're sure is at the prologue instruction.
+       gdb_test "break *\$pc" \
+           "Breakpoint ${::decimal} at ${::hex}: file .*/aarch64-cssc.c, line ${::decimal}\\." \
+           "$insn: break at prologue instruction"
+
+       # Record the initial register values.
+       foreach r $regs {
+           set ${r}_initial [capture_command_output "info register $r" ""]
+       }
+
+       gdb_test "break $after_seq" \
+           "Breakpoint ${::decimal} at ${::hex}: file .*/aarch64-cssc.c, line ${::decimal}\\." \
+           "$insn: break after instruction sequence"
+       gdb_continue_to_breakpoint "$insn: executed instruction sequence" \
+           [multi_line ".*/aarch64-cssc.c:${::decimal}" ".*"]
+
+       # Record the new register values.
+       foreach r $regs {
+           set ${r}_new [capture_command_output "info register $r" ""]
+       }
+
+       # Execute in reverse to before the instruction sequence.
+       gdb_test_no_output "set exec-direction reverse"
+
+       gdb_continue_to_breakpoint "reversed execution of instruction sequence" \
+           [multi_line ".*/aarch64-cssc.c:${::decimal}" \
+               "${::decimal}\[ \t\]+__asm__ volatile \\(\"${insn} .*\".*"]
+
+       # Record the final register values.
+       foreach r $regs {
+           set ${r}_final [capture_command_output "info register $r" ""]
+       }
+
+       foreach v { x19 x20 x21 } {
+           gdb_assert ![string compare [set ${v}_initial] [set ${v}_final]] \
+               "$insn: check $v initial value versus $v final value"
+       }
+
+       gdb_assert [string compare [set x19_initial] [set x19_new]] \
+               "$insn: check x19 initial value versus x19 new value"
+
+       foreach v { x20 x21 } {
+           gdb_assert ![string compare [set ${v}_initial] [set ${v}_new]] \
+               "$insn: check $v initial value versus $v new value"
+       }
+
+       # Restore forward execution and go to end of recording.
+       gdb_test_no_output "set exec-direction forward"
+       gdb_test "record goto end" \
+           [multi_line \
+               "Go forward to insn number ${::decimal}" \
+               "#0  main \\(\\) at .*/aarch64-cssc.c:${::decimal}" \
+               ".*"]
+    }
+}
+
+set cases {
+       { abs }
+       { cnt }
+       { ctz }
+       { smax-1 }
+       { smax-2 }
+       { smin-1 }
+       { smin-2 }
+       { umax-1 }
+       { umax-2 }
+       { umin-1 }
+       { umin-2 }
+}
+
+foreach c $cases {
+    lassign $c insn
+    test_single_asm $insn
+}
index 28709004570728cf73d30b17aec3ba10584f5ed6..4f7728d6fe5337c4dcbfa03c948cad06cf32b75b 100644 (file)
@@ -5287,6 +5287,58 @@ gdb_caching_proc allow_aarch64_fpmr_tests {} {
     return $allow_fpmr_tests
 }
 
+# Run a test on the target to see if it supports the AArch64 CSSC feature.
+# Return 1 if so, 0 if it does not.  Note this causes a restart of GDB.
+
+gdb_caching_proc allow_aarch64_cssc_tests {} {
+    global srcdir subdir gdb_prompt inferior_exited_re
+
+    set me "allow_aarch64_cssc_tests"
+
+    if { ![is_aarch64_target]} {
+       return 0
+    }
+
+    set compile_flags "{additional_flags=-march=armv8-a+cssc}"
+
+    # Compile a test program reading CSSC.
+    set src {
+       int main() {
+           asm volatile ("abs x0, x1" ::: "x0");
+           return 0;
+       }
+    }
+
+    if {![gdb_simple_compile $me $src executable $compile_flags]} {
+           return 0
+    }
+
+    # Compilation succeeded so now run it via gdb.
+    clean_restart
+    gdb_load $obj
+    gdb_run_cmd
+
+    gdb_expect {
+       -re ".*Illegal instruction.*${gdb_prompt} $" {
+           verbose -log "\n$me cssc support not detected"
+           set allow_cssc_tests 0
+       }
+       -re ".*$inferior_exited_re normally.*${gdb_prompt} $" {
+           verbose -log "\n$me: cssc support detected"
+           set allow_cssc_tests 1
+       }
+       default {
+         warning "\n$me: default case taken"
+           set allow_cssc_tests 0
+       }
+    }
+    gdb_exit
+    remote_file build delete $obj
+
+    verbose "$me:  returning $allow_cssc_tests" 2
+    return $allow_cssc_tests
+}
+
 # Run a test on the target to see if it supports AArch64 MOPS (Memory
 # Operations) extensions.  Return 1 if so, 0 if it does not.  Note this
 # causes a restart of GDB.