diff --git a/gdb/gdbserver/gdbthread.h b/gdb/gdbserver/gdbthread.h
index 8290ec1..aa77cd9 100644
--- a/gdb/gdbserver/gdbthread.h
+++ b/gdb/gdbserver/gdbthread.h
@@ -41,6 +41,10 @@ struct thread_info
   /* True if LAST_STATUS hasn't been reported to GDB yet.  */
   int status_pending_p;

+  /* This is used to store fork and exec event information until
+     it is reported to GDB.  */
+  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 a13631a..a18e8ee 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,22 +365,23 @@ 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
-handle_extended_wait (struct lwp_info *event_child, int wstat)
+static int
+handle_extended_wait (struct lwp_info *event_lwp, int wstat)
 {
   int event = linux_ptrace_get_extended_event (wstat);
-  struct thread_info *event_thr = get_lwp_thread (event_child);
+  struct thread_info *event_thr = get_lwp_thread (event_lwp);
   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;
       int ret, status;

+      /* Get the pid of the new lwp.  */
       ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_thr),
(PTRACE_TYPE_ARG3) 0,
 	      &new_pid);

@@ -399,6 +401,52 @@ 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 (event_thr);
+	  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 in the parent thread.  */
+	  event_thr->pending_follow.kind = TARGET_WAITKIND_FORKED;
+	  event_thr->pending_follow.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",
@@ -447,8 +495,13 @@ handle_extended_wait (struct lwp_info *event_child,
int wstat)
       /* Always resume the current thread.  If we are stopping
 	 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);
+      linux_resume_one_lwp (event_lwp, event_lwp->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
@@ -1100,6 +1153,55 @@ get_detach_signal (struct thread_info *thread)
     }
 }

+/* Prepare a fork child to be detached, if necessary.  If THREAD is
+   not a fork child, just return OK.  */
+
+static int
+linux_detach_fork (struct thread_info *thread)
+{
+  ptid_t child_ptid;
+  pid_t child_pid;
+  int status = W_STOPCODE (0);
+
+  /* Here we know that we are in a follow-fork, that we are following
+     the parent, and that we are going to detach the child.  */
+  child_ptid = thread->entry.id;
+  child_pid = ptid_get_pid (child_ptid);
+
+  /* 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_disable_event_reporting (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 lwp_info *child_lwp = find_lwp_pid (child_ptid);
+
+      signo = WSTOPSIG (status);
+      if (signo == SIGSTOP
+	  || (signo != 0 && !pass_signals[gdb_signal_from_host (signo)]))
+	{
+	  /* Clear the SIGSTOP.  */
+	  WSETSTOP (child_lwp->status_pending, 0);
+	}
+    }
+
+  return 0;
+}
+
 static int
 linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
 {
@@ -1125,6 +1227,9 @@ linux_detach_one_lwp (struct inferior_list_entry
*entry, void *args)
   /* Flush any pending changes to the process's registers.  */
   regcache_invalidate_thread (thread);

+  /* Prepare fork child for detach, if necessary.  */
+  linux_detach_fork (thread);
+
   /* Pass on any pending signal for this thread.  */
   sig = get_detach_signal (thread);

@@ -1885,8 +1990,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 +2591,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
@@ -2819,7 +2939,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 (&current_thread->pending_follow));

   run_breakpoint_commands (event_child->stop_pc);

@@ -2841,6 +2962,13 @@ retry:
 			  paddress (event_child->stop_pc),
 			  paddress (event_child->step_range_start),
 			  paddress (event_child->step_range_end));
+	  if (extended_event_reported (&current_thread->pending_follow))
+	    {
+	      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
@@ -2939,7 +3067,17 @@ retry:
 	unstop_all_lwps (1, event_child);
     }

-  ourstatus->kind = TARGET_WAITKIND_STOPPED;
+  if (extended_event_reported (&current_thread->pending_follow))
+    {
+      /* If the reported event is a fork, vfork or exec, let GDB know.  */
+      ourstatus->kind = current_thread->pending_follow.kind;
+      ourstatus->value = current_thread->pending_follow.value;
+
+      /* Reset the event lwp's waitstatus since we handled it already.  */
+      current_thread->pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
+    }
+  else
+    ourstatus->kind = TARGET_WAITKIND_STOPPED;

   if (current_thread->last_resume_kind == resume_stop
       && WSTOPSIG (w) == SIGSTOP)
@@ -2956,7 +3094,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));
     }
@@ -4748,8 +4886,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.  */
@@ -6147,13 +6285,17 @@ initialize_low (void)

   initialize_low_arch ();

