* infrun.c (handle_inferior_event): On a TARGET_WAITKIND_EXITED or
[deliverable/binutils-gdb.git] / gdb / inf-ptrace.c
index 9b485f02b5219435a3c598edefdacf0b48cd878c..7bdf2fac36cecdeb8d8b490924e427d449705fbc 100644 (file)
@@ -1,14 +1,14 @@
 /* Low-level child interface to ptrace.
 
    Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
-   1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007
+   1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -17,9 +17,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "command.h"
@@ -28,7 +26,6 @@
 #include "gdbcore.h"
 #include "regcache.h"
 
-#include "gdb_stdint.h"
 #include "gdb_assert.h"
 #include "gdb_string.h"
 #include "gdb_ptrace.h"
@@ -36,9 +33,8 @@
 #include <signal.h>
 
 #include "inf-child.h"
+#include "gdbthread.h"
 
-/* HACK: Save the ptrace ops returned by inf_ptrace_target.  */
-static struct target_ops *ptrace_ops_hack;
 \f
 
 #ifdef PT_GET_PROCESS_STATE
@@ -48,6 +44,7 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
 {
   pid_t pid, fpid;
   ptrace_state_t pe;
+  struct thread_info *last_tp = NULL;
 
   /* FIXME: kettenis/20050720: This stuff should really be passed as
      an argument by our caller.  */
@@ -59,6 +56,7 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
     gdb_assert (status.kind == TARGET_WAITKIND_FORKED);
 
     pid = ptid_get_pid (ptid);
+    last_tp = find_thread_pid (ptid);
   }
 
   if (ptrace (PT_GET_PROCESS_STATE, pid,
@@ -70,14 +68,42 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
 
   if (follow_child)
     {
-      inferior_ptid = pid_to_ptid (fpid);
-      detach_breakpoints (pid);
+      /* Copy user stepping state to the new inferior thread.  */
+      struct breakpoint *step_resume_breakpoint = last_tp->step_resume_breakpoint;
+      CORE_ADDR step_range_start = last_tp->step_range_start;
+      CORE_ADDR step_range_end = last_tp->step_range_end;
+      struct frame_id step_frame_id = last_tp->step_frame_id;
 
-      /* Reset breakpoints in the child as appropriate.  */
-      follow_inferior_reset_breakpoints ();
+      struct thread_info *tp;
+
+      /* Otherwise, deleting the parent would get rid of this
+        breakpoint.  */
+      last_tp->step_resume_breakpoint = NULL;
+
+      /* Before detaching from the parent, remove all breakpoints from
+        it.  */
+      detach_breakpoints (pid);
 
       if (ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
        perror_with_name (("ptrace"));
+
+      /* Switch inferior_ptid out of the parent's way.  */
+      inferior_ptid = pid_to_ptid (fpid);
+
+      /* Delete the parent.  */
+      detach_inferior (pid);
+
+      /* Add the child.  */
+      add_inferior (fpid);
+      tp = add_thread_silent (inferior_ptid);
+
+      tp->step_resume_breakpoint = step_resume_breakpoint;
+      tp->step_range_start = step_range_start;
+      tp->step_range_end = step_range_end;
+      tp->step_frame_id = step_frame_id;
+
+      /* Reset breakpoints in the child as appropriate.  */
+      follow_inferior_reset_breakpoints ();
     }
   else
     {
@@ -86,6 +112,7 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
 
       if (ptrace (PT_DETACH, fpid, (PTRACE_TYPE_ARG3)1, 0) == -1)
        perror_with_name (("ptrace"));
+      detach_inferior (pid);
     }
 
   return 0;
@@ -103,12 +130,22 @@ inf_ptrace_me (void)
   ptrace (PT_TRACE_ME, 0, (PTRACE_TYPE_ARG3)0, 0);
 }
 
-/* Start tracing PID.  */
+/* Start a new inferior Unix child process.  EXEC_FILE is the file to
+   run, ALLARGS is a string containing the arguments to the program.
+   ENV is the environment vector to pass.  If FROM_TTY is non-zero, be
+   chatty about it.  */
 
 static void
-inf_ptrace_him (int pid)
+inf_ptrace_create_inferior (struct target_ops *ops,
+                           char *exec_file, char *allargs, char **env,
+                           int from_tty)
 {
-  push_target (ptrace_ops_hack);
+  int pid;
+
+  pid = fork_inferior (exec_file, allargs, env, inf_ptrace_me, NULL,
+                      NULL, NULL);
+
+  push_target (ops);
 
   /* On some targets, there must be some explicit synchronization
      between the parent and child processes after the debugger
@@ -127,19 +164,6 @@ inf_ptrace_him (int pid)
   target_post_startup_inferior (pid_to_ptid (pid));
 }
 
-/* Start a new inferior Unix child process.  EXEC_FILE is the file to
-   run, ALLARGS is a string containing the arguments to the program.
-   ENV is the environment vector to pass.  If FROM_TTY is non-zero, be
-   chatty about it.  */
-
-static void
-inf_ptrace_create_inferior (char *exec_file, char *allargs, char **env,
-                           int from_tty)
-{
-  fork_inferior (exec_file, allargs, env, inf_ptrace_me, inf_ptrace_him,
-                NULL, NULL);
-}
-
 #ifdef PT_GET_PROCESS_STATE
 
 static void
@@ -160,7 +184,7 @@ inf_ptrace_post_startup_inferior (ptid_t pid)
 /* Clean up a rotting corpse of an inferior after it died.  */
 
 static void
-inf_ptrace_mourn_inferior (void)
+inf_ptrace_mourn_inferior (struct target_ops *ops)
 {
   int status;
 
@@ -170,7 +194,7 @@ inf_ptrace_mourn_inferior (void)
      only report its exit status to its original parent.  */
   waitpid (ptid_get_pid (inferior_ptid), &status, 0);
 
-  unpush_target (ptrace_ops_hack);
+  unpush_target (ops);
   generic_mourn_inferior ();
 }
 
@@ -178,11 +202,12 @@ inf_ptrace_mourn_inferior (void)
    be chatty about it.  */
 
 static void
-inf_ptrace_attach (char *args, int from_tty)
+inf_ptrace_attach (struct target_ops *ops, char *args, int from_tty)
 {
   char *exec_file;
   pid_t pid;
   char *dummy;
+  struct inferior *inf;
 
   if (!args)
     error_no_arg (_("process-id to attach"));
@@ -215,13 +240,20 @@ inf_ptrace_attach (char *args, int from_tty)
   ptrace (PT_ATTACH, pid, (PTRACE_TYPE_ARG3)0, 0);
   if (errno != 0)
     perror_with_name (("ptrace"));
-  attach_flag = 1;
 #else
   error (_("This system does not support attaching to a process"));
 #endif
 
   inferior_ptid = pid_to_ptid (pid);
-  push_target (ptrace_ops_hack);
+
+  inf = add_inferior (pid);
+  inf->attach_flag = 1;
+
+  /* Always add a main thread.  If some target extends the ptrace
+     target, it should decorate the ptid later with more info.  */
+  add_thread_silent (inferior_ptid);
+
+  push_target(ops);
 }
 
 #ifdef PT_GET_PROCESS_STATE
@@ -245,7 +277,7 @@ inf_ptrace_post_attach (int pid)
    specified by ARGS.  If FROM_TTY is non-zero, be chatty about it.  */
 
 static void
-inf_ptrace_detach (char *args, int from_tty)
+inf_ptrace_detach (struct target_ops *ops, char *args, int from_tty)
 {
   pid_t pid = ptid_get_pid (inferior_ptid);
   int sig = 0;
@@ -271,13 +303,13 @@ inf_ptrace_detach (char *args, int from_tty)
   ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, sig);
   if (errno != 0)
     perror_with_name (("ptrace"));
-  attach_flag = 0;
 #else
   error (_("This system does not support detaching from a process"));
 #endif
 
   inferior_ptid = null_ptid;
-  unpush_target (ptrace_ops_hack);
+  detach_inferior (pid);
+  unpush_target (ops);
 }
 
 /* Kill the inferior.  */
@@ -300,7 +332,7 @@ inf_ptrace_kill (void)
 /* Stop the inferior.  */
 
 static void
-inf_ptrace_stop (void)
+inf_ptrace_stop (ptid_t ptid)
 {
   /* Send a SIGINT to the process group.  This acts just like the user
      typed a ^C on the controlling terminal.  Note that using a
@@ -378,7 +410,7 @@ inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
          /* Claim it exited with unknown signal.  */
          ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
          ourstatus->value.sig = TARGET_SIGNAL_UNKNOWN;
-         return minus_one_ptid;
+         return inferior_ptid;
        }
 
       /* Ignore terminated detached child processes.  */
@@ -401,7 +433,7 @@ inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
        {
        case PTRACE_FORK:
          ourstatus->kind = TARGET_WAITKIND_FORKED;
-         ourstatus->value.related_pid = pe.pe_other_pid;
+         ourstatus->value.related_pid = pid_to_ptid (pe.pe_other_pid);
 
          /* Make sure the other end of the fork is stopped too.  */
          fpid = waitpid (pe.pe_other_pid, &status, 0);
@@ -416,7 +448,7 @@ inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
          gdb_assert (pe.pe_other_pid == pid);
          if (fpid == ptid_get_pid (inferior_ptid))
            {
-             ourstatus->value.related_pid = pe.pe_other_pid;
+             ourstatus->value.related_pid = pid_to_ptid (pe.pe_other_pid);
              return pid_to_ptid (fpid);
            }
 
@@ -574,8 +606,10 @@ inf_ptrace_thread_alive (ptid_t ptid)
 static void
 inf_ptrace_files_info (struct target_ops *ignore)
 {
+  struct inferior *inf = current_inferior ();
+
   printf_filtered (_("\tUsing the running image of %s %s.\n"),
-                  attach_flag ? "attached" : "child",
+                  inf->attach_flag ? "attached" : "child",
                   target_pid_to_str (inferior_ptid));
 }
 
@@ -605,7 +639,6 @@ inf_ptrace_target (void)
   t->to_stop = inf_ptrace_stop;
   t->to_xfer_partial = inf_ptrace_xfer_partial;
 
-  ptrace_ops_hack = t;
   return t;
 }
 \f
@@ -619,15 +652,16 @@ static CORE_ADDR (*inf_ptrace_register_u_offset)(struct gdbarch *, int, int);
 static void
 inf_ptrace_fetch_register (struct regcache *regcache, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   CORE_ADDR addr;
   size_t size;
   PTRACE_TYPE_RET *buf;
   int pid, i;
 
   /* This isn't really an address, but ptrace thinks of it as one.  */
-  addr = inf_ptrace_register_u_offset (current_gdbarch, regnum, 0);
+  addr = inf_ptrace_register_u_offset (gdbarch, regnum, 0);
   if (addr == (CORE_ADDR)-1
-      || gdbarch_cannot_fetch_register (current_gdbarch, regnum))
+      || gdbarch_cannot_fetch_register (gdbarch, regnum))
     {
       regcache_raw_supply (regcache, regnum, NULL);
       return;
@@ -639,7 +673,7 @@ inf_ptrace_fetch_register (struct regcache *regcache, int regnum)
   if (pid == 0)
     pid = ptid_get_pid (inferior_ptid);
 
-  size = register_size (current_gdbarch, regnum);
+  size = register_size (gdbarch, regnum);
   gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
   buf = alloca (size);
 
@@ -650,7 +684,8 @@ inf_ptrace_fetch_register (struct regcache *regcache, int regnum)
       buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)(uintptr_t)addr, 0);
       if (errno != 0)
        error (_("Couldn't read register %s (#%d): %s."),
-              REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+              gdbarch_register_name (gdbarch, regnum),
+              regnum, safe_strerror (errno));
 
       addr += sizeof (PTRACE_TYPE_RET);
     }
