* i386nbsd-nat.c (i386nbsd_supply_pcb): Cast to 'gdb_byte *' in
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 6207e4d3701e9c7dca2fee5911655a5af5ee5c9a..e996dc264ae631dc53facb246335247e0a05ef44 100644 (file)
@@ -1,5 +1,6 @@
 /* GNU/Linux native-dependent code common to multiple platforms.
-   Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+
+   Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
 #include "gdbthread.h"
 #include "gdbcmd.h"
 #include "regcache.h"
+#include <sys/param.h>         /* for MAXPATHLEN */
+#include <sys/procfs.h>                /* for elf_gregset etc. */
+#include "elf-bfd.h"           /* for elfcore_write_* */
+#include "gregset.h"           /* for gregset */
+#include "gdbcore.h"           /* for get_exec_file */
+#include <ctype.h>             /* for isdigit */
+#include "gdbthread.h"         /* for struct thread_info etc. */
+#include "gdb_stat.h"          /* for struct stat */
+#include <fcntl.h>             /* for O_RDONLY */
+
+#ifndef O_LARGEFILE
+#define O_LARGEFILE 0
+#endif
 
 /* If the system headers did not provide the constants, hard-code the normal
    values.  */
@@ -55,7 +69,7 @@
 #define PTRACE_EVENT_VFORK     2
 #define PTRACE_EVENT_CLONE     3
 #define PTRACE_EVENT_EXEC      4
-#define PTRACE_EVENT_VFORKDONE 5
+#define PTRACE_EVENT_VFORK_DONE        5
 #define PTRACE_EVENT_EXIT      6
 
 #endif /* PTRACE_EVENT_FORK */
 #endif
 
 static int debug_linux_nat;
-
-extern struct target_ops child_ops;
+static void
+show_debug_linux_nat (struct ui_file *file, int from_tty,
+                     struct cmd_list_element *c, const char *value)
+{
+  fprintf_filtered (file, _("Debugging of GNU/Linux lwp module is %s.\n"),
+                   value);
+}
 
 static int linux_parent_pid;
 
@@ -135,43 +154,82 @@ linux_tracefork_child (void)
   ptrace (PTRACE_TRACEME, 0, 0, 0);
   kill (getpid (), SIGSTOP);
   fork ();
-  exit (0);
+  _exit (0);
+}
+
+/* Wrapper function for waitpid which handles EINTR.  */
+
+static int
+my_waitpid (int pid, int *status, int flags)
+{
+  int ret;
+  do
+    {
+      ret = waitpid (pid, status, flags);
+    }
+  while (ret == -1 && errno == EINTR);
+
+  return ret;
 }
 
-/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.  We
+/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.
+
+   First, we try to enable fork tracing on ORIGINAL_PID.  If this fails,
+   we know that the feature is not available.  This may change the tracing
+   options for ORIGINAL_PID, but we'll be setting them shortly anyway.
+
+   However, if it succeeds, we don't know for sure that the feature is
+   available; old versions of PTRACE_SETOPTIONS ignored unknown options.  We
    create a child process, attach to it, use PTRACE_SETOPTIONS to enable
-   fork tracing, and let it fork.  If the process exits, we assume that
-   we can't use TRACEFORK; if we get the fork notification, and we can
-   extract the new child's PID, then we assume that we can.  */
+   fork tracing, and let it fork.  If the process exits, we assume that we
+   can't use TRACEFORK; if we get the fork notification, and we can extract
+   the new child's PID, then we assume that we can.  */
 
 static void
-linux_test_for_tracefork (void)
+linux_test_for_tracefork (int original_pid)
 {
   int child_pid, ret, status;
   long second_pid;
 
+  linux_supports_tracefork_flag = 0;
+  linux_supports_tracevforkdone_flag = 0;
+
+  ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACEFORK);
+  if (ret != 0)
+    return;
+
   child_pid = fork ();
   if (child_pid == -1)
-    perror_with_name ("linux_test_for_tracefork: fork");
+    perror_with_name (("fork"));
 
   if (child_pid == 0)
     linux_tracefork_child ();
 
-  ret = waitpid (child_pid, &status, 0);
+  ret = my_waitpid (child_pid, &status, 0);
   if (ret == -1)
-    perror_with_name ("linux_test_for_tracefork: waitpid");
+    perror_with_name (("waitpid"));
   else if (ret != child_pid)
-    error ("linux_test_for_tracefork: waitpid: unexpected result %d.", ret);
+    error (_("linux_test_for_tracefork: waitpid: unexpected result %d."), ret);
   if (! WIFSTOPPED (status))
-    error ("linux_test_for_tracefork: waitpid: unexpected status %d.", status);
-
-  linux_supports_tracefork_flag = 0;
+    error (_("linux_test_for_tracefork: waitpid: unexpected status %d."), status);
 
   ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
   if (ret != 0)
     {
-      ptrace (PTRACE_KILL, child_pid, 0, 0);
-      waitpid (child_pid, &status, 0);
+      ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+      if (ret != 0)
+       {
+         warning (_("linux_test_for_tracefork: failed to kill child"));
+         return;
+       }
+
+      ret = my_waitpid (child_pid, &status, 0);
+      if (ret != child_pid)
+       warning (_("linux_test_for_tracefork: failed to wait for killed child"));
+      else if (!WIFSIGNALED (status))
+       warning (_("linux_test_for_tracefork: unexpected wait status 0x%x from "
+                "killed child"), status);
+
       return;
     }
 
@@ -180,8 +238,12 @@ linux_test_for_tracefork (void)
                PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORKDONE);
   linux_supports_tracevforkdone_flag = (ret == 0);
 
