Don't emit symbols seen only in dynamic object, don't read duplicate
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 0710ac718acbbadee3883b8999b6f849cd733cbe..b0b9cf32b9367fe52ddedb6485d819760a5761af 100644 (file)
@@ -36,6 +36,7 @@
 #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 */
@@ -88,6 +89,7 @@
 /* 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 saved to_xfer_partial method, inherited from inf-ptrace.c.
    Called by our to_xfer_partial.  */
@@ -97,10 +99,6 @@ static LONGEST (*super_xfer_partial) (struct target_ops *,
                                      const gdb_byte *,
                                      ULONGEST, LONGEST);
 
-/* The saved to_mourn_inferior method, inherited from inf-ptrace.c.
-   Called by our to_mourn_inferior.  */
-static void (*super_mourn_inferior) (void);
-
 static int debug_linux_nat;
 static void
 show_debug_linux_nat (struct ui_file *file, int from_tty,
@@ -278,6 +276,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"));
+         my_waitpid (second_pid, &status, 0);
        }
     }
   else
@@ -337,12 +336,14 @@ void
 child_post_attach (int pid)
 {
   linux_enable_event_reporting (pid_to_ptid (pid));
+  check_for_thread_db ();
 }
 
 static void
 linux_child_post_startup_inferior (ptid_t ptid)
 {
   linux_enable_event_reporting (ptid);
+  check_for_thread_db ();
 }
 
 int
@@ -600,56 +601,6 @@ child_insert_exec_catchpoint (int pid)
     error (_("Your system does not support exec catchpoints."));
 }
 
-void
-kill_inferior (void)
-{
-  int status;
-  int pid =  PIDGET (inferior_ptid);
-  struct target_waitstatus last;
-  ptid_t last_ptid;
-  int ret;
-
-  if (pid == 0)
-    return;
-
-  /* First cut -- let's crudely do everything inline.  */
-  if (forks_exist_p ())
-    {
-      linux_fork_killall ();
-      pop_target ();
-      generic_mourn_inferior ();
-    }
-  else
-    {
-      /* If we're stopped while forking and we haven't followed yet,
-        kill the other task.  We need to do this first because the
-        parent will be sleeping if this is a vfork.  */
-
-      get_last_target_status (&last_ptid, &last);
-
-      if (last.kind == TARGET_WAITKIND_FORKED
-         || last.kind == TARGET_WAITKIND_VFORKED)
-       {
-         ptrace (PT_KILL, last.value.related_pid, 0, 0);
-         wait (&status);
-       }
-
-      /* Kill the current process.  */
-      ptrace (PT_KILL, pid, 0, 0);
-      ret = wait (&status);
-
-      /* We might get a SIGCHLD instead of an exit status.  This is
-        aggravated by the first kill above - a child has just died.  */
-
-      while (ret == pid && WIFSTOPPED (status))
-       {
-         ptrace (PT_KILL, pid, 0, 0);
-         ret = wait (&status);
-       }
-      target_mourn_inferior ();
-    }
-}
-
 /* On GNU/Linux there are no real LWP's.  The closest thing to LWP's
    are processes sharing the same VM space.  A multi-threaded process
    is basically a group of such processes.  However, such a grouping
@@ -688,9 +639,6 @@ static struct lwp_info *lwp_list;
 
 /* Number of LWPs in the list.  */
 static int num_lwps;
-
-/* Non-zero if we're running in "threaded" mode.  */
-static int threaded;
 \f
 
 #define GET_LWP(ptid)          ptid_get_lwp (ptid)
@@ -703,9 +651,6 @@ static int threaded;
 ptid_t trap_ptid;
 \f
 
