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 06/16 v3] Extended-remote Linux follow fork
Date: Fri, 31 Oct 2014 23:29:00 -0000	[thread overview]
Message-ID: <1414798134-11536-4-git-send-email-donb@codesourcery.com> (raw)
In-Reply-To: <1408580964-27916-1-git-send-email-donb@codesourcery.com>

This patch implements basic support for follow-fork and detach-on-fork on
extended-remote Linux targets.  Only 'fork' is supported in this patch;
'vfork' support is added n a subsequent patch.  Sufficient extended-remote
functionality has been implemented here to pass gdb.base/foll-fork.exp with
the catchpoint tests commented out.

The implementation follows the same general structure as for the native
implementation as much as possible.

This implementation included:
 * enabling fork events in linux-low.c in initialize_low and
   linux_enable_extended_features
 
   - this adds the ptrace option to trace fork events to the new functions
     from patch 4 that set up ptrace options.

 * handling fork events in gdbserver/linux-low.c:handle_extended_wait
 
   - when a fork event occurs in gdbserver, we must do the full creation
     of the new process, thread, lwp, and breakpoint lists.  This is
     required whether or not the new child is destined to be
     detached-on-fork, because GDB will make target calls that require all
     the structures.  In particular we need the breakpoint lists in order
     to remove the breakpoints from a detaching child.  If we are not
     detaching the child we will need all these structures anyway.

   - as part of this event handling we store the target_waitstatus in a new
     member of the parent thread_info structure, 'pending_follow'.  This
     mimics a similar mechanism used in the native implementation.  Here is
     it used in several ways:
     - in remote_detach_1 to distinguish between a process that is being
       detached-on-fork vs. just detached.  In the fork case we don't want
       to mourn the process because we want to keep the inferior around in
       case the user decides to run the inferior again.
     - to record the child pid for the expected follow_fork request.
     - to find the parent in follow_fork (and later, elsewhere).

   - we also store the waitstatus in a new lwp_info member, 'waitstatus',
     which is used in controlling the reporting of the event in
     linux_wait_1.  We cannot re-use pending_follow for this because we
     need to mark this one with 'ignored' status as part of the
     linux_wait_1 procedure to stop event processing, and we need to keep
     pending_follow intact for use later on.  We will also need this later
     on for exec event handling, where pending_follow makes no sense.

   - handle_extended_wait is given a return value, denoting whether the
     handled event should be reported to GDB.  Previously it had only
     handled clone events, which were never reported.

 * using a new predicate to control handling of the fork event (and 
   eventually all extended events) in linux_wait_1.  The predicate,
   extended_event_reported, checks a target_waitstatus.kind for an
   extended ptrace event.

 * implementing a new RSP 'T' Stop Reply Packet stop reason: "fork", in
   gdbserver/remote-utils.c and remote.c.

 * implementing new target and RSP support for target_follow_fork with
   target extended-remote.  (The RSP components were actually defined in
   patch 4, but they see their first use here).

   - extended_remote target routine extended_remote_follow_fork

   - RSP packet vFollowFork

   - in gdbserver struct target_ops, add functions linux_supports_follow_fork
     and linux_follow_fork.  The linux_follow_fork routine mimics the
     implementation of linux-nat.c:linux_child_follow_fork, but the data
     structures in use prevented turning this into a common function for now.

Tested on x64 Ubuntu Lucid, native, remote, extended-remote.

Thanks
--Don

