2005-02-11 H.J. Lu <hongjiu.lu@intel.com>
[deliverable/binutils-gdb.git] / gdb / linux-nat.c
index 88e8cb30e303c55527dc3e23262f8cb1df69d2c7..70df9eab1595abf6c3b6b4216e23e5ae8fd45ffb 100644 (file)
@@ -69,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 */
@@ -147,43 +147,82 @@ linux_tracefork_child (void)
   ptrace (PTRACE_TRACEME, 0, 0, 0);
   kill (getpid (), SIGSTOP);
   fork ();
-  exit (0);
+  _exit (0);
 }
 
-/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.  We
+/* 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.
+
+   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;
     }
 
@@ -192,8 +231,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)
     {
@@ -204,34 +247,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;
 }
 
@@ -242,12 +289,12 @@ linux_enable_event_reporting (ptid_t ptid)
   int pid = ptid_get_pid (ptid);
   int options;
 
-  if (! linux_supports_tracefork ())
+  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
@@ -308,15 +355,16 @@ child_follow_fork (int follow_child)
 
       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);
+             if ((status >> 16) != PTRACE_EVENT_VFORK_DONE)
+               warning (_("Unexpected waitpid result %06x when waiting for "
+                        "vfork-done"), status);
            }
          else
            {
@@ -398,7 +446,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 ();
@@ -431,13 +479,13 @@ linux_handle_extended_wait (int pid, int status,
                           (event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
          } while (ret == -1 && errno == EINTR);
          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)
@@ -469,35 +517,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
@@ -522,12 +564,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.  */
@@ -535,7 +577,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 ();
@@ -798,7 +840,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)
@@ -850,7 +892,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)));
@@ -861,7 +903,7 @@ linux_nat_attach (char *args, int from_tty)
   pid = 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);
@@ -898,7 +940,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)
@@ -927,7 +969,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)
@@ -960,7 +1002,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.  */
@@ -1711,7 +1753,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.  */
@@ -2247,7 +2289,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
@@ -2262,7 +2304,7 @@ 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
@@ -2332,7 +2374,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;
@@ -2429,7 +2471,7 @@ linux_nat_find_memory_regions (int (*func) (CORE_ADDR,
   /* 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\n", mapsfilename);
+    error (_("Could not open %s."), mapsfilename);
 
   if (info_verbose)
     fprintf_filtered (gdb_stdout,
@@ -2681,11 +2723,11 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       argv++;
     }
   if (pid == 0)
-    error ("No current process: you must name one.");
+    error (_("No current process: you must name one."));
 
   sprintf (fname1, "/proc/%lld", pid);
   if (stat (fname1, &dummy) != 0)
-    error ("No /proc directory: '%s'", fname1);
+    error (_("No /proc directory: '%s'"), fname1);
 
   printf_filtered ("process %lld\n", pid);
   if (cmdline_f || all)
@@ -2698,7 +2740,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
          fclose (procfile);
        }
       else
-       warning ("unable to open /proc file '%s'", fname1);
+       warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (cwd_f || all)
     {
@@ -2707,7 +2749,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       if (readlink (fname1, fname2, sizeof (fname2)) > 0)
        printf_filtered ("cwd = '%s'\n", fname2);
       else
-       warning ("unable to read link '%s'", fname1);
+       warning (_("unable to read link '%s'"), fname1);
     }
   if (exe_f || all)
     {
@@ -2716,7 +2758,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
       if (readlink (fname1, fname2, sizeof (fname2)) > 0)
        printf_filtered ("exe = '%s'\n", fname2);
       else
-       warning ("unable to read link '%s'", fname1);
+       warning (_("unable to read link '%s'"), fname1);
     }
   if (mappings_f || all)
     {
@@ -2776,7 +2818,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
          fclose (procfile);
        }
       else
-       warning ("unable to open /proc file '%s'", fname1);
+       warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (status_f || all)
     {
@@ -2788,7 +2830,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
          fclose (procfile);
        }
       else
-       warning ("unable to open /proc file '%s'", fname1);
+       warning (_("unable to open /proc file '%s'"), fname1);
     }
   if (stat_f || all)
     {
@@ -2883,7 +2925,7 @@ linux_nat_info_proc_cmd (char *args, int from_tty)
          fclose (procfile);
        }
       else
-       warning ("unable to open /proc file '%s'", fname1);
+       warning (_("unable to open /proc file '%s'"), fname1);
     }
 }
 
@@ -2935,7 +2977,7 @@ add_line_to_sigset (const char *line, sigset_t *sigs)
   int signum;
 
   if (line[len] != '\n')
-    error ("Could not parse signal set: %s", line);
+    error (_("Could not parse signal set: %s"), line);
 
   p = line;
   signum = len * 4;
@@ -2948,7 +2990,7 @@ add_line_to_sigset (const char *line, sigset_t *sigs)
       else if (*p >= 'a' && *p <= 'f')
        digit = *p - 'a' + 10;
       else
-       error ("Could not parse signal set: %s", line);
+       error (_("Could not parse signal set: %s"), line);
 
       signum -= 4;
 
@@ -2981,7 +3023,7 @@ linux_proc_pending_signals (int pid, sigset_t *pending, sigset_t *blocked, sigse
   sprintf (fname, "/proc/%d/status", pid);
   procfile = fopen (fname, "r");
   if (procfile == NULL)
-    error ("Could not open %s", fname);
+    error (_("Could not open %s"), fname);
 
   while (fgets (buffer, MAXPATHLEN, procfile) != NULL)
     {
@@ -3012,8 +3054,8 @@ _initialize_linux_nat (void)
   struct sigaction action;
   extern void thread_db_init (struct target_ops *);
 
-  child_ops.to_find_memory_regions = linux_nat_find_memory_regions;
-  child_ops.to_make_corefile_notes = linux_nat_make_corefile_notes;
+  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\
This page took 0.031858 seconds and 4 git commands to generate.