-# Copyright (C) 1997 Free Software Foundation, Inc.
+# Copyright 1997-2017 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 2 of the License, or
+# 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, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-# Please email any bugs, comments, and/or additions to this file to:
-# bug-gdb@prep.ai.mit.edu
-
-if $tracelevel then {
- strace $tracelevel
- }
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
-if { ![isnative] } then {
+# Until "set follow-fork-mode" and "catch fork" are implemented on
+# other targets...
+#
+if { ![istarget "*-*-linux*"] && ![istarget "*-*-openbsd*"] } then {
continue
}
-set prms_id 0
-set bug_id 0
+standard_testfile
-set testfile "foll-fork"
-set srcfile ${testfile}.c
-set binfile ${objdir}/${subdir}/${testfile}
+if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} {
+ return -1
+}
-if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
- gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
+proc check_fork_catchpoints {} {
+ global gdb_prompt
+
+ # Verify that the system supports "catch fork".
+ gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" "insert first fork catchpoint"
+ set has_fork_catchpoints 0
+ gdb_test_multiple "continue" "continue to first fork catchpoint" {
+ -re ".*Your system does not support this type\r\nof catchpoint.*$gdb_prompt $" {
+ unsupported "continue to first fork catchpoint"
+ }
+ -re ".*Catchpoint.*$gdb_prompt $" {
+ set has_fork_catchpoints 1
+ pass "continue to first fork catchpoint"
+ }
+ }
+
+ if {$has_fork_catchpoints == 0} {
+ unsupported "fork catchpoints"
+ return -code return
+ }
}
+# Test follow-fork to ensure that the correct process is followed, that
+# the followed process stops where it is expected to stop, that processes
+# are detached (or not) as expected, and that the inferior list has the
+# expected contents after following the fork. WHO is the argument to
+# the 'set follow-fork-mode' command, DETACH is the argument to the
+# 'set detach-on-fork' command, and CMD is the GDB command used to
+# execute the program past the fork. If the value of WHO or DETACH is
+# 'default', the corresponding GDB command is skipped for that test.
+# The value of CMD must be either 'next 2' or 'continue'.
+proc test_follow_fork { who detach cmd } {
+ global gdb_prompt
+ global srcfile
+ global testfile
+
+ with_test_prefix "follow $who, detach $detach, command \"$cmd\"" {
+
+ # Start a new debugger session each time so defaults are legitimate.
+ clean_restart $testfile
+
+ if ![runto_main] {
+ untested "could not run to main"
+ return -1
+ }
+ # The "Detaching..." and "Attaching..." messages may be hidden by
+ # default.
+ gdb_test_no_output "set verbose"
-# Until "set follow-fork-mode" and "catch fork" are implemented on
-# other targets...
-#
-if ![istarget "hppa*-hp-hpux*"] then {
- continue
-}
+ # Set follow-fork-mode if we aren't using the default.
+ if {$who == "default"} {
+ set who "parent"
+ } else {
+ gdb_test_no_output "set follow-fork $who"
+ }
-proc default_fork_parent_follow {} {
- global gdb_prompt
-
- send_gdb "show follow\n"
- gdb_expect {
- -re "Debugger response to a program call of fork or vfork is \"parent\"..*$gdb_prompt $"\
- {pass "default show parent follow, no catchpoints"}
- -re "$gdb_prompt $" {fail "default show parent follow, no catchpoints"}
- timeout {fail "(timeout) default show parent follow, no catchpoints"}
- }
- send_gdb "next 2\n"
- gdb_expect {
- -re "Detaching after fork from.*$gdb_prompt $"\
- {pass "default parent follow, no catchpoints"}
- -re "$gdb_prompt $" {fail "default parent follow, no catchpoints"}
- timeout {fail "(timeout) default parent follow, no catchpoints" }
- }
- # The child has been detached; allow time for any output it might
- # generate to arrive, so that output doesn't get confused with
- # any expected debugger output from a subsequent testpoint.
- #
- exec sleep 1
-}
+ gdb_test "show follow-fork" \
+ "Debugger response to a program call of fork or vfork is \"$who\"." \
+ "show follow-fork"
-proc explicit_fork_parent_follow {} {
- global gdb_prompt
-
- send_gdb "set follow parent\n"
- gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent"}
- timeout {fail "(timeout) set follow parent"}
- }
- send_gdb "show follow\n"
- gdb_expect {
- -re "Debugger response to a program call of fork or vfork is \"parent\"..*$gdb_prompt $"\
- {pass "explicit show parent follow, no catchpoints"}
- -re "$gdb_prompt $" {fail "explicit show parent follow, no catchpoints"}
- timeout {fail "(timeout) explicit show parent follow, no catchpoints"}
- }
- send_gdb "next 2\n"
- gdb_expect {
- -re "Detaching after fork from.*$gdb_prompt $"\
- {pass "explicit parent follow, no catchpoints"}
- -re "$gdb_prompt $" {fail "explicit parent follow, no catchpoints"}
- timeout {fail "(timeout) explicit parent follow, no catchpoints"}
- }
- # The child has been detached; allow time for any output it might
- # generate to arrive, so that output doesn't get confused with
- # any expected debugger output from a subsequent testpoint.
- #
- exec sleep 1
-}
+ # Set detach-on-fork mode if we aren't using the default.
+ if {$detach == "default"} {
+ set detach "on"
+ } else {
+ gdb_test_no_output "set detach-on-fork $detach"
+ }
+
+ gdb_test "show detach-on-fork" \
+ "Whether gdb will detach.* fork is $detach." \
+ "show detach-on-fork"
+
+ # Set a breakpoint after the fork if we aren't single-stepping
+ # past the fork.
+ if {$cmd == "continue"} {
+ set bp_after_fork [gdb_get_line_number "set breakpoint here"]
+ gdb_test "break ${srcfile}:$bp_after_fork" \
+ "Breakpoint.*, line $bp_after_fork.*" \
+ "set breakpoint after fork"
+ }
+
+ # Set up the output we expect to see after we run.
+ set expected_re ""
+ if {$who == "child"} {
+ set expected_re "Attaching after.* fork to.*"
+ if {$detach == "on"} {
+ append expected_re "Detaching after fork from .*"
+ }
+ append expected_re "set breakpoint here.*"
+ } elseif {$who == "parent" && $detach == "on"} {
+ set expected_re "Detaching after fork from .*set breakpoint here.*"
+ } else {
+ set expected_re ".*set breakpoint here.*"
+ }
+
+ # Test running past and following the fork, using the parameters
+ # set above.
+ gdb_test $cmd $expected_re "$cmd past fork"
+
+ # Check that we have the inferiors arranged correctly after
+ # following the fork.
+ set resume_unfollowed 0
+ if {$who == "parent" && $detach == "on"} {
+
+ # Follow parent / detach child: the only inferior is the parent.
+ gdb_test "info inferiors" "\\* 1 .* process.*" \
+ "info inferiors"
+
+ } elseif {$who == "parent" && $detach == "off"} {
+
+ # Follow parent / keep child: two inferiors under debug, the
+ # parent is the current inferior.
+ gdb_test "info inferiors" "\\* 1 .*process.* 2 .*process.*" \
+ "info inferiors"
+
+ gdb_test "inferior 2" "Switching to inferior 2 .*"
+ set resume_unfollowed 1
+
+ } elseif {$who == "child" && $detach == "on"} {
+
+ # Follow child / detach parent: the child is under debug and is
+ # the current inferior. The parent is listed but is not under
+ # debug.
+ gdb_test "info inferiors" " 1 .*<null>.*\\* 2 .*process.*" \
+ "info inferiors"
+
+ } elseif {$who == "child" && $detach == "off"} {
+
+ # Follow child / keep parent: two inferiors under debug, the
+ # child is the current inferior.
+ gdb_test "info inferiors" " 1 .*process.*\\* 2 .*process.*" \
+ "info inferiors"
+
+ gdb_test "inferior 1" "Switching to inferior 1 .*"
+ set resume_unfollowed 1
+ }
+
+ if {$resume_unfollowed == 1} {
+ if {$cmd == "next 2"} {
+
+ gdb_continue_to_end "continue unfollowed inferior to end"
-proc explicit_fork_child_follow {} {
- global gdb_prompt
-
- send_gdb "set follow child\n"
- gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child"}
- timeout {fail "(timeout) set follow child"}
- }
- send_gdb "show follow\n"
- gdb_expect {
- -re "Debugger response to a program call of fork or vfork is \"child\"..*$gdb_prompt $"\
- {pass "explicit show child follow, no catchpoints"}
- -re "$gdb_prompt $" {fail "explicit show child follow, no catchpoints"}
- timeout {fail "(timeout) explicit show child follow, no catchpoints"}
- }
- send_gdb "next 2\n"
- gdb_expect {
- -re "Detaching from program:.*Attaching after fork to.*$gdb_prompt $"\
- {pass "explicit child follow, no catchpoints"}
- -re "$gdb_prompt $" {fail "explicit child follow, no catchpoints"}
- timeout {fail "(timeout) explicit child follow, no catchpoints"}
- }
- # The child has been detached; allow time for any output it might
- # generate to arrive, so that output doesn't get confused with
- # any gdb_expected debugger output from a subsequent testpoint.
- #
- exec sleep 1
+ } elseif {$cmd == "continue"} {
+
+ gdb_continue_to_breakpoint \
+ "continue unfollowed inferior to bp" \
+ ".* set breakpoint here.*"
+ }
+ }
+ }
}
proc catch_fork_child_follow {} {
- global gdb_prompt
-
- send_gdb "catch fork\n"
- gdb_expect {
- -re "Catchpoint .*(fork).*$gdb_prompt $"\
- {pass "explicit child follow, set catch fork"}
- -re "$gdb_prompt $" {fail "explicit child follow, set catch fork"}
- timeout {fail "(timeout) explicit child follow, set catch fork"}
- }
-
- # Verify that the catchpoint is mentioned in an "info breakpoints",
- # and further that the catchpoint mentions no process id.
- #
- send_gdb "info breakpoints\n"
- gdb_expect {
- -re ".*catch fork.*keep y.*$gdb_prompt $"\
- {pass "info shows catchpoint without pid"}
- -re ".*catch fork.*process .*$gdb_prompt $"\
- {fail "info shows catchpoint without pid"}
- -re "$gdb_prompt $" {fail "info shows catchpoint without pid"}
- timeout {fail "(timeout) info shows catchpoint without pid"}
- }
-
- send_gdb "continue\n"
- gdb_expect {
- -re "Catchpoint.*(forked process.*),.*in _fork_sys.*$gdb_prompt $"\
- {pass "explicit child follow, catch fork"}
- -re "$gdb_prompt $" {fail "explicit child follow, catch fork"}
- timeout {fail "(timeout) explicit child follow, catch fork"}
- }
-
- # Verify that the catchpoint is mentioned in an "info breakpoints",
- # and further that the catchpoint managed to capture a process id.
- #
- send_gdb "info breakpoints\n"
- gdb_expect {
- -re ".*catch fork .*process \[0-9\]+.*$gdb_prompt $"\
- {pass "info shows catchpoint pid"}
- -re "$gdb_prompt $" {fail "info shows catchpoint pid"}
- timeout {fail "(timeout) info shows catchpoint pid"}
- }
-
- send_gdb "set follow child\n"
- gdb_expect {
- -re "$gdb_prompt $" {pass "set follow child"}
- timeout {fail "(timeout) set follow child"}
- }
- send_gdb "tbreak 24\n"
- gdb_expect {
- -re "Breakpoint.*, line 24.*$gdb_prompt $"\
- {pass "set follow child, tbreak"}
- -re "$gdb_prompt $" {fail "set follow child, tbreak"}
- timeout {fail "(timeout) set follow child, tbreak"}
- }
- send_gdb "continue\n"
- gdb_expect {
- -re ".*Detaching from program:.*Attaching after fork to.* at .*24.*$gdb_prompt $"\
- {pass "set follow child, hit tbreak"}
- -re "$gdb_prompt $" {fail "set follow child, hit tbreak"}
- timeout {fail "(timeout) set follow child, hit tbreak"}
- }
- # The child has been detached; allow time for any output it might
- # generate to arrive, so that output doesn't get confused with
- # any expected debugger output from a subsequent testpoint.
- #
- exec sleep 1
- send_gdb "delete breakpoints\n"
- gdb_expect {
- -re "Delete all breakpoints.*$" {
- send_gdb "y\n"
- gdb_expect {
- -re "$gdb_prompt $"\
- {pass "set follow child, cleanup"}
- timeout {fail "(timeout) set follow child, cleanup"}
- }
- }
- -re "$gdb_prompt $" {fail "set follow child, cleanup"}
- timeout {fail "(timeout) set follow child, cleanup"}
- }
+ global gdb_prompt
+ global srcfile
+
+ set bp_after_fork [gdb_get_line_number "set breakpoint here"]
+
+ gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" \
+ "explicit child follow, set catch fork"
+
+ # Verify that the catchpoint is mentioned in an "info breakpoints",
+ # and further that the catchpoint mentions no process id.
+ #
+ set test_name "info shows catchpoint without pid"
+ gdb_test_multiple "info breakpoints" "$test_name" {
+ -re ".*catchpoint.*keep y.*fork\[\r\n\]+$gdb_prompt $" {
+ pass "$test_name"
+ }
+ }
+
+ gdb_test "continue" \
+ "Catchpoint \[0-9\]* \\(forked process \[0-9\]*\\),.*" \
+ "explicit child follow, catch fork"
+
+ # Verify that the catchpoint is mentioned in an "info breakpoints",
+ # and further that the catchpoint managed to capture a process id.
+ #
+ set test_name "info shows catchpoint without pid"
+ gdb_test_multiple "info breakpoints" "$test_name" {
+ -re ".*catchpoint.*keep y.*fork, process.*$gdb_prompt $" {
+ pass "$test_name"
+ }
+ }
+
+ gdb_test_no_output "set follow-fork child"
+
+ gdb_test "tbreak ${srcfile}:$bp_after_fork" \
+ "Temporary breakpoint.*, line $bp_after_fork.*" \
+ "set follow-fork child, tbreak"
+
+ set expected_re "Attaching after.* fork to.*Detaching after fork from"
+ append expected_re ".* at .*$bp_after_fork.*"
+ gdb_test "continue" $expected_re "set follow-fork child, hit tbreak"
+
+ # The parent has been detached; allow time for any output it might
+ # generate to arrive, so that output doesn't get confused with
+ # any expected debugger output from a subsequent testpoint.
+ #
+ exec sleep 1
+
+ gdb_test "delete breakpoints" \
+ "" \
+ "set follow-fork child, cleanup" \
+ "Delete all breakpoints. \\(y or n\\) $" \
+ "y"
+}
+
+proc catch_fork_unpatch_child {} {
+ global gdb_prompt
+ global srcfile
+
+ set bp_exit [gdb_get_line_number "at exit"]
+
+ gdb_test "break callee" "file .*$srcfile, line .*" \
+ "unpatch child, break at callee"
+ gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" \
+ "unpatch child, set catch fork"
+
+ gdb_test "continue" \
+ "Catchpoint \[0-9\]* \\(forked process \[0-9\]*\\),.*" \
+ "unpatch child, catch fork"
+
+ # Delete all breakpoints and catchpoints.
+ delete_breakpoints
+
+ # Force $srcfile as the current GDB source can be in glibc sourcetree.
+ gdb_test "break $srcfile:$bp_exit" \
+ "Breakpoint .*file .*$srcfile, line .*" \
+ "unpatch child, breakpoint at exit call"
+
+ gdb_test_no_output "set follow-fork child" \
+ "unpatch child, set follow-fork child"
+
+ set test "unpatch child, unpatched parent breakpoints from child"
+ gdb_test_multiple "continue" $test {
+ -re "at exit.*$gdb_prompt $" {
+ pass "$test"
+ }
+ -re "SIGTRAP.*$gdb_prompt $" {
+ fail "$test"
+
+ # Explicitly kill this child, so we can continue gracefully
+ # with further testing...
+ send_gdb "kill\n"
+ gdb_expect {
+ -re ".*Kill the program being debugged.*y or n. $" {
+ send_gdb "y\n"
+ gdb_expect -re "$gdb_prompt $" {}
+ }
+ }
+ }
+ }
}
proc tcatch_fork_parent_follow {} {
- global gdb_prompt
-
- send_gdb "catch fork\n"
- gdb_expect {
- -re "Catchpoint .*(fork).*$gdb_prompt $"\
- {pass "explicit parent follow, set tcatch fork"}
- -re "$gdb_prompt $" {fail "explicit parent follow, set tcatch fork"}
- timeout {fail "(timeout) explicit parent follow, set tcatch fork"}
- }
+ global gdb_prompt
+ global srcfile
+
+ set bp_after_fork [gdb_get_line_number "set breakpoint here"]
+
+ gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" \
+ "explicit parent follow, set tcatch fork"
+
# ??rehrauer: I don't yet know how to get the id of the tcatch
# via this script, so that I can add a -do list to it. For now,
# do the follow stuff after the catch happens.
- send_gdb "continue\n"
- gdb_expect {
- -re ".*in _fork_sys.*$gdb_prompt $"\
- {pass "explicit parent follow, tcatch fork"}
- -re "$gdb_prompt $" {fail "explicit parent follow, tcatch fork"}
- timeout {fail "(timeout) explicit parent follow, tcatch fork"}
- }
- send_gdb "set follow parent\n"
- gdb_expect {
- -re "$gdb_prompt $" {pass "set follow parent"}
- timeout {fail "(timeout) set follow parent"}
- }
- send_gdb "tbreak 24\n"
- gdb_expect {
- -re "Breakpoint.*, line 24.*$gdb_prompt $"\
- {pass "set follow parent, tbreak"}
- -re "$gdb_prompt $" {fail "set follow parent, tbreak"}
- timeout {fail "(timeout) set follow child, tbreak"}
- }
- send_gdb "continue\n"
- gdb_expect {
- -re ".*Detaching after fork from.* at .*24.*$gdb_prompt $"\
- {pass "set follow parent, hit tbreak"}
- -re "$gdb_prompt $" {fail "set follow parent, hit tbreak"}
- timeout {fail "(timeout) set follow parent, hit tbreak"}
- }
- # The child has been detached; allow time for any output it might
- # generate to arrive, so that output doesn't get confused with
- # any expected debugger output from a subsequent testpoint.
- #
- exec sleep 1
- send_gdb "delete breakpoints\n"
- gdb_expect {
- -re "Delete all breakpoints.*$" {
- send_gdb "y\n"
- gdb_expect {
- -re "$gdb_prompt $"\
- {pass "set follow parent, cleanup"}
- timeout {fail "(timeout) set follow parent, cleanup"}
- }
- }
- -re "$gdb_prompt $" {fail "set follow parent, cleanup"}
- timeout {fail "(timeout) set follow parent, cleanup"}
- }
+ gdb_test "continue" \
+ "Catchpoint \[0-9\]* \\(forked process \[0-9\]*\\),.*" \
+ "explicit parent follow, tcatch fork"
+
+ gdb_test_no_output "set follow-fork parent"
+
+ gdb_test "tbreak ${srcfile}:$bp_after_fork" \
+ "Temporary breakpoint.*, line $bp_after_fork.*" \
+ "set follow-fork parent, tbreak"
+
+ gdb_test "continue" \
+ "Detaching after fork from.* at .*$bp_after_fork.*" \
+ "set follow-fork parent, hit tbreak"
+
+ # The child has been detached; allow time for any output it might
+ # generate to arrive, so that output doesn't get confused with
+ # any expected debugger output from a subsequent testpoint.
+ #
+ exec sleep 1
+
+ gdb_test "delete breakpoints" \
+ "" \
+ "set follow-fork parent, cleanup" \
+ "Delete all breakpoints. \\(y or n\\) $" \
+ "y"
}
proc do_fork_tests {} {
- global gdb_prompt
+ global gdb_prompt
+ global testfile
- # Verify that help is available for "set follow-fork-mode".
- #
- send_gdb "help set follow-fork-mode\n"
- gdb_expect {
- -re "Set debugger response to a program call of fork or vfork..*
+ # Verify that help is available for "set follow-fork-mode".
+ #
+ gdb_test "help set follow-fork-mode" \
+ "Set debugger response to a program call of fork or vfork..*
A fork or vfork creates a new process. follow-fork-mode can be:.*
.*parent - the original process is debugged after a fork.*
.*child - the new process is debugged after a fork.*
-.*ask - the debugger will ask for one of the above choices.*
-For \"parent\" or \"child\", the unfollowed process will run free..*
-By default, the debugger will follow the parent process..*$gdb_prompt $"\
- { pass "help set follow" }
- -re "$gdb_prompt $" { fail "help set follow" }
- timeout { fail "(timeout) help set follow" }
- }
-
- # Verify that we can set follow-fork-mode, using an abbreviation
- # for both the flag and its value.
- #
- send_gdb "set follow ch\n"
- send_gdb "show fol\n"
- gdb_expect {
- -re "Debugger response to a program call of fork or vfork is \"child\".*$gdb_prompt $"\
- {pass "set follow, using abbreviations"}
- timeout {fail "(timeout) set follow, using abbreviations"}
- }
-
- # Verify that we cannot set follow-fork-mode to nonsense.
- #
- send_gdb "set follow chork\n"
- gdb_expect {
- -re "Undefined item: \"chork\".*$gdb_prompt $"\
- {pass "set follow to nonsense is prohibited"}
- -re "$gdb_prompt $" {fail "set follow to nonsense is prohibited"}
- timeout {fail "(timeout) set follow to nonsense is prohibited"}
- }
- send_gdb "set follow parent\n"
- gdb_expect {
- -re "$gdb_prompt $" {pass "set follow to nonsense is prohibited (reset parent)"}
- timeout {fail "set follow to nonsense is prohibited (reset parent)"}
- }
-
- # Test the default behaviour, which is to follow the parent of a
- # fork, and detach from the child. Do this without catchpoints.
- #
- if [runto_main] then { default_fork_parent_follow }
-
- # Test the ability to explicitly follow the parent of a fork, and
- # detach from the child. Do this without catchpoints.
- #
- if [runto_main] then { explicit_fork_parent_follow }
-
- # Test the ability to follow the child of a fork, and detach from
- # the parent. Do this without catchpoints.
- #
- if [runto_main] then { explicit_fork_child_follow }
-
- # Test the ability to follow both child and parent of a fork. Do
- # this without catchpoints.
- # ??rehrauer: NYI. Will add testpoints here when implemented.
- #
-
- # Test the ability to have the debugger ask the user at fork-time
- # whether to follow the parent, child or both. Do this without
- # catchpoints.
- # ??rehrauer: NYI. Will add testpoints here when implemented.
- #
-
- # Test the ability to catch a fork, specify that the child be
- # followed, and continue. Make the catchpoint permanent.
- #
- if [runto_main] then { catch_fork_child_follow }
-
- # Test the ability to catch a fork, specify via a -do clause that
- # the parent be followed, and continue. Make the catchpoint temporary.
- #
- if [runto_main] then { tcatch_fork_parent_follow }
-}
+The unfollowed process will continue to run..*
+By default, the debugger will follow the parent process..*" \
+ "help set follow-fork"
+
+ # Verify that we can set follow-fork-mode, using an abbreviation
+ # for both the flag and its value.
+ #
+ gdb_test_no_output "set follow-fork ch"
+
+ gdb_test "show follow-fork" \
+ "Debugger response to a program call of fork or vfork is \"child\".*" \
+ "set follow-fork, using abbreviations"
+
+ # Verify that we cannot set follow-fork-mode to nonsense.
+ #
+ gdb_test "set follow-fork chork" "Undefined item: \"chork\".*" \
+ "set follow-fork to nonsense is prohibited"
+
+ gdb_test_no_output "set follow-fork parent" "reset parent"
+
+ # Check that fork catchpoints are supported, as an indicator for whether
+ # fork-following is supported.
+ if [runto_main] then { check_fork_catchpoints }
+
+ # Test the basic follow-fork functionality using all combinations of
+ # values for follow-fork-mode and detach-on-fork, using either a
+ # breakpoint or single-step to execute past the fork.
+ #
+ # The first loop should be sufficient to test the defaults. There
+ # is no need to test using the defaults in other permutations (e.g.
+ # "default" "on", "parent" "default", etc.).
+ foreach cmd {"next 2" "continue"} {
+ test_follow_fork "default" "default" $cmd
+ }
+
+ # Now test all explicit permutations.
+ foreach who {"parent" "child"} {
+ foreach detach {"on" "off"} {
+ foreach cmd {"next 2" "continue"} {
+ test_follow_fork $who $detach $cmd
+ }
+ }
+ }
-# Start with a fresh gdb
+ # Catchpoint tests.
-gdb_exit
-gdb_start
-gdb_reinitialize_dir $srcdir/$subdir
-gdb_load ${binfile}
+ # Restart to eliminate any effects of the follow-fork tests.
+ clean_restart $testfile
+ gdb_test_no_output "set verbose"
+
+ # Test the ability to catch a fork, specify that the child be
+ # followed, and continue. Make the catchpoint permanent.
+ #
+ if [runto_main] then { catch_fork_child_follow }
+
+ # Test that parent breakpoints are successfully detached from the
+ # child at fork time, even if the user removes them from the
+ # breakpoints list after stopping at a fork catchpoint.
+ if [runto_main] then { catch_fork_unpatch_child }
+
+ # Test the ability to catch a fork, specify via a -do clause that
+ # the parent be followed, and continue. Make the catchpoint temporary.
+ #
+ if [runto_main] then { tcatch_fork_parent_follow }
+}
+# The "Detaching..." and "Attaching..." messages may be hidden by
+# default.
+gdb_test_no_output "set verbose"
# This is a test of gdb's ability to follow the parent, child or both
# parent and child of a Unix fork() system call.