gdb/gdbserver/
2014-10-31  Don Breazeal  <donb@codesourcery.com>

	* gdbthread.h (struct thread_info) <pending_follow>: New member.
	* linux-low.c (handle_extended_wait): Change function type from
	void to int, handle PTRACE_EVENT_FORK, call internal_error.
	(is_parent_callback): New function.
	(linux_follow_fork): New function.
	(linux_low_filter_event): Handle return value from
	handle_extended_wait.
	(extended_event_reported): New function.
	(linux_write_memory): Add pid to debug print.
	(linux_target_ops) <follow_fork>: Initialize new member.
	(initialize_low): Add PTRACE_O_TRACEFORK option.
	* linux-low.h (struct lwp_info) <waitstatus>: New member.
	* lynx-low.c (lynx_target_ops) <follow_fork>: Initialize new member.
	* remote-utils.c (prepare_resume_reply): New RSP stop reason "fork"
	for 'T' stop reply.
	* server.c (handle_v_follow_fork): New function.
	(handle_v_requests): Handle vFollowFork packet, call
	handle_v_follow_fork.
	* target.h (struct target_ops) <follow_fork>: New member.
	(target_follow_fork): Define macro.
	* win32-low.c (win32_target_ops) <follow_fork>: Initialize new member.

gdb/
2014-10-31  Don Breazeal  <donb@codesourcery.com>

	* gdb/nat/linux-ptrace.c (current_ptrace_options): Update comment.
	* remote.c (extended_remote_follow_fork): Implement follow-fork.
	(remote_detach_1): Add target_ops argument, handle detach-on-fork.
	(remote_detach, extended_remote_detach): Call remote_detach_1
	with target_ops argument.
	(remote_parse_stop_reply): Handle new RSP stop reason "fork" in
	'T' stop reply packet.
	(remote_pid_to_str): Print process.
	(_initialize_remote): Call add_packet_config_cmd for new RSP packet.

---
 gdb/gdbserver/gdbthread.h    |    5 +
 gdb/gdbserver/linux-low.c    |  207 +++++++++++++++++++++++++++++++++++++++---
 gdb/gdbserver/linux-low.h    |    5 +
 gdb/gdbserver/lynx-low.c     |    1 +
 gdb/gdbserver/remote-utils.c |   14 +++-
 gdb/gdbserver/server.c       |   41 ++++++++
 gdb/gdbserver/target.h       |   13 +++
 gdb/gdbserver/win32-low.c    |    1 +
 gdb/nat/linux-ptrace.c       |    4 +-
 gdb/remote.c                 |   53 +++++++++--
 10 files changed, 319 insertions(+), 25 deletions(-)

diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
index 8290ec1..3d003b9 100644
--- a/gdb/gdbserver/gdbthread.h
+++ b/gdb/gdbserver/gdbthread.h
@@ -41,6 +41,11 @@ struct thread_info
   /* True if LAST_STATUS hasn't been reported to GDB yet.  */
   int status_pending_p;
 
+  /* This is used to remember when a fork or vfork event was caught by
+     a catchpoint, and thus the event is to be followed at the next
+     resume of the thread, and not immediately.  */
+  struct target_waitstatus pending_follow;
+
   /* Given `while-stepping', a thread may be collecting data for more
      than one tracepoint simultaneously.  E.g.:
 
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 8334578..db7ef09 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -20,6 +20,7 @@
 #include "linux-low.h"
 #include "nat/linux-osdata.h"
 #include "agent.h"
+#include "tdesc.h"
 
 #include "nat/linux-nat.h"
 #include "nat/linux-waitpid.h"
@@ -364,17 +365,17 @@ linux_add_process (int pid, int attached)
 }
 
 /* Handle a GNU/Linux extended wait response.  If we see a clone
-   event, we need to add the new LWP to our list (and not report the
-   trap to higher layers).  */
+   event, we need to add the new LWP to our list (and return 0 so as
+   not to report the trap to higher layers).  */
 
-static void
+static int
 handle_extended_wait (struct lwp_info *event_child, int wstat)
 {
   int event = linux_ptrace_get_extended_event (wstat);
   struct thread_info *event_thr = get_lwp_thread (event_child);
   struct lwp_info *new_lwp;
 
-  if (event == PTRACE_EVENT_CLONE)
+  if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_CLONE)
     {
       ptid_t ptid;
       unsigned long new_pid;
@@ -399,6 +400,56 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
 	    warning ("wait returned unexpected status 0x%x", status);
 	}
 
