* linux-nat.c (linux_nat_filter_event): Fix comment typo.
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 932119edfc58ce38fcb2954bc0948487f7ddc9fa..fc63fa30878c7928a79c18af1808a95a96c265b5 100644 (file)
@@ -1,13 +1,13 @@
 /* GNU/Linux native-dependent code common to multiple platforms.
 
 /* GNU/Linux native-dependent code common to multiple platforms.
 
-   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006
+   Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -16,9 +16,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "inferior.h"
 
 #include "defs.h"
 #include "inferior.h"
 #define __WALL          0x40000000 /* Wait for any child.  */
 #endif
 
 #define __WALL          0x40000000 /* Wait for any child.  */
 #endif
 
+#ifndef PTRACE_GETSIGINFO
+#define PTRACE_GETSIGINFO    0x4202
+#endif
+
 /* The single-threaded native GNU/Linux target_ops.  We save a pointer for
    the use of the multi-threaded target.  */
 static struct target_ops *linux_ops;
 static struct target_ops linux_ops_saved;
 
 /* The single-threaded native GNU/Linux target_ops.  We save a pointer for
    the use of the multi-threaded target.  */
 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);
+
 /* The saved to_xfer_partial method, inherited from inf-ptrace.c.
    Called by our to_xfer_partial.  */
 static LONGEST (*super_xfer_partial) (struct target_ops *, 
 /* The saved to_xfer_partial method, inherited from inf-ptrace.c.
    Called by our to_xfer_partial.  */
 static LONGEST (*super_xfer_partial) (struct target_ops *, 
@@ -113,6 +118,7 @@ static int linux_parent_pid;
 struct simple_pid_list
 {
   int pid;
 struct simple_pid_list
 {
   int pid;
+  int status;
   struct simple_pid_list *next;
 };
 struct simple_pid_list *stopped_pids;
   struct simple_pid_list *next;
 };
 struct simple_pid_list *stopped_pids;
@@ -131,16 +137,17 @@ static int linux_supports_tracevforkdone_flag = -1;
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
 static void
 /* Trivial list manipulation functions to keep track of a list of
    new stopped processes.  */
 static void
-add_to_pid_list (struct simple_pid_list **listp, int pid)
+add_to_pid_list (struct simple_pid_list **listp, int pid, int status)
 {
   struct simple_pid_list *new_pid = xmalloc (sizeof (struct simple_pid_list));
   new_pid->pid = pid;
 {
   struct simple_pid_list *new_pid = xmalloc (sizeof (struct simple_pid_list));
   new_pid->pid = pid;
+  new_pid->status = status;
   new_pid->next = *listp;
   *listp = new_pid;
 }
 
 static int
   new_pid->next = *listp;
   *listp = new_pid;
 }
 
 static int
-pull_pid_from_list (struct simple_pid_list **listp, int pid)
+pull_pid_from_list (struct simple_pid_list **listp, int pid, int *status)
 {
   struct simple_pid_list **p;
 
 {
   struct simple_pid_list **p;
 
@@ -148,6 +155,7 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid)
     if ((*p)->pid == pid)
       {
        struct simple_pid_list *next = (*p)->next;
     if ((*p)->pid == pid)
       {
        struct simple_pid_list *next = (*p)->next;
+       *status = (*p)->status;
        xfree (*p);
        *p = next;
        return 1;
        xfree (*p);
        *p = next;
        return 1;
@@ -155,10 +163,10 @@ pull_pid_from_list (struct simple_pid_list **listp, int pid)
   return 0;
 }
 
   return 0;
 }
 
-void
-linux_record_stopped_pid (int pid)
+static void
+linux_record_stopped_pid (int pid, int status)
 {
 {
-  add_to_pid_list (&stopped_pids, pid);
+  add_to_pid_list (&stopped_pids, pid, status);
 }
 
 \f
 }
 
 \f
@@ -276,6 +284,7 @@ linux_test_for_tracefork (int original_pid)
          ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
          if (ret != 0)
            warning (_("linux_test_for_tracefork: failed to kill second child"));
          ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
          if (ret != 0)
            warning (_("linux_test_for_tracefork: failed to kill second child"));
+         my_waitpid (second_pid, &status, 0);
        }
     }
   else
        }
     }
   else
@@ -331,8 +340,8 @@ linux_enable_event_reporting (ptid_t ptid)
   ptrace (PTRACE_SETOPTIONS, pid, 0, options);
 }
 
   ptrace (PTRACE_SETOPTIONS, pid, 0, options);
 }
 
-void
-child_post_attach (int pid)
+static void
+linux_child_post_attach (int pid)
 {
   linux_enable_event_reporting (pid_to_ptid (pid));
   check_for_thread_db ();
 {
   linux_enable_event_reporting (pid_to_ptid (pid));
   check_for_thread_db ();
@@ -345,8 +354,8 @@ linux_child_post_startup_inferior (ptid_t ptid)
   check_for_thread_db ();
 }
 
   check_for_thread_db ();
 }
 