-#if PTRACE_EVENT_SUPPORT
+#if FULL_PTRACE_EVENT_SUPPORT
   /* Always try to enable ptrace event extensions.  Leave
      PTRACE_O_TRACESYSGOOD out until it is supported.  */
   linux_ptrace_set_additional_flags (PTRACE_O_TRACEVFORKDONE
 				     | PTRACE_O_TRACEVFORK
 				     | PTRACE_O_TRACEFORK
 				     | PTRACE_O_TRACEEXEC);
+#else
+  /* Enable fork events.  */
+  linux_ptrace_set_additional_flags (PTRACE_O_TRACEFORK);
 #endif
   linux_test_for_event_reporting ();
+  /* Enable extended events.  */
 }
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 71c954f..39c9fbd 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -3546,9 +3546,12 @@ process_serial_event (void)
 	  discard_queued_stop_replies (pid);
 	  write_ok (own_buf);

-	  if (extended_protocol)
+	  if ((get_first_inferior (&all_threads) != NULL)
+	      || extended_protocol)
 	    {
-	      /* Treat this like a normal program exit.  */
+	      /* There is still at least one inferior remaining, or we
+		 are in extended mode, so don't terminate gdbserver and
+		 treat this like a normal program exit.  */
 	      last_status.kind = TARGET_WAITKIND_EXITED;
 	      last_status.value.integer = 0;
 	      last_ptid = pid_to_ptid (pid);
diff --git a/gdb/remote.c b/gdb/remote.c
index cb40955..d809fcd 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"
@@ -1441,7 +1442,6 @@ remote_multi_process_p (struct remote_state *rs)
   return packet_support (PACKET_multiprocess_feature) == PACKET_ENABLE;
 }

-#if PTRACE_EVENT_SUPPORT
 /* Returns true if fork events are supported.  */

 static int
@@ -1450,6 +1450,7 @@ remote_fork_event_p (struct remote_state *rs)
   return packet_support (PACKET_fork_event_feature) == PACKET_ENABLE;
 }

+#if PTRACE_EVENT_SUPPORT
 /* Returns true if vfork events are supported.  */

 static int
@@ -1467,6 +1468,51 @@ remote_exec_event_p (struct remote_state *rs)
 }
 #endif

+/* Target follow-fork function for remote targets.  On entry, and
+   at return, the current inferior is the fork parent.  */
+
+static int
+remote_follow_fork (struct target_ops *target, int follow_child,
+		    int detach_fork)
+{
+  struct remote_state *rs = get_remote_state ();
+
+  /* Checking the fork event is sufficient for both fork and vfork.  */
+  if (remote_fork_event_p (rs))
+    {
+      if (detach_fork && !follow_child)
+	{
+	  ptid_t child_ptid;
+	  pid_t child_pid;
+
+	  gdb_assert ((inferior_thread ()->pending_follow.kind
+		       == TARGET_WAITKIND_FORKED)
+		      || (inferior_thread ()->pending_follow.kind
+			  == TARGET_WAITKIND_VFORKED));
+	  child_ptid = inferior_thread ()->pending_follow.value.related_pid;
+	  child_pid = ptid_get_pid (child_ptid);
+
+	  /* Tell the remote target to detach.  */
+	  xsnprintf (rs->buf, get_remote_packet_size (), "D;%x", child_pid);
+
+	  putpkt (rs->buf);
+	  getpkt (&rs->buf, &rs->buf_size, 0);
+
+	  if (rs->buf[0] == 'O' && rs->buf[1] == 'K')
+	    ;
+	  else if (rs->buf[0] == '\0')
+	    error (_("Remote doesn't know how to detach"));
+	  else
+	    error (_("Can't detach process."));
+
+	  inferior_ptid = null_ptid;
+	  detach_inferior (child_pid);
+	  inf_child_maybe_unpush_target (target);
+	}
+    }
+  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;
@@ -1867,7 +1913,7 @@ set_general_process (void)
   struct remote_state *rs = get_remote_state ();

   /* If the remote can't handle multiple processes, don't bother.  */
-  if (!rs->extended || !remote_multi_process_p (rs))
+  if (!remote_multi_process_p (rs))
     return;

   /* We only need to change the remote current thread if it's pointing
@@ -4413,10 +4459,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."));
@@ -4450,22 +4498,31 @@ remote_detach_1 (const char *args, int from_tty,
int extended)
   else
     error (_("Can't detach process."));

-  if (from_tty && !extended)
+  if (from_tty && !extended && (number_of_inferiors () > 0))
     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);
 }
