e1316e60d4
Letting a "checkpoint" run to exit with "set non-stop on" behaves differently compared to the default all-stop mode ("set non-stop off"). Currently, in non-stop mode: (gdb) start Temporary breakpoint 1 at 0x40086b: file src/gdb/testsuite/gdb.base/checkpoint.c, line 28. Starting program: build/gdb/testsuite/gdb.base/checkpoint Temporary breakpoint 1, main () at src/gdb/testsuite/gdb.base/checkpoint.c:28 28 char *tmp = &linebuf[0]; (gdb) checkpoint checkpoint 1: fork returned pid 24948. (gdb) c Continuing. Copy complete. Deleting copy. [Inferior 1 (process 24944) exited normally] [Switching to process 24948] (gdb) info threads Id Target Id Frame 1 process 24948 "checkpoint" (running) No selected thread. See `help thread'. (gdb) c The program is not being run. (gdb) Two issues above: 1. Thread 1 got stuck in "(running)" state (it isn't really running) 2. While checkpoints try to preserve the illusion that the thread is still the same when the process exits, GDB switched to "No thread selected." instead of staying with thread 1 selected. Problem #1 is caused by handle_inferior_event and normal_stop not considering that when a TARGET_WAITKIND_SIGNALLED/TARGET_WAITKIND_EXITED event is reported, and the inferior is mourned, the target may still have execution. Problem #2 is caused by the make_cleanup_restore_current_thread cleanup installed by fetch_inferior_event not being able to find the original thread 1's ptid in the thread list, thus not being able to restore thread 1 as selected thread. The fix is to make the cleanup installed by make_cleanup_restore_current_thread aware of thread ptid changes, by installing a thread_ptid_changed observer that adjusts the cleanup's data. After the patch, we get the same in all-stop and non-stop modes: (gdb) c Continuing. Copy complete. Deleting copy. [Inferior 1 (process 25109) exited normally] [Switching to process 25113] (gdb) info threads Id Target Id Frame * 1 process 25113 "checkpoint" main () at src/gdb/testsuite/gdb.base/checkpoint.c:28 (gdb) Turns out the whole checkpoints.exp file can run in non-stop mode unmodified. I thought of moving most of the test file's contents to a procedure that can be called twice, once in non-stop mode and another in all-stop mode. But then, the test already takes close to 30 seconds to run on my machine, so I thought it'd be nicer to run all-stop and non-stop mode in parallel. Thus I added a new checkpoint-ns.exp file that just appends "set non-stop on" to GDBFLAGS and sources checkpoint.exp. gdb/ChangeLog: 2015-08-07 Pedro Alves <palves@redhat.com> * infrun.c (handle_inferior_event): If we get TARGET_WAITKIND_SIGNALLED or TARGET_WAITKIND_EXITED in non-stop mode, mark all threads of the exiting process as not-executing. (normal_stop): If we get TARGET_WAITKIND_SIGNALLED or TARGET_WAITKIND_EXITED in non-stop mode, finish all threads of the exiting process, if inferior_ptid still points at a process. * thread.c (struct current_thread_cleanup) <next>: New field. (current_thread_cleanup_chain): New global. (restore_current_thread_ptid_changed): New function. (restore_current_thread_cleanup_dtor): Remove the cleanup from the current_thread_cleanup_chain list. (make_cleanup_restore_current_thread): Add the cleanup data to the current_thread_cleanup_chain list. (_initialize_thread): Install restore_current_thread_ptid_changed as thread_ptid_changed observer. gdb/testsuite/ChangeLog: 2015-08-07 Pedro Alves <palves@redhat.com> * gdb.base/checkpoint-ns.exp: New file. * gdb.base/checkpoint.exp: Pass explicit "checkpoint.c" to standard_testfile.
375 lines
12 KiB
Text
375 lines
12 KiB
Text
# Copyright 2005-2015 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 <http://www.gnu.org/licenses/>. */
|
|
|
|
if { [is_remote target] || ![isnative] } then {
|
|
continue
|
|
}
|
|
|
|
# Until "set follow-fork-mode" and "catch fork" are implemented on
|
|
# other targets...
|
|
#
|
|
if {![istarget "*-*-linux*"]} then {
|
|
continue
|
|
}
|
|
|
|
# Must name the source file explicitly, otherwise when driven by
|
|
# checkpoints-ns.exp, we'd try compiling checkpoints-ns.c, which
|
|
# doesn't exist.
|
|
standard_testfile checkpoint.c
|
|
|
|
set pi_txt [gdb_remote_download host ${srcdir}/${subdir}/pi.txt]
|
|
if {[is_remote host]} {
|
|
set copy1_txt copy1.txt
|
|
} else {
|
|
set copy1_txt [standard_output_file copy1.txt]
|
|
}
|
|
|
|
if {[prepare_for_testing ${testfile}.exp $testfile $srcfile \
|
|
[list debug "additional_flags=-DPI_TXT=\"$pi_txt\" -DCOPY1_TXT=\"$copy1_txt\""]]} {
|
|
untested checkpoint.exp
|
|
return -1
|
|
}
|
|
|
|
global gdb_prompt
|
|
|
|
#
|
|
# This tests gdb checkpoint and restart.
|
|
#
|
|
|
|
runto_main
|
|
set break1_loc [gdb_get_line_number "breakpoint 1"]
|
|
set break2_loc [gdb_get_line_number "breakpoint 2"]
|
|
set break3_loc [gdb_get_line_number "breakpoint 3"]
|
|
set break4_loc [gdb_get_line_number "breakpoint 4"]
|
|
|
|
gdb_breakpoint $break1_loc
|
|
gdb_test "continue" "breakpoint 1.*" "break1 start"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 two"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 three"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 four"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 five"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 six"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 seven"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 eight"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 nine"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
gdb_test "continue 10" "breakpoint 1.*" "break1 ten"
|
|
|
|
gdb_test "checkpoint" ".*" ""
|
|
|
|
gdb_test "info checkpoints" \
|
|
" 10 .* 9 .* 8 .* 7 .* 6 .* 5 .* 4 .* 3 .* 2 .* 1 .*" \
|
|
"info checkpoints one"
|
|
|
|
delete_breakpoints
|
|
gdb_breakpoint $break2_loc
|
|
gdb_test "continue" "breakpoint 2.*" "break2 one"
|
|
|
|
gdb_test "restart 1" "Switching to .*breakpoint 1.*" "restart 1 one"
|
|
gdb_test "print i" " = 78" "verify i 1 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 1 one"
|
|
gdb_test "print lines" " = 1.*" "verify lines 1 one"
|
|
|
|
gdb_test "restart 2" "Switching to .*breakpoint 1.*" "restart 2 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 2 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 2 one"
|
|
gdb_test "print lines" " = 11.*" "verify lines 2 one"
|
|
|
|
gdb_test "restart 3" "Switching to .*breakpoint 1.*" "restart 3 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 3 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 3 one"
|
|
gdb_test "print lines" " = 21.*" "verify lines 3 one"
|
|
|
|
gdb_test "restart 4" "Switching to .*breakpoint 1.*" "restart 4 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 4 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 4 one"
|
|
gdb_test "print lines" " = 31.*" "verify lines 4 one"
|
|
|
|
gdb_test "restart 5" "Switching to .*breakpoint 1.*" "restart 5 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 5 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 5 one"
|
|
gdb_test "print lines" " = 41.*" "verify lines 5 one"
|
|
|
|
gdb_test "restart 6" "Switching to .*breakpoint 1.*" "restart 6 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 6 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 6 one"
|
|
gdb_test "print lines" " = 51.*" "verify lines 6 one"
|
|
|
|
gdb_test "restart 7" "Switching to .*breakpoint 1.*" "restart 7 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 7 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 7 one"
|
|
gdb_test "print lines" " = 61.*" "verify lines 7 one"
|
|
|
|
gdb_test "restart 8" "Switching to .*breakpoint 1.*" "restart 8 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 8 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 8 one"
|
|
gdb_test "print lines" " = 71.*" "verify lines 8 one"
|
|
|
|
gdb_test "restart 9" "Switching to .*breakpoint 1.*" "restart 9 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 9 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 9 one"
|
|
gdb_test "print lines" " = 81.*" "verify lines 9 one"
|
|
|
|
gdb_test "restart 10" "Switching to .*breakpoint 1.*" "restart 10 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 10 one"
|
|
gdb_test "print i + 1 == lines * 79" " = 1" "verify i 10 one"
|
|
gdb_test "print lines" " = 91.*" "verify lines 10 one"
|
|
|
|
#
|
|
# Now let the files be closed by the original process,
|
|
# and diff them.
|
|
|
|
gdb_test "restart 0" "Switching to .*breakpoint 2.*" "restart 0 one"
|
|
gdb_breakpoint $break3_loc
|
|
gdb_test "continue" "breakpoint 3.*" "break3 one"
|
|
|
|
gdb_test "shell diff -s $pi_txt $copy1_txt" \
|
|
"Files .*pi.txt and .*copy1.txt are identical.*" \
|
|
"Diff input and output one"
|
|
|
|
#
|
|
# And now run from various checkpoints, allowing
|
|
# various amounts of input and output.
|
|
#
|
|
|
|
gdb_breakpoint $break1_loc
|
|
|
|
gdb_test "restart 1" "Switching to .*c == EOF.*" "restart 1 two"
|
|
gdb_test "continue" ".*" ""
|
|
gdb_test "continue 100" "breakpoint 1.*" "breakpoint 1 1 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 1 two"
|
|
gdb_test "print lines" " = 102.*" "verify lines 1 two"
|
|
|
|
gdb_test "restart 2" "Switching to .*c == EOF.*" "restart 2 two"
|
|
gdb_test "continue" ".*" ""
|
|
gdb_test "continue 100" "breakpoint 1.*" "breakpoint 1 2 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 2 two"
|
|
gdb_test "print lines" " = 112.*" "verify lines 2 two"
|
|
|
|
gdb_test "restart 3" "Switching to .*c == EOF.*" "restart 3 two"
|
|
gdb_test "continue" ".*" ""
|
|
gdb_test "continue 500" "breakpoint 1.*" "breakpoint 1 3 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 3 two"
|
|
gdb_test "print lines" " = 522.*" "verify lines 3 two"
|
|
|
|
gdb_test "restart 4" "Switching to .*c == EOF.*" "restart 4 two"
|
|
gdb_test "continue" ".*" ""
|
|
gdb_test "continue 500" "breakpoint 1.*" "breakpoint 1 4 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 4 two"
|
|
gdb_test "print lines" " = 532.*" "verify lines 4 two"
|
|
|
|
gdb_test "restart 5" "Switching to .*c == EOF.*" "restart 5 two"
|
|
gdb_test "continue" ".*" ""
|
|
gdb_test "continue 1000" "breakpoint 1.*" "breakpoint 1 5 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 5 two"
|
|
gdb_test "print lines" " = 1042.*" "verify lines 5 two"
|
|
|
|
gdb_test "restart 6" "Switching to .*c == EOF.*" "restart 6 two"
|
|
gdb_test "continue" ".*" ""
|
|
gdb_test "continue 1000" "breakpoint 1.*" "breakpoint 1 6 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 6 two"
|
|
gdb_test "print lines" " = 1052.*" "verify lines 5 two"
|
|
|
|
gdb_test "restart 7" "Switching to .*c == EOF.*" "restart 7 two"
|
|
gdb_test "continue" ".*" ""
|
|
gdb_test "continue 1100" "breakpoint 1.*" "breakpoint 1 7 one"
|
|
gdb_test "step" "if .c == EOF.*" "step in 7 two"
|
|
gdb_test "print lines" " = 1162.*" "verify lines 7 two"
|
|
|
|
gdb_test "shell diff -s $pi_txt $copy1_txt" \
|
|
"Files .*pi.txt and .*copy1.txt are identical.*" \
|
|
"Diff input and output two"
|
|
|
|
#
|
|
# OK, now allow the original program to delete the output file,
|
|
# and verify that the checkpoints can still write to it.
|
|
#
|
|
|
|
gdb_test "restart 0" "Switching to .*breakpoint 3.*" "restart 0 one"
|
|
gdb_breakpoint $break4_loc
|
|
gdb_test "continue" "breakpoint 4.*" "break4 one"
|
|
|
|
gdb_test "shell diff $pi_txt $copy1_txt" \
|
|
"diff: .*copy1.txt: No such file or directory" \
|
|
"delete copy1"
|
|
|
|
delete_breakpoints
|
|
gdb_breakpoint $break2_loc
|
|
|
|
gdb_test "restart 1" "if .c == EOF.*" "restart 1 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 1 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 1"
|
|
|
|
gdb_test "restart 2" "if .c == EOF.*" "restart 2 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 2 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 2"
|
|
|
|
gdb_test "restart 3" "if .c == EOF.*" "restart 3 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 3 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 3"
|
|
|
|
gdb_test "restart 4" "if .c == EOF.*" "restart 4 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 4 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 4"
|
|
|
|
gdb_test "restart 5" "if .c == EOF.*" "restart 5 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 5 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 5"
|
|
|
|
gdb_test "restart 6" "if .c == EOF.*" "restart 6 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 6 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 6"
|
|
|
|
gdb_test "restart 7" "if .c == EOF.*" "restart 7 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 7 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 7"
|
|
|
|
gdb_test "restart 8" "if .c == EOF.*" "restart 8 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 8 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 8"
|
|
|
|
gdb_test "restart 9" "if .c == EOF.*" "restart 9 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 9 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 9"
|
|
|
|
gdb_test "restart 10" "if .c == EOF.*" "restart 10 three"
|
|
gdb_test "continue" "breakpoint 2.*" "break2 10 one"
|
|
gdb_test "print ftell (out) > 100000" " = 1.*" "outfile still open 10"
|
|
|
|
#
|
|
# Now confirm that if one fork exits, we automatically switch to another one.
|
|
#
|
|
|
|
delete_breakpoints
|
|
gdb_test "continue" \
|
|
"Deleting copy.*$inferior_exited_re normally.*Switching to.*" \
|
|
"Exit, dropped into next fork one"
|
|
|
|
gdb_test "continue" \
|
|
"Deleting copy.*$inferior_exited_re normally.*Switching to.*" \
|
|
"Exit, dropped into next fork two"
|
|
|
|
gdb_test "continue" \
|
|
"Deleting copy.*$inferior_exited_re normally.*Switching to.*" \
|
|
"Exit, dropped into next fork three"
|
|
|
|
gdb_test "continue" \
|
|
"Deleting copy.*$inferior_exited_re normally.*Switching to.*" \
|
|
"Exit, dropped into next fork four"
|
|
|
|
gdb_test "continue" \
|
|
"Deleting copy.*$inferior_exited_re normally.*Switching to.*" \
|
|
"Exit, dropped into next fork five"
|
|
|
|
#
|
|
# There should be still at least five forks left
|
|
#
|
|
|
|
gdb_test "info checkpoints" " 5 .* 4 .* 3 .* 2 .* 1 .*" \
|
|
"info checkpoints two"
|
|
|
|
#
|
|
# Kill should now terminate all of them.
|
|
#
|
|
|
|
gdb_test "kill" "" "kill all one" \
|
|
"Kill the program being debugged.*y or n. $" "y"
|
|
|
|
#
|
|
# and confirm that all are gone
|
|
#
|
|
|
|
gdb_test "restart 0" "Not found.*" "no more checkpoint 0"
|
|
gdb_test "restart 1" "Not found.*" "no more checkpoint 1"
|
|
gdb_test "restart 2" "Not found.*" "no more checkpoint 2"
|
|
gdb_test "restart 3" "Not found.*" "no more checkpoint 3"
|
|
gdb_test "restart 4" "Not found.*" "no more checkpoint 4"
|
|
gdb_test "restart 5" "Not found.*" "no more checkpoint 5"
|
|
gdb_test "restart 6" "Not found.*" "no more checkpoint 6"
|
|
gdb_test "restart 7" "Not found.*" "no more checkpoint 7"
|
|
gdb_test "restart 8" "Not found.*" "no more checkpoint 8"
|
|
gdb_test "restart 9" "Not found.*" "no more checkpoint 9"
|
|
gdb_test "restart 10" "Not found.*" "no more checkpoint 10"
|
|
|
|
#
|
|
# Now let's try setting a large number of checkpoints (>600)
|
|
#
|
|
|
|
gdb_exit
|
|
gdb_start
|
|
gdb_reinitialize_dir $srcdir/$subdir
|
|
gdb_load ${binfile}
|
|
|
|
runto_main
|
|
gdb_breakpoint $break1_loc
|
|
|
|
gdb_test "commands\nsilent\nif (lines % 2)\ncheckpoint\nend\n continue\nend" \
|
|
"" \
|
|
"set checkpoint breakpoint"
|
|
|
|
set prev_timeout $timeout
|
|
set timeout [expr $timeout + 120]
|
|
verbose "Timeout now $timeout sec."
|
|
|
|
gdb_breakpoint $break2_loc
|
|
gdb_test "continue" "breakpoint 2.*" "break2 with many checkpoints"
|
|
|
|
set count 0
|
|
set msg "info checkpoints with at least 600 checkpoints"
|
|
gdb_test_multiple "info checkpoints" $msg {
|
|
-re " $decimal process \[^\r\]*\r\n" {
|
|
incr count
|
|
exp_continue
|
|
}
|
|
-re "$gdb_prompt $" {
|
|
if { $count >= 600 } {
|
|
pass $msg
|
|
} else {
|
|
fail $msg
|
|
}
|
|
}
|
|
}
|
|
|
|
#
|
|
# OK, kill 'em all...
|
|
#
|
|
|
|
gdb_test "kill" "" "kill all one with many checkpoints" \
|
|
"Kill the program being debugged.*y or n. $" "y"
|
|
|
|
# Restore old timeout
|
|
set timeout $prev_timeout
|
|
verbose "Timeout now $timeout sec."
|
|
|
|
#
|
|
# Finished: cleanup
|
|
#
|