diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 66b1729..eabf262 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -419,8 +419,8 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
if (debug_threads)
{
- debug_printf ("HEW: Got fork event from LWP %ld, "
- "new child is %d\n",
+ debug_printf ("HEW: Got fork event "
+ "from LWP %ld, new child is %d\n",
ptid_get_lwp (ptid_of (event_thr)),
ptid_get_pid (ptid));
}
@@ -1045,6 +1045,24 @@ linux_kill (int pid)
{
struct process_info *process;
struct lwp_info *lwp;
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+
+ /* If we're stopped while forking and we haven't followed yet,
+ kill the child task. We need to do this first because the
+ parent will be sleeping if this is a vfork. */
+
+ get_last_target_status (&last_ptid, &last);
+
+ if (last.kind == TARGET_WAITKIND_FORKED
+ || last.kind == TARGET_WAITKIND_VFORKED)
+ {
+ lwp = find_lwp_pid (last.value.related_pid);
+ gdb_assert (lwp != NULL);
+ kill_wait_lwp (lwp);
+ process = find_process_pid (ptid_get_pid (last.value.related_pid));
+ the_target->mourn (process);
+ }
process = find_process_pid (pid);
if (process == NULL)
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 57190f6..f525d3e 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1301,6 +1301,15 @@ handle_qxfer_threads_worker (struct inferior_list_entry *inf, void *arg)
int core = target_core_of_thread (ptid);
char core_s[21];
+ /* Skip new threads created as the result of a fork if we are not done
+ handling that fork event. We won't know whether to tell GDB about
+ the new thread until we are done following the fork. */
+ if ((last_status.kind == TARGET_WAITKIND_FORKED
+ || last_status.kind == TARGET_WAITKIND_VFORKED)
+ && (ptid_get_pid (last_status.value.related_pid)
+ == ptid_get_pid (ptid)))
+ return;
+
write_ptid (ptid_s, ptid);
if (core != -1)
@@ -3992,3 +4001,12 @@ handle_target_event (int err, gdb_client_data client_data)
return 0;
}
+
+/* Retrieve the last waitstatus reported to GDB. */
+
+void
+get_last_target_status (ptid_t *ptid, struct target_waitstatus *last)
+{
+ *ptid = last_ptid;
+ *last = last_status;
+}
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 5284dac..86e584e 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -102,6 +102,8 @@ typedef int gdb_fildes_t;
/* Functions from server.c. */
extern int handle_serial_event (int err, gdb_client_data client_data);
extern int handle_target_event (int err, gdb_client_data client_data);
+extern void get_last_target_status (ptid_t *ptid,
+ struct target_waitstatus *last);
#include "remote-utils.h"
diff --git a/gdb/remote.c b/gdb/remote.c
index 6ea3c60..d59309f 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1449,7 +1449,6 @@ remote_fork_event_p (struct remote_state *rs)
return packet_support (PACKET_fork_event_feature) == PACKET_ENABLE;
}
-#if PTRACE_FORK_EVENTS
/* Returns true if vfork events are supported. */
static int
@@ -1457,7 +1456,7 @@ remote_vfork_event_p (struct remote_state *rs)
{
return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE;
}
-#endif
+
/* Target follow-fork function for remote targets. On entry, and
at return, the current inferior is the fork parent.
@@ -1509,6 +1508,46 @@ remote_follow_fork (struct target_ops *target, int follow_child,
return 0;
}
+/* Insert fork catchpoint target routine. If fork events are enabled
+ then return success, nothing more to do. */
+
+static int
+remote_insert_fork_catchpoint (struct target_ops *ops, int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return !remote_fork_event_p (rs);
+}
+
+/* Remove fork catchpoint target routine. Nothing to do, just
+ return success. */
+
+static int
+remote_remove_fork_catchpoint (struct target_ops *ops, int pid)
+{
+ return 0;
+}
+
+/* Insert vfork catchpoint target routine. If vfork events are enabled
+ then return success, nothing more to do. */
+
+static int
+remote_insert_vfork_catchpoint (struct target_ops *ops, int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return !remote_vfork_event_p (rs);
+}
+
+/* Remove vfork catchpoint target routine. Nothing to do, just
+ return success. */
+
+static int
+remote_remove_vfork_catchpoint (struct target_ops *ops, int pid)
+{
+ return 0;
+}
+
/* Tokens for use by the asynchronous signal handlers for SIGINT. */
static struct async_signal_handler *async_sigint_remote_twice_token;
static struct async_signal_handler *async_sigint_remote_token;
@@ -11766,6 +11805,10 @@ Specify the serial device it is connected to\n\
remote_ops.to_augmented_libraries_svr4_read =
remote_augmented_libraries_svr4_read;
remote_ops.to_follow_fork = remote_follow_fork;
+ remote_ops.to_insert_fork_catchpoint = remote_insert_fork_catchpoint;
+ remote_ops.to_remove_fork_catchpoint = remote_remove_fork_catchpoint;
+ remote_ops.to_insert_vfork_catchpoint = remote_insert_vfork_catchpoint;
+ remote_ops.to_remove_vfork_catchpoint = remote_remove_vfork_catchpoint;
}
/* Set up the extended remote vector by making a copy of the standard
diff --git a/gdb/testsuite/gdb.base/foll-fork.exp b/gdb/testsuite/gdb.base/foll-fork.exp
index 3f2d224..697570d 100644
--- a/gdb/testsuite/gdb.base/foll-fork.exp
+++ b/gdb/testsuite/gdb.base/foll-fork.exp
@@ -13,8 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-if { [is_remote target] || ![isnative] } then {
- continue
+if {![isnative]} then {
+ return 0
}
# Until "set follow-fork-mode" and "catch fork" are implemented on
diff --git a/gdb/testsuite/gdb.base/foll-vfork.exp b/gdb/testsuite/gdb.base/foll-vfork.exp
index 78c5cc8..ec8db33 100644
--- a/gdb/testsuite/gdb.base/foll-vfork.exp
+++ b/gdb/testsuite/gdb.base/foll-vfork.exp
@@ -18,8 +18,8 @@
# either execs or exits --- since those events take somewhat different
# code paths in GDB, both variants are exercised.
-if { [is_remote target] || ![isnative] } then {
- continue
+if {![isnative]} then {
+ return 0
}
# Until "set follow-fork-mode" and "catch vfork" are implemented on
diff --git a/gdb/testsuite/gdb.threads/fork-child-threads.exp b/gdb/testsuite/gdb.threads/fork-child-threads.exp
index 75e60e1..3815c92 100644
--- a/gdb/testsuite/gdb.threads/fork-child-threads.exp
+++ b/gdb/testsuite/gdb.threads/fork-child-threads.exp
@@ -13,12 +13,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-# Only GNU/Linux is known to support `set follow-fork-mode child'.
-if { ! [istarget "*-*-linux*"] } {
+if {![isnative] } then {
return 0
}
-if { [is_remote target] || ![isnative] } then {
+# Only GNU/Linux is known to support `set follow-fork-mode child'.
+if { ! [istarget "*-*-linux*"] } {
return 0
}
diff --git a/gdb/testsuite/gdb.threads/fork-thread-pending.exp b/gdb/testsuite/gdb.threads/fork-thread-pending.exp
index d229232..bbd980a 100644
--- a/gdb/testsuite/gdb.threads/fork-thread-pending.exp
+++ b/gdb/testsuite/gdb.threads/fork-thread-pending.exp
@@ -13,9 +13,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
-# There's no support for `set follow-fork-mode' in the remote
-# protocol.
-if { [is_remote target] } {
+if {![isnative]} {
return 0
}
@@ -31,6 +29,26 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab
return -1
}
+# Find a thread that did not fork and is not the main thread and
+# return its thread number. We can't just hard-code the thread
+# number since we have no guarantee as to the ordering of the threads
+# in gdb. We know that the main thread is in pthread_join and the
+# forking thread is in fork, so we use this rather ungainly regexp
+# to capture an entry from 'info threads' that doesn't show one of
+# those routines, then extract the thread number.
+
+proc find_unforked_thread { } {
+ gdb_test_multiple "info threads" "find unforked thread" {
+ -re "(\[^\r]*Thread\[^\r]* in \[^fp]\[^ot]\[^rh]\[^kr]\[^e]\[^a]\[^d]\[^_]\[^j]\[^\r]*\r\n)" {
+ regexp "(\[ ]*)(\[0-9]*)(\[ ]*Thread\[^\r]*\r\n)" $expect_out(0,string) ignore lead_spc threadnum rest
+ }
+ timeout {
+ set threadnum -1
+ }
+ }
+ return $threadnum
+}
+
clean_restart ${binfile}
if ![runto_main] then {
@@ -46,7 +64,8 @@ gdb_test "continue" "Catchpoint.*" "1, get to the fork event"
gdb_test "info threads" " Thread .* Thread .* Thread .* Thread .*" "1, multiple threads found"
-gdb_test "thread 1" ".*" "1, switched away from event thread"
+set threadnum [find_unforked_thread]
+gdb_test "thread $threadnum" ".*" "1, switched away from event thread to thread $threadnum"
gdb_test "continue" "Not resuming.*" "1, refused to resume"
diff --git a/gdb/testsuite/gdb.threads/watchpoint-fork.exp b/gdb/testsuite/gdb.threads/watchpoint-fork.exp
index a4557f8..a1dbd10 100644
--- a/gdb/testsuite/gdb.threads/watchpoint-fork.exp
+++ b/gdb/testsuite/gdb.threads/watchpoint-fork.exp
@@ -17,9 +17,8 @@
set testfile watchpoint-fork
-if [is_remote target] {
- kfail "remote/13584" "gdbserver does not support debugging across fork"
- return
+if {![isnative]} {
+ return 0
}
proc test {type symbol} {