* corelow.c (core_close): Don't hardcode the core's pid.
[deliverable/binutils-gdb.git] / gdb / inf-ptrace.c
index ec5d9a865b333b2ef4c5b4ed2aacf30781b1ce93..06792007cdfc941b191ccc0c53e650759345be05 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
+   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998,
+   1999, 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009
    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,
    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"
 #include "inferior.h"
 #include "inflow.h"
 #include "gdbcore.h"
-#include "observer.h"
 #include "regcache.h"
 
 #include "gdb_assert.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,44 @@ inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
 
   if (follow_child)
     {
+      /* 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;
+      int attach_flag = find_inferior_pid (pid)->attach_flag;
+      struct inferior *inf;
+      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.  */
+      remove_breakpoints ();
+
+      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);
-      detach_breakpoints (pid);
+
+      /* Delete the parent.  */
+      detach_inferior (pid);
+
+      /* Add the child.  */
+      inf = add_inferior (fpid);
+      inf->attach_flag = attach_flag;
+      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 ();
-
-      if (ptrace (PT_DETACH, pid, (PTRACE_TYPE_ARG3)1, 0) == -1)
-       perror_with_name (("ptrace"));
     }
   else
     {
@@ -86,6 +114,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 +132,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 +166,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 +186,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 +196,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 +204,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,17 +242,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);
 
-  /* Do this first, before anything has had a chance to query the
-     inferior's symbol table or similar.  */
-  observer_notify_inferior_created (&current_target, from_tty);
+  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
@@ -249,7 +279,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;
@@ -275,13 +305,15 @@ 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);
+
+  if (!have_inferiors ())
+    unpush_target (ops);
 }
 
 /* Kill the inferior.  */
@@ -304,7 +336,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
@@ -353,7 +385,8 @@ inf_ptrace_resume (ptid_t ptid, int step, enum target_signal signal)
    the status in *OURSTATUS.  */
 
 static ptid_t
-inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
+inf_ptrace_wait (struct target_ops *ops,
+                ptid_t ptid, struct target_waitstatus *ourstatus)
 {
   pid_t pid;
   int status, save_errno;
@@ -361,7 +394,6 @@ inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   do
     {
       set_sigint_trap ();
-      set_sigio_trap ();
 
       do
        {
@@ -370,7 +402,6 @@ inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
        }
       while (pid == -1 && errno == EINTR);
 
-      clear_sigio_trap ();
       clear_sigint_trap ();
 
       if (pid == -1)
@@ -382,7 +413,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.  */
@@ -405,7 +436,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);
@@ -420,7 +451,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);
            }
 
@@ -509,7 +540,8 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
                    < rounded_offset + sizeof (PTRACE_TYPE_RET)))
              /* Need part of initial word -- fetch it.  */
              buffer.word = ptrace (PT_READ_I, pid,
-                                   (PTRACE_TYPE_ARG3)(long)rounded_offset, 0);
+                                   (PTRACE_TYPE_ARG3)(uintptr_t)
+                                   rounded_offset, 0);
 
            /* Copy data to be written over corresponding part of
               buffer.  */
@@ -518,14 +550,16 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
 
            errno = 0;
            ptrace (PT_WRITE_D, pid,
-                   (PTRACE_TYPE_ARG3)(long)rounded_offset, buffer.word);
+                   (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+                   buffer.word);
            if (errno)
              {
                /* Using the appropriate one (I or D) is necessary for
                   Gould NP1, at least.  */
                errno = 0;
                ptrace (PT_WRITE_I, pid,
-                       (PTRACE_TYPE_ARG3)(long)rounded_offset, buffer.word);
+                       (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+                       buffer.word);
                if (errno)
                  return 0;
              }
@@ -535,7 +569,8 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
          {
            errno = 0;
            buffer.word = ptrace (PT_READ_I, pid,
-                                 (PTRACE_TYPE_ARG3)(long)rounded_offset, 0);
+                                 (PTRACE_TYPE_ARG3)(uintptr_t)rounded_offset,
+                                 0);
            if (errno)
              return 0;
            /* Copy appropriate bytes out of the buffer.  */
@@ -574,11 +609,19 @@ 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));
 }
 
+static char *
+inf_ptrace_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+  return normal_pid_to_str (ptid);
+}
+
 /* Create a prototype ptrace target.  The client can override it with
    local methods.  */
 
@@ -601,32 +644,35 @@ inf_ptrace_target (void)
 #endif
   t->to_mourn_inferior = inf_ptrace_mourn_inferior;
   t->to_thread_alive = inf_ptrace_thread_alive;
-  t->to_pid_to_str = normal_pid_to_str;
+  t->to_pid_to_str = inf_ptrace_pid_to_str;
   t->to_stop = inf_ptrace_stop;
   t->to_xfer_partial = inf_ptrace_xfer_partial;
 
-  ptrace_ops_hack = t;
   return t;
 }
 \f
 
 /* Pointer to a function that returns the offset within the user area
    where a particular register is stored.  */