-  ptrace (PTRACE_CONT, child_pid, 0, 0);
-  ret = waitpid (child_pid, &status, 0);
+  ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
+  if (ret != 0)
+    warning (_("linux_test_for_tracefork: failed to resume child"));
+
+  ret = my_waitpid (child_pid, &status, 0);
+
   if (ret == child_pid && WIFSTOPPED (status)
       && status >> 16 == PTRACE_EVENT_FORK)
     {
@@ -192,34 +254,38 @@ linux_test_for_tracefork (void)
          int second_status;
 
          linux_supports_tracefork_flag = 1;
-         waitpid (second_pid, &second_status, 0);
-         ptrace (PTRACE_DETACH, second_pid, 0, 0);
+         my_waitpid (second_pid, &second_status, 0);
+         ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
+         if (ret != 0)
+           warning (_("linux_test_for_tracefork: failed to kill second child"));
        }
     }
+  else
+    warning (_("linux_test_for_tracefork: unexpected result from waitpid "
+            "(%d, status 0x%x)"), ret, status);
 
-  if (WIFSTOPPED (status))
-    {
-      ptrace (PTRACE_DETACH, child_pid, 0, 0);
-      waitpid (child_pid, &status, 0);
-    }
+  ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+  if (ret != 0)
+    warning (_("linux_test_for_tracefork: failed to kill child"));
+  my_waitpid (child_pid, &status, 0);
 }
 
 /* Return non-zero iff we have tracefork functionality available.
    This function also sets linux_supports_tracefork_flag.  */
 
 static int
-linux_supports_tracefork (void)
+linux_supports_tracefork (int pid)
 {
   if (linux_supports_tracefork_flag == -1)
-    linux_test_for_tracefork ();
+    linux_test_for_tracefork (pid);
   return linux_supports_tracefork_flag;
 }
 
 static int
-linux_supports_tracevforkdone (void)
+linux_supports_tracevforkdone (int pid)
 {
   if (linux_supports_tracefork_flag == -1)
-    linux_test_for_tracefork ();
+    linux_test_for_tracefork (pid);
   return linux_supports_tracevforkdone_flag;
 }
 
