# This testcase is part of GDB, the GNU debugger.
#
# Copyright 2013-2020 Free Software Foundation, Inc.
#
# Contributed by Intel Corp. <markus.t.metzger@intel.com>
#
# 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/>.
if { [skip_btrace_tests] } {
unsupported "target does not support record-btrace"
return -1
}
standard_testfile
if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" "$binfile" executable {debug}] != "" } {
untested "failed to prepare"
return -1
}
clean_restart $testfile
if ![runto_main] {
untested "failed to run to 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
}
}