-/* This module's target-specific operations.  */
-static struct target_ops linux_nat_ops;
-
 /* Since we cannot wait (in linux_nat_wait) for the initial process and
    any cloned processes with a single call to waitpid, we have to use
    the WNOHANG flag and call waitpid in a loop.  To optimize
@@ -770,12 +715,10 @@ init_lwp_list (void)
 
   lwp_list = NULL;
   num_lwps = 0;
-  threaded = 0;
 }
 
-/* Add the LWP specified by PID to the list.  If this causes the
-   number of LWPs to become larger than one, go into "threaded" mode.
-   Return a pointer to the structure describing the new LWP.  */
+/* Add the LWP specified by PID to the list.  Return a pointer to the
+   structure describing the new LWP.  */
 
 static struct lwp_info *
 add_lwp (ptid_t ptid)
@@ -794,8 +737,7 @@ add_lwp (ptid_t ptid)
 
   lp->next = lwp_list;
   lwp_list = lp;
-  if (++num_lwps > 1)
-    threaded = 1;
+  ++num_lwps;
 
   return lp;
 }
@@ -816,8 +758,6 @@ delete_lwp (ptid_t ptid)
   if (!lp)
     return;
 
-  /* We don't go back to "non-threaded" mode if the number of threads
-     becomes less than two.  */
   num_lwps--;
 
   if (lpprev)
@@ -869,6 +809,21 @@ iterate_over_lwps (int (*callback) (struct lwp_info *, void *), void *data)
   return NULL;
 }
 
+/* Update our internal state when changing from one fork (checkpoint,
+   et cetera) to another indicated by NEW_PTID.  We can only switch
+   single-threaded applications, so we only create one new LWP, and
+   the previous list is discarded.  */
+
+void
+linux_nat_switch_fork (ptid_t new_ptid)
+{
+  struct lwp_info *lp;
+
+  init_lwp_list ();
+  lp = add_lwp (new_ptid);
+  lp->stopped = 1;
+}
+
 /* Record a PTID for later deletion.  */
 
 struct saved_ptids
@@ -946,10 +901,13 @@ exit_lwp (struct lwp_info *lp)
       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);
@@ -1012,7 +970,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
       gdb_assert (pid == GET_LWP (ptid)
                  && WIFSTOPPED (status) && WSTOPSIG (status));
 
-      child_post_attach (pid);
+      target_post_attach (pid);
 
       lp->stopped = 1;
 
@@ -1028,10 +986,10 @@ 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
-         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.  */
       lp->stopped = 1;
     }
 }
@@ -1048,7 +1006,8 @@ linux_nat_attach (char *args, int from_tty)
   linux_ops->to_attach (args, from_tty);
 
   /* Add the initial process as the first LWP to the list.  */
-  lp = add_lwp (BUILD_LWP (GET_PID (inferior_ptid), GET_PID (inferior_ptid)));
+  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
@@ -1324,10 +1283,11 @@ kill_lwp (int lwpid, int signo)
    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.  */
+   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
-linux_nat_handle_extended (struct lwp_info *lp, int status)
+linux_nat_handle_extended (struct lwp_info *lp, int status, int stopping)
 {
   linux_handle_extended_wait (GET_LWP (lp->ptid), status,
                              &lp->waitstatus);
@@ -1339,7 +1299,11 @@ linux_nat_handle_extended (struct lwp_info *lp, int status)
       new_lp = add_lwp (BUILD_LWP (lp->waitstatus.value.related_pid,
                                   GET_PID (inferior_ptid)));
       new_lp->cloned = 1;
-      new_lp->stopped = 1;
+
+      if (stopping)
+       new_lp->stopped = 1;
+      else
+       ptrace (PTRACE_CONT, lp->waitstatus.value.related_pid, 0, 0);
 
       lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
 
@@ -1423,7 +1387,7 @@ wait_lwp (struct lwp_info *lp)
        fprintf_unfiltered (gdb_stdlog,
                            "WL: Handling extended status 0x%06x\n",
                            status);
-      if (linux_nat_handle_extended (lp, status))
+      if (linux_nat_handle_extended (lp, status, 1))
        return wait_lwp (lp);
     }
 
@@ -1850,134 +1814,6 @@ resumed_callback (struct lwp_info *lp, void *data)
   return lp->resumed;
 }
 