@@ -227,15 +293,18 @@ linux_supports_tracevforkdone (void)
 void
 linux_enable_event_reporting (ptid_t ptid)
 {
-  int pid = ptid_get_pid (ptid);
+  int pid = ptid_get_lwp (ptid);
   int options;
 
-  if (! linux_supports_tracefork ())
+  if (pid == 0)
+    pid = ptid_get_pid (ptid);
+
+  if (! linux_supports_tracefork (pid))
     return;
 
   options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
     | PTRACE_O_TRACECLONE;
-  if (linux_supports_tracevforkdone ())
+  if (linux_supports_tracevforkdone (pid))
     options |= PTRACE_O_TRACEVFORKDONE;
 
   /* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
@@ -274,7 +343,9 @@ child_follow_fork (int follow_child)
 
   get_last_target_status (&last_ptid, &last_status);
   has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
-  parent_pid = ptid_get_pid (last_ptid);
+  parent_pid = ptid_get_lwp (last_ptid);
+  if (parent_pid == 0)
+    parent_pid = ptid_get_pid (last_ptid);
   child_pid = last_status.value.related_pid;
 
   if (! follow_child)
@@ -288,23 +359,28 @@ child_follow_fork (int follow_child)
         also, but they'll be reinserted below.  */
       detach_breakpoints (child_pid);
 
-      fprintf_filtered (gdb_stdout,
-                       "Detaching after fork from child process %d.\n",
-                       child_pid);
+      if (debug_linux_nat)
+       {
+         target_terminal_ours ();
+         fprintf_unfiltered (gdb_stdlog,
+                             "Detaching after fork from child process %d.\n",
+                             child_pid);
+       }
 
       ptrace (PTRACE_DETACH, child_pid, 0, 0);
 
       if (has_vforked)
        {
-         if (linux_supports_tracevforkdone ())
+         gdb_assert (linux_supports_tracefork_flag >= 0);
+         if (linux_supports_tracevforkdone (0))
            {
              int status;
 
              ptrace (PTRACE_CONT, parent_pid, 0, 0);
-             waitpid (parent_pid, &status, __WALL);
-             if ((status >> 16) != PTRACE_EVENT_VFORKDONE)
-               warning ("Unexpected waitpid result %06x when waiting for "
-                        "vfork-done", status);
+             my_waitpid (parent_pid, &status, __WALL);
+             if ((status >> 16) != PTRACE_EVENT_VFORK_DONE)
+               warning (_("Unexpected waitpid result %06x when waiting for "
+                        "vfork-done"), status);
            }
          else
            {
@@ -358,9 +434,13 @@ child_follow_fork (int follow_child)
       /* Before detaching from the parent, remove all breakpoints from it. */
       remove_breakpoints ();
 
-      fprintf_filtered (gdb_stdout,
-                       "Attaching after fork to child process %d.\n",
-                       child_pid);
+      if (debug_linux_nat)
+       {
+         target_terminal_ours ();
+         fprintf_unfiltered (gdb_stdlog,
+                             "Attaching after fork to child process %d.\n",
+                             child_pid);
+       }
 
       /* If we're vforking, we may want to hold on to the parent until
         the child exits or execs.  At exec time we can remove the old
@@ -386,7 +466,7 @@ child_follow_fork (int follow_child)
        target_detach (NULL, 0);
 
       inferior_ptid = pid_to_ptid (child_pid);
-      push_target (&child_ops);
+      push_target (&deprecated_child_ops);
 
       /* Reset breakpoints in the child as appropriate.  */
       follow_inferior_reset_breakpoints ();
@@ -414,18 +494,16 @@ linux_handle_extended_wait (int pid, int status,
        {
          /* The new child has a pending SIGSTOP.  We can't affect it until it
             hits the SIGSTOP, but we're already attached.  */
-         do {
-           ret = waitpid (new_pid, &status,
-                          (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
-         } while (ret == -1 && errno == EINTR);
+         ret = my_waitpid (new_pid, &status,
+                           (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
          if (ret == -1)
-           perror_with_name ("waiting for new child");
+           perror_with_name (_("waiting for new child"));
          else if (ret != new_pid)
            internal_error (__FILE__, __LINE__,
-                           "wait returned unexpected PID %d", ret);
+                           _("wait returned unexpected PID %d"), ret);
          else if (!WIFSTOPPED (status) || WSTOPSIG (status) != SIGSTOP)
            internal_error (__FILE__, __LINE__,
-                           "wait returned unexpected status 0x%x", status);
+                           _("wait returned unexpected status 0x%x"), status);
        }
 
       if (event == PTRACE_EVENT_FORK)
@@ -457,35 +535,29 @@ linux_handle_extended_wait (int pid, int status,
     }
 
   internal_error (__FILE__, __LINE__,
-                 "unknown ptrace event %d", event);
+                 _("unknown ptrace event %d"), event);
 }
 
 \f
-int
+void
 child_insert_fork_catchpoint (int pid)
 {
-  if (! linux_supports_tracefork ())
-    error ("Your system does not support fork catchpoints.");
-
-  return 0;
+  if (! linux_supports_tracefork (pid))
+    error (_("Your system does not support fork catchpoints."));
 }
 
-int
+void
 child_insert_vfork_catchpoint (int pid)
 {
-  if (!linux_supports_tracefork ())
-    error ("Your system does not support vfork catchpoints.");
-
-  return 0;
+  if (!linux_supports_tracefork (pid))
+    error (_("Your system does not support vfork catchpoints."));
 }
 
-int
+void
 child_insert_exec_catchpoint (int pid)
 {
-  if (!linux_supports_tracefork ())
-    error ("Your system does not support exec catchpoints.");
-
-  return 0;
+  if (!linux_supports_tracefork (pid))
+    error (_("Your system does not support exec catchpoints."));
 }
 
 void
@@ -510,12 +582,12 @@ kill_inferior (void)
       || last.kind == TARGET_WAITKIND_VFORKED)
     {
       ptrace (PT_KILL, last.value.related_pid, 0, 0);
-      ptrace_wait (null_ptid, &status);
+      wait (&status);
     }
 
   /* Kill the current process.  */
   ptrace (PT_KILL, pid, 0, 0);
-  ret = ptrace_wait (null_ptid, &status);
+  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.  */
@@ -523,7 +595,7 @@ kill_inferior (void)
   while (ret == pid && WIFSTOPPED (status))
     {
       ptrace (PT_KILL, pid, 0, 0);
-      ret = ptrace_wait (null_ptid, &status);
+      ret = wait (&status);
     }
 
   target_mourn_inferior ();
@@ -585,9 +657,6 @@ ptid_t trap_ptid;
 /* This module's target-specific operations.  */
 static struct target_ops linux_nat_ops;
 
-/* The standard child operations.  */
-extern struct target_ops child_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
@@ -771,7 +840,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
     }
 
   if (verbose)
-    printf_filtered ("[New %s]\n", target_pid_to_str (ptid));
+    printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
 
   found_lp = lp = find_lwp_pid (ptid);
   if (lp == NULL)
@@ -789,7 +858,7 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
       int status;
 
       if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
-       error ("Can't attach %s: %s", target_pid_to_str (ptid),
+       error (_("Can't attach %s: %s"), target_pid_to_str (ptid),
               safe_strerror (errno));
 
       if (debug_linux_nat)
@@ -797,11 +866,11 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
                            "LLAL: PTRACE_ATTACH %s, 0, 0 (OK)\n",
                            target_pid_to_str (ptid));
 
-      pid = waitpid (GET_LWP (ptid), &status, 0);
+      pid = my_waitpid (GET_LWP (ptid), &status, 0);
       if (pid == -1 && errno == ECHILD)
        {
          /* Try again with __WCLONE to check cloned processes.  */
-         pid = waitpid (GET_LWP (ptid), &status, __WCLONE);
+         pid = my_waitpid (GET_LWP (ptid), &status, __WCLONE);
          lp->cloned = 1;
        }
 
@@ -841,7 +910,7 @@ linux_nat_attach (char *args, int from_tty)
 
   /* FIXME: We should probably accept a list of process id's, and
      attach all of them.  */
-  child_ops.to_attach (args, from_tty);
+  deprecated_child_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)));
@@ -849,13 +918,13 @@ linux_nat_attach (char *args, int from_tty)
   /* 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.  */
-  pid = waitpid (GET_PID (inferior_ptid), &status, 0);
+  pid = my_waitpid (GET_PID (inferior_ptid), &status, 0);
   if (pid == -1 && errno == ECHILD)
     {
-      warning ("%s is a cloned process", target_pid_to_str (inferior_ptid));
+      warning (_("%s is a cloned process"), target_pid_to_str (inferior_ptid));
 
       /* Try again with __WCLONE to check cloned processes.  */
-      pid = waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
+      pid = my_waitpid (GET_PID (inferior_ptid), &status, __WCLONE);
       lp->cloned = 1;
     }
 
