diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 9bc9fa3..af4619f 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -413,6 +413,29 @@ linux_add_process (int pid, int attached)
 
 static CORE_ADDR get_pc (struct lwp_info *lwp);
 
+/* Implement the arch_setup target_ops method.  */
+
+static void
+linux_arch_setup (void)
+{
+  the_low_target.arch_setup ();
+}
+
+/* Call the target arch_setup function on THREAD.  */
+
+static void
+linux_arch_setup_thread (struct thread_info *thread)
+{
+  struct thread_info *saved_thread;
+
+  saved_thread = current_thread;
+  current_thread = thread;
+
+  linux_arch_setup ();
+
+  current_thread = saved_thread;
+}
+
 /* 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).  */
@@ -554,6 +577,56 @@ handle_extended_wait (struct lwp_info *event_lwp, int wstat)
       /* Report the event.  */
       return 0;
     }
+  else if (event == PTRACE_EVENT_EXEC && report_exec_events)
+    {
+      struct regcache *regcache;
+
+      if (debug_threads)
+	{
+	  debug_printf ("HEW: Got exec event from LWP %ld\n",
+			lwpid_of (event_thr));
+	}
+
+      /* If the exec was not called by the thread group leader, then
+	 the lwp_info and thread_info structures are out-of-date,
+	 containing information about the original leader thread and
+	 not the new exec'ing leader thread.  Invalidate the register
+	 cache without flushing it to the target.  */
+      regcache = (struct regcache *) inferior_regcache_data (event_thr);
+      free_register_cache (regcache);
+      set_inferior_regcache_data (event_thr, NULL);
+
+      /* The new executable may be for a different architecture than
+	 that of the execing process, so re-initialize the architecture.
+	 The call to get_pc will refill the register cache.  */
+      linux_arch_setup_thread (event_thr);
+      event_lwp->stop_pc = get_pc (event_lwp);
+
+      event_lwp->waitstatus.kind = TARGET_WAITKIND_EXECD;
+      event_lwp->waitstatus.value.execd_pathname
+	= xstrdup (linux_proc_pid_to_exec_file (lwpid_of (event_thr)));
+
+      /* Mark the exec status as pending.  */
+      event_lwp->stopped = 1;
+      event_lwp->status_pending_p = 1;
+      event_lwp->status_pending = wstat;
+      event_thr->last_resume_kind = resume_stop;
+      event_thr->last_status.kind = TARGET_WAITKIND_IGNORE;
+
+      if (non_stop && stopping_threads == NOT_STOPPING_THREADS)
+	{
+	  /* In non-stop mode, make sure we delete the lwp entry for a
+	     non-leader 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 when we stop all the threads.  */
+	  stop_all_lwps (0, event_lwp);
+	  unstop_all_lwps (0, event_lwp);
+	}
+
+      /* Report the event.  */
+      return 0;
+    }
 
   internal_error (__FILE__, __LINE__, _("unknown ptrace event %d"), event);
 }
@@ -819,14 +892,6 @@ linux_create_inferior (char *program, char **allargs)
   return pid;
 }
 
-/* Implement the arch_setup target_ops method.  */
-
-static void
-linux_arch_setup (void)
-{
-  the_low_target.arch_setup ();
-}
-
 /* Attach to an inferior process.  Returns 0 on success, ERRNO on
    error.  */
 
@@ -1614,7 +1679,7 @@ check_zombie_leaders (void)
 		      leader_pid, leader_lp!= NULL, num_lwps (leader_pid),
 		      linux_proc_pid_is_zombie (leader_pid));
 
