diff --git a/gdb/common/linux-procfs.c b/gdb/common/linux-procfs.c
index 1443a88..6333b0b 100644
--- a/gdb/common/linux-procfs.c
+++ b/gdb/common/linux-procfs.c
@@ -25,6 +25,7 @@
 
 #include "linux-procfs.h"
 #include "filestuff.h"
+#include "target.h"
 
 /* Return the TGID of LWPID from /proc/pid/status.  Returns -1 if not
    found.  */
@@ -119,3 +120,20 @@ linux_proc_pid_is_zombie (pid_t pid)
 {
   return linux_proc_pid_has_state (pid, "Z (zombie)");
 }
+
+/* Accepts an integer PID; Returns a string representing a file that
+   can be opened to get the symbols for the child process.  */
+
+char *
+linux_proc_pid_to_exec_file (struct target_ops *self, int pid)
+{
+  static char buf[PATH_MAX];
+  char name[PATH_MAX];
+
+  xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
+  memset (buf, 0, PATH_MAX);
+  if (readlink (name, buf, PATH_MAX - 1) <= 0)
+    strcpy (buf, name);
+
+  return buf;
+}
diff --git a/gdb/common/linux-procfs.h b/gdb/common/linux-procfs.h
index d13fff7..d3581de 100644
--- a/gdb/common/linux-procfs.h
+++ b/gdb/common/linux-procfs.h
@@ -40,4 +40,8 @@ extern int linux_proc_pid_is_stopped (pid_t pid);
 
 extern int linux_proc_pid_is_zombie (pid_t pid);
 
+/* Return pathname of exec file for process with PID.  */
+
+extern char *linux_proc_pid_to_exec_file (struct target_ops *self, int pid);
+
 #endif /* COMMON_LINUX_PROCFS_H */
diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c
index af1d306..9fac55a 100644
--- a/gdb/common/linux-ptrace.c
+++ b/gdb/common/linux-ptrace.c
@@ -494,8 +494,11 @@ linux_test_for_traceexit (int child_pid)
   if (ret == child_pid && WIFSTOPPED (status)
       && linux_is_extended_exit (status))
     {
-      /* PTRACE_O_TRACEEXIT is supported.  */
-      current_ptrace_options |= PTRACE_O_TRACEEXIT;
+      /* PTRACE_O_TRACEEXIT is supported.  We use exit events to
+	 implement support for exec events.  Since fork events are
+	 supported we know exec events are supported, so we enable
+	 exec events here.  */
+      current_ptrace_options |= PTRACE_O_TRACEEXIT | PTRACE_O_TRACEEXEC;
     }
 #endif
 }
@@ -606,3 +609,11 @@ linux_is_extended_fork (int wstat)
 {
   return (wstat >> 16 == PTRACE_EVENT_FORK);
 }
+
+/* Check wait status for extended exec event.  */
+
+int
+linux_is_extended_exec (int wstat)
+{
+  return (wstat >> 16 == PTRACE_EVENT_EXEC);
+}
diff --git a/gdb/common/linux-ptrace.h b/gdb/common/linux-ptrace.h
index eb93862..461cb5d 100644
--- a/gdb/common/linux-ptrace.h
+++ b/gdb/common/linux-ptrace.h
@@ -93,5 +93,6 @@ 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);
+extern int linux_is_extended_exec (int wstat);
 
 #endif /* COMMON_LINUX_PTRACE_H */
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 5404404..99b0360 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -495,6 +495,19 @@ handle_extended_wait (struct lwp_info *event_child, int *wstatp)
               (PTRACE_TYPE_ARG4) 0);
       return ret;
     }
+  else if (event == PTRACE_EVENT_EXEC)
+    {
+      if (debug_threads)
+	debug_printf ("HEW: Got exec event from LWP %ld\n",
+		      lwpid_of (event_thr));
+
+      event_child->waitstatus.kind = TARGET_WAITKIND_EXECD;
+      event_child->waitstatus.value.execd_pathname
+	= xstrdup (linux_proc_pid_to_exec_file (NULL, lwpid_of (event_thr)));
+
+      /* Report the event.  */
+      return 0;
+    }
   internal_error (__FILE__, __LINE__,
 	          _("unknown ptrace event %d"), event);
 }
@@ -1362,18 +1375,19 @@ check_zombie_leaders (void)
 	     program).  In the latter case, we can't waitpid the
 	     leader's exit status until all other threads are gone.
 
