diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 5af02ac..66b1729 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -381,7 +381,8 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
   struct thread_info *event_thr = get_lwp_thread (event_child);
   struct lwp_info *new_lwp;
 
-  if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_CLONE))
+  if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK)
+      || (event == PTRACE_EVENT_CLONE))
     {
       ptid_t ptid;
       unsigned long new_pid;
@@ -407,7 +408,7 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
 	    warning ("wait returned unexpected status 0x%x", status);
 	}
 
-      if (event == PTRACE_EVENT_FORK)
+      if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK)
 	{
 	  struct process_info *parent_proc;
 	  struct process_info *child_proc;
@@ -449,8 +450,12 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
 	  if (the_low_target.new_fork != NULL)
 	    the_low_target.new_fork (parent_proc, child_proc);
 
-	  /* Save fork info in the parent thread.  */
-	  event_thr->pending_follow.kind = TARGET_WAITKIND_FORKED;
+	  /* Save fork info for target processing and reporting to GDB.  */
+	  if (event == PTRACE_EVENT_FORK)
+	    event_thr->pending_follow.kind = TARGET_WAITKIND_FORKED;
+	  else if (event == PTRACE_EVENT_VFORK)
+	    event_thr->pending_follow.kind = TARGET_WAITKIND_VFORKED;
+
 	  event_thr->pending_follow.value.related_pid = ptid;
 
 	  /* Report the event.  */
@@ -507,6 +512,11 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
       /* Don't report the event.  */
       return 1;
     }
+  else if (event == PTRACE_EVENT_VFORK_DONE)
+    {
+      event_thr->pending_follow.kind = TARGET_WAITKIND_VFORK_DONE;
+      return 0;
+    }
 
   internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event);
 }
@@ -1883,6 +1893,8 @@ linux_low_enable_events (pid_t pid, int attached)
   /* If GDB doesn't want fork events, don't enable them.  */
   if (!report_fork_events)
     linux_ptrace_clear_additional_flags (PTRACE_O_TRACEFORK);
+  if (!report_vfork_events)
+    linux_ptrace_clear_additional_flags (PTRACE_O_TRACEVFORK);
 
   /* Enable all supported and requested events.  */
   linux_enable_event_reporting (pid, attached);
@@ -2541,7 +2553,9 @@ extended_event_reported (const struct target_waitstatus *waitstatus)
   if (waitstatus == NULL)
     return 0;
 
-  return (waitstatus->kind == TARGET_WAITKIND_FORKED);
+  return (waitstatus->kind == TARGET_WAITKIND_FORKED
+	  || waitstatus->kind == TARGET_WAITKIND_VFORKED
+	  || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE);
 }
 
 /* Wait for process, returns status.  */
@@ -6246,6 +6260,8 @@ initialize_low (void)
   initialize_low_arch ();
 
   /* Enable any extended ptrace events that are supported.  */
-  linux_ptrace_set_additional_flags (PTRACE_O_TRACEFORK);
+  linux_ptrace_set_additional_flags (PTRACE_O_TRACEFORK
+				     | PTRACE_O_TRACEVFORK
+				     | PTRACE_O_TRACEVFORKDONE);
   linux_test_for_event_reporting ();
 }
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index f0cc882..0a4b405 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -1115,15 +1115,18 @@ prepare_resume_reply (char *buf, ptid_t ptid,
     {
     case TARGET_WAITKIND_STOPPED:
     case TARGET_WAITKIND_FORKED:
+    case TARGET_WAITKIND_VFORKED:
       {
 	struct thread_info *saved_thread;
 	const char **regp;
 	struct regcache *regcache;
 
-	if (status->kind == TARGET_WAITKIND_FORKED && multi_process)
+	if ((status->kind == TARGET_WAITKIND_FORKED
+	     || status->kind == TARGET_WAITKIND_VFORKED) && multi_process)
 	  {
 	    enum gdb_signal signal = GDB_SIGNAL_TRAP;
-	    const char *event = "fork";
+	    const char *event = (status->kind == TARGET_WAITKIND_FORKED
+				 ? "fork" : "vfork");
 
 	    sprintf (buf, "T%02x%s:p%x.%lx;", signal, event,
 		     ptid_get_pid (status->value.related_pid),
@@ -1234,6 +1237,15 @@ prepare_resume_reply (char *buf, ptid_t ptid,
       else
 	sprintf (buf, "X%02x", status->value.sig);
       break;
+    case TARGET_WAITKIND_VFORK_DONE:
+      if (multi_process)
+	{
+	  enum gdb_signal signal = GDB_SIGNAL_TRAP;
+	  const char *event = "vforkdone";
+
+	  sprintf (buf, "T%02x%s:;", signal, event);
+	}
+      break;
     default:
       error ("unhandled waitkind");
       break;
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index ce6ffb9..5284dac 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -85,6 +85,7 @@ extern int disable_packet_qfThreadInfo;
 extern int run_once;
 extern int multi_process;
 extern int report_fork_events;
+extern int report_vfork_events;
 extern int non_stop;
 
 extern int disable_randomization;
diff --git a/gdb/remote.c b/gdb/remote.c
index 9e48205..6ea3c60 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1481,7 +1481,10 @@ remote_follow_fork (struct target_ops *target, int follow_child,
 	  pid_t child_pid;
 
 	  gdb_assert ((inferior_thread ()->pending_follow.kind
-		       == TARGET_WAITKIND_FORKED));
+		       == 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);
 
@@ -4502,7 +4505,8 @@ remote_detach_1 (struct target_ops *ops, const char *args,
     {
       inferior_ptid = null_ptid;
       detach_inferior (pid);
-      inf_child_maybe_unpush_target (ops);
+      if (!extended)
+	inf_child_maybe_unpush_target (ops);
     }
 }
 
@@ -5669,6 +5673,21 @@ Packet: '%s'\n"),
 		  event->ws.value.related_pid = read_ptid (++p1, &p);
 		  event->ws.kind = TARGET_WAITKIND_FORKED;
 		}
+	      else if (strncmp (p, "vfork", p1 - p) == 0)
+		{
+		  event->ws.value.related_pid = read_ptid (++p1, &p);
+		  event->ws.kind = TARGET_WAITKIND_VFORKED;
+		}
+	      else if (strncmp (p, "vforkdone", p1 - p) == 0)
+		{
+		  p1++;
+		  p_temp = p1;
+		  while (*p_temp && *p_temp != ';')
+		    p_temp++;
+
+		  event->ws.kind = TARGET_WAITKIND_VFORK_DONE;
+		  p = p_temp;
+		}
 	      else
 		{
 		  /* Silently skip unknown optional info.  */
@@ -7929,6 +7948,7 @@ remote_kill (struct target_ops *ops)
 {
   volatile struct gdb_exception ex;
   int pid = ptid_get_pid (inferior_ptid);
+  struct remote_state *rs = get_remote_state ();
   struct thread_info *tp = first_thread_of_process (pid);
 
   /* Catch errors so the user can quit from gdb even when we
@@ -7965,7 +7985,8 @@ remote_kill (struct target_ops *ops)
     {
       inferior_ptid = null_ptid;
       detach_inferior (pid);
-      inf_child_maybe_unpush_target (ops);
+      if (!rs->extended)
+	inf_child_maybe_unpush_target (ops);
     }
 }
 