+      if (event == PTRACE_EVENT_FORK)
+	{
+	  struct process_info *parent_proc;
+	  struct process_info *child_proc;
+	  struct lwp_info *child_lwp;
+	  struct target_desc *tdesc;
+
+	  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));
+	    }
+
+	  /* 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
+	     will be detached, since we will need the process object and the
+	     breakpoints to remove any breakpoints from memory when we
+	     detach, and the host side will access registers.  */
+	  child_proc = linux_add_process (new_pid, 0);
+	  gdb_assert (child_proc != NULL);
+	  child_lwp = add_lwp (ptid);
+	  gdb_assert (child_lwp != NULL);
+	  child_lwp->stopped = 1;
+	  parent_proc = get_thread_process (current_thread);
+	  child_proc->attached = parent_proc->attached;
+	  clone_all_breakpoints (&child_proc->breakpoints,
+				 &child_proc->raw_breakpoints,
+				 parent_proc->breakpoints);
+
+	  tdesc = xmalloc (sizeof (struct target_desc));
+	  copy_target_description (tdesc, parent_proc->tdesc);
+	  child_proc->tdesc = tdesc;
+	  child_lwp->must_set_ptrace_flags = 1;
+
+	  /* Save fork info for target processing.  */
+	  current_thread->pending_follow.kind = TARGET_WAITKIND_FORKED;
+	  current_thread->pending_follow.value.related_pid = ptid;
+
+	  /* Save fork info for reporting to GDB.  */
+	  event_child->waitstatus.kind = TARGET_WAITKIND_FORKED;
+	  event_child->waitstatus.value.related_pid = ptid;
+
+	  /* Report the event.  */
+	  return 0;
+	}
+
       if (debug_threads)
 	debug_printf ("HEW: Got clone event "
 		      "from LWP %ld, new child is LWP %ld\n",
@@ -448,7 +499,12 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
 	 threads, it will have a pending SIGSTOP; we may as well
 	 collect it now.  */
       linux_resume_one_lwp (event_child, event_child->stepping, 0, NULL);
+
+      /* Don't report the event.  */
+      return 1;
     }