-	     - There are 3 or more threads in the group, and a thread
+	     - There are multiple threads in the group, and a thread
 	     other than the leader exec'd.  On an exec, the Linux
 	     kernel destroys all other threads (except the execing
 	     one) in the thread group, and resets the execing thread's
 	     tid to the tgid.  No exit notification is sent for the
 	     execing thread -- from the ptracer's perspective, it
 	     appears as though the execing thread just vanishes.
-	     Until we reap all other threads except the leader and the
-	     execing thread, the leader will be zombie, and the
-	     execing thread will be in `D (disc sleep)'.  As soon as
-	     all other threads are reaped, the execing thread changes
-	     it's tid to the tgid, and the previous (zombie) leader
+	     Until we reap all other threads (if any) except the
+	     leader and the execing thread, the leader will be zombie,
+	     and the execing thread will be in `D (disc sleep)'.  As
+	     soon as all other threads are reaped, or have reported
+	     PTRACE_EVENT_EXIT events, the execing thread changes its
+	     tid to the tgid, and the previous (zombie) leader
 	     vanishes, giving place to the "new" leader.  We could try
 	     distinguishing the exit and exec cases, by waiting once
 	     more, and seeing if something comes out, but it doesn't
@@ -1381,7 +1395,11 @@ check_zombie_leaders (void)
 	     we'll re-add the new one once we see the exec event
 	     (which is just the same as what would happen if the
 	     previous leader did exit voluntarily before some other
-	     thread execs).  */
+	     thread execs).
+
+	     Note that when PTRACE_EVENT_EXEC is supported, we use
+	     that mechanism to detect thread exit, including the
+	     exit of zombie leaders.  */
 
 	  if (debug_threads)
 	    fprintf (stderr,
@@ -1777,6 +1795,57 @@ linux_low_filter_event (ptid_t filter_ptid, int lwpid, int *wstatp)
 
   child = find_lwp_pid (pid_to_ptid (lwpid));
 
+  /* Check for stop events reported by a process we didn't already
+     know about - anything not already in our LWP list.
+
+     If we're expecting to receive stopped processes after
+     fork, vfork, and clone events, then we'll just add the
+     new one to our list and go back to waiting for the event
+     to be reported - the stopped process might be returned
+     from waitpid before or after the event is.
+
+     But note the case of a non-leader thread exec'ing after the
+     leader having exited, and gone from our lists.  On an exec,
+     the Linux kernel destroys all other threads (except the execing
+     one) in the thread group, and resets the execing thread's tid
+     to the tgid.  No exit notification is sent for the execing
+     thread -- from the ptracer's perspective, it appears as though
+     the execing thread just vanishes.  When they are available, we
+     use exit events (PTRACE_EVENT_EXIT) to detect thread exit
+     reliably.  As soon as all other threads (if any) are reaped or
+     have reported their PTRACE_EVENT_EXIT events, the execing
+     thread changes it's tid to the tgid, and the previous (zombie)
+     leader vanishes, giving place to the "new" leader.  The lwp
+     entry for the previous leader is deleted when we handle its
+     exit event, and we re-add the new one here.  */
+
+  if (WIFSTOPPED (wstat) && child == NULL
+      && (WSTOPSIG (wstat) == SIGTRAP && linux_is_extended_exec (wstat)))
+    {
+      ptid_t child_ptid;
+
+      /* A multi-thread exec after we had seen the leader exiting.  */
+      if (debug_threads)
+	debug_printf ("LLW: Re-adding thread group leader LWP %d.\n",
+		      lwpid);
+
+      child_ptid = ptid_build (lwpid, lwpid, 0);
+      child = add_lwp (child_ptid);
+      child->stopped = 1;
+      current_inferior = child->thread;
+
+      if (non_stop && stopping_threads == NOT_STOPPING_THREADS)
+	{
+	  /* Make sure we delete the lwp entry for the exec'ing thread,
+	     which will have vanished.  We do this by sending a signal
+	     to all the other threads in the lwp list, deleting any
+	     that are not found.  Note that in all-stop mode this will
+	     happen before reporting the event.  */
+	  stop_all_lwps (0, child);
+	  unstop_all_lwps (0, child);
+	}
+    }
+
   /* If we didn't find a process, one of two things presumably happened:
      - A process we started and then detached from has exited.  Ignore it.
      - A process we are controlling has forked and the new child's stop
@@ -2108,8 +2177,7 @@ linux_wait_for_event_filtered (ptid_t wait_ptid, ptid_t filter_ptid,
 	 - When a non-leader thread execs, that thread just vanishes
 	   without reporting an exit (so we'd hang if we waited for it
 	   explicitly in that case).  The exec event is reported to
-	   the TGID pid (although we don't currently enable exec
-	   events).  */
+	   the TGID pid.  */
       errno = 0;
       ret = my_waitpid (-1, wstatp, options | WNOHANG);
 
@@ -2506,6 +2574,20 @@ linux_stabilize_threads (void)
     }
 }
 
