diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 369bfbe..d5f6fe0 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -222,6 +222,7 @@ static int finish_step_over (struct lwp_info *lwp);
 static CORE_ADDR get_stop_pc (struct lwp_info *lwp);
 static void async_file_mark (void);
 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.  */
@@ -366,12 +367,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 return 0 so as
-   not to 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.  If an
+   exit event occurred in the last thread of a process, the wait
+   status in WSTATP will be updated with the exit status of the
+   process.  */
 
 static int
-handle_extended_wait (struct lwp_info *event_child, int wstat)
+handle_extended_wait (struct lwp_info *event_child, int *wstatp)
 {
+  int wstat = *wstatp;
   int event = linux_ptrace_get_extended_event (wstat);
   struct thread_info *event_thr = get_lwp_thread (event_child);
   struct lwp_info *new_lwp;
@@ -524,6 +530,38 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
       event_child->waitstatus.kind = TARGET_WAITKIND_VFORK_DONE;
       return 0;
     }
+  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 );
+
+      ptrace (PTRACE_GETEVENTMSG, lwpid, (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);
 }
@@ -2001,8 +2039,9 @@ lp_status_maybe_breakpoint (struct lwp_info *lp)
    NULL otherwise.  */
 
 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;
 
@@ -2054,7 +2093,8 @@ 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_ptrace_get_extended_event (wstat) != PTRACE_EVENT_EXIT))
     {
       if (debug_threads
 	  && the_low_target.get_pc != NULL)
@@ -2090,7 +2130,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)
 	{
@@ -2128,10 +2169,15 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int wstat)
   if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
       && linux_is_extended_waitstatus (wstat))
     {
-      if (handle_extended_wait (child, wstat))
+      if (handle_extended_wait (child, &wstat))
 	return NULL;
       else
-	return child;
+	{
+	  /* Update caller's wstat in case handle_extended_wait
+	     changed it.  */
+	  *wstatp = wstat;
+	  return child;
+	}
     }
 
   if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGSTOP
@@ -2354,8 +2400,7 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid,
 			    (long) ret, status_to_str (*wstatp));
 	    }
 
-	  event_child = linux_low_filter_event (filter_ptid,
-						ret, *wstatp);
+	  event_child = linux_low_filter_event (filter_ptid, ret, wstatp);
 	  if (event_child != NULL)
 	    {
 	      /* We got an event to report to the core.  */
@@ -6484,6 +6529,7 @@ initialize_low (void)
   /* Enable extended events.  */
   linux_ptrace_set_requested_options (PTRACE_O_TRACEFORK
 				      | PTRACE_O_TRACEVFORK
-				      | PTRACE_O_TRACEVFORKDONE);
+				      | PTRACE_O_TRACEVFORKDONE
+				      | PTRACE_O_TRACEEXIT);
   linux_ptrace_check_options ();
 }
diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c
index 5f3f123..e8fd58c 100644
--- a/gdb/nat/linux-ptrace.c
+++ b/gdb/nat/linux-ptrace.c
@@ -313,6 +313,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.  */
 
@@ -350,6 +351,8 @@ linux_ptrace_check_options (void)
 
   linux_test_for_tracefork (child_pid);
 
+  linux_test_for_traceexit (child_pid);
+
   /* Clean things up and kill any pending children.  */
   do
     {
@@ -464,6 +467,53 @@ 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;
+  int status;
+  int i;
+
+  /* Check if the caller wants PTRACE_O_TRACEEXIT.  */
+  if ((requested_ptrace_options & PTRACE_O_TRACEEXIT) == 0)
+    return;
+
+  /* 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.
+
+     We try twice (at most) to handle the case where the grandchild
+     process exits, causing a SIGCHLD to be delivered to the child
+     process, stopping it before exit.  */
+  for (i = 0; i < 2; i++)
+    {
+      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_ptrace_get_extended_event (status) == PTRACE_EVENT_EXIT)
+	{
+	  /* PTRACE_O_TRACEEXIT is supported.  */
+	  available_ptrace_options |= PTRACE_O_TRACEEXIT;
+	}
+    }
+}
+
 /* Enable reporting of supported ptrace events.  If
    USE_AVAILABLE_OPTIONS is false, then exclude the events
    specified in available_ptrace_options.  If PID is non-zero,