+
+  internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event);
 }
 
 /* Return the PC as read from the regcache of LWP, without any
@@ -1173,6 +1229,97 @@ linux_detach (int pid)
   return 0;
 }
 
+/* Callback used to find the parent process of a fork.  */
+
+static int
+is_parent_callback (struct inferior_list_entry *entry, void *ignore)
+{
+  struct thread_info *thread = (struct thread_info *) entry;
+
+  if (thread->pending_follow.kind == TARGET_WAITKIND_FORKED
+      || thread->pending_follow.kind == TARGET_WAITKIND_VFORKED)
+    return 1;
+
+  return 0;
+}
+
+/* Handle a fork in the inferior process.  Mainly this consists of
+   handling the case where we are detaching the new child process by
+   cleaning up its state so it can proceed.  Note that if we are
+   detaching the parent process, GDB has already done that via
+   target_detach.  */
+
+static int
+linux_follow_fork (int follow_child, int detach_fork)
+{
+  struct inferior_list_entry *parent_inf;
+  struct thread_info *parent_thread;
+
+  parent_inf = find_inferior (&all_threads, is_parent_callback, NULL);
+
+  /* If we can't find the parent, we are following the child and the
+     parent has already been detached.  Nothing to do, so return OK.  */
+  if (parent_inf == NULL)
+    return 0;
+
+  parent_thread = (struct thread_info *)parent_inf;
+  parent_thread->pending_follow.kind = TARGET_WAITKIND_IGNORE;
+
+  if (!follow_child)
+    {
+      if (detach_fork)
+	{
+	  int status = W_STOPCODE (0);
+	  ptid_t child_ptid = parent_thread->pending_follow.value.related_pid;
+	  pid_t child_pid = ptid_get_pid (child_ptid);
+	  struct lwp_info *child_lwp = find_lwp_pid (child_ptid);
+
+	  if (the_low_target.prepare_to_resume != NULL)
+	    the_low_target.prepare_to_resume (child_lwp);
+
+	  /* When debugging an inferior in an architecture that supports
+	     hardware single stepping on a kernel without commit
+	     6580807da14c423f0d0a708108e6df6ebc8bc83d, the vfork child
+	     process starts with the TIF_SINGLESTEP/X86_EFLAGS_TF bits
+	     set if the parent process had them set.
+	     To work around this, single step the child process
+	     once before detaching to clear the flags.  */
+
+	  if (can_hardware_single_step ())
+	    {
+	      linux_ptrace_disable_options (child_pid);
+	      if (ptrace (PTRACE_SINGLESTEP, child_pid, 0, 0) < 0)
+		perror_with_name (_("Couldn't do single step"));
+	      if (my_waitpid (child_pid, &status, 0) < 0)
+		perror_with_name (_("Couldn't wait vfork process"));
+	    }
+
+	  if (WIFSTOPPED (status))
+	    {
+	      int signo;
+	      struct process_info *child_proc;
+
+	      signo = WSTOPSIG (status);
+	      if (signo == SIGSTOP
+		  || (signo != 0
+		      && !pass_signals[gdb_signal_from_host (signo)]))
+		signo = 0;
+
+	      ptrace (PTRACE_DETACH, child_pid, 0, signo);
+
+	      /* Deallocate all process-related storage.  */
+	      child_proc = find_process_pid (child_pid);
+	      if (child_proc != NULL)
+		the_target->mourn (child_proc);
+
+	      current_thread = NULL;
+	    }
+	}
+    }
+
+  return 0;
+}
+
 /* Remove all LWPs that belong to process PROC from the lwp list.  */
 
 static int
@@ -1885,8 +2032,10 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
   if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
       && linux_is_extended_waitstatus (wstat))
     {
-      handle_extended_wait (child, wstat);
-      return NULL;
+      if (handle_extended_wait (child, wstat))
+	return NULL;
+      else
+	return child;
     }
 
   if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGSTOP
@@ -2484,6 +2633,19 @@ linux_stabilize_threads (void)
     }
 }
 
+/* Return non-zero if WAITSTATUS reflects an extended linux
+   event that gdbserver supports.  Otherwise, return zero.  */
+
+static int
+extended_event_reported (const struct target_waitstatus *waitstatus)
+{
+
+  if (waitstatus == NULL)
+    return 0;
+
+  return (waitstatus->kind == TARGET_WAITKIND_FORKED);
+}
+
 /* Wait for process, returns status.  */
 
 static ptid_t
@@ -2847,7 +3009,8 @@ retry:
 		       && !bp_explains_trap && !trace_event)
 		   || (gdb_breakpoint_here (event_child->stop_pc)
 		       && gdb_condition_true_at_breakpoint (event_child->stop_pc)
-		       && gdb_no_commands_at_breakpoint (event_child->stop_pc)));
+		       && gdb_no_commands_at_breakpoint (event_child->stop_pc))
+		   || extended_event_reported (&event_child->waitstatus));
 
   run_breakpoint_commands (event_child->stop_pc);
 
@@ -2869,6 +3032,13 @@ retry:
 			  paddress (event_child->stop_pc),
 			  paddress (event_child->step_range_start),
 			  paddress (event_child->step_range_end));
