diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c
index efbd1ea..af1d306 100644
--- a/gdb/common/linux-ptrace.c
+++ b/gdb/common/linux-ptrace.c
@@ -310,6 +310,7 @@ linux_child_function (gdb_byte *child_stack)
 
 static void linux_test_for_tracesysgood (int child_pid);
 static void linux_test_for_tracefork (int child_pid);
+static void linux_test_for_traceexit (int child_pid);
 
 /* Determine ptrace features available on this target.  */
 
@@ -341,6 +342,8 @@ linux_check_ptrace_features (void)
 
   linux_test_for_tracefork (child_pid);
 
+  linux_test_for_traceexit (child_pid);
+
   /* Clean things up and kill any pending children.  */
   do
     {
@@ -461,6 +464,43 @@ linux_test_for_tracefork (int child_pid)
 	     "(%d, status 0x%x)"), ret, status);
 }
 
+/* Determine if PTRACE_O_TRACEEXIT can be used to follow exit
+   events.  */
+
+static void
+linux_test_for_traceexit (int child_pid)
+{
+  int ret, status;
+
+#ifdef GDBSERVER
+  /* Test for PTRACE_O_TRACEEXIT.  First try to set the option.
+     If this fails, we know for sure that it is not supported.  */
+  ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0,
+                (PTRACE_TYPE_ARG4) PTRACE_O_TRACEEXIT);
+  if (ret != 0)
+    return;
+
+  /* We don't know for sure that the feature is available; old
+     versions of PTRACE_SETOPTIONS ignored unknown options.  So
+     see if the process exit will generate a PTRACE_EVENT_EXIT.  */
+  ret = ptrace (PTRACE_CONT, child_pid, (PTRACE_TYPE_ARG3) 0,
+                (PTRACE_TYPE_ARG4) 0);
+  if (ret != 0)
+    warning (_("linux_test_for_traceexit: failed to resume child"));
+
+  ret = my_waitpid (child_pid, &status, 0);
+
+  /* Check if we received an exit event notification.  */
+  if (ret == child_pid && WIFSTOPPED (status)
+      && linux_is_extended_exit (status))
+    {
+      /* PTRACE_O_TRACEEXIT is supported.  */
+      current_ptrace_options |= PTRACE_O_TRACEEXIT;
+    }
+#endif
+}
+
+
 /* Enable reporting of all currently supported ptrace events.  */
 
 void
@@ -542,3 +582,27 @@ linux_ptrace_init_warnings (void)
 
   linux_ptrace_test_ret_to_nx ();
 }
+
+/* Check wait status for any extended event.  */
+
+int
+linux_is_extended_waitstatus (int wstat)
+{
+  return (wstat >> 16 != 0);
+}
+
+/* Check wait status for extended exit event.  */
+
+int
+linux_is_extended_exit (int wstat)
+{
+  return (wstat >> 16 == PTRACE_EVENT_EXIT);
+}
+
+/* Check wait status for extended fork event.  */
+
+int
+linux_is_extended_fork (int wstat)
+{
+  return (wstat >> 16 == PTRACE_EVENT_FORK);
+}
diff --git a/gdb/common/linux-ptrace.h b/gdb/common/linux-ptrace.h
index 881d9c9..eb93862 100644
--- a/gdb/common/linux-ptrace.h
+++ b/gdb/common/linux-ptrace.h
@@ -90,5 +90,8 @@ extern int linux_supports_tracefork (void);
 extern int linux_supports_traceclone (void);
 extern int linux_supports_tracevforkdone (void);
 extern int linux_supports_tracesysgood (void);
+extern int linux_is_extended_waitstatus (int wstat);
+extern int linux_is_extended_exit (int wstat);
+extern int linux_is_extended_fork (int wstat);
 
 #endif /* COMMON_LINUX_PTRACE_H */
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 1932ff2..5404404 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -224,6 +224,7 @@ static void proceed_all_lwps (void);
 static int finish_step_over (struct lwp_info *lwp);
 static CORE_ADDR get_stop_pc (struct lwp_info *lwp);
 static int kill_lwp (unsigned long lwpid, int signo);
+static int num_lwps (int pid);
 
 /* True if the low target can hardware single-step.  Such targets
    don't need a BREAKPOINT_REINSERT_ADDR callback.  */
@@ -368,12 +369,15 @@ 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 EVENT_CHILD to our list (and not
+   report the trap to higher layers).  This function returns non-zero
+   if the event should be ignored and we should wait again.  The wait
+   status in WSTATP may be modified if an exit event occurred.  */
 