-/* Local mourn_inferior -- we need to override mourn_inferior
-   so that we can do something clever if one of several forks
-   has exited.  */
-
-static void
-child_mourn_inferior (void)
-{
-  int status;
-
-  if (! forks_exist_p ())
-    {
-      /* Normal case, no other forks available.  */
-      super_mourn_inferior ();
-      return;
-    }
-  else
-    {
-      /* Multi-fork case.  The current inferior_ptid has exited, but
-        there are other viable forks to debug.  Delete the exiting
-        one and context-switch to the first available.  */
-      linux_fork_mourn_inferior ();
-    }
-}
-
-/* We need to override child_wait to support attaching to cloned
-   processes, since a normal wait (as done by the default version)
-   ignores those processes.  */
-
-/* Wait for child PTID to do something.  Return id of the child,
-   minus_one_ptid in case of error; store status into *OURSTATUS.  */
-
-ptid_t
-child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
-{
-  int save_errno;
-  int status;
-  pid_t pid;
-
-  ourstatus->kind = TARGET_WAITKIND_IGNORE;
-
-  do
-    {
-      set_sigint_trap ();      /* Causes SIGINT to be passed on to the
-                                  attached process.  */
-      set_sigio_trap ();
-
-      pid = my_waitpid (GET_PID (ptid), &status, 0);
-      if (pid == -1 && errno == ECHILD)
-       /* Try again with __WCLONE to check cloned processes.  */
-       pid = my_waitpid (GET_PID (ptid), &status, __WCLONE);
-
-      if (debug_linux_nat)
-       {
-         fprintf_unfiltered (gdb_stdlog,
-                             "CW:  waitpid %ld received %s\n",
-                             (long) pid, status_to_str (status));
-       }
-
-      save_errno = errno;
-
-      /* Make sure we don't report an event for the exit of the
-         original program, if we've detached from it.  */
-      if (pid != -1 && !WIFSTOPPED (status) && pid != GET_PID (inferior_ptid))
-       {
-         pid = -1;
-         save_errno = EINTR;
-       }
-
-      /* Check for stop events reported by a process we didn't already
-        know about - in this case, anything other than inferior_ptid.
-
-        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 we want to handle debugging of
-        CLONE_PTRACE processes we need to do more here, i.e. switch
-        to multi-threaded mode.  */
-      if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGSTOP
-         && pid != GET_PID (inferior_ptid))
-       {
-         linux_record_stopped_pid (pid);
-         pid = -1;
-         save_errno = EINTR;
-       }
-
-      /* Handle GNU/Linux's extended waitstatus for trace events.  */
-      if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
-         && status >> 16 != 0)
-       {
-         linux_handle_extended_wait (pid, status, ourstatus);
-
-         /* If we see a clone event, detach the child, and don't
-            report the event.  It would be nice to offer some way to
-            switch into a non-thread-db based threaded mode at this
-            point.  */
-         if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS)
-           {
-             ptrace (PTRACE_DETACH, ourstatus->value.related_pid, 0, 0);
-             ourstatus->kind = TARGET_WAITKIND_IGNORE;
-             ptrace (PTRACE_CONT, pid, 0, 0);
-             pid = -1;
-             save_errno = EINTR;
-           }
-       }
-
-      clear_sigio_trap ();
-      clear_sigint_trap ();
-    }
-  while (pid == -1 && save_errno == EINTR);
-
-  if (pid == -1)
-    {
-      warning (_("Child process unexpectedly missing: %s"),
-              safe_strerror (errno));
-
-      /* Claim it exited with unknown signal.  */
-      ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
-      ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
-      return minus_one_ptid;
-    }
-
-  if (ourstatus->kind == TARGET_WAITKIND_IGNORE)
-    store_waitstatus (ourstatus, status);
-
-  return pid_to_ptid (pid);
-}
-
 /* Stop an active thread, verify it still exists, then resume it.  */
 
 static int
@@ -2009,6 +1845,19 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   pid_t pid = PIDGET (ptid);
   sigset_t flush_mask;
 
