1 # Copyright (C) 2015-2024 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 16 require supports_reverse !use_gdb_stub 17 18 standard_testfile 19 20 if {[prepare_for_testing "failed to prepare" $testfile $srcfile \ 21 [list debug]]} { 22 return -1 23 } 24 if {![runto_main]} { 25 return 26 } 27 28 # Read function name from testcases[N]. 29 30 proc read_testcase { n } { 31 global gdb_prompt 32 33 set result -1 34 gdb_test_multiple "print testcases\[${n}\]" "read name of test case ${n}" { 35 -re "\[$\].*= .*<(.*)>.*$gdb_prompt $" { 36 set result $expect_out(1,string) 37 } 38 -re "$gdb_prompt $" { } 39 } 40 41 return $result 42 } 43 44 # In each function FUNC, GDB turns on process record, and single step 45 # until program goes to the end of the function. Then, single step 46 # backward. In each of forward single step and backward single step, 47 # the contents of registers are saved, and test compares them. If 48 # there is any differences, a FAIL is emitted. 49 50 proc test { func testcase_nr } { 51 global hex decimal 52 global gdb_prompt 53 54 with_test_prefix "$func" { 55 gdb_start_cmd $testcase_nr 56 gdb_test "" "" "wait for prompt" 57 58 gdb_breakpoint $func 59 gdb_test "continue" 60 61 set last_insn "" 62 set test "disassemble $func" 63 gdb_test_multiple $test $test { 64 -re ".*($hex) <\\+$decimal>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { 65 set last_insn $expect_out(1,string) 66 } 67 } 68 if { $last_insn == "" } { 69 fail "find the last instruction of function $func" 70 } 71 72 # Activate process record/replay 73 gdb_test_no_output "record" "turn on process record" 74 75 # Registers contents before each forward single step. 76 set count 0 77 set insn_addr "" 78 for {} {$count < 500} {incr count} { 79 set prev_insn_addr $insn_addr 80 set insn_addr "" 81 gdb_test_multiple "x/i \$pc" "" { 82 -re ".* ($hex) <.*>:\[ \t\]*(.*)\r\n$gdb_prompt $" { 83 set insn_addr $expect_out(1,string) 84 set insn_array($count) $expect_out(2,string) 85 } 86 } 87 88 if { $insn_addr == "" } { 89 break 90 } 91 92 if { $last_insn == $insn_addr } { 93 break 94 } 95 96 if { $prev_insn_addr == $insn_addr } { 97 # Failed to make progress, might have run into SIGILL. 98 fail "no progress at: $expect_out(2,string)" 99 # Ignore the last instruction recorded 100 incr count -1 101 break 102 } 103 104 set pre_regs($count) [capture_command_output "info all-registers" ""] 105 gdb_test -nopass "si" 106 } 107 108 # Registers contents after each backward single step. 109 for {set i [expr $count - 1]} {$i >= 0} {incr i -1} { 110 gdb_test -nopass "reverse-stepi" 111 set post_regs($i) [capture_command_output "info all-registers" ""] 112 } 113 114 # Compare the register contents. 115 for {set i 0} {$i < $count} {incr i} { 116 if { ![gdb_assert { [string compare $pre_regs($i) $post_regs($i)] == 0 } \ 117 "compare registers on insn $i:$insn_array($i)"] } { 118 119 foreach pre_line [split $pre_regs($i) \n] post_line [split $post_regs($i) \n] { 120 if { [string compare $pre_line $post_line] } { 121 verbose -log " -:$pre_line" 122 verbose -log " +:$post_line" 123 } 124 } 125 } 126 } 127 gdb_test "record stop" 128 } 129 } 130 131 set n_testcases [get_integer_valueof "n_testcases" 0] 132 133 if { ${n_testcases} == 0 } { 134 untested "no test" 135 return 1 136 } 137 138 for { set i 0 } { ${i} < ${n_testcases} } { incr i } { 139 set testcase [read_testcase $i] 140 141 test $testcase $i 142 } 143