+	  if (extended_event_reported (&event_child->waitstatus))
+	    {
+	      char *str = target_waitstatus_to_string (ourstatus);
+	      debug_printf ("LWP %ld: extended event with waitstatus %s\n",
+			    lwpid_of (get_lwp_thread (event_child)), str);
+	      xfree (str);
+	    }
 	}
 
       /* We're not reporting this breakpoint to GDB, so apply the
@@ -2967,7 +3137,17 @@ retry:
 	unstop_all_lwps (1, event_child);
     }
 
-  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+  if (extended_event_reported (&event_child->waitstatus))
+    {
+      /* If the reported event is a fork, vfork or exec, let GDB know.  */
+      ourstatus->kind = event_child->waitstatus.kind;
+      ourstatus->value = event_child->waitstatus.value;
+
+      /* Reset the event child's waitstatus since we handled it already.  */
+      event_child->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+    }
+  else
+    ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
   if (current_thread->last_resume_kind == resume_stop
       && WSTOPSIG (w) == SIGSTOP)
@@ -2984,7 +3164,7 @@ retry:
 	 but, it stopped for other reasons.  */
       ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w));
     }
-  else
+  else if (ourstatus->kind == TARGET_WAITKIND_STOPPED)
     {
       ourstatus->value.sig = gdb_signal_from_host (WSTOPSIG (w));
     }
@@ -4776,8 +4956,8 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
 	val = val & 0xffff;
       else if (len == 3)
 	val = val & 0xffffff;
-      debug_printf ("Writing %0*x to 0x%08lx\n", 2 * ((len < 4) ? len : 4),
-		    val, (long)memaddr);
+      debug_printf ("Writing %0*x to 0x%08lx in process %d\n",
+		    2 * ((len < 4) ? len : 4), val, (long)memaddr, pid);
     }
 
   /* Fill start and end extra bytes of buffer with existing memory data.  */
@@ -6126,6 +6306,7 @@ static struct target_ops linux_target_ops = {
   linux_supports_vfork_events,
   linux_supports_exec_events,
   linux_enable_extended_features,
+  linux_follow_fork,
 #ifdef USE_THREAD_DB
   thread_db_handle_monitor_command,
 #else
@@ -6202,7 +6383,7 @@ initialize_low (void)
 
   initialize_low_arch ();
 
-  /* Placeholder to enable extended events.  */
-  linux_ptrace_set_requested_options (0);
+  /* Enable extended events.  */
+  linux_ptrace_set_requested_options (PTRACE_O_TRACEFORK);
   linux_ptrace_check_options ();
 }
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 4820929..a903430 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -266,6 +266,11 @@ struct lwp_info
      status_pending).  */
   int dead;
 
+  /* If WAITSTATUS->KIND != TARGET_WAITKIND_IGNORE, the waitstatus for
+     this LWP's last event.  This is used to maintain the current status
+     during event processing.  */
+  struct target_waitstatus waitstatus;
+
   /* When stopped is set, the last wait status recorded for this lwp.  */
   int last_status;
 
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index 3ccc032..c2d0ee7 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -755,6 +755,7 @@ static struct target_ops lynx_target_ops = {
   NULL,  /* supports_vfork_events */
   NULL,  /* supports_exec_events */
   NULL,  /* enable_extended_features */
+  NULL,  /* follow_fork */
   NULL,  /* handle_monitor_command */
 };
 
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 373fc15..e62b4b8 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -1105,12 +1105,24 @@ prepare_resume_reply (char *buf, ptid_t ptid,
   switch (status->kind)
     {
     case TARGET_WAITKIND_STOPPED:
+    case TARGET_WAITKIND_FORKED:
       {
 	struct thread_info *saved_thread;
 	const char **regp;
 	struct regcache *regcache;
 
-	sprintf (buf, "T%02x", status->value.sig);
+	if (status->kind == TARGET_WAITKIND_FORKED && multi_process)
+	  {
+	    enum gdb_signal signal = GDB_SIGNAL_TRAP;
+	    const char *event = "fork";
+
+	    sprintf (buf, "T%02x%s:p%x.%lx;", signal, event,
+		      ptid_get_pid (status->value.related_pid),
+		      ptid_get_lwp (status->value.related_pid));
+	  }
+	else
+	  sprintf (buf, "T%02x", status->value.sig);
+
 	buf += strlen (buf);
 
 	saved_thread = current_thread;
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index d297403..b1720de 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -2544,6 +2544,29 @@ handle_v_kill (char *own_buf)
     }
 }
 
+/* Handle forked process.  */
+
+static void
+handle_v_follow_fork (char *own_buf)
+{
+  int follow_child;
+  int detach_fork;
+  char *p = &own_buf[12];
+  int ret;
+
+  gdb_assert (extended_protocol);
+
+  follow_child = strtol (p, NULL, 16);
+  p = strchr (p, ';') + 1;
+  detach_fork = strtol (p, NULL, 16);
+
+  ret = target_follow_fork (follow_child, detach_fork);
+  if (ret == 0)
+    write_ok (own_buf);
+  else
+    write_enn (own_buf);
+}
+
 /* Handle all of the extended 'v' packets.  */
 void
 handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
@@ -2609,6 +2632,24 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
       return;
     }
 
