public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Don Breazeal <donb@codesourcery.com>
To: <gdb-patches@sourceware.org>
Subject: [PATCH 09/16 v2] Extended-remote fork catchpoints
Date: Thu, 21 Aug 2014 00:33:00 -0000	[thread overview]
Message-ID: <1408580964-27916-10-git-send-email-donb@codesourcery.com> (raw)
In-Reply-To: <1407434395-19089-1-git-send-email-donb@codesourcery.com>

This patch implements catchpoints for fork events on extended-remote linux
targets.

Implementation appeared to be straightforward, requiring four new functions
in remote.c to implement insert/remove of fork/vfork catchpoints.  These
functions are essentially stubs that just return 0 ('success').  If the
fork events were being reported, then catchpoints were set and hit.

However, there are some extra issues that arise with catchpoints.

1) Thread creation reporting -- fork catchpoints are hit before the
   follow_fork has been completed.  In the native implementation, the new
   process is not 'reported' until after the follow is done.  It doesn't
   show up in the inferiors list or the threads list.  However, in
   gdbserver, an 'info threads' will retrieve the new thread info from the
   target and add it to GDB's data structures.  Because of this premature
   report, things on the GDB side eventually get very confused.

   So in gdbserver, in server.c:handle_qxfer_threads_worker, we check
   'last_status' and if it shows a FORK event, we know that we are in an
   unfollowed fork and we do not report the new (forked) thread to GDB.

2) Kill process before fork is followed -- on the native side in
   linux-nat.c:linux_nat_kill, there is some code to handle the case where
   a fork has occurred but follow_fork hasn't been called yet.  It does
   this by using the last status to determine if a follow is pending, and
   if it is, to kill the child task.  I implemented similar code in
   linux-low.c:linux_kill.

3) One of the tests related to fork catchpoints,
   gdb.threads/fork-thread-pending.exp, depended on the threads being
   reported in a specific order.  GDBserver reported the threads in a
   different order, that is, 'info threads' showed the same threads, but in
   a different order.  The test used a hard-coded thread number to find a
   threads that (a) was not the main thread (blocked in pthread_join), and
   (b) was not the forking thread (stopped in fork).

   I implemented a new proc, find_unforked_thread, that uses a pretty
   brute-force method of finding a thread.  I considered just hard-coding
   another number (the native case used thread 2, which was the forking
   thread in the remote case), but that didn't seem future-proof.
   Suggestions on how to do this better would be welcome.
  
Tested on x64 Ubuntu Lucid, native, remote, extended-remote.  Tested the
case of killing the forking process before the fork has been followed
manually.  It wasn't clear to me how to check that a process had actually
been killed from a dejagnu test.

Thanks
--Don

gdb/
2014-08-20  Don Breazeal  <donb@codesourcery.com>
	* remote.c (extended_remote_insert_fork_catchpoint): New function.
	(extended_remote_remove_fork_catchpoint): New function.
	(extended_remote_insert_vfork_catchpoint): New function.
	(extended_remote_remove_vfork_catchpoint): New function.
	(init_extended_remote_ops): Initialize target vector with
	new fork catchpoint functions.

gdb/gdbserver/
2014-08-20  Don Breazeal  <donb@codesourcery.com>

	* linux-low.c (handle_extended_wait): Fix braces in multi-line if.
	(linux_kill): Kill forked child when between fork and follow_fork.
	* server.c (handle_qxfer_threads_worker): Skip forked child thread
	when between fork and follow_fork.
	(get_last_target_status): New function.
	* server.h (get_last_target_status): Declare new function.

gdb/testsuite/
2014-08-20  Don Breazeal  <donb@codesourcery.com>
	* gdb.threads/fork-thread-pending.exp (find_unforked_thread):
	New proc.

---
 gdb/gdbserver/linux-low.c                         |   28 +++++++++++--
 gdb/gdbserver/server.c                            |   18 ++++++++
 gdb/gdbserver/server.h                            |    2 +
 gdb/remote.c                                      |   44 +++++++++++++++++++++
 gdb/testsuite/gdb.threads/fork-thread-pending.exp |   23 ++++++++++-
 5 files changed, 110 insertions(+), 5 deletions(-)

diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 5617f5e..2d9bd4a 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -415,10 +415,12 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
 	  ptid = ptid_build (new_pid, new_pid, 0);
 
 	  if (debug_threads)
-	    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));
+	    {
+	      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));
+	    }
 
 	  /* Add the new process to the tables and clone the breakpoint
 	     lists of the parent.  We need to do this even if the new process
@@ -1066,6 +1068,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 4dbdeb8..888160d 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1316,6 +1316,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)
@@ -4047,3 +4056,12 @@ using_extended_protocol (void)
 {
   return extended_protocol;
 }
+
+/* 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 2c5377b..17491bc 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -115,6 +115,8 @@ typedef int gdb_fildes_t;
 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 int using_extended_protocol (void);
+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 6939eb5..6694ca2 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -7855,6 +7855,42 @@ extended_remote_kill (struct target_ops *ops)
   target_mourn_inferior ();
 }
 
+/* Insert fork catchpoint target routine.  If fork events are enabled
+   then return success, nothing more to do.  */
+
+static int
+extended_remote_insert_fork_catchpoint (struct target_ops *ops, int pid)
+{
+  return !extended_remote_feature_supported (FORK_EVENT);
+}
+
+/* Remove fork catchpoint target routine.  Nothing to do, just
+   return success.  */
+
+static int
+extended_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
+extended_remote_insert_vfork_catchpoint (struct target_ops *ops, int pid)
+{
+  return !extended_remote_feature_supported (VFORK_EVENT);
+}
+
+/* Remove vfork catchpoint target routine.  Nothing to do, just
+   return success.  */
+
+static int
+extended_remote_remove_vfork_catchpoint (struct target_ops *ops, int pid)
+{
+  return 0;
+}
+
 /* Target routine for follow-fork.  */
 
 static int
@@ -11717,6 +11753,14 @@ init_extended_remote_ops (void)
 Specify the serial device it is connected to (e.g. /dev/ttya).";
   extended_remote_ops.to_open = extended_remote_open;
   extended_remote_ops.to_create_inferior = extended_remote_create_inferior;
+  extended_remote_ops.to_insert_fork_catchpoint
+    = extended_remote_insert_fork_catchpoint;
+  extended_remote_ops.to_remove_fork_catchpoint
+    = extended_remote_remove_fork_catchpoint;
+  extended_remote_ops.to_insert_vfork_catchpoint
+    = extended_remote_insert_vfork_catchpoint;
+  extended_remote_ops.to_remove_vfork_catchpoint
+    = extended_remote_remove_vfork_catchpoint;
   extended_remote_ops.to_follow_fork = extended_remote_follow_fork;
   extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
   extended_remote_ops.to_detach = extended_remote_detach;
diff --git a/gdb/testsuite/gdb.threads/fork-thread-pending.exp b/gdb/testsuite/gdb.threads/fork-thread-pending.exp
index 57e45c9..e8c4830 100644
--- a/gdb/testsuite/gdb.threads/fork-thread-pending.exp
+++ b/gdb/testsuite/gdb.threads/fork-thread-pending.exp
@@ -31,6 +31,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 +66,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 2" ".*" "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"
 
-- 
1.7.0.4

  parent reply	other threads:[~2014-08-21  0:33 UTC|newest]

