OSDN Git Service

2012-01-19 Pedro Alves <palves@redhat.com>
[pf3gnuchains/pf3gnuchains4x.git] / gdb / linux-nat.c
index 4595c06..30f9062 100644 (file)
@@ -1,7 +1,6 @@
 /* GNU/Linux native-dependent code common to multiple platforms.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
-   2011 Free Software Foundation, Inc.
+   Copyright (C) 2001-2012 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -59,6 +58,7 @@
 #include <sys/vfs.h>
 #include "solib.h"
 #include "linux-osdata.h"
+#include "cli/cli-utils.h"
 
 #ifndef SPUFS_MAGIC
 #define SPUFS_MAGIC 0x23c9b64e
@@ -174,7 +174,10 @@ static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
 /* The method to call, if any, when a new thread is attached.  */
-static void (*linux_nat_new_thread) (ptid_t);
+static void (*linux_nat_new_thread) (struct lwp_info *);
+
+/* Hook to call prior to resuming a thread.  */
+static void (*linux_nat_prepare_to_resume) (struct lwp_info *);
 
 /* The method to call, if any, when the siginfo object needs to be
    converted between the layout returned by ptrace, and the layout in
@@ -1072,6 +1075,15 @@ status_to_str (int status)
   return buf;
 }
 
+/* Destroy and free LP.  */
+
+static void
+lwp_free (struct lwp_info *lp)
+{
+  xfree (lp->arch_private);
+  xfree (lp);
+}
+
 /* Remove all LWPs belong to PID from the lwp list.  */
 
 static void
@@ -1092,7 +1104,7 @@ purge_lwp_list (int pid)
          else
            lpprev->next = lp->next;
 
-         xfree (lp);
+         lwp_free (lp);
        }
       else
        lpprev = lp;
@@ -1138,8 +1150,16 @@ add_lwp (ptid_t ptid)
   lp->next = lwp_list;
   lwp_list = lp;
 
+  /* Let the arch specific bits know about this new thread.  Current
+     clients of this callback take the opportunity to install
+     watchpoints in the new thread.  Don't do this for the first
+     thread though.  If we're spawning a child ("run"), the thread
+     executes the shell wrapper first, and we shouldn't touch it until
+     it execs the program we want to debug.  For "attach", it'd be
+     okay to call the callback, but it's not necessary, because
+     watchpoints can't yet have been inserted into the inferior.  */
   if (num_lwps (GET_PID (ptid)) > 1 && linux_nat_new_thread != NULL)
-    linux_nat_new_thread (ptid);
+    linux_nat_new_thread (lp);
 
   return lp;
 }
@@ -1165,7 +1185,7 @@ delete_lwp (ptid_t ptid)
   else
     lwp_list = lp->next;
 
-  xfree (lp);
+  lwp_free (lp);
 }
 
 /* Return a pointer to the structure describing the LWP corresponding
@@ -1723,6 +1743,8 @@ detach_callback (struct lwp_info *lp, void *data)
       /* Pass on any pending signal for this LWP.  */
       get_pending_status (lp, &status);
 
+      if (linux_nat_prepare_to_resume != NULL)
+       linux_nat_prepare_to_resume (lp);
       errno = 0;
       if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0,
                  WSTOPSIG (status)) < 0)
@@ -1783,6 +1805,8 @@ linux_nat_detach (struct target_ops *ops, char *args, int from_tty)
                            target_pid_to_str (main_lwp->ptid));
     }
 
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (main_lwp);
   delete_lwp (main_lwp->ptid);
 
   if (forks_exist_p ())
@@ -1824,6 +1848,8 @@ resume_lwp (struct lwp_info *lp, int step)
                                "RC:  PTRACE_CONT %s, 0, 0 (resuming sibling)\n",
                                target_pid_to_str (lp->ptid));
 
+         if (linux_nat_prepare_to_resume != NULL)
+           linux_nat_prepare_to_resume (lp);
          linux_ops->to_resume (linux_ops,
                                pid_to_ptid (GET_LWP (lp->ptid)),
                                step, TARGET_SIGNAL_0);