+  /* The first time we get here after starting a new inferior, we may
+     not have added it to the LWP list yet - this is the earliest
+     moment at which we know its PID.  */
+  if (num_lwps == 0)
+    {
+      gdb_assert (!is_lwp (inferior_ptid));
+
+      inferior_ptid = BUILD_LWP (GET_PID (inferior_ptid),
+                                GET_PID (inferior_ptid));
+      lp = add_lwp (inferior_ptid);
+      lp->resumed = 1;
+    }
+
   sigemptyset (&flush_mask);
 
   /* Make sure SIGCHLD is blocked.  */
@@ -2020,9 +1869,8 @@ linux_nat_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 
 retry:
 
-  /* Make sure there is at least one LWP that has been resumed, at
-     least if there are any LWPs at all.  */
-  gdb_assert (num_lwps == 0 || iterate_over_lwps (resumed_callback, NULL));
+  /* Make sure there is at least one LWP that has been resumed.  */
+  gdb_assert (iterate_over_lwps (resumed_callback, NULL));
 
   /* First check if there is a LWP with a wait status pending.  */
   if (pid == -1)
@@ -2161,23 +2009,20 @@ retry:
              if (options & __WCLONE)
                lp->cloned = 1;
 
-             if (threaded)
-               {
-                 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);
-                   }
+             gdb_assert (WIFSTOPPED (status)
+                         && WSTOPSIG (status) == SIGSTOP);
+             lp->signalled = 1;
 
-                 add_thread (lp->ptid);
-                 printf_unfiltered (_("[New %s]\n"),
-                                    target_pid_to_str (lp->ptid));
+             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.  */
@@ -2187,7 +2032,7 @@ retry:
                fprintf_unfiltered (gdb_stdlog,
                                    "LLW: Handling extended status 0x%06x\n",
                                    status);