-static CORE_ADDR (*inf_ptrace_register_u_offset)(int);
+static CORE_ADDR (*inf_ptrace_register_u_offset)(struct gdbarch *, int, int);
 
 /* Fetch register REGNUM from the inferior.  */
 
 static void
-inf_ptrace_fetch_register (int regnum)
+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;
 
-  if (CANNOT_FETCH_REGISTER (regnum))
+  /* This isn't really an address, but ptrace thinks of it as one.  */
+  addr = inf_ptrace_register_u_offset (gdbarch, regnum, 0);
+  if (addr == (CORE_ADDR)-1
+      || gdbarch_cannot_fetch_register (gdbarch, regnum))
     {
-      regcache_raw_supply (current_regcache, regnum, NULL);
+      regcache_raw_supply (regcache, regnum, NULL);
       return;
     }
 
@@ -636,10 +682,7 @@ inf_ptrace_fetch_register (int regnum)
   if (pid == 0)
     pid = ptid_get_pid (inferior_ptid);
 
-  /* This isn't really an address, but ptrace thinks of it as one.  */
-  addr = inf_ptrace_register_u_offset (regnum);
-  size = register_size (current_gdbarch, regnum);
-
+  size = register_size (gdbarch, regnum);
   gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
   buf = alloca (size);
 
@@ -647,40 +690,47 @@ inf_ptrace_fetch_register (int regnum)
   for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
     {
       errno = 0;
-      buf[i] = ptrace (PT_READ_U, pid, (PTRACE_TYPE_ARG3)addr, 0);
+      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);
     }
-  regcache_raw_supply (current_regcache, regnum, buf);
+  regcache_raw_supply (regcache, regnum, buf);
 }
 
 /* Fetch register REGNUM from the inferior.  If REGNUM is -1, do this
    for all registers.  */
 
 static void
-inf_ptrace_fetch_registers (int regnum)
+inf_ptrace_fetch_registers (struct regcache *regcache, int regnum)
 {
   if (regnum == -1)
-    for (regnum = 0; regnum < NUM_REGS; regnum++)
-      inf_ptrace_fetch_register (regnum);
+    for (regnum = 0;
+        regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+        regnum++)
+      inf_ptrace_fetch_register (regcache, regnum);
   else
-    inf_ptrace_fetch_register (regnum);
+    inf_ptrace_fetch_register (regcache, regnum);
 }
 
 /* Store register REGNUM into the inferior.  */
 
 static void
-inf_ptrace_store_register (int regnum)
+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;
 
-  if (CANNOT_STORE_REGISTER (regnum))
+  /* This isn't really an address, but ptrace thinks of it as one.  */
+  addr = inf_ptrace_register_u_offset (gdbarch, regnum, 1);
+  if (addr == (CORE_ADDR)-1 
+      || gdbarch_cannot_store_register (gdbarch, regnum))
     return;
 
   /* Cater for systems like GNU/Linux, that implement threads as
@@ -689,22 +739,20 @@ inf_ptrace_store_register (int regnum)
   if (pid == 0)
     pid = ptid_get_pid (inferior_ptid);
 
-  /* This isn't really an address, but ptrace thinks of it as one.  */
-  addr = inf_ptrace_register_u_offset (regnum);
-  size = register_size (current_gdbarch, regnum);
-
+  size = register_size (gdbarch, regnum);
   gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
   buf = alloca (size);
 
   /* Write the register contents into the inferior a chunk at a time.  */
-  regcache_raw_collect (current_regcache, regnum, buf);
+  regcache_raw_collect (regcache, regnum, buf);
   for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
     {
       errno = 0;
-      ptrace (PT_WRITE_U, pid, (PTRACE_TYPE_ARG3)addr, buf[i]);
+      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);
     }
@@ -714,13 +762,15 @@ inf_ptrace_store_register (int regnum)
    this for all registers.  */
 
 void
-inf_ptrace_store_registers (int regnum)
+inf_ptrace_store_registers (struct regcache *regcache, int regnum)
 {
   if (regnum == -1)
-    for (regnum = 0; regnum < NUM_REGS; regnum++)
-      inf_ptrace_store_register (regnum);
+    for (regnum = 0;
+        regnum < gdbarch_num_regs (get_regcache_arch (regcache));
+        regnum++)
+      inf_ptrace_store_register (regcache, regnum);
   else
-    inf_ptrace_store_register (regnum);
+    inf_ptrace_store_register (regcache, regnum);
 }
 
 /* Create a "traditional" ptrace target.  REGISTER_U_OFFSET should be
@@ -728,7 +778,8 @@ inf_ptrace_store_registers (int regnum)
    particular register is stored.  */
 
 struct target_ops *
-inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)(int))
+inf_ptrace_trad_target (CORE_ADDR (*register_u_offset)
+                                       (struct gdbarch *, int, int))
 {
   struct target_ops *t = inf_ptrace_target();
 
This page took 0.032541 seconds and 4 git commands to generate.