@@ -1968,6 +1994,8 @@ linux_nat_resume (struct target_ops *ops,
   /* Convert to something the lower layer understands.  */
   ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, ptid, step, signo);
   memset (&lp->siginfo, 0, sizeof (lp->siginfo));
   lp->stopped_by_watchpoint = 0;
@@ -2137,6 +2165,8 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping)
   /* Note that gdbarch_get_syscall_number may access registers, hence
      fill a regcache.  */
   registers_changed ();
+  if (linux_nat_prepare_to_resume != NULL)
+    linux_nat_prepare_to_resume (lp);
   linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                        lp->step, TARGET_SIGNAL_0);
   return 1;
@@ -2324,6 +2354,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
                    fprintf_unfiltered (gdb_stdlog,
                                        "LHEW: resuming new LWP %ld\n",
                                        GET_LWP (new_lp->ptid));
+                 if (linux_nat_prepare_to_resume != NULL)
+                   linux_nat_prepare_to_resume (new_lp);
                  linux_ops->to_resume (linux_ops, pid_to_ptid (new_pid),
                                        0, TARGET_SIGNAL_0);
                  new_lp->stopped = 0;
@@ -2333,6 +2365,8 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
          if (debug_linux_nat)
            fprintf_unfiltered (gdb_stdlog,
                                "LHEW: resuming parent LWP %d\n", pid);
+         if (linux_nat_prepare_to_resume != NULL)
+           linux_nat_prepare_to_resume (lp);
          linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                                0, TARGET_SIGNAL_0);
 
@@ -2596,6 +2630,14 @@ stop_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
+/* Request a stop on LWP.  */
+
+void
+linux_stop_lwp (struct lwp_info *lwp)
+{
+  stop_callback (lwp, NULL);
+}
+
 /* Return non-zero if LWP PID has a pending SIGINT.  */
 
 static int
@@ -3176,7 +3218,7 @@ stop_and_resume_callback (struct lwp_info *lp, void *data)
    other lwp.  In that case set *NEW_PENDING_P to true.  */
 
 static struct lwp_info *
-linux_nat_filter_event (int lwpid, int status, int options, int *new_pending_p)
+linux_nat_filter_event (int lwpid, int status, int *new_pending_p)
 {
   struct lwp_info *lp;
 
@@ -3191,7 +3233,27 @@ linux_nat_filter_event (int lwpid, int status, int options, int *new_pending_p)
      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.  */
+     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.  The non-leader
+     thread changes its tid to the tgid.  */
+
+  if (WIFSTOPPED (status) && lp == NULL
+      && (WSTOPSIG (status) == SIGTRAP && status >> 16 == PTRACE_EVENT_EXEC))
+    {
+      /* A multi-thread exec after we had seen the leader exiting.  */
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: Re-adding thread group leader LWP %d.\n",
+                           lwpid);
+
+      lp = add_lwp (BUILD_LWP (lwpid, lwpid));
+      lp->stopped = 1;
+      lp->resumed = 1;
+      add_thread (lp->ptid);
+    }
+
   if (WIFSTOPPED (status) && !lp)
     {
       add_to_pid_list (&stopped_pids, lwpid, status);
@@ -3205,33 +3267,6 @@ linux_nat_filter_event (int lwpid, int status, int options, int *new_pending_p)
   if (!WIFSTOPPED (status) && !lp)
     return NULL;
 
-  /* NOTE drow/2003-06-17: This code seems to be meant for debugging
-     CLONE_PTRACE processes which do not use the thread library -
-     otherwise we wouldn't find the new LWP this way.  That doesn't
-     currently work, and the following code is currently unreachable
-     due to the two blocks above.  If it's fixed some day, this code
-     should be broken out into a function so that we can also pick up
-     LWPs from the new interface.  */
-  if (!lp)
-    {
-      lp = add_lwp (BUILD_LWP (lwpid, GET_PID (inferior_ptid)));
-      if (options & __WCLONE)
-       lp->cloned = 1;
-
-      gdb_assert (WIFSTOPPED (status)
-                 && WSTOPSIG (status) == SIGSTOP);
-      lp->signalled = 1;
-
-      if (!in_thread_list (inferior_ptid))
-       {
-         inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
-                                    GET_PID (inferior_ptid));
-         add_thread (inferior_ptid);
-       }
-
-      add_thread (lp->ptid);
-    }
-
   /* Handle GNU/Linux's syscall SIGTRAPs.  */
   if (WIFSTOPPED (status) && WSTOPSIG (status) == SYSCALL_SIGTRAP)
     {
@@ -3339,6 +3374,8 @@ linux_nat_filter_event (int lwpid, int status, int options, int *new_pending_p)
 
          registers_changed ();
 
+         if (linux_nat_prepare_to_resume != NULL)
+           linux_nat_prepare_to_resume (lp);
          linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
          if (debug_linux_nat)
@@ -3370,6 +3407,8 @@ linux_nat_filter_event (int lwpid, int status, int options, int *new_pending_p)
       lp->ignore_sigint = 0;
 
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+       linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3392,6 +3431,71 @@ linux_nat_filter_event (int lwpid, int status, int options, int *new_pending_p)
   return lp;
 }
 