-int
-child_follow_fork (struct target_ops *ops, int follow_child)
+static int
+linux_child_follow_fork (struct target_ops *ops, int follow_child)
 {
   ptid_t last_ptid;
   struct target_waitstatus last_status;
 {
   ptid_t last_ptid;
   struct target_waitstatus last_status;
@@ -374,7 +383,7 @@ child_follow_fork (struct target_ops *ops, int follow_child)
       /* Detach new forked process?  */
       if (detach_fork)
        {
       /* Detach new forked process?  */
       if (detach_fork)
        {
-         if (debug_linux_nat)
+         if (info_verbose || debug_linux_nat)
            {
              target_terminal_ours ();
              fprintf_filtered (gdb_stdlog,
            {
              target_terminal_ours ();
              fprintf_filtered (gdb_stdlog,
@@ -459,7 +468,7 @@ child_follow_fork (struct target_ops *ops, int follow_child)
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
 
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
 
-      if (debug_linux_nat)
+      if (info_verbose || debug_linux_nat)
        {
          target_terminal_ours ();
          fprintf_filtered (gdb_stdlog,
        {
          target_terminal_ours ();
          fprintf_filtered (gdb_stdlog,
@@ -501,12 +510,14 @@ child_follow_fork (struct target_ops *ops, int follow_child)
          target_detach (NULL, 0);
        }
 
          target_detach (NULL, 0);
        }
 
-      inferior_ptid = pid_to_ptid (child_pid);
+      inferior_ptid = ptid_build (child_pid, child_pid, 0);
 
       /* Reinstall ourselves, since we might have been removed in
         target_detach (which does other necessary cleanup).  */
 
       push_target (ops);
 
       /* Reinstall ourselves, since we might have been removed in
         target_detach (which does other necessary cleanup).  */
 
       push_target (ops);
+      linux_nat_switch_fork (inferior_ptid);
+      check_for_thread_db ();
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
@@ -515,86 +526,23 @@ child_follow_fork (struct target_ops *ops, int follow_child)
   return 0;
 }
 
   return 0;
 }
 
-ptid_t
-linux_handle_extended_wait (int pid, int status,
-                           struct target_waitstatus *ourstatus)
-{
-  int event = status >> 16;
-
-  if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK
-      || event == PTRACE_EVENT_CLONE)
-    {
-      unsigned long new_pid;
-      int ret;
-
-      ptrace (PTRACE_GETEVENTMSG, pid, 0, &new_pid);
-
-      /* If we haven't already seen the new PID stop, wait for it now.  */
-      if (! pull_pid_from_list (&stopped_pids, new_pid))
-       {
-         /* The new child has a pending SIGSTOP.  We can't affect it until it
-            hits the SIGSTOP, but we're already attached.  */
-         ret = my_waitpid (new_pid, &status,
-                           (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
-         if (ret == -1)
-           perror_with_name (_("waiting for new child"));
-         else if (ret != new_pid)
-           internal_error (__FILE__, __LINE__,
-                           _("wait returned unexpected PID %d"), ret);
-         else if (!WIFSTOPPED (status) || WSTOPSIG (status) != SIGSTOP)
-           internal_error (__FILE__, __LINE__,
-                           _("wait returned unexpected status 0x%x"), status);
-       }
-
-      if (event == PTRACE_EVENT_FORK)
-       ourstatus->kind = TARGET_WAITKIND_FORKED;
-      else if (event == PTRACE_EVENT_VFORK)
-       ourstatus->kind = TARGET_WAITKIND_VFORKED;
-      else
-       ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
-
-      ourstatus->value.related_pid = new_pid;
-      return inferior_ptid;
-    }
-
-  if (event == PTRACE_EVENT_EXEC)
-    {
-      ourstatus->kind = TARGET_WAITKIND_EXECD;
-      ourstatus->value.execd_pathname
-       = xstrdup (child_pid_to_exec_file (pid));
-
-      if (linux_parent_pid)
-       {
-         detach_breakpoints (linux_parent_pid);
-         ptrace (PTRACE_DETACH, linux_parent_pid, 0, 0);
-
-         linux_parent_pid = 0;
-       }
-
-      return inferior_ptid;
-    }
-
-  internal_error (__FILE__, __LINE__,
-                 _("unknown ptrace event %d"), event);
-}
-
 \f
 \f
-void
-child_insert_fork_catchpoint (int pid)
+static void
+linux_child_insert_fork_catchpoint (int pid)
 {
   if (! linux_supports_tracefork (pid))
     error (_("Your system does not support fork catchpoints."));
 }
 
 {
   if (! linux_supports_tracefork (pid))
     error (_("Your system does not support fork catchpoints."));
 }
 
-void
-child_insert_vfork_catchpoint (int pid)
+static void
+linux_child_insert_vfork_catchpoint (int pid)
 {
   if (!linux_supports_tracefork (pid))
     error (_("Your system does not support vfork catchpoints."));
 }
 
 {
   if (!linux_supports_tracefork (pid))
     error (_("Your system does not support vfork catchpoints."));
 }
 
-void
-child_insert_exec_catchpoint (int pid)
+static void
+linux_child_insert_exec_catchpoint (int pid)
 {
   if (!linux_supports_tracefork (pid))
     error (_("Your system does not support exec catchpoints."));
 {
   if (!linux_supports_tracefork (pid))
     error (_("Your system does not support exec catchpoints."));
@@ -634,7 +582,7 @@ child_insert_exec_catchpoint (int pid)
      because the "zombies" stay around.  */
 
 /* List of known LWPs.  */
      because the "zombies" stay around.  */
 
 /* List of known LWPs.  */
-static struct lwp_info *lwp_list;
+struct lwp_info *lwp_list;
 
 /* Number of LWPs in the list.  */
 static int num_lwps;
 
 /* Number of LWPs in the list.  */
 static int num_lwps;
@@ -675,6 +623,7 @@ static sigset_t blocked_mask;
 /* Prototypes for local functions.  */
 static int stop_wait_callback (struct lwp_info *lp, void *data);
 static int linux_nat_thread_alive (ptid_t ptid);
 /* Prototypes for local functions.  */
 static int stop_wait_callback (struct lwp_info *lp, void *data);
 static int linux_nat_thread_alive (ptid_t ptid);
+static char *linux_child_pid_to_exec_file (int pid);
 \f
 /* Convert wait status STATUS to a string.  Used for printing debug
    messages only.  */
 \f
 /* Convert wait status STATUS to a string.  Used for printing debug
    messages only.  */
@@ -717,7 +666,8 @@ init_lwp_list (void)
 }
 
 /* Add the LWP specified by PID to the list.  Return a pointer to the
 }
 
 /* Add the LWP specified by PID to the list.  Return a pointer to the
-   structure describing the new LWP.  */
+   structure describing the new LWP.  The LWP should already be stopped
+   (with an exception for the very first LWP).  */
 
 static struct lwp_info *
 add_lwp (ptid_t ptid)
 
 static struct lwp_info *
 add_lwp (ptid_t ptid)
@@ -738,6 +688,9 @@ add_lwp (ptid_t ptid)
   lwp_list = lp;
   ++num_lwps;
 
   lwp_list = lp;
   ++num_lwps;
 
+  if (num_lwps > 1 && linux_nat_new_thread != NULL)
+    linux_nat_new_thread (ptid);
+
   return lp;
 }
 
   return lp;
 }
 
@@ -914,12 +867,13 @@ exit_lwp (struct lwp_info *lp)
 
 /* Attach to the LWP specified by PID.  If VERBOSE is non-zero, print
    a message telling the user that a new LWP has been added to the
 
 /* Attach to the LWP specified by PID.  If VERBOSE is non-zero, print
    a message telling the user that a new LWP has been added to the
-   process.  */
+   process.  Return 0 if successful or -1 if the new LWP could not
+   be attached.  */
 
 
-void
-lin_lwp_attach_lwp (ptid_t ptid, int verbose)
+int
+lin_lwp_attach_lwp (ptid_t ptid)
 {
 {
-  struct lwp_info *lp, *found_lp;
+  struct lwp_info *lp;
 
   gdb_assert (is_lwp (ptid));
 
 
   gdb_assert (is_lwp (ptid));
 
@@ -931,12 +885,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
       sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
     }
 
       sigprocmask (SIG_BLOCK, &blocked_mask, NULL);
     }
 
-  if (verbose)
-    printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
-
-  found_lp = lp = find_lwp_pid (ptid);
-  if (lp == NULL)
-    lp = add_lwp (ptid);
+  lp = find_lwp_pid (ptid);
 
   /* We assume that we're already attached to any LWP that has an id
      equal to the overall process id, and to any LWP that is already
 
   /* We assume that we're already attached to any LWP that has an id
      equal to the overall process id, and to any LWP that is already
@@ -944,14 +893,23 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
      and we've had PID wraparound since we last tried to stop all threads,
      this assumption might be wrong; fortunately, this is very unlikely
      to happen.  */
      and we've had PID wraparound since we last tried to stop all threads,
      this assumption might be wrong; fortunately, this is very unlikely
      to happen.  */
-  if (GET_LWP (ptid) != GET_PID (ptid) && found_lp == NULL)
+  if (GET_LWP (ptid) != GET_PID (ptid) && lp == NULL)
     {
       pid_t pid;
       int status;
     {
       pid_t pid;
       int status;
+      int cloned = 0;
 
       if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
 
       if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
-       error (_("Can't attach %s: %s"), target_pid_to_str (ptid),
-              safe_strerror (errno));
+       {
+         /* If we fail to attach to the thread, issue a warning,
+            but continue.  One way this can happen is if thread
+            creation is interrupted; as of Linux kernel 2.6.19, a
+            bug may place threads in the thread list and then fail
+            to create them.  */
+         warning (_("Can't attach %s: %s"), target_pid_to_str (ptid),
+                  safe_strerror (errno));
+         return -1;
+       }
 
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
 
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -963,12 +921,16 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
        {
          /* Try again with __WCLONE to check cloned processes.  */
          pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE);
        {
          /* Try again with __WCLONE to check cloned processes.  */
          pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE);
-         lp->cloned = 1;
+         cloned = 1;
        }
 
       gdb_assert (pid == GET_LWP (ptid)
                  && WIFSTOPPED (status) && WSTOPSIG (status));
 
        }
 
       gdb_assert (pid == GET_LWP (ptid)
                  && WIFSTOPPED (status) && WSTOPSIG (status));
 
+      if (lp == NULL)
+       lp = add_lwp (ptid);
+      lp->cloned = cloned;
+
       target_post_attach (pid);
 
       lp->stopped = 1;
       target_post_attach (pid);
 
       lp->stopped = 1;
@@ -985,12 +947,16 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
     {
       /* We assume that the LWP representing the original process is
          already stopped.  Mark it as stopped in the data structure
     {
       /* We assume that the LWP representing the original process is
          already stopped.  Mark it as stopped in the data structure
-         that the linux ptrace layer uses to keep track of threads.
-         Note that this won't have already been done since the main
-         thread will have, we assume, been stopped by an attach from a
-         different layer.  */
+         that the GNU/linux ptrace layer uses to keep track of
+         threads.  Note that this won't have already been done since
+         the main thread will have, we assume, been stopped by an
+         attach from a different layer.  */
+      if (lp == NULL)
+       lp = add_lwp (ptid);
       lp->stopped = 1;
     }
       lp->stopped = 1;
     }
+
+  return 0;
 }
 
 static void
 }
 
 static void
@@ -999,15 +965,12 @@ linux_nat_attach (char *args, int from_tty)
   struct lwp_info *lp;
   pid_t pid;
   int status;
   struct lwp_info *lp;
   pid_t pid;
   int status;
+  int cloned = 0;
 
   /* FIXME: We should probably accept a list of process id's, and
      attach all of them.  */
   linux_ops->to_attach (args, from_tty);
 
 
   /* FIXME: We should probably accept a list of process id's, and
      attach all of them.  */
   linux_ops->to_attach (args, from_tty);
 
-  /* Add the initial process as the first LWP to the list.  */
-  inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
-  lp = add_lwp (inferior_ptid);
-
   /* Make sure the initial process is stopped.  The user-level threads
      layer might want to poke around in the inferior, and that won't
      work if things haven't stabilized yet.  */
   /* Make sure the initial process is stopped.  The user-level threads
      layer might want to poke around in the inferior, and that won't
      work if things haven't stabilized yet.  */
@@ -1018,12 +981,17 @@ linux_nat_attach (char *args, int from_tty)
 
       /* Try again with __WCLONE to check cloned processes.  */
       pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
 
       /* Try again with __WCLONE to check cloned processes.  */
       pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
-      lp->cloned = 1;
+      cloned = 1;
     }
 
   gdb_assert (pid == GET_PID (inferior_ptid)
              && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
 
     }
 
   gdb_assert (pid == GET_PID (inferior_ptid)
              && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP);
 
+  /* Add the initial process as the first LWP to the list.  */
+  inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid));
+  lp = add_lwp (inferior_ptid);
+  lp->cloned = cloned;
+
   lp->stopped = 1;
 
   /* Fake the SIGSTOP that core GDB expects.  */
   lp->stopped = 1;
 
   /* Fake the SIGSTOP that core GDB expects.  */
@@ -1123,8 +1091,6 @@ resume_callback (struct lwp_info *lp, void *data)
 {
   if (lp->stopped && lp->status == 0)
     {
 {
   if (lp->stopped && lp->status == 0)
     {
-      struct thread_info *tp;
-
       linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
                            0, TARGET_SIGNAL_0);
       if (debug_linux_nat)
       linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
                            0, TARGET_SIGNAL_0);
       if (debug_linux_nat)
@@ -1133,6 +1099,7 @@ resume_callback (struct lwp_info *lp, void *data)
                            target_pid_to_str (lp->ptid));
       lp->stopped = 0;
       lp->step = 0;
                            target_pid_to_str (lp->ptid));
       lp->stopped = 0;
       lp->step = 0;
+      memset (&lp->siginfo, 0, sizeof (lp->siginfo));
     }
 
   return 0;
     }
 
   return 0;