@@ -664,7 +699,9 @@ static void
 inf_ptrace_fetch_registers (struct regcache *regcache, int regnum)
 {
   if (regnum == -1)
-    for (regnum = 0; regnum < gdbarch_num_regs (current_gdbarch); regnum++)
+    for (regnum = 0;
+        regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+        regnum++)
       inf_ptrace_fetch_register (regcache, regnum);
   else
     inf_ptrace_fetch_register (regcache, regnum);
@@ -675,15 +712,16 @@ inf_ptrace_fetch_registers (struct regcache *regcache, int regnum)
 static void
 inf_ptrace_store_register (const struct regcache *regcache, int regnum)
 {
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
   CORE_ADDR addr;
   size_t size;
   PTRACE_TYPE_RET *buf;
   int pid, i;
 
   /* This isn't really an address, but ptrace thinks of it as one.  */
-  addr = inf_ptrace_register_u_offset (current_gdbarch, regnum, 1);
+  addr = inf_ptrace_register_u_offset (gdbarch, regnum, 1);
   if (addr == (CORE_ADDR)-1 
-      || gdbarch_cannot_store_register (current_gdbarch, regnum))
+      || gdbarch_cannot_store_register (gdbarch, regnum))
     return;
 
   /* Cater for systems like GNU/Linux, that implement threads as
@@ -692,7 +730,7 @@ inf_ptrace_store_register (const struct regcache *regcache, int regnum)
   if (pid == 0)
     pid = ptid_get_pid (inferior_ptid);
 
-  size = register_size (current_gdbarch, regnum);
+  size = register_size (gdbarch, regnum);
   gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
   buf = alloca (size);
 
@@ -704,7 +742,8 @@ inf_ptrace_store_register (const struct regcache *regcache, int regnum)
       ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)(uintptr_t)addr, buf[i]);
       if (errno != 0)
        error (_("Couldn't write register %s (#%d): %s."),
-              REGISTER_NAME (regnum), regnum, safe_strerror (errno));
+              gdbarch_register_name (gdbarch, regnum),
+              regnum, safe_strerror (errno));
 
       addr += sizeof (PTRACE_TYPE_RET);
     }
@@ -717,7 +756,9 @@ void
 inf_ptrace_store_registers (struct regcache *regcache, int regnum)
 {
   if (regnum == -1)
-    for (regnum = 0; regnum < gdbarch_num_regs (current_gdbarch); regnum++)
+    for (regnum = 0;
+        regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+        regnum++)
       inf_ptrace_store_register (regcache, regnum);
   else
     inf_ptrace_store_register (regcache, regnum);
This page took 0.028062 seconds and 4 git commands to generate.