+/* Detect zombie thread group leaders, and "exit" them.  We can't reap
+   their exits until all other threads in the group have exited.  */
+
+static void
+check_zombie_leaders (void)
+{
+  struct inferior *inf;
+
+  ALL_INFERIORS (inf)
+    {
+      struct lwp_info *leader_lp;
+
+      if (inf->pid == 0)
+       continue;
+
+      leader_lp = find_lwp_pid (pid_to_ptid (inf->pid));
+      if (leader_lp != NULL
+         /* Check if there are other threads in the group, as we may
+            have raced with the inferior simply exiting.  */
+         && num_lwps (inf->pid) > 1
+         && linux_lwp_is_zombie (inf->pid))
+       {
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "CZL: Thread group leader %d zombie "
+                               "(it exited, or another thread execd).\n",
+                               inf->pid);
+
+         /* A leader zombie can mean one of two things:
+
+            - It exited, and there's an exit status pending
+            available, or only the leader exited (not the whole
+            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
+            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
+            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
+            sound useful.  The previous leader _does_ go away, and
+            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).  */
+
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "CZL: Thread group leader %d vanished.\n",
+                               inf->pid);
+         exit_lwp (leader_lp);
+       }
+    }
+}
+
 static ptid_t
 linux_nat_wait_1 (struct target_ops *ops,
                  ptid_t ptid, struct target_waitstatus *ourstatus,
@@ -3400,9 +3504,7 @@ linux_nat_wait_1 (struct target_ops *ops,
   static sigset_t prev_mask;
   enum resume_kind last_resume_kind;
   struct lwp_info *lp;
-  int options;
   int status;
-  pid_t pid;
 
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog, "LLW: enter\n");
@@ -3424,41 +3526,14 @@ linux_nat_wait_1 (struct target_ops *ops,
   /* Make sure SIGCHLD is blocked.  */
   block_child_signals (&prev_mask);
 
-  if (ptid_equal (ptid, minus_one_ptid))
-    pid = -1;
-  else if (ptid_is_pid (ptid))
-    /* A request to wait for a specific tgid.  This is not possible
-       with waitpid, so instead, we wait for any child, and leave
-       children we're not interested in right now with a pending
-       status to report later.  */
-    pid = -1;
-  else
-    pid = GET_LWP (ptid);
-
 retry:
   lp = NULL;
   status = 0;
-  options = 0;
-
-  /* Make sure that of those LWPs we want to get an event from, there
-     is at least one LWP that has been resumed.  If there's none, just
-     bail out.  The core may just be flushing asynchronously all
-     events.  */
-  if (iterate_over_lwps (ptid, resumed_callback, NULL) == NULL)
-    {
-      ourstatus->kind = TARGET_WAITKIND_IGNORE;
-
-      if (debug_linux_nat)
-       fprintf_unfiltered (gdb_stdlog, "LLW: exit (no resumed LWP)\n");
-
-      restore_child_signals_mask (&prev_mask);
-      return minus_one_ptid;
-    }
 
   /* First check if there is a LWP with a wait status pending.  */
-  if (pid == -1)
+  if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
     {
-      /* Any LWP that's been resumed will do.  */
+      /* Any LWP in the PTID group that's been resumed will do.  */
       lp = iterate_over_lwps (ptid, status_callback, NULL);
       if (lp)
        {
@@ -3468,11 +3543,6 @@ retry:
                                status_to_str (lp->status),
                                target_pid_to_str (lp->ptid));
        }
-
-      /* But if we don't find one, we'll have to wait, and check both
-        cloned and uncloned processes.  We start with the cloned
-        processes.  */
-      options = __WCLONE | WNOHANG;
     }
   else if (is_lwp (ptid))
     {
@@ -3491,12 +3561,6 @@ retry:
                            status_to_str (lp->status),
                            target_pid_to_str (lp->ptid));
 
-      /* If we have to wait, take into account whether PID is a cloned
-         process or not.  And we have to convert it to something that
-         the layer beneath us can understand.  */
-      options = lp->cloned ? __WCLONE : 0;
-      pid = GET_LWP (ptid);
-
       /* We check for lp->waitstatus in addition to lp->status,
         because we can have pending process exits recorded in
         lp->status and W_EXITCODE(0,0) == 0.  We should probably have
@@ -3519,6 +3583,8 @@ retry:
       /* Resume the thread.  It should halt immediately returning the
          pending SIGSTOP.  */
       registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+       linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -3557,15 +3623,34 @@ retry:
       set_sigint_trap ();
     }
 