Thread overview: 110+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-08-07 18:00 [PATCH 00/10] Linux extended-remote fork events Don Breazeal
2014-08-07 18:00 ` [PATCH 02/10] Refactor follow-fork message printing Don Breazeal
2014-08-07 18:00 ` [PATCH 01/10] Refactor native follow-fork Don Breazeal
2014-08-07 18:00 ` [PATCH 04/10] Enhance extended ptrace event setup Don Breazeal
2014-08-13 17:50   ` Breazeal, Don
2014-08-07 18:00 ` [PATCH 03/10] Refactor extended ptrace event status Don Breazeal
2014-08-07 18:00 ` [PATCH 07/10] Extended-remote arch-specific follow fork Don Breazeal
2014-08-07 18:00 ` [PATCH 05/10] GDBserver clone breakpoint list Don Breazeal
2014-08-07 18:00 ` [PATCH 06/10] Extended-remote follow fork Don Breazeal
2014-08-07 18:01 ` [PATCH 10/10] Extended-remote fork event documentation Don Breazeal
2014-08-07 19:31   ` Eli Zaretskii
2014-08-08 15:35     ` Breazeal, Don
2014-08-07 18:01 ` [PATCH 09/10] Extended-remote fork catchpoints Don Breazeal
2014-08-07 18:01 ` [PATCH 08/10] Extended-remote follow vfork Don Breazeal
2014-08-21  0:29 ` [PATCH 01/16 v2] Refactor native follow-fork Don Breazeal
2014-09-05 14:20   ` Pedro Alves
2014-09-05 18:56     ` Breazeal, Don
2014-09-05 20:20       ` Breazeal, Don
2014-09-09 10:57       ` Pedro Alves
2014-09-08 23:54     ` Breazeal, Don
2014-09-09 11:09       ` Pedro Alves
2014-09-12 16:50         ` Breazeal, Don
2014-09-22 15:53           ` Breazeal, Don
2014-09-26 18:13           ` Pedro Alves
2014-09-29 18:08             ` Breazeal, Don
2014-09-30 10:56               ` Pedro Alves
2014-09-30 18:43                 ` Breazeal, Don
2014-08-21  0:29 ` [Patch 00/16 v2] Linux extended-remote fork and exec events Don Breazeal
2014-09-04 20:57   ` Breazeal, Don
2014-10-31 23:29   ` [PATCH 04/16 v3] Determine supported extended-remote features Don Breazeal
2014-11-13 12:59     ` Pedro Alves
2014-11-13 18:28       ` Breazeal, Don
2014-11-13 18:33         ` Pedro Alves
2014-11-13 19:08           ` Pedro Alves
2014-11-13 18:37         ` Breazeal, Don
2014-11-13 18:48           ` Pedro Alves
2014-12-06  0:30             ` Breazeal, Don
2015-01-12 22:36           ` Don Breazeal
2015-01-21 21:02             ` Breazeal, Don
2014-10-31 23:29   ` [PATCH 07/16 v3] Extended-remote arch-specific follow fork Don Breazeal
2014-10-31 23:29   ` [PATCH 00/16 v3] Linux extended-remote fork and exec events Don Breazeal
2014-11-12 15:54     ` Pedro Alves
2014-11-13 13:41     ` Pedro Alves
2014-11-13 13:51       ` Pedro Alves
2014-11-13 14:58         ` Pedro Alves
2014-11-13 19:14     ` Pedro Alves
2014-10-31 23:29   ` [PATCH 08/16 v3] Extended-remote follow vfork Don Breazeal
2014-10-31 23:29   ` [PATCH 05/16 v3] GDBserver clone breakpoint list Don Breazeal
2014-10-31 23:29   ` [PATCH 06/16 v3] Extended-remote Linux follow fork Don Breazeal
2014-11-13 13:00     ` Pedro Alves
2014-11-13 18:53       ` Breazeal, Don
2014-11-13 18:59         ` Pedro Alves
2014-11-13 19:06           ` Breazeal, Don
2014-12-06  0:31             ` Breazeal, Don
2015-01-23 12:53               ` Pedro Alves
2015-01-23 17:18                 ` Breazeal, Don
     [not found]                 ` <1422222420-25421-1-git-send-email-donb@codesourcery.com>