-      if (leader_lp != NULL
+      if (leader_lp != NULL && !leader_lp->stopped
 	  /* Check if there are other threads in the group, as we may
 	     have raced with the inferior simply exiting.  */
 	  && !last_thread_of_process_p (leader_pid)
@@ -2040,6 +2105,9 @@ linux_low_ptrace_options (int attached)
   if (report_vfork_events)
     options |= (PTRACE_O_TRACEVFORK | PTRACE_O_TRACEVFORKDONE);
 
+  if (report_exec_events)
+    options |= PTRACE_O_TRACEEXEC;
+
   return options;
 }
 
@@ -2056,6 +2124,38 @@ linux_low_filter_event (int lwpid, int wstat)
 
   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 (because
+     check_zombie_leaders deleted it).  The non-leader thread
+     changes its tid to the tgid.  */
+
+  if (WIFSTOPPED (wstat) && (child == NULL) && (WSTOPSIG (wstat) == SIGTRAP)
+      && (linux_ptrace_get_extended_event (wstat) == PTRACE_EVENT_EXEC))
+    {
+      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"
+			"after exec.\n", lwpid);
+	}
+
+      child_ptid = ptid_build (lwpid, lwpid, 0);
+      child = add_lwp (child_ptid);
+      child->stopped = 1;
+      current_thread = child->thread;
+    }
+
   /* 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
@@ -2113,17 +2213,10 @@ linux_low_filter_event (int lwpid, int wstat)
 	{
 	  if (proc->attached)
 	    {
-	      struct thread_info *saved_thread;
-
 	      /* This needs to happen after we have attached to the
 		 inferior and it is stopped for the first time, but
 		 before we access any inferior registers.  */
-	      saved_thread = current_thread;
-	      current_thread = thread;
-
-	      the_low_target.arch_setup ();
-
-	      current_thread = saved_thread;
+	      linux_arch_setup_thread (thread);
 	    }
 	  else
 	    {
@@ -2357,8 +2450,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);
 
@@ -2756,7 +2848,8 @@ extended_event_reported (const struct target_waitstatus *waitstatus)
 
   return (waitstatus->kind == TARGET_WAITKIND_FORKED
 	  || waitstatus->kind == TARGET_WAITKIND_VFORKED
-	  || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE);
+	  || waitstatus->kind == TARGET_WAITKIND_VFORK_DONE
+	  || waitstatus->kind == TARGET_WAITKIND_EXECD);
 }
 
 /* Wait for process, returns status.  */
@@ -3301,7 +3394,8 @@ linux_wait_1 (ptid_t ptid,
       ourstatus->value.sig = GDB_SIGNAL_0;
     }
   else if (current_thread->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.  */
@@ -3419,6 +3513,7 @@ static void
 send_sigstop (struct lwp_info *lwp)
 {
   int pid;
+  int ret;
 
   pid = lwpid_of (get_lwp_thread (lwp));
 
@@ -3436,7 +3531,20 @@ 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 because a thread that was not the thread group leader
+	 called exec and took over the leader's lwp.  */
+      delete_lwp (lwp);
+      set_desired_thread (0);
+
+      if (debug_threads)
+	debug_printf ("send_sigstop: lwp %d has vanished\n", pid);
+    }
 }
 
 static int
@@ -5623,6 +5731,14 @@ linux_supports_vfork_events (void)
   return linux_supports_tracefork ();
 }
 
+/* Check if exec events are supported.  */
+
+static int
+linux_supports_exec_events (void)
+{
+  return linux_supports_traceexec ();
+}
+
 /* Callback for 'find_inferior'.  Set the (possibly changed) ptrace
    options for the specified lwp.  */
 