-  /* Translate generic target_wait options into waitpid options.  */
-  if (target_options & TARGET_WNOHANG)
-    options |= WNOHANG;
+  /* But if we don't find a pending event, we'll have to wait.  */
 
   while (lp == NULL)
     {
       pid_t lwpid;
 
-      lwpid = my_waitpid (pid, &status, options);
+      /* Always use -1 and WNOHANG, due to couple of a kernel/ptrace
+        quirks:
+
+        - If the thread group leader exits while other threads in the
+          thread group still exist, waitpid(TGID, ...) hangs.  That
+          waitpid won't return an exit status until the other threads
+          in the group are reapped.
+
+        - 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.  */
+
+      errno = 0;
+      lwpid = my_waitpid (-1, &status,  __WCLONE | WNOHANG);
+      if (lwpid == 0 || (lwpid == -1 && errno == ECHILD))
+       lwpid = my_waitpid (-1, &status, WNOHANG);
+
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LNW: waitpid(-1, ...) returned %d, %s\n",
+                           lwpid, errno ? safe_strerror (errno) : "ERRNO-OK");
 
       if (lwpid > 0)
        {
@@ -3573,8 +3658,6 @@ retry:
             now have pending events to handle.  */
          int new_pending;
 
-         gdb_assert (pid == -1 || lwpid == pid);
-
          if (debug_linux_nat)
            {
              fprintf_unfiltered (gdb_stdlog,
@@ -3582,14 +3665,12 @@ retry:
                                  (long) lwpid, status_to_str (status));
            }
 
-         lp = linux_nat_filter_event (lwpid, status, options, &new_pending);
+         lp = linux_nat_filter_event (lwpid, status, &new_pending);
 
          /* STATUS is now no longer valid, use LP->STATUS instead.  */
          status = 0;
 
-         if (lp
-             && ptid_is_pid (ptid)
-             && ptid_get_pid (lp->ptid) != ptid_get_pid (ptid))
+         if (lp && !ptid_match (lp->ptid, ptid))
            {
              gdb_assert (lp->resumed);
 
@@ -3662,69 +3743,65 @@ retry:
                  store_waitstatus (&lp->waitstatus, lp->status);
                }
 
-             if (new_pending)
-               goto retry;
-
              /* Keep looking.  */
              lp = NULL;
-             continue;
            }
 