-             if (linux_nat_handle_extended (lp, status))
+             if (linux_nat_handle_extended (lp, status, 0))
                {
                  status = 0;
                  continue;
@@ -2319,7 +2164,10 @@ retry:
     {
       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)
        {
@@ -2379,12 +2227,9 @@ retry:
      the comment in cancel_breakpoints_callback to find out why.  */
   iterate_over_lwps (cancel_breakpoints_callback, lp);
 
-  /* If we're not running in "threaded" mode, we'll report the bare
-     process id.  */
-
   if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
     {
-      trap_ptid = (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+      trap_ptid = lp->ptid;
       if (debug_linux_nat)
        fprintf_unfiltered (gdb_stdlog,
                            "LLW: trap_ptid is %s.\n",
@@ -2401,7 +2246,7 @@ retry:
   else
     store_waitstatus (ourstatus, status);
 
-  return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
+  return lp->ptid;
 }
 
 static int
@@ -2466,20 +2311,35 @@ kill_wait_callback (struct lwp_info *lp, void *data)
 static void
 linux_nat_kill (void)
 {
-  /* Kill all LWP's ...  */
-  iterate_over_lwps (kill_callback, NULL);
+  struct target_waitstatus last;
+  ptid_t last_ptid;
+  int status;
 
-  /* ... and wait until we've flushed all events.  */
-  iterate_over_lwps (kill_wait_callback, NULL);
+  /* If we're stopped while forking and we haven't followed yet,
+     kill the other task.  We need to do this first because the
+     parent will be sleeping if this is a vfork.  */
 
-  target_mourn_inferior ();
-}
+  get_last_target_status (&last_ptid, &last);
 
-static void
-linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
-                        int from_tty)
-{
-  linux_ops->to_create_inferior (exec_file, allargs, env, from_tty);
+  if (last.kind == TARGET_WAITKIND_FORKED
+      || last.kind == TARGET_WAITKIND_VFORKED)
+    {
+      ptrace (PT_KILL, last.value.related_pid, 0, 0);
+      wait (&status);
+    }
+
+  if (forks_exist_p ())
+    linux_fork_killall ();
+  else
+    {
+      /* Kill all LWP's ...  */
+      iterate_over_lwps (kill_callback, NULL);
+
+      /* ... and wait until we've flushed all events.  */
+      iterate_over_lwps (kill_wait_callback, NULL);
+    }
+
+  target_mourn_inferior ();
 }
 
 static void
@@ -2494,7 +2354,14 @@ linux_nat_mourn_inferior (void)
   sigprocmask (SIG_SETMASK, &normal_mask, NULL);
   sigemptyset (&blocked_mask);
 
-  linux_ops->to_mourn_inferior ();
+  if (! forks_exist_p ())
+    /* Normal case, no other forks available.  */
+    linux_ops->to_mourn_inferior ();
+  else
+    /* Multi-fork case.  The current inferior_ptid has exited, but
+       there are other viable forks to debug.  Delete the exiting
+       one and context-switch to the first available.  */
+    linux_fork_mourn_inferior ();
 }
 
 static LONGEST
@@ -2528,7 +2395,13 @@ linux_nat_thread_alive (ptid_t ptid)
                        "LLTA: PTRACE_PEEKUSER %s, 0, 0 (%s)\n",
                        target_pid_to_str (ptid),
                        errno ? safe_strerror (errno) : "OK");
-  if (errno)
+
+  /* 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;
 
   return 1;
@@ -2539,7 +2412,7 @@ linux_nat_pid_to_str (ptid_t ptid)
 {
   static char buf[64];
 
-  if (is_lwp (ptid))
+  if (lwp_list && lwp_list->next && is_lwp (ptid))
     {
       snprintf (buf, sizeof (buf), "LWP %ld", GET_LWP (ptid));
       return buf;
@@ -2548,59 +2421,6 @@ linux_nat_pid_to_str (ptid_t ptid)
   return normal_pid_to_str (ptid);
 }
 
-static void
-linux_nat_fetch_registers (int regnum)
-{
-  /* to_fetch_registers will honor the LWP ID, so we can use it directly.  */
-  linux_ops->to_fetch_registers (regnum);
-}
-
-static void
-linux_nat_store_registers (int regnum)
-{
-  /* to_store_registers will honor the LWP ID, so we can use it directly.  */
-  linux_ops->to_store_registers (regnum);
-}
-
-static void
-linux_nat_child_post_startup_inferior (ptid_t ptid)
-{
-  linux_ops->to_post_startup_inferior (ptid);
-}
-
-static void
-init_linux_nat_ops (void)
-{
-#if 0
-  linux_nat_ops.to_open = linux_nat_open;
-#endif
-  linux_nat_ops.to_shortname = "lwp-layer";
-  linux_nat_ops.to_longname = "lwp-layer";
-  linux_nat_ops.to_doc = "Low level threads support (LWP layer)";
-  linux_nat_ops.to_attach = linux_nat_attach;
-  linux_nat_ops.to_detach = linux_nat_detach;
-  linux_nat_ops.to_resume = linux_nat_resume;
-  linux_nat_ops.to_wait = linux_nat_wait;
-  linux_nat_ops.to_fetch_registers = linux_nat_fetch_registers;
-  linux_nat_ops.to_store_registers = linux_nat_store_registers;
-  linux_nat_ops.to_xfer_partial = linux_nat_xfer_partial;
-  linux_nat_ops.to_kill = linux_nat_kill;
-  linux_nat_ops.to_create_inferior = linux_nat_create_inferior;
-  linux_nat_ops.to_mourn_inferior = linux_nat_mourn_inferior;
-  linux_nat_ops.to_thread_alive = linux_nat_thread_alive;
-  linux_nat_ops.to_pid_to_str = linux_nat_pid_to_str;
-  linux_nat_ops.to_post_startup_inferior
-    = linux_nat_child_post_startup_inferior;
-  linux_nat_ops.to_post_attach = child_post_attach;
-  linux_nat_ops.to_insert_fork_catchpoint = child_insert_fork_catchpoint;
-  linux_nat_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
-  linux_nat_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint;
-
-  linux_nat_ops.to_stratum = thread_stratum;
-  linux_nat_ops.to_has_thread_control = tc_schedlock;
-  linux_nat_ops.to_magic = OPS_MAGIC;
-}
-
 static void
 sigchld_handler (int signo)
 {
@@ -2728,21 +2548,50 @@ linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
   gdb_fpxregset_t fpxregs;
 #endif
   unsigned long lwp = ptid_get_lwp (ptid);
+  struct gdbarch *gdbarch = current_gdbarch;
+  const struct regset *regset;
+  int core_regset_p;
+
+  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,
+                           &gregs, sizeof (gregs));
+  else
+    fill_gregset (&gregs, -1);
 