+  if (strncmp (own_buf, "vFollowFork;", 6) == 0)
+    {
+      if (!target_running ())
+	{
+	  fprintf (stderr, "No process to follow\n");
+	  write_enn (own_buf);
+	  return;
+	}
+      if (!extended_protocol || !multi_process)
+	{
+	  fprintf (stderr, "Target doesn't support follow-fork\n");
+	  write_enn (own_buf);
+	  return;
+	}
+      handle_v_follow_fork (own_buf);
+      return;
+    }
+
   if (handle_notif_ack (own_buf, packet_len))
     return;
 
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 570f57d..58afc6a 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -93,6 +93,7 @@ struct target_ops
 
   int (*detach) (int pid);
 
+
   /* The inferior process has died.  Do what is right.  */
 
   void (*mourn) (struct process_info *proc);
@@ -274,6 +275,10 @@ struct target_ops
   /* Enable features that are only available in extended mode.  */
   void (*enable_extended_features) (void);
 
+  /* Handle a call to fork as specified by follow-fork-mode and
+     detach-on-fork.  */
+  int (*follow_fork) (int follow_child, int detach_fork);
+
   /* If not NULL, target-specific routine to process monitor command.
      Returns 1 if handled, or 0 to perform default processing.  */
   int (*handle_monitor_command) (char *);
@@ -450,6 +455,14 @@ int kill_inferior (int);
   (the_target->supports_multi_process ? \
    (*the_target->supports_multi_process) () : 0)
 