-         if (lp)
-           break;
-         else
+         if (new_pending)
            {
-             if (new_pending)
-               goto retry;
+             /* Some LWP now has a pending event.  Go all the way
+                back to check it.  */
+             goto retry;
+           }
 
-             if (pid == -1)
-               {
-                 /* waitpid did return something.  Restart over.  */
-                 options |= __WCLONE;
-               }
-             continue;
+         if (lp)
+           {
+             /* We got an event to report to the core.  */
+             break;
            }
+
+         /* Retry until nothing comes out of waitpid.  A single
+            SIGCHLD can indicate more than one child stopped.  */
+         continue;
        }
 
-      if (pid == -1)
-       {
-         /* Alternate between checking cloned and uncloned processes.  */
-         options ^= __WCLONE;
+      /* Check for zombie thread group leaders.  Those can't be reaped
+        until all other threads in the thread group are.  */
+      check_zombie_leaders ();
 
-         /* And every time we have checked both:
-            In async mode, return to event loop;
-            In sync mode, suspend waiting for a SIGCHLD signal.  */
-         if (options & __WCLONE)
-           {
-             if (target_options & TARGET_WNOHANG)
-               {
-                 /* No interesting event.  */
-                 ourstatus->kind = TARGET_WAITKIND_IGNORE;
+      /* If there are no resumed children left, bail.  We'd be stuck
+        forever in the sigsuspend call below otherwise.  */
+      if (iterate_over_lwps (ptid, resumed_callback, NULL) == NULL)
+       {
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog, "LLW: exit (no resumed LWP)\n");
 
-                 if (debug_linux_nat)
-                   fprintf_unfiltered (gdb_stdlog, "LLW: exit (ignore)\n");
+         ourstatus->kind = TARGET_WAITKIND_NO_RESUMED;
 
-                 restore_child_signals_mask (&prev_mask);
-                 return minus_one_ptid;
-               }
+         if (!target_can_async_p ())
+           clear_sigint_trap ();
 
-             sigsuspend (&suspend_mask);
-           }
+         restore_child_signals_mask (&prev_mask);
+         return minus_one_ptid;
        }
-      else if (target_options & TARGET_WNOHANG)
-       {
-         /* No interesting event for PID yet.  */
-         ourstatus->kind = TARGET_WAITKIND_IGNORE;
 
+      /* No interesting event to report to the core.  */
+
+      if (target_options & TARGET_WNOHANG)
+       {
          if (debug_linux_nat)
            fprintf_unfiltered (gdb_stdlog, "LLW: exit (ignore)\n");
 
+         ourstatus->kind = TARGET_WAITKIND_IGNORE;
          restore_child_signals_mask (&prev_mask);
          return minus_one_ptid;
        }
 
       /* We shouldn't end up here unless we want to try again.  */
       gdb_assert (lp == NULL);
+
+      /* Block until we get an event reported with SIGCHLD.  */
+      sigsuspend (&suspend_mask);
     }
 
   if (!target_can_async_p ())
@@ -3757,6 +3834,8 @@ retry:
             newly attached threads may cause an unwanted delay in
             getting them running.  */
          registers_changed ();
+         if (linux_nat_prepare_to_resume != NULL)
+           linux_nat_prepare_to_resume (lp);
          linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                                lp->step, signo);
          if (debug_linux_nat)
@@ -3813,7 +3892,7 @@ retry:
         from among those that have had events.  Giving equal priority
         to all LWPs that have had events helps prevent
         starvation.  */
