aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/infrun.c8
-rw-r--r--gdb/testsuite/gdb.base/vfork-follow-parent.c29
-rw-r--r--gdb/testsuite/gdb.base/vfork-follow-parent.exp50
3 files changed, 75 insertions, 12 deletions
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 8286026..72852e6 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -713,7 +713,7 @@ holding the child stopped. Try \"set detach-on-fork\" or \
(do not restore the parent as the current inferior). */
gdb::optional<scoped_restore_current_thread> maybe_restore;
- if (!follow_child)
+ if (!follow_child && !sched_multi)
maybe_restore.emplace ();
switch_to_thread (*child_inf->threads ().begin ());
@@ -3400,8 +3400,10 @@ proceed (CORE_ADDR addr, enum gdb_signal siggnal)
struct gdbarch *gdbarch;
CORE_ADDR pc;
- /* If we're stopped at a fork/vfork, follow the branch set by the
- "set follow-fork-mode" command; otherwise, we'll just proceed
+ /* If we're stopped at a fork/vfork, switch to either the parent or child
+ thread as defined by the "set follow-fork-mode" command, or, if both
+ the parent and child are controlled by GDB, and schedule-multiple is
+ on, follow the child. If none of the above apply then we just proceed
resuming the current thread. */
if (!follow_fork ())
{
diff --git a/gdb/testsuite/gdb.base/vfork-follow-parent.c b/gdb/testsuite/gdb.base/vfork-follow-parent.c
index df45b9c..15ff84a 100644
--- a/gdb/testsuite/gdb.base/vfork-follow-parent.c
+++ b/gdb/testsuite/gdb.base/vfork-follow-parent.c
@@ -17,6 +17,10 @@
#include <unistd.h>
+#include <string.h>
+#include <limits.h>
+#include <stdio.h>
+
static volatile int unblock_parent = 0;
static void
@@ -25,7 +29,7 @@ break_parent (void)
}
int
-main (void)
+main (int argc, char **argv)
{
alarm (30);
@@ -40,7 +44,28 @@ main (void)
break_parent ();
}
else
- _exit (0);
+ {
+#if defined TEST_EXEC
+ char prog[PATH_MAX];
+ int len;
+
+ strcpy (prog, argv[0]);
+ len = strlen (prog);
+ for (; len > 0; --len)
+ {
+ if (prog[len - 1] == '/')
+ break;
+ }
+ strcpy (&prog[len], "vforked-prog");
+ execlp (prog, prog, (char *) 0);
+ perror ("exec failed");
+ _exit (1);
+#elif defined TEST_EXIT
+ _exit (0);
+#else
+#error Define TEST_EXEC or TEST_EXIT
+#endif
+ }
return 0;
}
diff --git a/gdb/testsuite/gdb.base/vfork-follow-parent.exp b/gdb/testsuite/gdb.base/vfork-follow-parent.exp
index 89c3800..70b54e7 100644
--- a/gdb/testsuite/gdb.base/vfork-follow-parent.exp
+++ b/gdb/testsuite/gdb.base/vfork-follow-parent.exp
@@ -19,10 +19,28 @@
# schedule-multiple on" or "set detach-on-fork on". Test these two resolution
# methods.
-standard_testfile
+standard_testfile .c vforked-prog.c
-if { [build_executable "failed to prepare" \
- ${testfile} ${srcfile}] } {
+set binfile ${testfile}-exit
+set binfile2 ${testfile}-exec
+set binfile3 vforked-prog
+
+if { [build_executable "compile $binfile3" $binfile3 $srcfile2] } {
+ untested "failed to compile third test binary"
+ return -1
+}
+
+set remote_exec_prog [gdb_remote_download target $binfile3]
+
+set opts [list debug additional_flags=-DTEST_EXIT]
+if { [build_executable "compile ${binfile}" ${binfile} ${srcfile} ${opts}] } {
+ untested "failed to compile first test binary"
+ return
+}
+
+set opts [list debug additional_flags=-DTEST_EXEC]
+if { [build_executable "compile ${binfile2}" ${binfile2} ${srcfile} ${opts}] } {
+ untested "failed to compile second test binary"
return
}
@@ -31,8 +49,12 @@ if { [build_executable "failed to prepare" \
# or "schedule-multiple" (the two alternatives the message suggests to the
# user).
-proc do_test { resolution_method } {
- clean_restart $::binfile
+proc do_test { exec_file resolution_method target_non_stop non_stop } {
+ save_vars { ::GDBFLAGS } {
+ append ::GDBFLAGS " -ex \"maint set target-non-stop ${target_non_stop}\""
+ append ::GDBFLAGS " -ex \"set non-stop ${non_stop}\""
+ clean_restart $exec_file
+ }
gdb_test_no_output "set detach-on-fork off"
@@ -40,6 +62,10 @@ proc do_test { resolution_method } {
return
}
+ # Delete the breakpoint on main so we don't bit the breakpoint in
+ # the case that the vfork child performs an exec.
+ delete_breakpoints
+
gdb_test "break break_parent"
gdb_test "continue" \
@@ -75,6 +101,16 @@ proc do_test { resolution_method } {
"continue to break_parent"
}
-foreach_with_prefix resolution_method {detach-on-fork schedule-multiple} {
- do_test $resolution_method
+foreach_with_prefix exec_file [list $binfile $binfile2] {
+ foreach_with_prefix target-non-stop {on off} {
+ # This test was written assuming non-stop mode is off.
+ foreach_with_prefix non-stop {off} {
+ if {!${target-non-stop} && ${non-stop}} {
+ continue
+ }
+ foreach_with_prefix resolution_method {detach-on-fork schedule-multiple} {
+ do_test $exec_file $resolution_method ${target-non-stop} ${non-stop}
+ }
+ }
+ }
}