# Copyright 2008-2024 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 . */ # This file is part of the GDB testsuite. It tests reverse stepping. # Lots of code borrowed from "step-test.exp". # # Test step and next in reverse # require supports_reverse standard_testfile if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } { return -1 } runto_main if [supports_process_record] { # Activate process record/replay gdb_test_no_output "record" "turn on process record" } # plain vanilla step/next (no count) gdb_test "next" ".*NEXT TEST 1.*" "next test 1" gdb_test "step" ".*STEP TEST 1.*" "step test 1" # step/next with count gdb_test "next 2" ".*NEXT TEST 2.*" "next test 2" gdb_test "step 3" ".*STEP TEST 2.*" "step test 2" # Next through a recursive function call. gdb_test "next 2" "NEXT OVER THIS CALL.*" "next over recursion" # step over call gdb_test "next" ".*STEP INTO THIS CALL.*" "next over call" # step into call gdb_test "step" ".*ARRIVED IN CALLEE.*" "step into call" # finish out of call set test_message "finish out of fn call" gdb_test_multiple "finish" "$test_message" { -re "FINISH TEST.*$gdb_prompt $" { pass "$test_message" } -re "STEP INTO THIS CALL.*$gdb_prompt $" { send_gdb "step\n" exp_continue } } # stepi over flat code (no calls) set test_message "simple stepi" gdb_test_multiple "stepi" "$test_message" { -re "STEPI TEST.*$gdb_prompt $" { pass "$test_message" } -re "FINISH TEST.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "NEXTI TEST.*$gdb_prompt $" { fail "$test_message (too far)" } } # stepi into a function call set alphanum_re "\[a-zA-Z0-9\]" set pic_thunk_re "__$alphanum_re*\\.get_pc_thunk\\.$alphanum_re* \\(\\)" set test_message "stepi into function call" gdb_test_multiple "stepi" "$test_message" { -re "ARRIVED IN CALLEE.*$gdb_prompt $" { pass "$test_message" } -re "NEXTI TEST.*$gdb_prompt $" { fail "$test_message (too far)" } -re "RETURN FROM CALLEE.*$gdb_prompt $" { fail "$test_message (too far)" } -re "ENTER CALLEE.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "STEPI TEST.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "$pic_thunk_re.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } } # stepi thru return of a function call set test_message "stepi back from function call" gdb_test_multiple "stepi" "$test_message" { -re -wrap "NEXTI TEST.*" { pass "$test_message" } -re "ARRIVED IN CALLEE.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "RETURN FROM CALLEE.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "STEPI TEST.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "ENTER CALLEE.*$gdb_prompt $" { fail "$test_message (too far)" } } ### ### ### # Set reverse execution direction gdb_test_no_output "set exec-dir reverse" "set reverse execution" # stepi backward thru return and into a function set stepi_location [gdb_get_line_number "ARRIVED IN CALLEE" "$srcfile"] set test_message "reverse stepi thru function return" gdb_test_multiple "stepi" "$test_message" { -re "NEXTI TEST.*$gdb_prompt $" { fail "$test_message (start statement)" } -re "RETURN FROM CALLEE.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "$hex\[ \t\]*$stepi_location.*ARRIVED IN CALLEE.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "ARRIVED IN CALLEE.*$gdb_prompt $" { pass "$test_message" } -re "ENTER CALLEE.*$gdb_prompt $" { fail "$test_message (too far)" } -re "STEPI TEST.*$gdb_prompt $" { fail "$test_message (too far)" } } # stepi backward out of a function call # When testing stepi, we dont want to infinitely step if we're not moving # so we store the starting PC, in case we land on the same line as above set start_pc [get_hexadecimal_valueof "\$pc" 0 "get PC at start"] set get_pc_count 0 set stepi_location [gdb_get_line_number "STEPI TEST" "$srcfile"] set test_message "reverse stepi from a function call" gdb_test_multiple "stepi" "$test_message" { -re "ARRIVED IN CALLEE.*$gdb_prompt $" { incr get_pc_count if { [get_hexadecimal_valueof "\$pc" 0 "get PC again $get_pc_count"] == $start_pc } { fail "$test_message (start statement)" } else { send_gdb "stepi\n" exp_continue } } -re "ENTER CALLEE.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "$pic_thunk_re.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "${hex} in main .*:$stepi_location.*STEPI TEST.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "STEPI TEST.*$gdb_prompt $" { pass "$test_message" } -re "STEP INTO THIS CALL.*$gdb_prompt $" { fail "$test_message (too far)" } } # stepi backward over flat code (no calls) set stepi_location [gdb_get_line_number "FINISH TEST" "$srcfile"] set test_message "simple reverse stepi" gdb_test_multiple "stepi" "$test_message" { -re "STEPI TEST.*$gdb_prompt $" { fail "$test_message (start statement)" } -re "$hex\[ \t\]*$stepi_location.* FINISH TEST.*$gdb_prompt $" { send_gdb "stepi\n" exp_continue } -re "$stepi_location.* FINISH TEST.*$gdb_prompt $" { pass "$test_message" } -re "STEP INTO THIS CALL.*$gdb_prompt $" { fail "$test_message (too far)" } } # step backward into function (thru return) gdb_test "step" "(RETURN FROM CALLEE|ARRIVED IN CALLEE).*" \ "reverse step into fn call" # step backward out of called function (thru call) set test_message "reverse step out of called fn" gdb_test_multiple "step" "$test_message" { -re "STEP INTO THIS CALL.*.*$gdb_prompt $" { pass "$test_message" } -re "ARRIVED IN CALLEE.*$gdb_prompt $" { send_gdb "step\n" exp_continue } -re "ENTER CALLEE.*$gdb_prompt $" { send_gdb "step\n" exp_continue } } # Next backward over call. gdb_test "next" ".*NEXT OVER THIS CALL.*" "reverse next over call" set step_out 0 set max_iterations 1000 gdb_test_multiple "next" "reverse next over recursion" { -re -wrap ".*NEXT OVER THIS RECURSION.*" { pass "$gdb_test_name" } -re -wrap ".*RECURSIVE CALL.*" { fail "$gdb_test_name" set step_out 1 } } if { "$step_out" == 1 } { set iterations 0 gdb_test_multiple "next" "stepping out of recursion" { -re -wrap "^main.*NEXT OVER THIS RECURSION.*" { set step_out 0 pass "$gdb_test_name" } -re -wrap "^\[0-9\].*" { incr iterations if { $iterations == $max_iterations } { fail "$gdb_test_name (reached $max_iterations iterations)" return } send_gdb "next\n" exp_continue } } } # Step forward over recursion again so we can test stepping over calls # inside the recursion itself. gdb_test_no_output "set exec-dir forward" "forward again to test recursion" gdb_test "next" "NEXT OVER THIS CALL.*" "reverse next over recursion again" gdb_test_no_output "set exec-dir reverse" "reverse again to test recursion" gdb_test "step" ".*EXIT RECURSIVE FUNCTION.*" "enter recursive function" set seen_recursive_call 0 set iterations 0 gdb_test_multiple "next" "step over recursion inside the recursion" { -re -wrap ".*RECURSIVE CALL.*" { incr seen_recursive_call incr iterations if { $iterations == $max_iterations } { fail "$gdb_test_name (reached $max_iterations iterations)" return } send_gdb "next\n" exp_continue } -re -wrap ".*NEXT OVER THIS RECURSION.*" { gdb_assert {"$seen_recursive_call" == 1} \ "step over recursion inside the recursion" } -re -wrap "^\[0-9\].*" { incr iterations if { $iterations == $max_iterations } { fail "$gdb_test_name (reached $max_iterations iterations)" return } send_gdb "next\n" exp_continue } } # step/next backward with count gdb_test "step 3" ".*REVERSE STEP TEST 1.*" "reverse step test 1" gdb_test "next 2" ".*REVERSE NEXT TEST 1.*" "reverse next test 1" # step/next backward without count gdb_test "step" ".*STEP TEST 1.*" "reverse step test 2" gdb_test "next" ".*NEXT TEST 1.*" "reverse next test 2" # Finish test by running forward to the end. # FIXME return to this later... # gdb_test_no_output "set exec-dir forward" "set forward execution" # gdb_continue_to_end "step-reverse.exp"