-      if (pid == -1)
+      if (ptid_equal (ptid, minus_one_ptid) || ptid_is_pid (ptid))
        select_event_lwp (ptid, &lp, &status);
 
       /* Now that we've selected our final event LWP, cancel any
@@ -3891,24 +3970,30 @@ resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
       && lp->status == 0
       && lp->waitstatus.kind == TARGET_WAITKIND_IGNORE)
     {
+      struct regcache *regcache = get_thread_regcache (lp->ptid);
+      struct gdbarch *gdbarch = get_regcache_arch (regcache);
+      CORE_ADDR pc = regcache_read_pc (regcache);
+
       gdb_assert (is_executing (lp->ptid));
 
       /* Don't bother if there's a breakpoint at PC that we'd hit
         immediately, and we're not waiting for this LWP.  */
       if (!ptid_match (lp->ptid, *wait_ptid_p))
        {
-         struct regcache *regcache = get_thread_regcache (lp->ptid);
-         CORE_ADDR pc = regcache_read_pc (regcache);
-
          if (breakpoint_inserted_here_p (get_regcache_aspace (regcache), pc))
            return 0;
        }
 
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
-                           "RSRL: resuming stopped-resumed LWP %s\n",
-                           target_pid_to_str (lp->ptid));
+                           "RSRL: resuming stopped-resumed LWP %s at %s: step=%d\n",
+                           target_pid_to_str (lp->ptid),
+                           paddress (gdbarch, pc),
+                           lp->step);
 
+      registers_changed ();
+      if (linux_nat_prepare_to_resume != NULL)
+       linux_nat_prepare_to_resume (lp);
       linux_ops->to_resume (linux_ops, pid_to_ptid (GET_LWP (lp->ptid)),
                            lp->step, TARGET_SIGNAL_0);
       lp->stopped = 0;