@@ -1182,68 +1149,69 @@ linux_nat_resume (ptid_t ptid, int step, enum target_signal signo)
     ptid = inferior_ptid;
 
   lp = find_lwp_pid (ptid);
     ptid = inferior_ptid;
 
   lp = find_lwp_pid (ptid);
-  if (lp)
-    {
-      ptid = pid_to_ptid (GET_LWP (lp->ptid));
+  gdb_assert (lp != NULL);
 
 
-      /* Remember if we're stepping.  */
-      lp->step = step;
+  ptid = pid_to_ptid (GET_LWP (lp->ptid));
 
 
-      /* Mark this LWP as resumed.  */
-      lp->resumed = 1;
+  /* Remember if we're stepping.  */
+  lp->step = step;
 
 
-      /* If we have a pending wait status for this thread, there is no
-        point in resuming the process.  But first make sure that
-        linux_nat_wait won't preemptively handle the event - we
-        should never take this short-circuit if we are going to
-        leave LP running, since we have skipped resuming all the
-        other threads.  This bit of code needs to be synchronized
-        with linux_nat_wait.  */
+  /* Mark this LWP as resumed.  */
+  lp->resumed = 1;
 
 
-      if (lp->status && WIFSTOPPED (lp->status))
-       {
-         int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
+  /* If we have a pending wait status for this thread, there is no
+     point in resuming the process.  But first make sure that
+     linux_nat_wait won't preemptively handle the event - we
+     should never take this short-circuit if we are going to
+     leave LP running, since we have skipped resuming all the
+     other threads.  This bit of code needs to be synchronized
+     with linux_nat_wait.  */
 
 
-         if (signal_stop_state (saved_signo) == 0
-             && signal_print_state (saved_signo) == 0
-             && signal_pass_state (saved_signo) == 1)
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLR: Not short circuiting for ignored "
-                                   "status 0x%x\n", lp->status);
-
-             /* FIXME: What should we do if we are supposed to continue
-                this thread with a signal?  */
-             gdb_assert (signo == TARGET_SIGNAL_0);
-             signo = saved_signo;
-             lp->status = 0;
-           }
-       }
+  if (lp->status && WIFSTOPPED (lp->status))
+    {
+      int saved_signo = target_signal_from_host (WSTOPSIG (lp->status));
 
 
-      if (lp->status)
+      if (signal_stop_state (saved_signo) == 0
+         && signal_print_state (saved_signo) == 0
+         && signal_pass_state (saved_signo) == 1)
        {
        {
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "LLR: Not short circuiting for ignored "
+                               "status 0x%x\n", lp->status);
+
          /* FIXME: What should we do if we are supposed to continue
             this thread with a signal?  */
          gdb_assert (signo == TARGET_SIGNAL_0);
          /* FIXME: What should we do if we are supposed to continue
             this thread with a signal?  */
          gdb_assert (signo == TARGET_SIGNAL_0);
+         signo = saved_signo;
+         lp->status = 0;
+       }
+    }
 
 
-         if (debug_linux_nat)
-           fprintf_unfiltered (gdb_stdlog,
-                               "LLR: Short circuiting for status 0x%x\n",
-                               lp->status);
+  if (lp->status)
+    {
+      /* FIXME: What should we do if we are supposed to continue
+        this thread with a signal?  */
+      gdb_assert (signo == TARGET_SIGNAL_0);
 
 
-         return;
-       }
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLR: Short circuiting for status 0x%x\n",
+                           lp->status);
 
 
-      /* Mark LWP as not stopped to prevent it from being continued by
-         resume_callback.  */
-      lp->stopped = 0;
+      return;
     }
 
     }
 
+  /* Mark LWP as not stopped to prevent it from being continued by
+     resume_callback.  */
+  lp->stopped = 0;
+
   if (resume_all)
     iterate_over_lwps (resume_callback, NULL);
 
   linux_ops->to_resume (ptid, step, signo);
   if (resume_all)
     iterate_over_lwps (resume_callback, NULL);
 
   linux_ops->to_resume (ptid, step, signo);
+  memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
                        "LLR: %s %s, %s (resume event thread)\n",
   if (debug_linux_nat)
     fprintf_unfiltered (gdb_stdlog,
                        "LLR: %s %s, %s (resume event thread)\n",
@@ -1278,44 +1246,113 @@ kill_lwp (int lwpid, int signo)
   return kill (lwpid, signo);
 }
 
   return kill (lwpid, signo);
 }
 
-/* Handle a GNU/Linux extended wait response.  Most of the work we
-   just pass off to linux_handle_extended_wait, but if it reports a
-   clone event we need to add the new LWP 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 STOPPING
-   is true, the new LWP remains stopped, otherwise it is continued.  */
+/* 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).  This function returns non-zero if the
+   event should be ignored and we should wait again.  If STOPPING is
+   true, the new LWP remains stopped, otherwise it is continued.  */
 
 static int
 
 static int