@@ -889,7 +958,7 @@ detach_callback (struct lwp_info *lp, void *data)
       errno = 0;
       if (ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0,
                  WSTOPSIG (lp->status)) < 0)
-       error ("Can't continue %s: %s", target_pid_to_str (lp->ptid),
+       error (_("Can't continue %s: %s"), target_pid_to_str (lp->ptid),
               safe_strerror (errno));
 
       if (debug_linux_nat)
@@ -918,7 +987,7 @@ detach_callback (struct lwp_info *lp, void *data)
       errno = 0;
       if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0,
                  WSTOPSIG (lp->status)) < 0)
-       error ("Can't detach %s: %s", target_pid_to_str (lp->ptid),
+       error (_("Can't detach %s: %s"), target_pid_to_str (lp->ptid),
               safe_strerror (errno));
 
       if (debug_linux_nat)
@@ -951,7 +1020,7 @@ linux_nat_detach (char *args, int from_tty)
   sigemptyset (&blocked_mask);
 
   inferior_ptid = pid_to_ptid (GET_PID (inferior_ptid));
-  child_ops.to_detach (args, from_tty);
+  deprecated_child_ops.to_detach (args, from_tty);
 }
 
 /* Resume LP.  */
@@ -1120,10 +1189,10 @@ wait_lwp (struct lwp_info *lp)
   gdb_assert (!lp->stopped);
   gdb_assert (lp->status == 0);
 