-static void
-handle_extended_wait (struct lwp_info *event_child, int wstat)
+static int
+handle_extended_wait (struct lwp_info *event_child, int *wstatp)
 {
+  int wstat = *wstatp;
   int event = wstat >> 16;
   struct thread_info *event_thr = get_lwp_thread (event_child);
   struct lwp_info *new_lwp;
@@ -452,7 +456,47 @@ 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;
+     }
+  else if (event == PTRACE_EVENT_EXIT)
+    {
+      unsigned long exit_status;
+      unsigned long lwpid = lwpid_of (event_thr);
+      int ret;
+
+      if (debug_threads)
+        debug_printf ("HEW: Got exit event from LWP %ld\n",
+                      lwpid_of (event_thr));
+
+      ptrace (PTRACE_GETEVENTMSG, lwpid_of (event_thr), (PTRACE_TYPE_ARG3) 0,
+	      &exit_status);
+
+      if (num_lwps (pid_of (event_thr)) > 1)
+        {
+	  /* If there is at least one more LWP, then the program still
+	     exists and the exit should not be reported to GDB.  */
+          delete_lwp (event_child);
+          ret = 1;
+        }
+      else
+        {
+          /* Set the exit status to the actual exit status, so normal
+             WIFEXITED/WIFSIGNALLED processing and reporting for the
+             last lwp in the process can proceed from here.  */
+          *wstatp = exit_status;
+          ret = 0;
+        }
+
+      /* Resume the thread so that it actually exits.  Subsequent exit
+         events for LWPs that were deleted above will be ignored.  */
+      ptrace (PTRACE_CONT, lwpid, (PTRACE_TYPE_ARG3) 0,
+              (PTRACE_TYPE_ARG4) 0);
+      return ret;
     }
+  internal_error (__FILE__, __LINE__,
+	          _("unknown ptrace event %d"), event);
 }
 
 /* Return the PC as read from the regcache of LWP, without any
@@ -516,7 +560,7 @@ get_stop_pc (struct lwp_info *lwp)
   if (WSTOPSIG (lwp->last_status) == SIGTRAP
       && !lwp->stepping
       && !lwp->stopped_by_watchpoint
-      && lwp->last_status >> 16 == 0)
+      && !linux_is_extended_waitstatus (lwp->last_status))
     stop_pc -= the_low_target.decr_pc_after_break;
 
   if (debug_threads)
@@ -1036,7 +1080,7 @@ get_detach_signal (struct thread_info *thread)
     }
 
   /* Extended wait statuses aren't real SIGTRAPs.  */
-  if (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+  if (WSTOPSIG (status) == SIGTRAP && linux_is_extended_waitstatus (status))
     {
       if (debug_threads)
 	debug_printf ("GPS: lwp %s had stopped with extended "
@@ -1721,11 +1765,13 @@ cancel_breakpoint (struct lwp_info *lwp)
 
 /* Do low-level handling of the event, and check if we should go on
    and pass it to caller code.  Return the affected lwp if we are, or
-   NULL otherwise.  */
+   NULL otherwise.  The wait status in WSTATP may be modified if an
+   exit event occurred.  */
 
 static struct lwp_info *
-linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
+linux_low_filter_event (ptid_t filter_ptid, int lwpid, int *wstatp)
 {
+  int wstat = *wstatp;
   struct lwp_info *child;
   struct thread_info *thread;
 
@@ -1777,7 +1823,7 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
      architecture being defined already (so that CHILD has a valid
      regcache), and on LAST_STATUS being set (to check for SIGTRAP or
      not).  */
-  if (WIFSTOPPED (wstat))
+  if (WIFSTOPPED (wstat) && !linux_is_extended_exit (wstat))
     {
       if (debug_threads
 	  && the_low_target.get_pc != NULL)
@@ -1813,7 +1859,8 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
      changes the debug registers meanwhile, we have the cached data we
      can rely on.  */
 
-  if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP)
+  if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
+      && !linux_is_extended_waitstatus (wstat))
     {
       if (the_low_target.stopped_by_watchpoint == NULL)
 	{
@@ -1849,10 +1896,17 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
     }
 
   if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
-      && wstat >> 16 != 0)
+      && linux_is_extended_waitstatus (wstat))
     {
-      handle_extended_wait (child, wstat);
-      return NULL;
+      if (handle_extended_wait (child, &wstat))
+        return NULL;
+      else
+        {
+          /* Update caller's wstat in case handle_extended_wait fixed
+             it up to reflect the actual status.  */
+          *wstatp = wstat;
+          return child;
+        }
     }
 
   if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGSTOP
@@ -2072,7 +2126,7 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid,
 	    }
 
 	  event_child = linux_low_filter_event (filter_ptid,
-						ret, *wstatp);
+						ret, wstatp);
 	  if (event_child != NULL)
 	    {
 	      /* We got an event to report to the core.  */