-linux_nat_handle_extended (struct lwp_info *lp, int status, int stopping)
+linux_handle_extended_wait (struct lwp_info *lp, int status,
+                           int stopping)
 {
 {
-  linux_handle_extended_wait (GET_LWP (lp->ptid), status,
-                             &lp->waitstatus);
+  int pid = GET_LWP (lp->ptid);
+  struct target_waitstatus *ourstatus = &lp->waitstatus;
+  struct lwp_info *new_lp = NULL;
+  int event = status >> 16;
 
 
-  /* TARGET_WAITKIND_SPURIOUS is used to indicate clone events.  */
-  if (lp->waitstatus.kind == TARGET_WAITKIND_SPURIOUS)
+  if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK
+      || event == PTRACE_EVENT_CLONE)
     {
     {
-      struct lwp_info *new_lp;
-      new_lp = add_lwp (BUILD_LWP (lp->waitstatus.value.related_pid,
-                                  GET_PID (inferior_ptid)));
-      new_lp->cloned = 1;
+      unsigned long new_pid;
+      int ret;
 
 
-      if (stopping)
-       new_lp->stopped = 1;
+      ptrace (PTRACE_GETEVENTMSG, pid, 0, &new_pid);
+
+      /* If we haven't already seen the new PID stop, wait for it now.  */
+      if (! pull_pid_from_list (&stopped_pids, new_pid, &status))
+       {
+         /* The new child has a pending SIGSTOP.  We can't affect it until it
+            hits the SIGSTOP, but we're already attached.  */
+         ret = my_waitpid (new_pid, &status,
+                           (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
+         if (ret == -1)
+           perror_with_name (_("waiting for new child"));
+         else if (ret != new_pid)
+           internal_error (__FILE__, __LINE__,
+                           _("wait returned unexpected PID %d"), ret);
+         else if (!WIFSTOPPED (status))
+           internal_error (__FILE__, __LINE__,
+                           _("wait returned unexpected status 0x%x"), status);
+       }
+
+      ourstatus->value.related_pid = new_pid;
+
+      if (event == PTRACE_EVENT_FORK)
+       ourstatus->kind = TARGET_WAITKIND_FORKED;
+      else if (event == PTRACE_EVENT_VFORK)
+       ourstatus->kind = TARGET_WAITKIND_VFORKED;
       else
       else
-       ptrace (PTRACE_CONT, lp->waitstatus.value.related_pid, 0, 0);
+       {
+         ourstatus->kind = TARGET_WAITKIND_IGNORE;
+         new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (inferior_ptid)));
+         new_lp->cloned = 1;
 
 
-      lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+         if (WSTOPSIG (status) != SIGSTOP)
+           {
+             /* This can happen if someone starts sending signals to
+                the new thread before it gets a chance to run, which
+                have a lower number than SIGSTOP (e.g. SIGUSR1).
+                This is an unlikely case, and harder to handle for
+                fork / vfork than for clone, so we do not try - but
+                we handle it for clone events here.  We'll send
+                the other signal on to the thread below.  */
+
+             new_lp->signalled = 1;
+           }
+         else
+           status = 0;
 
 
-      if (debug_linux_nat)
-       fprintf_unfiltered (gdb_stdlog,
-                           "LLHE: Got clone event from LWP %ld, resuming\n",
-                           GET_LWP (lp->ptid));
-      ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+         if (stopping)
+           new_lp->stopped = 1;
+         else
+           {
+             new_lp->resumed = 1;
+             ptrace (PTRACE_CONT, lp->waitstatus.value.related_pid, 0,
+                     status ? WSTOPSIG (status) : 0);
+           }
 
 
-      return 1;
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "LHEW: Got clone event from LWP %ld, resuming\n",
+                               GET_LWP (lp->ptid));
+         ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
+
+         return 1;
+       }
+
+      return 0;
     }
 
     }
 
-  return 0;
+  if (event == PTRACE_EVENT_EXEC)
+    {
+      ourstatus->kind = TARGET_WAITKIND_EXECD;
+      ourstatus->value.execd_pathname
+       = xstrdup (linux_child_pid_to_exec_file (pid));
+
+      if (linux_parent_pid)
+       {
+         detach_breakpoints (linux_parent_pid);
+         ptrace (PTRACE_DETACH, linux_parent_pid, 0, 0);
+
+         linux_parent_pid = 0;
+       }
+
+      return 0;
+    }
+
+  internal_error (__FILE__, __LINE__,
+                 _("unknown ptrace event %d"), event);
 }
 
 /* Wait for LP to stop.  Returns the wait status, or 0 if the LWP has
 }
 
 /* Wait for LP to stop.  Returns the wait status, or 0 if the LWP has
@@ -1386,13 +1423,29 @@ wait_lwp (struct lwp_info *lp)
        fprintf_unfiltered (gdb_stdlog,
                            "WL: Handling extended status 0x%06x\n",
                            status);
        fprintf_unfiltered (gdb_stdlog,
                            "WL: Handling extended status 0x%06x\n",
                            status);
-      if (linux_nat_handle_extended (lp, status, 1))
+      if (linux_handle_extended_wait (lp, status, 1))
        return wait_lwp (lp);
     }
 
   return status;
 }
 
        return wait_lwp (lp);
     }
 
   return status;
 }
 
+/* Save the most recent siginfo for LP.  This is currently only called
+   for SIGTRAP; some ports use the si_addr field for
+   target_stopped_data_address.  In the future, it may also be used to
+   restore the siginfo of requeued signals.  */
+
+static void
+save_siginfo (struct lwp_info *lp)
+{
+  errno = 0;
+  ptrace (PTRACE_GETSIGINFO, GET_LWP (lp->ptid),
+         (PTRACE_TYPE_ARG3) 0, &lp->siginfo);
+
+  if (errno != 0)
+    memset (&lp->siginfo, 0, sizeof (lp->siginfo));
+}
+
 /* Send a SIGSTOP to LP.  */
 
 static int
 /* Send a SIGSTOP to LP.  */
 
 static int
@@ -1478,6 +1531,9 @@ stop_wait_callback (struct lwp_info *lp, void *data)
                 user will delete or disable the breakpoint, but the
                 thread will have already tripped on it.  */
 
                 user will delete or disable the breakpoint, but the
                 thread will have already tripped on it.  */
 
+             /* Save the trap's siginfo in case we need it later.  */
+             save_siginfo (lp);
+
              /* Now resume this LWP and get the SIGSTOP event. */
              errno = 0;
              ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
              /* Now resume this LWP and get the SIGSTOP event. */
              errno = 0;
              ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
@@ -1626,7 +1682,15 @@ flush_callback (struct lwp_info *lp, void *data)
        lp->status = 0;
     }
 
        lp->status = 0;
     }
 
-  while (linux_nat_has_pending (GET_LWP (lp->ptid), &pending, flush_mask))
+  /* While there is a pending signal we would like to flush, continue
+     the inferior and collect another signal.  But if there's already
+     a saved status that we don't want to flush, we can't resume the
+     inferior - if it stopped for some other reason we wouldn't have
+     anywhere to save the new status.  In that case, we must leave the
+     signal unflushed (and possibly generate an extra SIGINT stop).
+     That's much less bad than losing a signal.  */
+  while (lp->status == 0
+        && linux_nat_has_pending (GET_LWP (lp->ptid), &pending, flush_mask))
     {
       int ret;
       
     {
       int ret;
       
@@ -1734,7 +1798,8 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
   if (lp->status != 0
       && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
       && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
   if (lp->status != 0
       && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
       && breakpoint_inserted_here_p (read_pc_pid (lp->ptid) -
-                                    DECR_PC_AFTER_BREAK))
+                                    gdbarch_decr_pc_after_break
+                                      (current_gdbarch)))
     {
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
     {
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
@@ -1742,8 +1807,10 @@ cancel_breakpoints_callback (struct lwp_info *lp, void *data)
                            target_pid_to_str (lp->ptid));
 
       /* Back up the PC if necessary.  */
                            target_pid_to_str (lp->ptid));
 
       /* Back up the PC if necessary.  */
-      if (DECR_PC_AFTER_BREAK)
-       write_pc_pid (read_pc_pid (lp->ptid) - DECR_PC_AFTER_BREAK, lp->ptid);
+      if (gdbarch_decr_pc_after_break (current_gdbarch))
+       write_pc_pid (read_pc_pid (lp->ptid) - gdbarch_decr_pc_after_break
+                                                (current_gdbarch),
+                     lp->ptid);
 
       /* Throw away the SIGTRAP.  */
       lp->status = 0;
 
       /* Throw away the SIGTRAP.  */
       lp->status = 0;
@@ -1835,6 +1902,173 @@ stop_and_resume_callback (struct lwp_info *lp, void *data)
   return 0;
 }
 
   return 0;
 }
 