@@ -3950,7 +4035,8 @@ linux_nat_wait (struct target_ops *ops,
      may be more.  If we requested a specific lwp or process, also
      assume there may be more.  */
   if (target_can_async_p ()
-      && (ourstatus->kind != TARGET_WAITKIND_IGNORE
+      && ((ourstatus->kind != TARGET_WAITKIND_IGNORE
+          && ourstatus->kind != TARGET_WAITKIND_NO_RESUMED)
          || !ptid_equal (ptid, minus_one_ptid)))
     async_file_mark ();
 
@@ -4717,71 +4803,57 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 
 /* Implement the "info proc" command.  */
 
+enum info_proc_what
+  {
+    /* Display the default cmdline, cwd and exe outputs.  */
+    IP_MINIMAL,
+
+    /* Display `info proc mappings'.  */
+    IP_MAPPINGS,
+
+    /* Display `info proc status'.  */
+    IP_STATUS,
+
+    /* Display `info proc stat'.  */
+    IP_STAT,
+
+    /* Display `info proc cmdline'.  */
+    IP_CMDLINE,
+
+    /* Display `info proc exe'.  */
+    IP_EXE,
+
+    /* Display `info proc cwd'.  */
+    IP_CWD,
+
+    /* Display all of the above.  */
+    IP_ALL
+  };
+
 static void
-linux_nat_info_proc_cmd (char *args, int from_tty)
+linux_nat_info_proc_cmd_1 (char *args, enum info_proc_what what, int from_tty)
 {
   /* A long is used for pid instead of an int to avoid a loss of precision
      compiler warning from the output of strtoul.  */
   long pid = PIDGET (inferior_ptid);
   FILE *procfile;
-  char **argv = NULL;
   char buffer[MAXPATHLEN];
   char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
-  int cmdline_f = 1;
-  int cwd_f = 1;
-  int exe_f = 1;
-  int mappings_f = 0;
-  int status_f = 0;
-  int stat_f = 0;
-  int all = 0;
+  int cmdline_f = (what == IP_MINIMAL || what == IP_CMDLINE || what == IP_ALL);
+  int cwd_f = (what == IP_MINIMAL || what == IP_CWD || what == IP_ALL);
+  int exe_f = (what == IP_MINIMAL || what == IP_EXE || what == IP_ALL);
+  int mappings_f = (what == IP_MAPPINGS || what == IP_ALL);
+  int status_f = (what == IP_STATUS || what == IP_ALL);
+  int stat_f = (what == IP_STAT || what == IP_ALL);
   struct stat dummy;
 
-  if (args)
-    {
-      /* Break up 'args' into an argv array.  */
-      argv = gdb_buildargv (args);
-      make_cleanup_freeargv (argv);
-    }
-  while (argv != NULL && *argv != NULL)
-    {
-      if (isdigit (argv[0][0]))
-       {
-         pid = strtoul (argv[0], NULL, 10);
-       }
-      else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
-       {
-         mappings_f = 1;
-       }
-      else if (strcmp (argv[0], "status") == 0)
-       {
-         status_f = 1;
-       }
-      else if (strcmp (argv[0], "stat") == 0)
-       {
-         stat_f = 1;
-       }
-      else if (strcmp (argv[0], "cmd") == 0)
-       {
-         cmdline_f = 1;
-       }
-      else if (strncmp (argv[0], "exe", strlen (argv[0])) == 0)
-       {
-         exe_f = 1;
-       }
-      else if (strcmp (argv[0], "cwd") == 0)
-       {
-         cwd_f = 1;
-       }
-      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
-       {
-         all = 1;
-       }
-      else
-       {
-         /* [...] (future options here).  */
-       }
-      argv++;
-    }
+  if (args && isdigit (args[0]))
+    pid = strtoul (args, &args, 10);
+
+  args = skip_spaces (args);
+  if (args && args[0])
+    error (_("Too many parameters: %s"), args);
+
   if (pid == 0)
     error (_("No current process: you must name one."));
 
@@ -4790,7 +4862,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     error (_("No /proc directory: '%s'"), fname1);
 
   printf_filtered (_("process %ld\n"), pid);
-  if (cmdline_f || all)
+  if (cmdline_f)
     {
       sprintf (fname1, "/proc/%ld/cmdline", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4806,7 +4878,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (cwd_f || all)
+  if (cwd_f)
     {
       sprintf (fname1, "/proc/%ld/cwd", pid);
       memset (fname2, 0, sizeof (fname2));
@@ -4815,7 +4887,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
        warning (_("unable to read link '%s'"), fname1);
     }
-  if (exe_f || all)
+  if (exe_f)
     {
       sprintf (fname1, "/proc/%ld/exe", pid);
       memset (fname2, 0, sizeof (fname2));
@@ -4824,7 +4896,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
        warning (_("unable to read link '%s'"), fname1);
     }
-  if (mappings_f || all)
+  if (mappings_f)
     {
       sprintf (fname1, "/proc/%ld/maps", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4886,7 +4958,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (status_f || all)
+  if (status_f)
     {
       sprintf (fname1, "/proc/%ld/status", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -4900,7 +4972,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       else
        warning (_("unable to open /proc file '%s'"), fname1);
     }
-  if (stat_f || all)
+  if (stat_f)
     {
       sprintf (fname1, "/proc/%ld/stat", pid);
       if ((procfile = fopen (fname1, "r")) != NULL)
@@ -5000,6 +5072,70 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
     }
 }
 
+/* Implement `info proc' when given without any futher parameters.  */
+
+static void
+linux_nat_info_proc_cmd (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_MINIMAL, from_tty);
+}
+
+/* Implement `info proc mappings'.  */
+
+static void
+linux_nat_info_proc_cmd_mappings (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_MAPPINGS, from_tty);
+}
+
+/* Implement `info proc stat'.  */
+
+static void
+linux_nat_info_proc_cmd_stat (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_STAT, from_tty);
+}
+
+/* Implement `info proc status'.  */
+
+static void
+linux_nat_info_proc_cmd_status (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_STATUS, from_tty);
+}
+
+/* Implement `info proc cwd'.  */
+
+static void
+linux_nat_info_proc_cmd_cwd (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_CWD, from_tty);
+}
+
+/* Implement `info proc cmdline'.  */
+
+static void
+linux_nat_info_proc_cmd_cmdline (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_CMDLINE, from_tty);
+}
+
+/* Implement `info proc exe'.  */
+
+static void
+linux_nat_info_proc_cmd_exe (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_EXE, from_tty);
+}
+
+/* Implement `info proc all'.  */
+
+static void
+linux_nat_info_proc_cmd_all (char *args, int from_tty)
+{
+  linux_nat_info_proc_cmd_1 (args, IP_ALL, from_tty);
+}
+
 /* Implement the to_xfer_partial interface for memory reads using the /proc
    filesystem.  Because we can use a single read() call for /proc, this
    can be much more efficient than banging away at PTRACE_PEEKTEXT,
@@ -5581,8 +5717,8 @@ static void
 linux_nat_close (int quitting)
 {
   /* Unregister from the event loop.  */
