* win32-nat.c (psapi_module_handle): Remove static.
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index f050e7e83f91545f2f90f89e5ff562de0140f542..9a39ab64386ac2724aea4243a8ff72134e31540d 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
    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"
@@ -36,6 +34,7 @@
 #include "gdbthread.h"
 #include "gdbcmd.h"
 #include "regcache.h"
 #include "gdbthread.h"
 #include "gdbcmd.h"
 #include "regcache.h"
+#include "regset.h"
 #include "inf-ptrace.h"
 #include "auxv.h"
 #include <sys/param.h>         /* for MAXPATHLEN */
 #include "inf-ptrace.h"
 #include "auxv.h"
 #include <sys/param.h>         /* for MAXPATHLEN */
 #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 *, 
@@ -112,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;
@@ -130,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;
 
@@ -147,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;
@@ -154,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
@@ -275,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
@@ -330,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 ();
@@ -344,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;
@@ -500,12 +510,13 @@ 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);
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
@@ -514,86 +525,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."));
@@ -633,7 +581,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;
@@ -674,6 +622,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.  */
@@ -716,7 +665,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)
@@ -737,6 +687,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;
 }
 
@@ -899,10 +852,13 @@ exit_lwp (struct lwp_info *lp)
       struct thread_info *thr;
 
       thr = iterate_over_threads (find_thread_from_lwp, &lp->ptid);
       struct thread_info *thr;
 
       thr = iterate_over_threads (find_thread_from_lwp, &lp->ptid);
-      if (thr && !ptid_equal (thr->ptid, inferior_ptid))
-       delete_thread (thr->ptid);
-      else
-       record_dead_thread (thr->ptid);
+      if (thr)
+       {
+         if (!ptid_equal (thr->ptid, inferior_ptid))
+           delete_thread (thr->ptid);
+         else
+           record_dead_thread (thr->ptid);
+       }
     }
 
   delete_lwp (lp->ptid);
     }
 
   delete_lwp (lp->ptid);
@@ -910,12 +866,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
+int
 lin_lwp_attach_lwp (ptid_t ptid, int verbose)
 {
 lin_lwp_attach_lwp (ptid_t ptid, int verbose)
 {
-  struct lwp_info *lp, *found_lp;
+  struct lwp_info *lp;
 
   gdb_assert (is_lwp (ptid));
 
 
   gdb_assert (is_lwp (ptid));
 
@@ -927,12 +884,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
@@ -940,14 +892,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,
@@ -959,12 +920,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;
@@ -981,12 +946,19 @@ 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;
     }
+
+  if (verbose)
+    printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
+
+  return 0;
 }
 
 static void
 }
 
 static void
@@ -995,15 +967,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.  */
@@ -1014,12 +983,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.  */
@@ -1119,8 +1093,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)
@@ -1129,6 +1101,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;
@@ -1178,68 +1151,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",
@@ -1274,39 +1248,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.  */
+/* 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)
+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;
-      new_lp->stopped = 1;
+      unsigned long new_pid;
+      int ret;
 
 
-      lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+      ptrace (PTRACE_GETEVENTMSG, pid, 0, &new_pid);
 
 
-      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 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);
+       }
 
 
-      return 1;
+      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
+       {
+         ourstatus->kind = TARGET_WAITKIND_IGNORE;
+         new_lp = add_lwp (BUILD_LWP (new_pid, GET_PID (inferior_ptid)));
+         new_lp->cloned = 1;
+
+         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 (stopping)
+           new_lp->stopped = 1;
+         else
+           {
+             new_lp->resumed = 1;
+             ptrace (PTRACE_CONT, lp->waitstatus.value.related_pid, 0,
+                     status ? WSTOPSIG (status) : 0);
+           }
+
+         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
@@ -1377,13 +1425,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))
+      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
@@ -1469,6 +1533,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);
@@ -1617,7 +1684,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;
       
@@ -1725,7 +1800,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,
@@ -1733,8 +1809,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;
@@ -1971,7 +2049,7 @@ retry:
             from waitpid before or after the event is.  */
          if (WIFSTOPPED (status) && !lp)
            {
             from waitpid before or after the event is.  */
          if (WIFSTOPPED (status) && !lp)
            {
-             linux_record_stopped_pid (lwpid);
+             linux_record_stopped_pid (lwpid, status);
              status = 0;
              continue;
            }
              status = 0;
              continue;
            }