+/* Check if we should go on and pass this event to common code.
+   Return the affected lwp if we are, or NULL otherwise.  */
+static struct lwp_info *
+linux_nat_filter_event (int lwpid, int status, int options)
+{
+  struct lwp_info *lp;
+
+  lp = 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.  */
+  if (WIFSTOPPED (status) && !lp)
+    {
+      linux_record_stopped_pid (lwpid, status);
+      return NULL;
+    }
+
+  /* Make sure we don't report an event for the exit of an LWP not in
+     our list, i.e.  not part of the current process.  This can happen
+     if we detach from a program we original forked and then it
+     exits.  */
+  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);
+    }
+
+  /* Save the trap's siginfo in case we need it later.  */
+  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
+    save_siginfo (lp);
+
+  /* Handle GNU/Linux's extended waitstatus for trace events.  */
+  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
+    {
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: Handling extended status 0x%06x\n",
+                           status);
+      if (linux_handle_extended_wait (lp, status, 0))
+       return NULL;
+    }
+
+  /* Check if the thread has exited.  */
+  if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
+    {
+      /* If this is the main thread, we must stop all threads and
+        verify if they are still alive.  This is because in the nptl
+        thread model, there is no signal issued for exiting LWPs
+        other than the main thread.  We only get the main thread exit
+        signal once all child threads have already exited.  If we
+        stop all the threads and use the stop_wait_callback to check
+        if they have exited we can determine whether this signal
+        should be ignored or whether it means the end of the debugged
+        application, regardless of which threading model is being
+        used.  */
+      if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
+       {
+         lp->stopped = 1;
+         iterate_over_lwps (stop_and_resume_callback, NULL);
+       }
+
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: %s exited.\n",
+                           target_pid_to_str (lp->ptid));
+
+      exit_lwp (lp);
+
+      /* If there is at least one more LWP, then the exit signal was
+        not the end of the debugged application and should be
+        ignored.  */
+      if (num_lwps > 0)
+       {
+         /* Make sure there is at least one thread running.  */
+         gdb_assert (iterate_over_lwps (running_callback, NULL));
+
+         /* Discard the event.  */
+         return NULL;
+       }
+    }
+
+  /* Check if the current LWP has previously exited.  In the nptl
+     thread model, LWPs other than the main thread do not issue
+     signals when they exit so we must check whenever the thread has
+     stopped.  A similar check is made in stop_wait_callback().  */
+  if (num_lwps > 1 && !linux_nat_thread_alive (lp->ptid))
+    {
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: %s exited.\n",
+                           target_pid_to_str (lp->ptid));
+
+      exit_lwp (lp);
+
+      /* Make sure there is at least one thread running.  */
+      gdb_assert (iterate_over_lwps (running_callback, NULL));
+
+      /* Discard the event.  */
+      return NULL;
+    }
+
+  /* Make sure we don't report a SIGSTOP that we sent ourselves in
+     an attempt to stop an LWP.  */
+  if (lp->signalled
+      && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
+    {
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: Delayed SIGSTOP caught for %s.\n",
+                           target_pid_to_str (lp->ptid));
+
+      /* This is a delayed SIGSTOP.  */
+      lp->signalled = 0;
+
+      registers_changed ();
+
+      linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
+                           lp->step, TARGET_SIGNAL_0);
+      if (debug_linux_nat)
+       fprintf_unfiltered (gdb_stdlog,
+                           "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
+                           lp->step ?
+                           "PTRACE_SINGLESTEP" : "PTRACE_CONT",
+                           target_pid_to_str (lp->ptid));
+
+      lp->stopped = 0;
+      gdb_assert (lp->resumed);
+
+      /* Discard the event.  */
+      return NULL;
+    }
+
+  /* An interesting event.  */
+  gdb_assert (lp);
+  return lp;
+}
+
 static ptid_t
 linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 {
 static ptid_t
 linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 {
@@ -1967,165 +2201,10 @@ retry:
                                  (long) lwpid, status_to_str (status));
            }
 
                                  (long) lwpid, status_to_str (status));
            }
 
-         lp = 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.  */
-         if (WIFSTOPPED (status) && !lp)
-           {
-             linux_record_stopped_pid (lwpid);
-             status = 0;
-             continue;
-           }
-
-         /* Make sure we don't report an event for the exit of an LWP not in
-            our list, i.e.  not part of the current process.  This can happen
-            if we detach from a program we original forked and then it
-            exits.  */
-         if (!WIFSTOPPED (status) && !lp)
-           {
-             status = 0;
-             continue;
-           }
-
-         /* 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.  */
+         lp = linux_nat_filter_event (lwpid, status, options);
          if (!lp)
            {
          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);
-             printf_unfiltered (_("[New %s]\n"),
-                                target_pid_to_str (lp->ptid));
-           }
-
-         /* Handle GNU/Linux's extended waitstatus for trace events.  */
-         if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: Handling extended status 0x%06x\n",
-                                   status);
-             if (linux_nat_handle_extended (lp, status, 0))
-               {
-                 status = 0;
-                 continue;
-               }
-           }
-
-         /* Check if the thread has exited.  */
-         if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
-           {
-             /* If this is the main thread, we must stop all threads and
-                verify if they are still alive.  This is because in the nptl
-                thread model, there is no signal issued for exiting LWPs
-                other than the main thread.  We only get the main thread
-                exit signal once all child threads have already exited.
-                If we stop all the threads and use the stop_wait_callback
-                to check if they have exited we can determine whether this
-                signal should be ignored or whether it means the end of the
-                debugged application, regardless of which threading model
-                is being used.  */
-             if (GET_PID (lp->ptid) == GET_LWP (lp->ptid))
-               {
-                 lp->stopped = 1;
-                 iterate_over_lwps (stop_and_resume_callback, NULL);
-               }
-
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: %s exited.\n",
-                                   target_pid_to_str (lp->ptid));
-
-             exit_lwp (lp);
-
-             /* If there is at least one more LWP, then the exit signal
-                was not the end of the debugged application and should be
-                ignored.  */
-             if (num_lwps > 0)
-               {
-                 /* Make sure there is at least one thread running.  */
-                 gdb_assert (iterate_over_lwps (running_callback, NULL));
-
-                 /* Discard the event.  */
-                 status = 0;
-                 continue;
-               }
-           }
-
-         /* Check if the current LWP has previously exited.  In the nptl
-            thread model, LWPs other than the main thread do not issue
-            signals when they exit so we must check whenever the thread
-            has stopped.  A similar check is made in stop_wait_callback().  */
-         if (num_lwps > 1 && !linux_nat_thread_alive (lp->ptid))
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: %s exited.\n",
-                                   target_pid_to_str (lp->ptid));
-
-             exit_lwp (lp);
-
-             /* Make sure there is at least one thread running.  */
-             gdb_assert (iterate_over_lwps (running_callback, NULL));
-
-             /* Discard the event.  */
-             status = 0;
-             continue;
-           }
-
-         /* Make sure we don't report a SIGSTOP that we sent
-            ourselves in an attempt to stop an LWP.  */
-         if (lp->signalled
-             && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP)
-           {
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: Delayed SIGSTOP caught for %s.\n",
-                                   target_pid_to_str (lp->ptid));
-
-             /* This is a delayed SIGSTOP.  */
-             lp->signalled = 0;
-
-             registers_changed ();
-             linux_ops->to_resume (pid_to_ptid (GET_LWP (lp->ptid)),
-                                   lp->step, TARGET_SIGNAL_0);
-             if (debug_linux_nat)
-               fprintf_unfiltered (gdb_stdlog,
-                                   "LLW: %s %s, 0, 0 (discard SIGSTOP)\n",
-                                   lp->step ?
-                                   "PTRACE_SINGLESTEP" : "PTRACE_CONT",
-                                   target_pid_to_str (lp->ptid));
-
-             lp->stopped = 0;
-             gdb_assert (lp->resumed);
-
-             /* Discard the event.  */
+             /* A discarded event.  */
              status = 0;
              continue;
            }
              status = 0;
              continue;
            }
