1# Copyright (C) 2015-2023 Free Software Foundation, Inc. 2# 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16if ![supports_reverse] { 17 return 18} 19 20# Check if start command is supported. 21require use_gdb_stub 0 22 23standard_testfile 24 25if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ 26 [list debug]]} { 27 return -1 28} 29if {![runto_main]} { 30 return 31} 32 33# Read function name from testcases[N]. 34 35proc read_testcase { n } { 36 global gdb_prompt 37 38 set result -1 39 gdb_test_multiple "print testcases\[${n}\]" "read name of test case ${n}" { 40 -re "\[$\].*= .*<(.*)>.*$gdb_prompt $" { 41 set result $expect_out(1,string) 42 } 43 -re "$gdb_prompt $" { } 44 } 45 46 return $result 47} 48 49# In each function FUNC, GDB turns on process record, and single step 50# until program goes to the end of the function. Then, single step 51# backward. In each of forward single step and backward single step, 52# the contents of registers are saved, and test compares them. If 53# there is any differences, a FAIL is emitted. 54 55proc test { func testcase_nr } { 56 global hex decimal 57 global gdb_prompt 58 59 with_test_prefix "$func" { 60 gdb_start_cmd $testcase_nr 61 gdb_test "" "" "wait for prompt" 62 63 gdb_breakpoint $func 64 gdb_test "continue" 65 66 set last_insn "" 67 set test "disassemble $func" 68 gdb_test_multiple $test $test { 69 -re ".*($hex) <\\+$decimal>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { 70 set last_insn $expect_out(1,string) 71 } 72 } 73 if { $last_insn == "" } { 74 fail "find the last instruction of function $func" 75 } 76 77 # Activate process record/replay 78 gdb_test_no_output "record" "turn on process record" 79 80 # Registers contents before each forward single step. 81 set count 0 82 set insn_addr "" 83 for {} {$count < 500} {incr count} { 84 set prev_insn_addr $insn_addr 85 set insn_addr "" 86 gdb_test_multiple "x/i \$pc" "" { 87 -re ".* ($hex) <.*>:\[ \t\]*(.*)\r\n$gdb_prompt $" { 88 set insn_addr $expect_out(1,string) 89 set insn_array($count) $expect_out(2,string) 90 } 91 } 92 93 if { $insn_addr == "" } { 94 break 95 } 96 97 if { $last_insn == $insn_addr } { 98 break 99 } 100 101 if { $prev_insn_addr == $insn_addr } { 102 # Failed to make progress, might have run into SIGILL. 103 unsupported "no progress at: $expect_out(2,string)" 104 break 105 } 106 107 set pre_regs($count) [capture_command_output "info all-registers" ""] 108 gdb_test -nopass "si" 109 } 110 111 # Registers contents after each backward single step. 112 for {set i [expr $count - 1]} {$i >= 0} {incr i -1} { 113 gdb_test -nopass "reverse-stepi" 114 set post_regs($i) [capture_command_output "info all-registers" ""] 115 } 116 117 # Compare the register contents. 118 for {set i 0} {$i < $count} {incr i} { 119 if { ![gdb_assert { [string compare $pre_regs($i) $post_regs($i)] == 0 } \ 120 "compare registers on insn $i:$insn_array($i)"] } { 121 122 foreach pre_line [split $pre_regs($i) \n] post_line [split $post_regs($i) \n] { 123 if { [string compare $pre_line $post_line] } { 124 verbose -log " -:$pre_line" 125 verbose -log " +:$post_line" 126 } 127 } 128 } 129 } 130 gdb_test "record stop" 131 } 132} 133 134set n_testcases [get_integer_valueof "n_testcases" 0] 135 136if { ${n_testcases} == 0 } { 137 untested "no test" 138 return 1 139} 140 141for { set i 0 } { ${i} < ${n_testcases} } { incr i } { 142 set testcase [read_testcase $i] 143 144 test $testcase $i 145} 146