2015-01-25 21:49                   ` [PATCH v4 5/7] Arch-specific remote " Don Breazeal
2015-02-10 16:37                     ` Pedro Alves
2015-01-25 21:49                   ` [PATCH v4 6/7] Remote follow vfork Don Breazeal
2015-02-10 16:39                     ` Pedro Alves
2015-01-25 21:50                   ` [PATCH v4 1/7] Identify remote fork event support Don Breazeal
2015-02-10 16:34                     ` Pedro Alves
2015-01-25 21:50                   ` [PATCH v4 2/7] Clone remote breakpoints Don Breazeal
2015-01-25 21:58                   ` [PATCH v4 7/7] Remote fork catch Don Breazeal
2015-01-26  0:07                   ` [PATCH v4 3/7 v3] Extended-remote Linux follow fork Don Breazeal
2015-02-10 16:36                     ` Pedro Alves
2015-01-26  0:20                   ` [PATCH v4 4/7] Target remote " Don Breazeal
2015-01-12 22:39             ` [PATCH 06/16 v3] Extended-remote Linux " Don Breazeal
2015-01-12 22:49               ` Breazeal, Don
2014-10-31 23:30   ` [PATCH 11/16 v3] Extended-remote Linux exit events Don Breazeal
2014-11-13 19:18     ` Pedro Alves
2014-10-31 23:30   ` [PATCH 09/16 v3] Extended-remote fork catchpoints Don Breazeal
2014-10-31 23:30   ` [PATCH 10/16 v3] Extended-remote fork event documentation Don Breazeal
2014-10-31 23:30   ` [PATCH 12/16 v3] Extended-remote follow exec Don Breazeal
2014-10-31 23:30   ` [PATCH 13/16 v3] Extended-remote exec catchpoints Don Breazeal
2014-10-31 23:31   ` [PATCH 15/16 v3] Extended-remote exec event documentation Don Breazeal
2014-10-31 23:31   ` [PATCH 16/16 v3] Non-stop follow exec tests Don Breazeal
2014-10-31 23:31   ` [PATCH 14/16 v3] Suppress spurious warnings with extended-remote follow exec Don Breazeal
2014-08-21  0:30 ` [PATCH 03/16 v2] Refactor ptrace extended event status Don Breazeal
2014-09-09 11:31   ` Pedro Alves
2014-09-19 18:14     ` [pushed] " Breazeal, Don
2014-08-21  0:30 ` [PATCH 02/16 v2] Refactor follow-fork message printing Don Breazeal
2014-09-26 19:52   ` Pedro Alves
2014-09-26 20:14     ` Breazeal, Don
2014-10-03 23:51       ` Breazeal, Don
2014-10-15 16:08       ` Pedro Alves
2014-10-22 23:47         ` Breazeal, Don
2014-10-24 12:35           ` Pedro Alves
2014-10-24 18:45             ` Breazeal, Don
2014-08-21  0:30 ` [PATCH 04/16 v2] Determine supported extended-remote features Don Breazeal
2014-10-15 16:17   ` Pedro Alves
2014-10-21 23:23     ` Breazeal, Don
2014-10-22 21:48       ` Pedro Alves
2014-10-31 23:38         ` Breazeal, Don
2014-08-21  0:31 ` [PATCH 06/16 v2] Extended-remote Linux follow fork Don Breazeal
2014-09-19 20:57   ` Breazeal, Don
2014-08-21  0:31 ` [PATCH 05/16 v2] GDBserver clone breakpoint list Don Breazeal
2014-10-15 17:40   ` Pedro Alves
2014-10-31 23:44     ` Breazeal, Don
2014-08-21  0:31 ` [PATCH 07/16 v2] Extended-remote arch-specific follow fork Don Breazeal
2014-09-19 21:26   ` Breazeal, Don
2014-08-21  0:32 ` [PATCH 08/16 v2] Extended-remote follow vfork Don Breazeal
2014-08-21  0:33 ` Don Breazeal [this message]
2014-08-21  0:33 ` [PATCH 11/16 v2] Extended-remote Linux exit events Don Breazeal
2014-08-21  0:33 ` [PATCH 10/16 v2] Extended-remote fork event documentation Don Breazeal
2014-08-21  0:34 ` [PATCH 13/16 v2] Extended-remote exec catchpoints Don Breazeal
2014-08-21  0:34 ` [PATCH 12/16 v2] Extended-remote follow exec Don Breazeal
2014-08-21  0:35 ` [PATCH 14/16 v2] Suppress spurious warnings with extended-remote " Don Breazeal
2014-08-21  0:36 ` [PATCH 16/16 v2] Non-stop follow exec tests Don Breazeal
2014-08-21  0:36 ` [PATCH 15/16 v2] Extended-remote exec event documentation Don Breazeal

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1408580964-27916-10-git-send-email-donb@codesourcery.com \
    --to=donb@codesourcery.com \
    --cc=gdb-patches@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).