@@ -2279,11 +2358,18 @@ kill_wait_callback (struct lwp_info *lp, void *data)
       do
        {
          pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
       do
        {
          pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
-         if (pid != (pid_t) -1 && debug_linux_nat)
+         if (pid != (pid_t) -1)
            {
            {
-             fprintf_unfiltered (gdb_stdlog,
-                                 "KWC: wait %s received unknown.\n",
-                                 target_pid_to_str (lp->ptid));
+             if (debug_linux_nat)
+               fprintf_unfiltered (gdb_stdlog,
+                                   "KWC: wait %s received unknown.\n",
+                                   target_pid_to_str (lp->ptid));
+             /* The Linux kernel sometimes fails to kill a thread
+                completely after PTRACE_KILL; that goes from the stop
+                point in do_fork out to the one in
+                get_signal_to_deliever and waits again.  So kill it
+                again.  */
+             kill_callback (lp, NULL);
            }
        }
       while (pid == GET_LWP (lp->ptid));
            }
        }
       while (pid == GET_LWP (lp->ptid));
@@ -2294,11 +2380,14 @@ kill_wait_callback (struct lwp_info *lp, void *data)
   do
     {
       pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
   do
     {
       pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
-      if (pid != (pid_t) -1 && debug_linux_nat)
+      if (pid != (pid_t) -1)
        {
        {
-         fprintf_unfiltered (gdb_stdlog,
-                             "KWC: wait %s received unk.\n",
-                             target_pid_to_str (lp->ptid));
+         if (debug_linux_nat)
+           fprintf_unfiltered (gdb_stdlog,
+                               "KWC: wait %s received unk.\n",
+                               target_pid_to_str (lp->ptid));
+         /* See the call to kill_callback above.  */
+         kill_callback (lp, NULL);
        }
     }
   while (pid == GET_LWP (lp->ptid));
        }
     }
   while (pid == GET_LWP (lp->ptid));
@@ -2395,11 +2484,11 @@ linux_nat_thread_alive (ptid_t ptid)
                        target_pid_to_str (ptid),
                        errno ? safe_strerror (errno) : "OK");
 
                        target_pid_to_str (ptid),
                        errno ? safe_strerror (errno) : "OK");
 
-  /* Not every Linux target implements PTRACE_PEEKUSER.
-     But we can handle that case gracefully since ptrace
-     will first do a lookup for the process based upon the
-     passed-in pid.  If that fails we will get either -ESRCH
-     or -EPERM, otherwise the child exists and is alive.  */
+  /* Not every Linux kernel implements PTRACE_PEEKUSER.  But we can
+     handle that case gracefully since ptrace will first do a lookup
+     for the process based upon the passed-in pid.  If that fails we
+     will get either -ESRCH or -EPERM, otherwise the child exists and
+     is alive.  */
   if (errno == ESRCH || errno == EPERM)
     return 0;
 
   if (errno == ESRCH || errno == EPERM)
     return 0;
 
@@ -2431,8 +2520,8 @@ sigchld_handler (int signo)
 /* Accepts an integer PID; Returns a string representing a file that
    can be opened to get the symbols for the child process.  */
 
 /* Accepts an integer PID; Returns a string representing a file that
    can be opened to get the symbols for the child process.  */
 
-char *
-child_pid_to_exec_file (int pid)
+static char *
+linux_child_pid_to_exec_file (int pid)
 {
   char *name1, *name2;
 
 {
   char *name1, *name2;
 
@@ -2521,7 +2610,7 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
                            size, paddr_nz (addr),
                            read ? 'r' : ' ',
                            write ? 'w' : ' ', exec ? 'x' : ' ');
                            size, paddr_nz (addr),
                            read ? 'r' : ' ',
                            write ? 'w' : ' ', exec ? 'x' : ' ');
-         if (filename && filename[0])
+         if (filename[0])
            fprintf_filtered (gdb_stdout, " for %s", filename);
          fprintf_filtered (gdb_stdout, "\n");
        }
            fprintf_filtered (gdb_stdout, " for %s", filename);
          fprintf_filtered (gdb_stdout, "\n");
        }
@@ -2547,19 +2636,26 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
   gdb_fpxregset_t fpxregs;
 #endif
   unsigned long lwp = ptid_get_lwp (ptid);
   gdb_fpxregset_t fpxregs;
 #endif
   unsigned long lwp = ptid_get_lwp (ptid);
-  struct gdbarch *gdbarch = current_gdbarch;
+  struct regcache *regcache = get_thread_regcache (ptid);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   const struct regset *regset;
   int core_regset_p;
   const struct regset *regset;
   int core_regset_p;
+  struct cleanup *old_chain;
+
+  old_chain = save_inferior_ptid ();
+  inferior_ptid = ptid;
+  target_fetch_registers (regcache, -1);
+  do_cleanups (old_chain);
 
   core_regset_p = gdbarch_regset_from_core_section_p (gdbarch);
   if (core_regset_p
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
                                                     sizeof (gregs))) != NULL
       && regset->collect_regset != NULL)
 
   core_regset_p = gdbarch_regset_from_core_section_p (gdbarch);
   if (core_regset_p
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg",
                                                     sizeof (gregs))) != NULL
       && regset->collect_regset != NULL)
-    regset->collect_regset (regset, current_regcache, -1,
+    regset->collect_regset (regset, regcache, -1,
                            &gregs, sizeof (gregs));
   else
                            &gregs, sizeof (gregs));
   else
-    fill_gregset (&gregs, -1);
+    fill_gregset (regcache, &gregs, -1);
 
   note_data = (char *) elfcore_write_prstatus (obfd,
                                               note_data,
 
   note_data = (char *) elfcore_write_prstatus (obfd,
                                               note_data,
@@ -2571,10 +2667,10 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
                                                     sizeof (fpregs))) != NULL
       && regset->collect_regset != NULL)
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
                                                     sizeof (fpregs))) != NULL
       && regset->collect_regset != NULL)
-    regset->collect_regset (regset, current_regcache, -1,
+    regset->collect_regset (regset, regcache, -1,
                            &fpregs, sizeof (fpregs));
   else
                            &fpregs, sizeof (fpregs));
   else
-    fill_fpregset (&fpregs, -1);
+    fill_fpregset (regcache, &fpregs, -1);
 
   note_data = (char *) elfcore_write_prfpreg (obfd,
                                              note_data,
 
   note_data = (char *) elfcore_write_prfpreg (obfd,
                                              note_data,
@@ -2586,10 +2682,10 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg-xfp",
                                                     sizeof (fpxregs))) != NULL
       && regset->collect_regset != NULL)
       && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg-xfp",
                                                     sizeof (fpxregs))) != NULL
       && regset->collect_regset != NULL)
-    regset->collect_regset (regset, current_regcache, -1,
+    regset->collect_regset (regset, regcache, -1,
                            &fpxregs, sizeof (fpxregs));
   else
                            &fpxregs, sizeof (fpxregs));
   else