+/* Return non-zero if WAITSTATUS reflects an extended linux
+   event.  Otherwise, return 0.  Note that extended EXIT
+   events are fixed up and handled like normal events, so
+   they are not considered here.  */
+
+static int
+extended_event_reported (const struct target_waitstatus *waitstatus)
+{
+  if (waitstatus == NULL)
+    return 0;
+
+  return (waitstatus->kind == TARGET_WAITKIND_EXECD);
+}
+
 /* Wait for process, returns status.  */
 
 static ptid_t
@@ -2869,7 +2951,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);
 
@@ -2891,6 +2974,14 @@ retry:
 			  paddress (event_child->stop_pc),
 			  paddress (event_child->step_range_start),
 			  paddress (event_child->step_range_end));
+	  if (debug_threads
+	      && 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
@@ -2989,7 +3080,19 @@ 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_inferior->last_resume_kind == resume_stop
       && WSTOPSIG (w) == SIGSTOP)
@@ -3000,13 +3103,14 @@ retry:
       ourstatus->value.sig = GDB_SIGNAL_0;
     }
   else if (current_inferior->last_resume_kind == resume_stop
-	   && WSTOPSIG (w) != SIGSTOP)
+	   && WSTOPSIG (w) != SIGSTOP
+	   && !extended_event_reported (ourstatus))
     {
       /* A thread that has been requested to stop by GDB with vCont;t,
 	 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));
     }
@@ -3112,6 +3216,7 @@ static void
 send_sigstop (struct lwp_info *lwp)
 {
   int pid;
+  int ret;
 
   pid = lwpid_of (get_lwp_thread (lwp));
 
@@ -3129,7 +3234,21 @@ send_sigstop (struct lwp_info *lwp)
     debug_printf ("Sending sigstop to lwp %d\n", pid);
 
   lwp->stop_expected = 1;
-  kill_lwp (pid, SIGSTOP);
+  errno = 0;
+  ret = kill_lwp (pid, SIGSTOP);
+  if (ret == -1 && errno == ESRCH)
+    {
+      /* If the kill fails with "No such process", on GNU/Linux we know
+	 that the LWP has vanished - it is not a zombie, it is gone.
+	 This is due to a thread other than the thread group leader
+	 calling exec.  See comments in linux_low_filter_event regarding
+	 PTRACE_EVENT_EXEC.  */
+      delete_lwp (lwp);
+      set_desired_inferior (0);
+
+      if (debug_threads)
+	debug_printf ("send_sigstop: lwp %d has vanished\n", pid);
+    }
 }
 
 static int
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index 498b221..fea6deb 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -269,6 +269,11 @@ struct lwp_info
   /* When stopped is set, the last wait status recorded for this lwp.  */
   int last_status;
 