-  fill_gregset (&gregs, -1);
   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, current_regcache, -1,
+                           &fpregs, sizeof (fpregs));
+  else
+    fill_fpregset (&fpregs, -1);
+
   note_data = (char *) elfcore_write_prfpreg (obfd,
                                              note_data,
                                              note_size,
                                              &fpregs, sizeof (fpregs));
+
 #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, current_regcache, -1,
+                           &fpxregs, sizeof (fpxregs));
+  else
+    fill_fpxregset (&fpxregs, -1);
+
   note_data = (char *) elfcore_write_prxfpreg (obfd,
                                               note_data,
                                               note_size,
@@ -2849,7 +2698,8 @@ linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
       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,
@@ -3312,8 +3162,6 @@ linux_target (void)
 #else
   t = inf_ptrace_trad_target (linux_register_u_offset);
 #endif
-  t->to_wait = child_wait;
-  t->to_kill = kill_inferior;
   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;
@@ -3327,18 +3175,48 @@ linux_target (void)
   super_xfer_partial = t->to_xfer_partial;
   t->to_xfer_partial = linux_xfer_partial;
 
-  super_mourn_inferior = t->to_mourn_inferior;
-  t->to_mourn_inferior = child_mourn_inferior;
-
-  linux_ops = t;
   return t;
 }
 
+void
+linux_nat_add_target (struct target_ops *t)
+{
+  /* 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
+     process stratum target.  */
+  linux_ops_saved = *t;
+  linux_ops = &linux_ops_saved;
+
+  /* Override some methods for multithreading.  */
+  t->to_attach = linux_nat_attach;
+  t->to_detach = linux_nat_detach;
+  t->to_resume = linux_nat_resume;
+  t->to_wait = linux_nat_wait;
+  t->to_xfer_partial = linux_nat_xfer_partial;
+  t->to_kill = linux_nat_kill;
+  t->to_mourn_inferior = linux_nat_mourn_inferior;
+  t->to_thread_alive = linux_nat_thread_alive;
+  t->to_pid_to_str = linux_nat_pid_to_str;
+  t->to_has_thread_control = tc_schedlock;
+
+  /* We don't change the stratum; this target will sit at
+     process_stratum and thread_db will set at thread_stratum.  This
+     is a little strange, since this is a multi-threaded-capable
+     target, but we want to be on the stack below thread_db, and we
+     also want to be used for single-threaded processes.  */
+
+  add_target (t);
+
+  /* TODO: Eliminate this and have libthread_db use
+     find_target_beneath.  */
+  thread_db_init (t);
+}
+
 void
 _initialize_linux_nat (void)
 {
   struct sigaction action;
-  extern void thread_db_init (struct target_ops *);
 
   add_info ("proc", linux_nat_info_proc_cmd, _("\
 Show /proc process information about any running process.\n\
@@ -3349,10 +3227,6 @@ Specify any of the following keywords for detailed info:\n\
   status   -- list a different bunch of random process info.\n\
   all      -- list all available /proc info."));
 
-  init_linux_nat_ops ();
-  add_target (&linux_nat_ops);
-  thread_db_init (&linux_nat_ops);
-
   /* Save the original signal mask.  */
   sigprocmask (SIG_SETMASK, NULL, &normal_mask);
 
This page took 0.041574 seconds and 4 git commands to generate.