@@ -6711,6 +6827,7 @@ static struct target_ops linux_target_ops = {
   linux_supports_multi_process,
   linux_supports_fork_events,
   linux_supports_vfork_events,
+  linux_supports_exec_events,
   linux_handle_new_gdb_connection,
 #ifdef USE_THREAD_DB
   thread_db_handle_monitor_command,
diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c
index 5cf03be..f56d982 100644
--- a/gdb/gdbserver/lynx-low.c
+++ b/gdb/gdbserver/lynx-low.c
@@ -765,6 +765,7 @@ static struct target_ops lynx_target_ops = {
   NULL,  /* supports_multi_process */
   NULL,  /* supports_fork_events */
   NULL,  /* supports_vfork_events */
+  NULL,  /* supports_exec_events */
   NULL,  /* handle_new_gdb_connection */
   NULL,  /* handle_monitor_command */
 };
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index bb31456..79d5ee8 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -1116,6 +1116,7 @@ prepare_resume_reply (char *buf, ptid_t ptid,
     case TARGET_WAITKIND_STOPPED:
     case TARGET_WAITKIND_FORKED:
     case TARGET_WAITKIND_VFORKED:
+    case TARGET_WAITKIND_EXECD:
       {
 	struct thread_info *saved_thread;
 	const char **regp;
@@ -1133,6 +1134,25 @@ prepare_resume_reply (char *buf, ptid_t ptid,
 	    buf = write_ptid (buf, status->value.related_pid);
 	    strcat (buf, ";");
 	  }
+	else if ((status->kind == TARGET_WAITKIND_EXECD) && multi_process)
+	  {
+	    enum gdb_signal signal = GDB_SIGNAL_TRAP;
+	    const char *event = "exec";
+	    char hexified_pathname[PATH_MAX];
+
+	    sprintf (buf, "T%02x%s:", signal, 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);
+	  }
 	else
 	  sprintf (buf, "T%02x", status->value.sig);
 
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 2918770..ee0a044 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -59,6 +59,7 @@ int run_once;
 int multi_process;
 int report_fork_events;
 int report_vfork_events;
+int report_exec_events;
 int non_stop;
 int swbreak_feature;
 int hwbreak_feature;
@@ -2109,6 +2110,12 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
 		  if (target_supports_vfork_events ())
 		    report_vfork_events = 1;
 		}
+	      if (strcmp (p, "exec-events+") == 0)
+		{
+		  /* GDB supports and wants exec events if possible.  */
+		  if (target_supports_exec_events ())
+		    report_exec_events = 1;
+		}
 	      else
 		target_process_qsupported (p);
 
@@ -2165,6 +2172,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       if (target_supports_vfork_events ())
 	strcat (own_buf, ";vfork-events+");
 
+      if (target_supports_exec_events ())
+	strcat (own_buf, ";exec-events+");
+
       if (target_supports_non_stop ())
 	strcat (own_buf, ";QNonStop+");
 
@@ -3547,6 +3557,7 @@ captured_main (int argc, char *argv[])
       multi_process = 0;
       report_fork_events = 0;
       report_vfork_events = 0;
+      report_exec_events = 0;
       /* Be sure we're out of tfind mode.  */
       current_traceframe = -1;
       cont_thread = null_ptid;
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 09a5624..258909d 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -86,6 +86,7 @@ extern int run_once;
 extern int multi_process;
 extern int report_fork_events;
 extern int report_vfork_events;
+extern int report_exec_events;
 extern int non_stop;
 
 /* True if the "swbreak+" feature is active.  In that case, GDB wants
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index fefd8d1..83a55cd 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -290,6 +290,9 @@ struct target_ops
   /* Returns true if vfork events are supported.  */
   int (*supports_vfork_events) (void);
 
+  /* Returns true if exec events are supported.  */
+  int (*supports_exec_events) (void);
+
   /* Allows target to re-initialize connection-specific settings.  */
   void (*handle_new_gdb_connection) (void);
 
@@ -468,6 +471,10 @@ int kill_inferior (int);
   (the_target->supports_vfork_events ? \
    (*the_target->supports_vfork_events) () : 0)
 
+#define target_supports_exec_events() \
+  (the_target->supports_exec_events ? \
+   (*the_target->supports_exec_events) () : 0)
+
 #define target_handle_new_gdb_connection()		 \
   do							 \
     {							 \
diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c
index 7ccb3dd..53f6696 100644
--- a/gdb/gdbserver/win32-low.c
+++ b/gdb/gdbserver/win32-low.c
@@ -1832,6 +1832,7 @@ static struct target_ops win32_target_ops = {
   NULL, /* supports_multi_process */
   NULL, /* supports_fork_events */
   NULL, /* supports_vfork_events */
+  NULL, /* supports_exec_events */
   NULL, /* handle_new_gdb_connection */
   NULL, /* handle_monitor_command */
   NULL, /* core_of_thread */
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 445a612..249d867 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1056,6 +1056,7 @@ follow_exec (ptid_t ptid, char *execd_pathname)
   struct thread_info *th, *tmp;
   struct inferior *inf = current_inferior ();
   int pid = ptid_get_pid (ptid);
+  ptid_t process_ptid;
 
   /* This is an exec event that we actually wish to pay attention to.
      Refresh our symbol table to the newly exec'd program, remove any
@@ -1122,8 +1123,9 @@ follow_exec (ptid_t ptid, char *execd_pathname)
   update_breakpoints_after_exec ();
 
   /* What is this a.out's name?  */
+  process_ptid = pid_to_ptid (pid);
   printf_unfiltered (_("%s is executing new program: %s\n"),
-		     target_pid_to_str (inferior_ptid),
+		     target_pid_to_str (process_ptid),
 		     execd_pathname);
 
   /* We've followed the inferior through an exec.  Therefore, the
diff --git a/gdb/nat/linux-ptrace.c b/gdb/nat/linux-ptrace.c
index f097c8a..235dfba 100644
--- a/gdb/nat/linux-ptrace.c
+++ b/gdb/nat/linux-ptrace.c
@@ -528,9 +528,7 @@ ptrace_supports_feature (int ptrace_options)
 }
 
 /* Returns non-zero if PTRACE_EVENT_FORK is supported by ptrace,
-   0 otherwise.  Note that if PTRACE_EVENT_FORK is supported so is
-   PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK,
-   since they were all added to the kernel at the same time.  */
+   0 otherwise.  */
 
 int
 linux_supports_tracefork (void)
@@ -538,6 +536,15 @@ linux_supports_tracefork (void)
   return ptrace_supports_feature (PTRACE_O_TRACEFORK);
 }
 
+/* Returns non-zero if PTRACE_EVENT_EXEC is supported by ptrace,
+   0 otherwise.  */
+
+int
+linux_supports_traceexec (void)
+{
+  return ptrace_supports_feature (PTRACE_O_TRACEEXEC);
+}
+
 /* Returns non-zero if PTRACE_EVENT_CLONE is supported by ptrace,
    0 otherwise.  Note that if PTRACE_EVENT_CLONE is supported so is
    PTRACE_EVENT_FORK, PTRACE_EVENT_EXEC and PTRACE_EVENT_VFORK,
diff --git a/gdb/nat/linux-ptrace.h b/gdb/nat/linux-ptrace.h
index 41f668c..c2ecf3c 100644
--- a/gdb/nat/linux-ptrace.h
+++ b/gdb/nat/linux-ptrace.h
@@ -161,6 +161,7 @@ extern void linux_check_ptrace_features (void);
 extern void linux_enable_event_reporting (pid_t pid, int attached);
 extern void linux_disable_event_reporting (pid_t pid);
 extern int linux_supports_tracefork (void);
+extern int linux_supports_traceexec (void);
 extern int linux_supports_traceclone (void);
 extern int linux_supports_tracevforkdone (void);
 extern int linux_supports_tracesysgood (void);
diff --git a/gdb/remote.c b/gdb/remote.c
index 4ac393b..1aeba30 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1367,6 +1367,9 @@ enum {
   /* Support for the Qbtrace-conf:pt:size packet.  */
   PACKET_Qbtrace_conf_pt_size,
 
+  /* Support for exec events.  */
+  PACKET_exec_event_feature,
+
   PACKET_MAX
 };
 
@@ -4187,6 +4190,8 @@ static const struct protocol_feature remote_protocol_features[] = {
     PACKET_fork_event_feature },
   { "vfork-events", PACKET_DISABLE, remote_supported_packet,
     PACKET_vfork_event_feature },
+  { "exec-events", PACKET_DISABLE, remote_supported_packet,
+    PACKET_exec_event_feature },
   { "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet,
     PACKET_Qbtrace_conf_pt_size }
 };
@@ -4275,6 +4280,9 @@ remote_query_supported (void)
 	  if (packet_set_cmd_state (PACKET_vfork_event_feature)
 	      != AUTO_BOOLEAN_FALSE)
 	    q = remote_query_supported_append (q, "vfork-events+");
+	  if (packet_set_cmd_state (PACKET_exec_event_feature)
+	      != AUTO_BOOLEAN_FALSE)
+	    q = remote_query_supported_append (q, "exec-events+");
 	}
 
       q = reconcat (q, "qSupported:", q, (char *) NULL);
@@ -5934,6 +5942,31 @@ Packet: '%s'\n"),
 	      event->ws.kind = TARGET_WAITKIND_VFORK_DONE;
 	      p = skip_to_semicolon (p1 + 1);
 	    }
+	  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 = xstrdup (pathname);
+	      /* Reset the architecture in case the new executable is
+		 different from the execing executable.  We need to
+		 do this right now, before any register access, to
+		 keep the client and remote architectures in sync.  */
+	      target_clear_description ();
+	      exec_file_attach (remote_exec_file, 0);
+	    }
 	  else
 	    {
 	      ULONGEST pnum;
@@ -12983,6 +13016,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
   add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_pt_size],
        "Qbtrace-conf:pt:size", "btrace-conf-pt-size", 0);
 
+  add_packet_config_cmd (&remote_protocol_packets[PACKET_exec_event_feature],
+			 "exec-event-feature", "exec-event-feature", 0);
+
   /* Assert that we've registered "set remote foo-packet" commands
      for all packet configs.  */
   {