-  pid = waitpid (GET_LWP (lp->ptid), &status, 0);
+  pid = my_waitpid (GET_LWP (lp->ptid), &status, 0);
   if (pid == -1 && errno == ECHILD)
     {
-      pid = waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
+      pid = my_waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
       if (pid == -1 && errno == ECHILD)
        {
          /* The thread has previously exited.  We need to delete it
@@ -1167,7 +1236,7 @@ wait_lwp (struct lwp_info *lp)
          /* Core GDB cannot deal with us deleting the current thread.  */
          if (!ptid_equal (lp->ptid, inferior_ptid))
            delete_thread (lp->ptid);
-         printf_unfiltered ("[%s exited]\n",
+         printf_unfiltered (_("[%s exited]\n"),
                             target_pid_to_str (lp->ptid));
        }
 
@@ -1419,7 +1488,7 @@ flush_callback (struct lwp_info *lp, void *data)
   if (lp->status)
     {
       if (debug_linux_nat)
-       printf_unfiltered ("FC: LP has pending status %06x\n", lp->status);
+       printf_unfiltered (_("FC: LP has pending status %06x\n"), lp->status);
       if (WIFSTOPPED (lp->status) && sigismember (flush_mask, WSTOPSIG (lp->status)))
        lp->status = 0;
     }
@@ -1635,10 +1704,10 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
                                   attached process.  */
       set_sigio_trap ();
 
-      pid = waitpid (GET_PID (ptid), &status, 0);
+      pid = my_waitpid (GET_PID (ptid), &status, 0);
       if (pid == -1 && errno == ECHILD)
        /* Try again with __WCLONE to check cloned processes.  */
-       pid = waitpid (GET_PID (ptid), &status, __WCLONE);
+       pid = my_waitpid (GET_PID (ptid), &status, __WCLONE);
 
       if (debug_linux_nat)
        {
@@ -1702,7 +1771,7 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 
   if (pid == -1)
     {
-      warning ("Child process unexpectedly missing: %s",
+      warning (_("Child process unexpectedly missing: %s"),
               safe_strerror (errno));
 
       /* Claim it exited with unknown signal.  */
@@ -1849,7 +1918,7 @@ retry:
     {
       pid_t lwpid;
 
-      lwpid = waitpid (pid, &status, options);
+      lwpid = my_waitpid (pid, &status, options);
       if (lwpid > 0)
        {
          gdb_assert (pid == -1 || lwpid == pid);
@@ -1916,7 +1985,7 @@ retry:
                    }
 
                  add_thread (lp->ptid);
-                 printf_unfiltered ("[New %s]\n",
+                 printf_unfiltered (_("[New %s]\n"),
                                     target_pid_to_str (lp->ptid));
                }
            }
@@ -1944,7 +2013,7 @@ retry:
                     thread.  */
                  if (!ptid_equal (lp->ptid, inferior_ptid))
                    delete_thread (lp->ptid);
-                 printf_unfiltered ("[%s exited]\n",
+                 printf_unfiltered (_("[%s exited]\n"),
                                     target_pid_to_str (lp->ptid));
                }
 
@@ -1997,7 +2066,7 @@ retry:
                     thread.  */
                  if (!ptid_equal (lp->ptid, inferior_ptid))
                    delete_thread (lp->ptid);
-                 printf_unfiltered ("[%s exited]\n",
+                 printf_unfiltered (_("[%s exited]\n"),
                                     target_pid_to_str (lp->ptid));
                }
              if (debug_linux_nat)
@@ -2193,7 +2262,7 @@ kill_wait_callback (struct lwp_info *lp, void *data)
     {
       do
        {
-         pid = waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
+         pid = my_waitpid (GET_LWP (lp->ptid), NULL, __WCLONE);
          if (pid != (pid_t) -1 && debug_linux_nat)
            {
              fprintf_unfiltered (gdb_stdlog,
@@ -2208,7 +2277,7 @@ kill_wait_callback (struct lwp_info *lp, void *data)
 
   do
     {
-      pid = waitpid (GET_LWP (lp->ptid), NULL, 0);
+      pid = my_waitpid (GET_LWP (lp->ptid), NULL, 0);
       if (pid != (pid_t) -1 && debug_linux_nat)
        {
          fprintf_unfiltered (gdb_stdlog,
@@ -2238,7 +2307,7 @@ static void
 linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
                         int from_tty)
 {
-  child_ops.to_create_inferior (exec_file, allargs, env, from_tty);
+  deprecated_child_ops.to_create_inferior (exec_file, allargs, env, from_tty);
 }
 
 static void
@@ -2253,12 +2322,13 @@ linux_nat_mourn_inferior (void)
   sigprocmask (SIG_SETMASK, &normal_mask, NULL);
   sigemptyset (&blocked_mask);
 
-  child_ops.to_mourn_inferior ();
+  deprecated_child_ops.to_mourn_inferior ();
 }
 
 static int
-linux_nat_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
-                    struct mem_attrib *attrib, struct target_ops *target)
+linux_nat_xfer_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len,
+                      int write, struct mem_attrib *attrib,
+                      struct target_ops *target)
 {
   struct cleanup *old_chain = save_inferior_ptid ();
   int xfer;
@@ -2323,7 +2393,7 @@ init_linux_nat_ops (void)
      honor the LWP id, so we can use them directly.  */
   linux_nat_ops.to_fetch_registers = fetch_inferior_registers;
   linux_nat_ops.to_store_registers = store_inferior_registers;
-  linux_nat_ops.to_xfer_memory = linux_nat_xfer_memory;
+  linux_nat_ops.deprecated_xfer_memory = linux_nat_xfer_memory;
   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;
@@ -2348,13 +2418,670 @@ sigchld_handler (int signo)
      arrival of a SIGCHLD.  */
 }
 
+/* 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)
+{
+  char *name1, *name2;
+
+  name1 = xmalloc (MAXPATHLEN);
+  name2 = xmalloc (MAXPATHLEN);
+  make_cleanup (xfree, name1);
+  make_cleanup (xfree, name2);
+  memset (name2, 0, MAXPATHLEN);
+
+  sprintf (name1, "/proc/%d/exe", pid);
+  if (readlink (name1, name2, MAXPATHLEN) > 0)
+    return name2;
+  else
+    return name1;
+}
+
+/* Service function for corefiles and info proc.  */
+
+static int
+read_mapping (FILE *mapfile,
+             long long *addr,
+             long long *endaddr,
+             char *permissions,
+             long long *offset,
+             char *device, long long *inode, char *filename)
+{
+  int ret = fscanf (mapfile, "%llx-%llx %s %llx %s %llx",
+                   addr, endaddr, permissions, offset, device, inode);
+
+  filename[0] = '\0';
+  if (ret > 0 && ret != EOF)
+    {
+      /* Eat everything up to EOL for the filename.  This will prevent
+         weird filenames (such as one with embedded whitespace) from
+         confusing this code.  It also makes this code more robust in
+         respect to annotations the kernel may add after the filename.
+
+         Note the filename is used for informational purposes
+         only.  */
+      ret += fscanf (mapfile, "%[^\n]\n", filename);
+    }
+
+  return (ret != 0 && ret != EOF);
+}
+
+/* Fills the "to_find_memory_regions" target vector.  Lists the memory
+   regions in the inferior for a corefile.  */
+
+static int
+linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
+                                           unsigned long,
+                                           int, int, int, void *), void *obfd)
+{
+  long long pid = PIDGET (inferior_ptid);
+  char mapsfilename[MAXPATHLEN];
+  FILE *mapsfile;
+  long long addr, endaddr, size, offset, inode;
+  char permissions[8], device[8], filename[MAXPATHLEN];
+  int read, write, exec;
+  int ret;
+
+  /* Compose the filename for the /proc memory map, and open it.  */
+  sprintf (mapsfilename, "/proc/%lld/maps", pid);
+  if ((mapsfile = fopen (mapsfilename, "r")) == NULL)
+    error (_("Could not open %s."), mapsfilename);
+
+  if (info_verbose)
+    fprintf_filtered (gdb_stdout,
+                     "Reading memory regions from %s\n", mapsfilename);
+
+  /* Now iterate until end-of-file.  */
+  while (read_mapping (mapsfile, &addr, &endaddr, &permissions[0],
+                      &offset, &device[0], &inode, &filename[0]))
+    {
+      size = endaddr - addr;
+
+      /* Get the segment's permissions.  */
+      read = (strchr (permissions, 'r') != 0);
+      write = (strchr (permissions, 'w') != 0);
+      exec = (strchr (permissions, 'x') != 0);
+
+      if (info_verbose)
+       {
+         fprintf_filtered (gdb_stdout,
+                           "Save segment, %lld bytes at 0x%s (%c%c%c)",
+                           size, paddr_nz (addr),
+                           read ? 'r' : ' ',
+                           write ? 'w' : ' ', exec ? 'x' : ' ');
+         if (filename && filename[0])
+           fprintf_filtered (gdb_stdout, " for %s", filename);
+         fprintf_filtered (gdb_stdout, "\n");
+       }
+
+      /* Invoke the callback function to create the corefile
+        segment.  */
+      func (addr, size, read, write, exec, obfd);
+    }
+  fclose (mapsfile);
+  return 0;
+}
+
+/* Records the thread's register state for the corefile note
+   section.  */
+
+static char *
+linux_nat_do_thread_registers (bfd *obfd, ptid_t ptid,
+                              char *note_data, int *note_size)
+{
+  gdb_gregset_t gregs;
+  gdb_fpregset_t fpregs;
+#ifdef FILL_FPXREGSET
+  gdb_fpxregset_t fpxregs;
+#endif
+  unsigned long lwp = ptid_get_lwp (ptid);
+
+  fill_gregset (&gregs, -1);
+  note_data = (char *) elfcore_write_prstatus (obfd,
+                                              note_data,
+                                              note_size,
+                                              lwp,
+                                              stop_signal, &gregs);
+
+  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);
+  note_data = (char *) elfcore_write_prxfpreg (obfd,
+                                              note_data,
+                                              note_size,
+                                              &fpxregs, sizeof (fpxregs));
+#endif
+  return note_data;
+}
+
+struct linux_nat_corefile_thread_data
+{
+  bfd *obfd;
+  char *note_data;
+  int *note_size;
+  int num_notes;
+};
+
+/* Called by gdbthread.c once per thread.  Records the thread's
+   register state for the corefile note section.  */
+
+static int
+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++;
+  inferior_ptid = saved_ptid;
+  registers_changed ();
+  target_fetch_registers (-1); /* FIXME should not be necessary;
+                                  fill_gregset should do it automatically. */
+  return 0;
+}
+
+/* Records the register state for the corefile note section.  */
+
+static char *
+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 note_data;
+}
+
+/* Fills the "to_make_corefile_note" target vector.  Builds the note
+   section for a corefile, and returns it in a malloc buffer.  */
+
+static char *
+linux_nat_make_corefile_notes (bfd *obfd, int *note_size)
+{
+  struct linux_nat_corefile_thread_data thread_args;
+  struct cleanup *old_chain;
+  char fname[16] = { '\0' };
+  char psargs[80] = { '\0' };
+  char *note_data = NULL;
+  ptid_t current_ptid = inferior_ptid;
+  gdb_byte *auxv;
+  int auxv_len;
+
+  if (get_exec_file (0))
+    {
+      strncpy (fname, strrchr (get_exec_file (0), '/') + 1, sizeof (fname));
+      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));
+       }
+      note_data = (char *) elfcore_write_prpsinfo (obfd,
+                                                  note_data,
+                                                  note_size, fname, psargs);
+    }
+
+  /* Dump information for threads.  */
+  thread_args.obfd = obfd;
+  thread_args.note_data = note_data;
+  thread_args.note_size = note_size;
+  thread_args.num_notes = 0;
+  iterate_over_lwps (linux_nat_corefile_thread_callback, &thread_args);
+  if (thread_args.num_notes == 0)
+    {
+      /* iterate_over_threads didn't come up with any threads; just
+         use inferior_ptid.  */
+      note_data = linux_nat_do_registers (obfd, inferior_ptid,
+                                         note_data, note_size);
+    }
+  else
+    {
+      note_data = thread_args.note_data;
+    }
+
+  auxv_len = target_auxv_read (&current_target, &auxv);
+  if (auxv_len > 0)
+    {
+      note_data = elfcore_write_note (obfd, note_data, note_size,
+                                     "CORE", NT_AUXV, auxv, auxv_len);
+      xfree (auxv);
+    }
+
+  make_cleanup (xfree, note_data);
+  return note_data;
+}
+
+/* Implement the "info proc" command.  */
+
+static void
+linux_nat_info_proc_cmd (char *args, int from_tty)
+{
+  long long pid = PIDGET (inferior_ptid);
+  FILE *procfile;
+  char **argv = NULL;
+  char buffer[MAXPATHLEN];
+  char fname1[MAXPATHLEN], fname2[MAXPATHLEN];
+  int cmdline_f = 1;
+  int cwd_f = 1;
+  int exe_f = 1;
+  int mappings_f = 0;
+  int environ_f = 0;
+  int status_f = 0;
+  int stat_f = 0;
+  int all = 0;
+  struct stat dummy;
+
+  if (args)
+    {
+      /* Break up 'args' into an argv array.  */
+      if ((argv = buildargv (args)) == NULL)
+       nomem (0);
+      else
+       make_cleanup_freeargv (argv);
+    }
+  while (argv != NULL && *argv != NULL)
+    {
+      if (isdigit (argv[0][0]))
+       {
+         pid = strtoul (argv[0], NULL, 10);
+       }
+      else if (strncmp (argv[0], "mappings", strlen (argv[0])) == 0)
+       {
+         mappings_f = 1;
+       }
+      else if (strcmp (argv[0], "status") == 0)
+       {
+         status_f = 1;
+       }
+      else if (strcmp (argv[0], "stat") == 0)
+       {
+         stat_f = 1;
+       }
+      else if (strcmp (argv[0], "cmd") == 0)
+       {
+         cmdline_f = 1;
+       }
+      else if (strncmp (argv[0], "exe", strlen (argv[0])) == 0)
+       {
+         exe_f = 1;
+       }
+      else if (strcmp (argv[0], "cwd") == 0)
+       {
+         cwd_f = 1;
+       }
+      else if (strncmp (argv[0], "all", strlen (argv[0])) == 0)
+       {
+         all = 1;
+       }
+      else
+       {
+         /* [...] (future options here) */
+       }
+      argv++;
+    }
+  if (pid == 0)
+    error (_("No current process: you must name one."));
+
+  sprintf (fname1, "/proc/%lld", pid);
+  if (stat (fname1, &dummy) != 0)
+    error (_("No /proc directory: '%s'"), fname1);
+
+  printf_filtered (_("process %lld\n"), pid);
+  if (cmdline_f || all)
+    {
+      sprintf (fname1, "/proc/%lld/cmdline", pid);
+      if ((procfile = fopen (fname1, "r")) > 0)
+       {
+         fgets (buffer, sizeof (buffer), procfile);
+         printf_filtered ("cmdline = '%s'\n", buffer);
+         fclose (procfile);
+       }
+      else
+       warning (_("unable to open /proc file '%s'"), fname1);
+    }
+  if (cwd_f || all)
+    {
+      sprintf (fname1, "/proc/%lld/cwd", pid);
+      memset (fname2, 0, sizeof (fname2));
+      if (readlink (fname1, fname2, sizeof (fname2)) > 0)
+       printf_filtered ("cwd = '%s'\n", fname2);
+      else
+       warning (_("unable to read link '%s'"), fname1);
+    }
+  if (exe_f || all)
+    {
+      sprintf (fname1, "/proc/%lld/exe", pid);
+      memset (fname2, 0, sizeof (fname2));
+      if (readlink (fname1, fname2, sizeof (fname2)) > 0)
+       printf_filtered ("exe = '%s'\n", fname2);
+      else
+       warning (_("unable to read link '%s'"), fname1);
+    }
+  if (mappings_f || all)
+    {
+      sprintf (fname1, "/proc/%lld/maps", pid);
+      if ((procfile = fopen (fname1, "r")) > 0)
+       {
+         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)
+           {
+             printf_filtered ("\t%10s %10s %10s %10s %7s\n",
+                          "Start Addr",
+                          "  End Addr",
+                          "      Size", "    Offset", "objfile");
+            }
+         else
+            {
+             printf_filtered ("  %18s %18s %10s %10s %7s\n",
+                          "Start Addr",
+                          "  End Addr",
+                          "      Size", "    Offset", "objfile");
+           }
+
+         while (read_mapping (procfile, &addr, &endaddr, &permissions[0],
+                              &offset, &device[0], &inode, &filename[0]))
+           {
+             size = endaddr - addr;
+
+             /* FIXME: carlton/2003-08-27: Maybe the printf_filtered
+                calls here (and possibly above) should be abstracted
+                out into their own functions?  Andrew suggests using
+                a generic local_address_string instead to print out
+                the addresses; that makes sense to me, too.  */
+
+             if (TARGET_ADDR_BIT == 32)
+               {
+                 printf_filtered ("\t%#10lx %#10lx %#10x %#10x %7s\n",
+                              (unsigned long) addr,    /* FIXME: pr_addr */
+                              (unsigned long) endaddr,
+                              (int) size,
+                              (unsigned int) offset,
+                              filename[0] ? filename : "");
+               }
+             else
+               {
+                 printf_filtered ("  %#18lx %#18lx %#10x %#10x %7s\n",
+                              (unsigned long) addr,    /* FIXME: pr_addr */
+                              (unsigned long) endaddr,
+                              (int) size,
+                              (unsigned int) offset,
+                              filename[0] ? filename : "");
+               }
+           }
+
+         fclose (procfile);
+       }
+      else
+       warning (_("unable to open /proc file '%s'"), fname1);
+    }
+  if (status_f || all)
+    {
+      sprintf (fname1, "/proc/%lld/status", pid);
+      if ((procfile = fopen (fname1, "r")) > 0)
+       {
+         while (fgets (buffer, sizeof (buffer), procfile) != NULL)
+           puts_filtered (buffer);
+         fclose (procfile);
+       }
+      else
+       warning (_("unable to open /proc file '%s'"), fname1);
+    }
+  if (stat_f || all)
+    {
+      sprintf (fname1, "/proc/%lld/stat", pid);
+      if ((procfile = fopen (fname1, "r")) > 0)
+       {
+         int itmp;
+         char ctmp;
+
+         if (fscanf (procfile, "%d ", &itmp) > 0)
+           printf_filtered (_("Process: %d\n"), itmp);
+         if (fscanf (procfile, "%s ", &buffer[0]) > 0)
+           printf_filtered (_("Exec file: %s\n"), buffer);
+         if (fscanf (procfile, "%c ", &ctmp) > 0)
+           printf_filtered (_("State: %c\n"), ctmp);
+         if (fscanf (procfile, "%d ", &itmp) > 0)
+           printf_filtered (_("Parent process: %d\n"), itmp);
+         if (fscanf (procfile, "%d ", &itmp) > 0)
+           printf_filtered (_("Process group: %d\n"), itmp);
+         if (fscanf (procfile, "%d ", &itmp) > 0)
+           printf_filtered (_("Session id: %d\n"), itmp);
+         if (fscanf (procfile, "%d ", &itmp) > 0)
+           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 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);
+#endif
+         fclose (procfile);
+       }
+      else
+       warning (_("unable to open /proc file '%s'"), fname1);
+    }
+}
+
+int
+linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len, int write,
+                       struct mem_attrib *attrib, struct target_ops *target)
+{
+  int fd, ret;
+  char filename[64];
+
+  if (write)
+    return 0;
+
+  /* Don't bother for one word.  */
+  if (len < 3 * sizeof (long))
+    return 0;
+
+  /* We could keep this file open and cache it - possibly one per
+     thread.  That requires some juggling, but is even faster.  */
+  sprintf (filename, "/proc/%d/mem", PIDGET (inferior_ptid));
+  fd = open (filename, O_RDONLY | O_LARGEFILE);
+  if (fd == -1)
+    return 0;
+
+  /* If pread64 is available, use it.  It's faster if the kernel
+     supports it (only one syscall), and it's 64-bit safe even on
+     32-bit platforms (for instance, SPARC debugging a SPARC64
+     application).  */
+#ifdef HAVE_PREAD64
+  if (pread64 (fd, myaddr, len, addr) != len)
+#else
+  if (lseek (fd, addr, SEEK_SET) == -1 || read (fd, myaddr, len) != len)
+#endif
+    ret = 0;
+  else
+    ret = len;
+
+  close (fd);
+  return ret;
+}
+
+/* Parse LINE as a signal set and add its set bits to SIGS.  */
+
+static void
+add_line_to_sigset (const char *line, sigset_t *sigs)
+{
+  int len = strlen (line) - 1;
+  const char *p;
+  int signum;
+
+  if (line[len] != '\n')
+    error (_("Could not parse signal set: %s"), line);
+
+  p = line;
+  signum = len * 4;
+  while (len-- > 0)
+    {
+      int digit;
+
+      if (*p >= '0' && *p <= '9')
+       digit = *p - '0';
+      else if (*p >= 'a' && *p <= 'f')
+       digit = *p - 'a' + 10;
+      else
+       error (_("Could not parse signal set: %s"), line);
+
+      signum -= 4;
+
+      if (digit & 1)
+       sigaddset (sigs, signum + 1);
+      if (digit & 2)
+       sigaddset (sigs, signum + 2);
+      if (digit & 4)
+       sigaddset (sigs, signum + 3);
+      if (digit & 8)
+       sigaddset (sigs, signum + 4);
+
+      p++;
+    }
+}
+
+/* Find process PID's pending signals from /proc/pid/status and set
+   SIGS to match.  */
+
+void
+linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigset_t *ignored)
+{
+  FILE *procfile;
+  char buffer[MAXPATHLEN], fname[MAXPATHLEN];
+  int signum;
+
+  sigemptyset (pending);
+  sigemptyset (blocked);
+  sigemptyset (ignored);
+  sprintf (fname, "/proc/%d/status", pid);
+  procfile = fopen (fname, "r");
+  if (procfile == NULL)
+    error (_("Could not open %s"), fname);
+
+  while (fgets (buffer, MAXPATHLEN, procfile) != NULL)
+    {
+      /* Normal queued signals are on the SigPnd line in the status
+        file.  However, 2.6 kernels also have a "shared" pending
+        queue for delivering signals to a thread group, so check for
+        a ShdPnd line also.
+
+        Unfortunately some Red Hat kernels include the shared pending
+        queue but not the ShdPnd status field.  */
+
+      if (strncmp (buffer, "SigPnd:\t", 8) == 0)
+       add_line_to_sigset (buffer + 8, pending);
+      else if (strncmp (buffer, "ShdPnd:\t", 8) == 0)
+       add_line_to_sigset (buffer + 8, pending);
+      else if (strncmp (buffer, "SigBlk:\t", 8) == 0)
+       add_line_to_sigset (buffer + 8, blocked);
+      else if (strncmp (buffer, "SigIgn:\t", 8) == 0)
+       add_line_to_sigset (buffer + 8, ignored);
+    }
+
+  fclose (procfile);
+}
+
 void
 _initialize_linux_nat (void)
 {
   struct sigaction action;
-
   extern void thread_db_init (struct target_ops *);
 
+  deprecated_child_ops.to_find_memory_regions = linux_nat_find_memory_regions;
+  deprecated_child_ops.to_make_corefile_notes = linux_nat_make_corefile_notes;
+
+  add_info ("proc", linux_nat_info_proc_cmd, _("\
+Show /proc process information about any running process.\n\
+Specify any process id, or use the program being debugged by default.\n\
+Specify any of the following keywords for detailed info:\n\
+  mappings -- list of mapped memory regions.\n\
+  stat     -- list a bunch of random process info.\n\
+  status   -- list a different bunch of random process info.\n\
+  all      -- list all available /proc info."));
+
   init_linux_nat_ops ();
   add_target (&linux_nat_ops);
   thread_db_init (&linux_nat_ops);
@@ -2364,7 +3091,7 @@ _initialize_linux_nat (void)
 
   action.sa_handler = sigchld_handler;
   sigemptyset (&action.sa_mask);
-  action.sa_flags = 0;
+  action.sa_flags = SA_RESTART;
   sigaction (SIGCHLD, &action, NULL);
 
   /* Make sure we don't block SIGCHLD during a sigsuspend.  */
@@ -2373,11 +3100,13 @@ _initialize_linux_nat (void)
 
   sigemptyset (&blocked_mask);
 
-  deprecated_add_show_from_set
-    (add_set_cmd ("lin-lwp", no_class, var_zinteger,
-                 (char *) &debug_linux_nat,
-                 "Set debugging of GNU/Linux lwp module.\n\
-Enables printf debugging output.\n", &setdebuglist), &showdebuglist);
+  add_setshow_zinteger_cmd ("lin-lwp", no_class, &debug_linux_nat, _("\
+Set debugging of GNU/Linux lwp module."), _("\
+Show debugging of GNU/Linux lwp module."), _("\
+Enables printf debugging output."),
+                           NULL,
+                           show_debug_linux_nat,
+                           &setdebuglist, &showdebuglist);
 }
 \f
 
@@ -2435,7 +3164,7 @@ lin_thread_get_thread_signals (sigset_t *set)
 
   action.sa_handler = sigchld_handler;
   sigemptyset (&action.sa_mask);
-  action.sa_flags = 0;
+  action.sa_flags = SA_RESTART;
   sigaction (cancel, &action, NULL);
 
   /* We block the "cancel" signal throughout this code ...  */
This page took 0.03949 seconds and 4 git commands to generate.