+  /* If WAITSTATUS->KIND != TARGET_WAITKIND_IGNORE, the waitstatus for
+     this LWP's last event.  This may correspond to LAST_STATUS above,
+     or to the current status during event processing.  */
+  struct target_waitstatus waitstatus;
+
   /* When stopped is set, this is where the lwp stopped, with
      decr_pc_after_break already accounted for.  */
   CORE_ADDR stop_pc;
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 4fcafa0..9ce25dc 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -1111,14 +1111,40 @@ prepare_resume_reply (char *buf, ptid_t ptid,
   switch (status->kind)
     {
     case TARGET_WAITKIND_STOPPED:
+    case TARGET_WAITKIND_EXECD:
       {
 	struct thread_info *saved_inferior;
 	const char **regp;
 	struct regcache *regcache;
+	enum gdb_signal signal;
+
+	if (status->kind == TARGET_WAITKIND_EXECD)
+	  signal = GDB_SIGNAL_TRAP;
+	else
+	  signal = status->value.sig;
+
+	sprintf (buf, "T%02x", signal);
 
-	sprintf (buf, "T%02x", status->value.sig);
 	buf += strlen (buf);
 
+	if (status->kind == TARGET_WAITKIND_EXECD && multi_process)
+	  {
+	    const char *event = "exec";
+	    char hexified_pathname[PATH_MAX];
+
+	    sprintf (buf, "%s:", event);
+	    buf += strlen (buf);
+
+	    /* Encode pathname to hexified format.  */
+	    bin2hex ((const gdb_byte *) status->value.execd_pathname,
+		     hexified_pathname, strlen(status->value.execd_pathname));
+
+	    sprintf (buf, "%s;", hexified_pathname);
+	    xfree (status->value.execd_pathname);
+	    status->value.execd_pathname = NULL;
+	    buf += strlen (buf);
+	  }
+
 	saved_inferior = current_inferior;
 
 	current_inferior = find_thread_ptid (ptid);
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index e84ee95..762811c 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -845,7 +845,6 @@ linux_nat_pass_signals (struct target_ops *self,
 /* Prototypes for local functions.  */
 static int stop_wait_callback (struct lwp_info *lp, void *data);
 static int linux_thread_alive (ptid_t ptid);
-static char *linux_child_pid_to_exec_file (struct target_ops *self, int pid);
 
 
 
@@ -2172,7 +2171,7 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
 
       ourstatus->kind = TARGET_WAITKIND_EXECD;
       ourstatus->value.execd_pathname
-	= xstrdup (linux_child_pid_to_exec_file (NULL, pid));
+	= xstrdup (linux_proc_pid_to_exec_file (NULL, pid));
 
       return 0;
     }
@@ -4008,23 +4007,6 @@ linux_nat_thread_name (struct target_ops *self, struct thread_info *thr)
   return result;
 }
 
-/* Accepts an integer PID; Returns a string representing a file that
-   can be opened to get the symbols for the child process.  */
-
-static char *
-linux_child_pid_to_exec_file (struct target_ops *self, int pid)
-{
-  static char buf[PATH_MAX];
-  char name[PATH_MAX];
-
-  xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
-  memset (buf, 0, PATH_MAX);
-  if (readlink (name, buf, PATH_MAX - 1) <= 0)
-    strcpy (buf, name);
-
-  return buf;
-}
-
 /* Records the thread's register state for the corefile note
    section.  */
 
@@ -4473,7 +4455,7 @@ linux_target_install_ops (struct target_ops *t)
   t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint;
   t->to_remove_exec_catchpoint = linux_child_remove_exec_catchpoint;
   t->to_set_syscall_catchpoint = linux_child_set_syscall_catchpoint;
-  t->to_pid_to_exec_file = linux_child_pid_to_exec_file;
+  t->to_pid_to_exec_file = linux_proc_pid_to_exec_file;
   t->to_post_startup_inferior = linux_child_post_startup_inferior;
   t->to_post_attach = linux_child_post_attach;
   t->to_follow_fork = linux_child_follow_fork;
diff --git a/gdb/remote.c b/gdb/remote.c
index 964bd41..ffe9df4 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -5415,11 +5415,13 @@ remote_parse_stop_reply (char *buf, struct stop_reply *event)
 	     pnum and set p1 to point to the character following it.
 	     Otherwise p1 points to p.  */
 
-	  /* If this packet is an awatch packet, don't parse the 'a'
-	     as a register number.  */
+	  /* If this packet has a stop reason string that starts
+	     with a character that could be a hex digit, don't parse
+	     it 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, "exec", strlen ("exec") != 0))
 	    {
 	      /* Read the ``P'' register number.  */
 	      pnum = strtol (p, &p_temp, 16);
@@ -5471,6 +5473,25 @@ Packet: '%s'\n"),
 		  p = unpack_varlen_hex (++p1, &c);
 		  event->core = c;
 		}
+	      else if (strncmp (p, "exec", p1 - p) == 0)
+		{
+		  ULONGEST pid;
+		  char pathname[PATH_MAX];
+
+		  p = unpack_varlen_hex (++p1, &pid);
+
+		  /* Save the pathname for event reporting and for
+		     the next run command. */
+		  hex2bin (p1, (gdb_byte *) pathname, (p - p1)/2);
+		  /* Add the null terminator.  */
+		  pathname[(p - p1)/2] = '\0';
+		  /* This is freed during event handling.  */
+		  event->ws.value.execd_pathname = xstrdup (pathname);
+		  event->ws.kind = TARGET_WAITKIND_EXECD;
+		  /* Save the pathname for the next run command.  */
+		  xfree (remote_exec_file);
+		  remote_exec_file = pathname;
+		}
 	      else
 		{
 		  /* Silently skip unknown optional info.  */
