# This testcase is part of GDB, the GNU debugger. # # Copyright 2013-2023 Free Software Foundation, Inc. # # Contributed by Intel Corp. # # 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 . require allow_btrace_tests standard_testfile if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" "$binfile" executable {debug}] != "" } { untested "failed to prepare" return -1 } clean_restart $testfile if ![runto_main] { return -1 } # set up breakpoints set bp_1 [gdb_get_line_number "bp.1" $srcfile] set bp_2 [gdb_get_line_number "bp.2" $srcfile] set bp_3 [gdb_get_line_number "bp.3" $srcfile] proc gdb_cont_to_line { line } { gdb_breakpoint $line gdb_continue_to_breakpoint "cont to $line" ".*$line\r\n.*" delete_breakpoints } proc check_replay_insn { thread insn } { gdb_test "thread apply $thread info record" \ "Replay in progress\. At instruction $insn\." } proc check_not_replaying { thread } { global gdb_prompt set test "thread $thread not replaying" gdb_test_multiple "thread apply $thread info record" $test { -re "Replay in progress" { fail $test } -re "$gdb_prompt $" { pass $test } } } # trace the code between the two breakpoints delete_breakpoints gdb_cont_to_line $srcfile:$bp_1 # make sure GDB knows about the new thread gdb_test "info threads" ".*" gdb_test_no_output "record btrace" gdb_cont_to_line $srcfile:$bp_2 proc test_navigate {} { with_test_prefix "navigate" { gdb_test "thread 1" ".*" with_test_prefix "thread 1" { gdb_test "record goto begin" ".*" check_replay_insn 1 1 check_not_replaying 2 } gdb_test "thread 2" ".*" with_test_prefix "thread 2" { gdb_test "record goto begin" ".*" check_replay_insn 1 1 check_replay_insn 2 1 } } } proc test_step {} { with_test_prefix "step" { gdb_test "thread 1" ".*" with_test_prefix "thread 1" { gdb_test "stepi" ".*" check_replay_insn 1 2 check_replay_insn 2 1 } gdb_test "thread 2" ".*" with_test_prefix "thread 2" { gdb_test "stepi" ".*" check_replay_insn 1 2 check_replay_insn 2 2 } } } proc test_cont {} { with_test_prefix "cont" { gdb_test "thread 1" ".*" with_test_prefix "thread 1" { gdb_test "continue" "No more reverse-execution history.*" check_not_replaying 1 check_replay_insn 2 2 } gdb_test "thread 2" ".*" with_test_prefix "thread 2" { gdb_test "continue" "No more reverse-execution history.*" check_not_replaying 1 check_not_replaying 2 } } } proc test_cont_all {} { with_test_prefix "cont-all" { gdb_test "continue" "No more reverse-execution history.*" # this works because we're lock-stepping threads that executed exactly # the same code starting from the same instruction. check_not_replaying 1 check_not_replaying 2 } } proc test_rstep {} { with_test_prefix "reverse-step" { gdb_test "thread apply all record goto 3" gdb_test "thread 1" ".*" with_test_prefix "thread 1" { gdb_test "reverse-stepi" ".*" check_replay_insn 1 2 check_replay_insn 2 3 } gdb_test "thread 2" ".*" with_test_prefix "thread 2" { gdb_test "reverse-stepi" ".*" check_replay_insn 1 2 check_replay_insn 2 2 } } } proc test_goto_end {} { with_test_prefix "goto-end" { gdb_test "thread apply all record goto end" check_not_replaying 1 check_not_replaying 2 } } foreach schedlock { "replay" "on" "step" } { with_test_prefix "schedlock-$schedlock" { gdb_test_no_output "set scheduler-locking $schedlock" test_navigate test_step if { $schedlock == "step" } { test_cont_all } else { test_cont } test_rstep test_goto_end } } # schedlock-off is difficult to test since we can't really say where the other # thread will be when the resumed thread stops. # navigate back into the history for thread 1 and continue thread 2 with_test_prefix "cont-to-end" { # this test only works for scheduler-locking replay gdb_test_no_output "set scheduler-locking replay" gdb_test "thread 1" ".*" with_test_prefix "thread 1" { gdb_test "record goto begin" ".*" check_replay_insn 1 1 } gdb_test "thread 2" ".*" with_test_prefix "thread 2" { gdb_test "record goto end" ".*" check_not_replaying 2 # if we reach the breakpoint, thread 2 terminated... gdb_cont_to_line $srcfile:$bp_3 # and thread 1 stopped replaying check_not_replaying 1 } }