-  if (target_is_async_p ())
-    target_async (NULL, 0);
+  if (linux_nat_is_async_p ())
+    linux_nat_async (NULL, 0);
 
   if (linux_ops->to_close)
     linux_ops->to_close (quitting);
@@ -5755,7 +5891,8 @@ linux_nat_add_target (struct target_ops *t)
 
 /* Register a method to call whenever a new thread is attached.  */
 void
-linux_nat_set_new_thread (struct target_ops *t, void (*new_thread) (ptid_t))
+linux_nat_set_new_thread (struct target_ops *t,
+                         void (*new_thread) (struct lwp_info *))
 {
   /* Save the pointer.  We only support a single registered instance
      of the GNU/Linux native target, so we do not need to map this to
@@ -5776,6 +5913,16 @@ linux_nat_set_siginfo_fixup (struct target_ops *t,
   linux_nat_siginfo_fixup = siginfo_fixup;
 }
 
+/* Register a method to call prior to resuming a thread.  */
+
+void
+linux_nat_set_prepare_to_resume (struct target_ops *t,
+                                void (*prepare_to_resume) (struct lwp_info *))
+{
+  /* Save the pointer.  */
+  linux_nat_prepare_to_resume = prepare_to_resume;
+}
+
 /* Return the saved siginfo associated with PTID.  */
 struct siginfo *
 linux_nat_get_siginfo (ptid_t ptid)
@@ -5793,14 +5940,42 @@ extern initialize_file_ftype _initialize_linux_nat;
 void
 _initialize_linux_nat (void)
 {
-  add_info ("proc", linux_nat_info_proc_cmd, _("\
+  static struct cmd_list_element *info_proc_cmdlist;
+
+  add_prefix_cmd ("proc", class_info, linux_nat_info_proc_cmd,
+                 _("\
 Show /proc process information about any running process.\n\
-Specify any process id, or use the program being debugged by default.\n\
-Specify any of the following keywords for detailed info:\n\
-  mappings -- list of mapped memory regions.\n\
-  stat     -- list a bunch of random process info.\n\
-  status   -- list a different bunch of random process info.\n\
-  all      -- list all available /proc info."));
+Specify any process id, or use the program being debugged by default."),
+                 &info_proc_cmdlist, "info proc ",
+                 1/*allow-unknown*/, &infolist);
+
+  add_cmd ("mappings", class_info, linux_nat_info_proc_cmd_mappings, _("\
+List of mapped memory regions."),
+          &info_proc_cmdlist);
+
+  add_cmd ("stat", class_info, linux_nat_info_proc_cmd_stat, _("\
+List process info from /proc/PID/stat."),
+          &info_proc_cmdlist);
+
+  add_cmd ("status", class_info, linux_nat_info_proc_cmd_status, _("\
+List process info from /proc/PID/status."),
+          &info_proc_cmdlist);
+
+  add_cmd ("cwd", class_info, linux_nat_info_proc_cmd_cwd, _("\
+List current working directory of the process."),
+          &info_proc_cmdlist);
+
+  add_cmd ("cmdline", class_info, linux_nat_info_proc_cmd_cmdline, _("\
+List command line arguments of the process."),
+          &info_proc_cmdlist);
+
+  add_cmd ("exe", class_info, linux_nat_info_proc_cmd_exe, _("\
+List absolute filename for executable of the process."),
+          &info_proc_cmdlist);
+
+  add_cmd ("all", class_info, linux_nat_info_proc_cmd_all, _("\
+List all available /proc info."),
+          &info_proc_cmdlist);
 
   add_setshow_zinteger_cmd ("lin-lwp", class_maintenance,
                            &debug_linux_nat, _("\