@@ -2015,6 +2093,10 @@ retry:
                                 target_pid_to_str (lp->ptid));
            }
 
                                 target_pid_to_str (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)
            {
          /* Handle GNU/Linux's extended waitstatus for trace events.  */
          if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
            {
@@ -2022,7 +2104,7 @@ retry:
                fprintf_unfiltered (gdb_stdlog,
                                    "LLW: Handling extended status 0x%06x\n",
                                    status);
                fprintf_unfiltered (gdb_stdlog,
                                    "LLW: Handling extended status 0x%06x\n",
                                    status);
-             if (linux_nat_handle_extended (lp, status))
+             if (linux_handle_extended_wait (lp, status, 0))
                {
                  status = 0;
                  continue;
                {
                  status = 0;
                  continue;
@@ -2154,7 +2236,10 @@ retry:
     {
       int signo = target_signal_from_host (WSTOPSIG (status));
 
     {
       int signo = target_signal_from_host (WSTOPSIG (status));
 
-      if (signal_stop_state (signo) == 0
+      /* If we get a signal while single-stepping, we may need special
+        care, e.g. to skip the signal handler.  Defer to common code.  */
+      if (!lp->step
+         && signal_stop_state (signo) == 0
          && signal_print_state (signo) == 0
          && signal_pass_state (signo) == 1)
        {
          && signal_print_state (signo) == 0
          && signal_pass_state (signo) == 1)
        {
@@ -2383,11 +2468,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;
 
@@ -2419,8 +2504,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;
 
@@ -2509,7 +2594,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");
        }
@@ -2535,21 +2620,57 @@ 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 regcache *regcache = get_thread_regcache (ptid);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  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)
+    regset->collect_regset (regset, regcache, -1,
+                           &gregs, sizeof (gregs));
+  else
+    fill_gregset (regcache, &gregs, -1);
 
 
-  fill_gregset (&gregs, -1);
   note_data = (char *) elfcore_write_prstatus (obfd,
                                               note_data,
                                               note_size,
                                               lwp,
                                               stop_signal, &gregs);
 
   note_data = (char *) elfcore_write_prstatus (obfd,
                                               note_data,
                                               note_size,
                                               lwp,
                                               stop_signal, &gregs);
 
-  fill_fpregset (&fpregs, -1);
+  if (core_regset_p
+      && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg2",
+                                                    sizeof (fpregs))) != NULL
+      && regset->collect_regset != NULL)
+    regset->collect_regset (regset, regcache, -1,
+                           &fpregs, sizeof (fpregs));
+  else
+    fill_fpregset (regcache, &fpregs, -1);
+
   note_data = (char *) elfcore_write_prfpreg (obfd,
                                              note_data,
                                              note_size,
                                              &fpregs, sizeof (fpregs));
   note_data = (char *) elfcore_write_prfpreg (obfd,
                                              note_data,
                                              note_size,
                                              &fpregs, sizeof (fpregs));
+
 #ifdef FILL_FPXREGSET
 #ifdef FILL_FPXREGSET
-  fill_fpxregset (&fpxregs, -1);
+  if (core_regset_p
+      && (regset = gdbarch_regset_from_core_section (gdbarch, ".reg-xfp",
+                                                    sizeof (fpxregs))) != NULL
+      && regset->collect_regset != NULL)
+    regset->collect_regset (regset, regcache, -1,
+                           &fpxregs, sizeof (fpxregs));
+  else
+    fill_fpxregset (regcache, &fpxregs, -1);
+
   note_data = (char *) elfcore_write_prxfpreg (obfd,
                                               note_data,
                                               note_size,
   note_data = (char *) elfcore_write_prxfpreg (obfd,
                                               note_data,
                                               note_size,
@@ -2573,21 +2694,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;
 }
 
@@ -2597,15 +2710,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
@@ -2616,7 +2725,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;
@@ -2629,9 +2740,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,
@@ -2656,7 +2776,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,
@@ -2747,7 +2868,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);
@@ -2777,13 +2898,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",
@@ -2809,7 +2930,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 */
@@ -2837,7 +2958,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);
@@ -2849,14 +2970,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);
@@ -2870,71 +2992,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);
        }
@@ -3090,47 +3212,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;
 }
@@ -3138,8 +3257,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
@@ -3172,6 +3289,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.043828 seconds and 4 git commands to generate.