-    fill_fpxregset (&fpxregs, -1);
+    fill_fpxregset (regcache, &fpxregs, -1);
 
   note_data = (char *) elfcore_write_prxfpreg (obfd,
                                               note_data,
 
   note_data = (char *) elfcore_write_prxfpreg (obfd,
                                               note_data,
@@ -2614,21 +2710,13 @@ static int
 linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
 {
   struct linux_nat_corefile_thread_data *args = data;
 linux_nat_corefile_thread_callback (struct lwp_info *ti, void *data)
 {
   struct linux_nat_corefile_thread_data *args = data;
-  ptid_t saved_ptid = inferior_ptid;
 
 
-  inferior_ptid = ti->ptid;
-  registers_changed ();
-  target_fetch_registers (-1); /* FIXME should not be necessary;
-                                  fill_gregset should do it automatically. */
   args->note_data = linux_nat_do_thread_registers (args->obfd,
                                                   ti->ptid,
                                                   args->note_data,
                                                   args->note_size);
   args->num_notes++;
   args->note_data = linux_nat_do_thread_registers (args->obfd,
                                                   ti->ptid,
                                                   args->note_data,
                                                   args->note_size);
   args->num_notes++;
-  inferior_ptid = saved_ptid;
-  registers_changed ();
-  target_fetch_registers (-1); /* FIXME should not be necessary;
-                                  fill_gregset should do it automatically. */
+
   return 0;
 }
 
   return 0;
 }
 
@@ -2638,15 +2726,11 @@ static char *
 linux_nat_do_registers (bfd *obfd, ptid_t ptid,
                        char *note_data, int *note_size)
 {
 linux_nat_do_registers (bfd *obfd, ptid_t ptid,
                        char *note_data, int *note_size)
 {
-  registers_changed ();
-  target_fetch_registers (-1); /* FIXME should not be necessary;
-                                  fill_gregset should do it automatically. */
   return linux_nat_do_thread_registers (obfd,
                                        ptid_build (ptid_get_pid (inferior_ptid),
                                                    ptid_get_pid (inferior_ptid),
                                                    0),
                                        note_data, note_size);
   return linux_nat_do_thread_registers (obfd,
                                        ptid_build (ptid_get_pid (inferior_ptid),
                                                    ptid_get_pid (inferior_ptid),
                                                    0),
                                        note_data, note_size);
-  return note_data;
 }
 
 /* Fills the "to_make_corefile_note" target vector.  Builds the note
 }
 
 /* Fills the "to_make_corefile_note" target vector.  Builds the note
@@ -2657,7 +2741,9 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
 {
   struct linux_nat_corefile_thread_data thread_args;
   struct cleanup *old_chain;
 {
   struct linux_nat_corefile_thread_data thread_args;
   struct cleanup *old_chain;
+  /* The variable size must be >= sizeof (prpsinfo_t.pr_fname).  */
   char fname[16] = { '\0' };
   char fname[16] = { '\0' };
+  /* The variable size must be >= sizeof (prpsinfo_t.pr_psargs).  */
   char psargs[80] = { '\0' };
   char *note_data = NULL;
   ptid_t current_ptid = inferior_ptid;
   char psargs[80] = { '\0' };
   char *note_data = NULL;
   ptid_t current_ptid = inferior_ptid;
@@ -2670,9 +2756,18 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
       strncpy (psargs, get_exec_file (0), sizeof (psargs));
       if (get_inferior_args ())
        {
       strncpy (psargs, get_exec_file (0), sizeof (psargs));
       if (get_inferior_args ())
        {
-         strncat (psargs, " ", sizeof (psargs) - strlen (psargs));
-         strncat (psargs, get_inferior_args (),
-                  sizeof (psargs) - strlen (psargs));
+         char *string_end;
+         char *psargs_end = psargs + sizeof (psargs);
+
+         /* linux_elfcore_write_prpsinfo () handles zero unterminated
+            strings fine.  */
+         string_end = memchr (psargs, 0, sizeof (psargs));
+         if (string_end != NULL)
+           {
+             *string_end++ = ' ';
+             strncpy (string_end, get_inferior_args (),
+                      psargs_end - string_end);
+           }
        }
       note_data = (char *) elfcore_write_prpsinfo (obfd,
                                                   note_data,
        }
       note_data = (char *) elfcore_write_prpsinfo (obfd,
                                                   note_data,
@@ -2697,7 +2792,8 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
       note_data = thread_args.note_data;
     }
 
       note_data = thread_args.note_data;
     }
 
-  auxv_len = target_auxv_read (&current_target, &auxv);
+  auxv_len = target_read_alloc (&current_target, TARGET_OBJECT_AUXV,
+                               NULL, &auxv);
   if (auxv_len > 0)
     {
       note_data = elfcore_write_note (obfd, note_data, note_size,
   if (auxv_len > 0)
     {
       note_data = elfcore_write_note (obfd, note_data, note_size,
@@ -2788,7 +2884,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
   if (cmdline_f || all)
     {
       sprintf (fname1, "/proc/%lld/cmdline", pid);
   if (cmdline_f || all)
     {
       sprintf (fname1, "/proc/%lld/cmdline", pid);
-      if ((procfile = fopen (fname1, "r")) > 0)
+      if ((procfile = fopen (fname1, "r")) != NULL)
        {
          fgets (buffer, sizeof (buffer), procfile);
          printf_filtered ("cmdline = '%s'\n", buffer);
        {
          fgets (buffer, sizeof (buffer), procfile);
          printf_filtered ("cmdline = '%s'\n", buffer);
@@ -2818,13 +2914,13 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
   if (mappings_f || all)
     {
       sprintf (fname1, "/proc/%lld/maps", pid);
   if (mappings_f || all)
     {
       sprintf (fname1, "/proc/%lld/maps", pid);
-      if ((procfile = fopen (fname1, "r")) > 0)
+      if ((procfile = fopen (fname1, "r")) != NULL)
        {
          long long addr, endaddr, size, offset, inode;
          char permissions[8], device[8], filename[MAXPATHLEN];
 
          printf_filtered (_("Mapped address spaces:\n\n"));
        {
          long long addr, endaddr, size, offset, inode;
          char permissions[8], device[8], filename[MAXPATHLEN];
 
          printf_filtered (_("Mapped address spaces:\n\n"));
-         if (TARGET_ADDR_BIT == 32)
+         if (gdbarch_addr_bit (current_gdbarch) == 32)
            {
              printf_filtered ("\t%10s %10s %10s %10s %7s\n",
                           "Start Addr",
            {
              printf_filtered ("\t%10s %10s %10s %10s %7s\n",
                           "Start Addr",
@@ -2850,7 +2946,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
                 a generic local_address_string instead to print out
                 the addresses; that makes sense to me, too.  */
 
                 a generic local_address_string instead to print out
                 the addresses; that makes sense to me, too.  */
 
-             if (TARGET_ADDR_BIT == 32)
+             if (gdbarch_addr_bit (current_gdbarch) == 32)
                {
                  printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
                               (unsigned long) addr,    /* FIXME: pr_addr */
                {
                  printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
                               (unsigned long) addr,    /* FIXME: pr_addr */
@@ -2878,7 +2974,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
   if (status_f || all)
     {
       sprintf (fname1, "/proc/%lld/status", pid);
   if (status_f || all)
     {
       sprintf (fname1, "/proc/%lld/status", pid);
-      if ((procfile = fopen (fname1, "r")) > 0)
+      if ((procfile = fopen (fname1, "r")) != NULL)
        {
          while (fgets (buffer, sizeof (buffer), procfile) != NULL)
            puts_filtered (buffer);
        {
          while (fgets (buffer, sizeof (buffer), procfile) != NULL)
            puts_filtered (buffer);
@@ -2890,14 +2986,15 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
   if (stat_f || all)
     {
       sprintf (fname1, "/proc/%lld/stat", pid);
   if (stat_f || all)
     {
       sprintf (fname1, "/proc/%lld/stat", pid);
-      if ((procfile = fopen (fname1, "r")) > 0)
+      if ((procfile = fopen (fname1, "r")) != NULL)
        {
          int itmp;
          char ctmp;
        {
          int itmp;
          char ctmp;
+         long ltmp;
 
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("Process: %d\n"), itmp);
 
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("Process: %d\n"), itmp);
-         if (fscanf (procfile, "%s ", &buffer[0]) > 0)
+         if (fscanf (procfile, "(%[^)]) ", &buffer[0]) > 0)
            printf_filtered (_("Exec file: %s\n"), buffer);
          if (fscanf (procfile, "%c ", &ctmp) > 0)
            printf_filtered (_("State: %c\n"), ctmp);
            printf_filtered (_("Exec file: %s\n"), buffer);
          if (fscanf (procfile, "%c ", &ctmp) > 0)
            printf_filtered (_("State: %c\n"), ctmp);
@@ -2911,71 +3008,71 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
            printf_filtered (_("TTY: %d\n"), itmp);
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("TTY owner process group: %d\n"), itmp);
            printf_filtered (_("TTY: %d\n"), itmp);
          if (fscanf (procfile, "%d ", &itmp) > 0)
            printf_filtered (_("TTY owner process group: %d\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Flags: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Minor faults (no memory page): %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Minor faults, children: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Major faults (memory page faults): %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Major faults, children: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("utime: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("stime: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("utime, children: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("stime, children: %d\n", itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("jiffies remaining in current time slice: %d\n"),
-                            itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered ("'nice' value: %d\n", itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("jiffies until next timeout: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered ("jiffies until next SIGALRM: %u\n",
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("start time (jiffies since system boot): %d\n"),
-                            itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Virtual memory size: %u\n"),
-                            (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Resident set size: %u\n"), (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered ("rlim: %u\n", (unsigned int) itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Start of text: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("End of text: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)
-           printf_filtered (_("Start of stack: 0x%x\n"), itmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Flags: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Minor faults (no memory page): %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Minor faults, children: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Major faults (memory page faults): %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Major faults, children: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("utime: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("stime: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("utime, children: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("stime, children: %ld\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("jiffies remaining in current time slice: %ld\n"),
+                            ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("'nice' value: %ld\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("jiffies until next timeout: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("jiffies until next SIGALRM: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("start time (jiffies since system boot): %ld\n"),
+                            ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Virtual memory size: %lu\n"),
+                            (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Resident set size: %lu\n"), (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("rlim: %lu\n"), (unsigned long) ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Start of text: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("End of text: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)
+           printf_filtered (_("Start of stack: 0x%lx\n"), ltmp);
 #if 0                          /* Don't know how architecture-dependent the rest is...
                                   Anyway the signal bitmap info is available from "status".  */
 #if 0                          /* Don't know how architecture-dependent the rest is...
                                   Anyway the signal bitmap info is available from "status".  */
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("Kernel stack pointer: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("Kernel instr pointer: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Pending signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Blocked signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Ignored signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%d ", &itmp) > 0)
-           printf_filtered (_("Catched signals bitmap: 0x%x\n"), itmp);
-         if (fscanf (procfile, "%u ", &itmp) > 0)      /* FIXME arch? */
-           printf_filtered (_("wchan (system call): 0x%x\n"), itmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("Kernel stack pointer: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("Kernel instr pointer: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Pending signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Blocked signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Ignored signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%ld ", &ltmp) > 0)
+           printf_filtered (_("Catched signals bitmap: 0x%lx\n"), ltmp);
+         if (fscanf (procfile, "%lu ", &ltmp) > 0)     /* FIXME arch? */
+           printf_filtered (_("wchan (system call): 0x%lx\n"), ltmp);
 #endif
          fclose (procfile);
        }
 #endif
          fclose (procfile);
        }
@@ -3131,47 +3228,44 @@ linux_xfer_partial (struct target_ops *ops, enum target_object object,
                             offset, len);
 }
 
                             offset, len);
 }
 
-#ifndef FETCH_INFERIOR_REGISTERS
-
-/* Return the address in the core dump or inferior of register
-   REGNO.  */
+/* Create a prototype generic GNU/Linux target.  The client can override
+   it with local methods.  */
 
 
-static CORE_ADDR
-linux_register_u_offset (int regno)
+static void
+linux_target_install_ops (struct target_ops *t)
 {
 {
-  /* FIXME drow/2005-09-04: The hardcoded use of register_addr should go
-     away.  This requires disentangling the various definitions of it
-     (particularly alpha-nat.c's).  */
-  return register_addr (regno, 0);
-}
-
-#endif
+  t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint;
+  t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint;
+  t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint;
+  t->to_pid_to_exec_file = linux_child_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;
+  t->to_find_memory_regions = linux_nat_find_memory_regions;
+  t->to_make_corefile_notes = linux_nat_make_corefile_notes;
 
 
-/* Create a prototype generic Linux target.  The client can override
-   it with local methods.  */
+  super_xfer_partial = t->to_xfer_partial;
+  t->to_xfer_partial = linux_xfer_partial;
+}
 
 struct target_ops *
 linux_target (void)
 {
   struct target_ops *t;
 
 
 struct target_ops *
 linux_target (void)
 {
   struct target_ops *t;
 
-#ifdef FETCH_INFERIOR_REGISTERS
   t = inf_ptrace_target ();
   t = inf_ptrace_target ();
-#else
-  t = inf_ptrace_trad_target (linux_register_u_offset);
-#endif
-  t->to_insert_fork_catchpoint = child_insert_fork_catchpoint;
-  t->to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
-  t->to_insert_exec_catchpoint = child_insert_exec_catchpoint;
-  t->to_pid_to_exec_file = child_pid_to_exec_file;
-  t->to_post_startup_inferior = linux_child_post_startup_inferior;
-  t->to_post_attach = child_post_attach;
-  t->to_follow_fork = child_follow_fork;
-  t->to_find_memory_regions = linux_nat_find_memory_regions;
-  t->to_make_corefile_notes = linux_nat_make_corefile_notes;
+  linux_target_install_ops (t);
 
 
-  super_xfer_partial = t->to_xfer_partial;
-  t->to_xfer_partial = linux_xfer_partial;
+  return t;
+}
+
+struct target_ops *
+linux_trad_target (CORE_ADDR (*register_u_offset)(struct gdbarch *, int, int))
+{
+  struct target_ops *t;
+
+  t = inf_ptrace_trad_target (register_u_offset);
+  linux_target_install_ops (t);
 
   return t;
 }
 
   return t;
 }
@@ -3179,8 +3273,6 @@ linux_target (void)
 void
 linux_nat_add_target (struct target_ops *t)
 {
 void
 linux_nat_add_target (struct target_ops *t)
 {
-  extern void thread_db_init (struct target_ops *);
-
   /* Save the provided single-threaded target.  We save this in a separate
      variable because another target we've inherited from (e.g. inf-ptrace)
      may have saved a pointer to T; we want to use it for the final
   /* Save the provided single-threaded target.  We save this in a separate
      variable because another target we've inherited from (e.g. inf-ptrace)
      may have saved a pointer to T; we want to use it for the final
@@ -3213,6 +3305,27 @@ linux_nat_add_target (struct target_ops *t)
   thread_db_init (t);
 }
 
   thread_db_init (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))
+{
+  /* 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
+     T.  */
+  linux_nat_new_thread = new_thread;
+}
+
+/* Return the saved siginfo associated with PTID.  */
+struct siginfo *
+linux_nat_get_siginfo (ptid_t ptid)
+{
+  struct lwp_info *lp = find_lwp_pid (ptid);
+
+  gdb_assert (lp != NULL);
+
+  return &lp->siginfo;
+}
+
 void
 _initialize_linux_nat (void)
 {
 void
 _initialize_linux_nat (void)
 {
This page took 0.046416 seconds and 4 git commands to generate.