+#define target_supports_follow_fork() \
+ (the_target->supports_follow_fork ? \
+  (*the_target->supports_follow_fork) () : 0)
+
+#define target_follow_fork(follow_child, detach_fork) \
+  (the_target->follow_fork ? \
+   (*the_target->follow_fork) (follow_child, detach_fork) : 0)
+
 #define target_process_qsupported(query)		\
   do							\
     {							\
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 9ae2f94..6185e15 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -1827,6 +1827,7 @@ static struct target_ops win32_target_ops = {
   NULL, /* supports_vfork_events */
   NULL, /* supports_exec_events */
   NULL, /* enable_extended_features */
+  NULL, /* follow_fork */
   NULL, /* handle_monitor_command */
   NULL, /* core_of_thread */
   NULL, /* read_loadmap */
diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c
index 7871d95..5f3f123 100644
--- a/gdb/nat/linux-ptrace.c
+++ b/gdb/nat/linux-ptrace.c
@@ -36,8 +36,8 @@ static int requested_ptrace_options;
    of the requested options are supported.  */
 static int available_ptrace_options = -1;
 
-/* Stores the currently enabled ptrace options, or the default
-   option(s) that will be enabled once a process is loaded.  */
+/* Stores the currently enabled ptrace options, or the options
+   that will be enabled once a process is loaded.  */
 static int current_ptrace_options;
 
 /* Find all possible reasons we could fail to attach PID and append
diff --git a/gdb/remote.c b/gdb/remote.c
index 77c68d8..1d110f9 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -24,6 +24,7 @@
 #include <fcntl.h>
 #include "inferior.h"
 #include "infrun.h"
+#include "inf-child.h"
 #include "bfd.h"
 #include "symfile.h"
 #include "target.h"
@@ -1484,8 +1485,17 @@ extended_remote_follow_fork (struct target_ops *target, int follow_child,
      We will also follow vforks if they are supported.  */
   if (extended_remote_fork_event_p (rs))
     {
-      /* FIXME: Implement follow-fork here.  */
-      return -1;
+      char *p = rs->buf;
+      char *endbuf = rs->buf + get_remote_packet_size ();
+
+      xsnprintf (rs->buf, get_remote_packet_size (), "vFollowFork;%d;%d",
+		 follow_child, detach_fork);
+
+      putpkt (rs->buf);
+      getpkt (&rs->buf, &rs->buf_size, 0);
+
+      if (rs->buf[0] == 'E')
+	return 1;
     }
   return 0;
 }
@@ -3999,6 +4009,8 @@ static const struct protocol_feature remote_protocol_features[] = {
     PACKET_QStartNoAckMode },
   { "multiprocess", PACKET_DISABLE, remote_supported_packet,
     PACKET_multiprocess_feature },
+  { "vFollowFork", PACKET_DISABLE, remote_supported_packet,
+    PACKET_vFollowFork },
   { "QNonStop", PACKET_DISABLE, remote_supported_packet, PACKET_QNonStop },
   { "qXfer:siginfo:read", PACKET_DISABLE, remote_supported_packet,
     PACKET_qXfer_siginfo_read },
@@ -4407,10 +4419,12 @@ remote_open_1 (const char *name, int from_tty,
    die when it hits one.  */
 
 static void
-remote_detach_1 (const char *args, int from_tty, int extended)
+remote_detach_1 (struct target_ops *ops, const char *args,
+		 int from_tty, int extended)
 {
   int pid = ptid_get_pid (inferior_ptid);
   struct remote_state *rs = get_remote_state ();
+  struct thread_info *tp = first_thread_of_process (pid);
 
   if (args)
     error (_("Argument given to \"detach\" when remotely debugging."));
@@ -4447,19 +4461,28 @@ remote_detach_1 (const char *args, int from_tty, int extended)
   if (from_tty && !extended)
     puts_filtered (_("Ending remote debugging.\n"));
 
-  target_mourn_inferior ();
+  /* If doing detach-on-fork, we don't mourn, because that will delete
+     breakpoints that should be available for the child.  */
+  if (tp->pending_follow.kind != TARGET_WAITKIND_FORKED)
+    target_mourn_inferior ();
+  else
+    {
+      inferior_ptid = null_ptid;
+      detach_inferior (pid);
+      inf_child_maybe_unpush_target (ops);
+    }
 }
 
 static void
 remote_detach (struct target_ops *ops, const char *args, int from_tty)
 {
-  remote_detach_1 (args, from_tty, 0);
+  remote_detach_1 (ops, args, from_tty, 0);
 }
 
 static void
 extended_remote_detach (struct target_ops *ops, const char *args, int from_tty)
 {
-  remote_detach_1 (args, from_tty, 1);
+  remote_detach_1 (ops, args, from_tty, 1);
 }
 
 /* Same as remote_detach, but don't send the "D" packet; just disconnect.  */
@@ -5555,7 +5578,8 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event)
 	     as a register number.  */
 
 	  if (strncmp (p, "awatch", strlen("awatch")) != 0
-	      && strncmp (p, "core", strlen ("core") != 0))
+	      && strncmp (p, "core", strlen ("core") != 0)
+	      && strncmp (p, "fork", strlen ("fork") != 0))
 	    {
 	      /* Read the ``P'' register number.  */
 	      pnum = strtol (p, &p_temp, 16);
@@ -5607,6 +5631,11 @@ Packet: '%s'\n"),
 		  p = unpack_varlen_hex (++p1, &c);
 		  event->core = c;
 		}
+	      else if (strncmp (p, "fork", p1 - p) == 0)
+		{
+		  event->ws.value.related_pid = read_ptid (++p1, &p);
+		  event->ws.kind = TARGET_WAITKIND_FORKED;
+		}
 	      else
 		{
 		  /* Silently skip unknown optional info.  */
@@ -9418,8 +9447,11 @@ remote_pid_to_str (struct target_ops *ops, ptid_t ptid)
       if (ptid_equal (magic_null_ptid, ptid))
 	xsnprintf (buf, sizeof buf, "Thread <main>");
       else if (rs->extended && remote_multi_process_p (rs))
-	xsnprintf (buf, sizeof buf, "Thread %d.%ld",
-		   ptid_get_pid (ptid), ptid_get_lwp (ptid));
+	if (ptid_get_lwp (ptid) == 0)
+	  return normal_pid_to_str (ptid);
+	else
+	  xsnprintf (buf, sizeof buf, "Thread %d.%ld",
+		     ptid_get_pid (ptid), ptid_get_lwp (ptid));
       else
 	xsnprintf (buf, sizeof buf, "Thread %ld",
 		   ptid_get_lwp (ptid));
@@ -12177,6 +12209,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_vKill],
 			 "vKill", "kill", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_vFollowFork],
+			 "vFollowFork", "follow-fork", 0);
+
   add_packet_config_cmd (&remote_protocol_packets[PACKET_qAttached],
 			 "qAttached", "query-attached", 0);
 
-- 
1.7.0.4

  parent reply	other threads:[~2014-10-31 23:29 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 01/10] Refactor native follow-fork Don Breazeal
2014-08-07 18:00 ` [PATCH 02/10] Refactor follow-fork message printing 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 05/10] GDBserver clone breakpoint list Don Breazeal
2014-08-07 18:00 ` [PATCH 07/10] Extended-remote arch-specific follow fork Don Breazeal
2014-08-07 18:00 ` [PATCH 03/10] Refactor extended ptrace event status Don Breazeal
2014-08-07 18:00 ` [PATCH 06/10] Extended-remote follow fork Don Breazeal
2014-08-07 18:01 ` [PATCH 09/10] Extended-remote fork catchpoints 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 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 08/16 v3] Extended-remote follow vfork 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   ` Don Breazeal [this message]
2014-11-13 13:00     ` [PATCH 06/16 v3] Extended-remote Linux follow fork 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 6/7] Remote follow vfork Don Breazeal
2015-02-10 16:39                     ` Pedro Alves
2015-01-25 21:49                   ` [PATCH v4 5/7] Arch-specific remote follow fork Don Breazeal
2015-02-10 16:37                     ` Pedro Alves
2015-01-25 21:50                   ` [PATCH v4 2/7] Clone remote breakpoints Don Breazeal
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: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:29   ` [PATCH 05/16 v3] GDBserver clone breakpoint list Don Breazeal
2014-10-31 23:29   ` [PATCH 07/16 v3] Extended-remote arch-specific follow fork Don Breazeal
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:30   ` [PATCH 09/16 v3] Extended-remote fork catchpoints 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:30   ` [PATCH 10/16 v3] Extended-remote fork event documentation Don Breazeal
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:31   ` [PATCH 16/16 v3] Non-stop follow exec tests Don Breazeal
2014-10-31 23:31   ` [PATCH 15/16 v3] Extended-remote exec event documentation 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 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: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: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 ` [PATCH 09/16 v2] Extended-remote fork catchpoints Don Breazeal
2014-08-21  0:33 ` [PATCH 10/16 v2] Extended-remote fork event documentation Don Breazeal
2014-08-21  0:33 ` [PATCH 11/16 v2] Extended-remote Linux exit events 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=1414798134-11536-4-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).