* linux-thread-db.c (thread_db_mourn_inferior): Remove breakpoints
[deliverable/binutils-gdb.git] / gdb / inf-ptrace.c
index 9c4a77fcb3b60e0ad723995893cf860a7d24801a..9e2ea846e214a0a244fa2b9afd4a265c6e4ba2ee 100644 (file)
@@ -1,6 +1,6 @@
 /* Low-level child interface to ptrace.
 
-   Copyright 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+   Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
    1998, 1999, 2000, 2001, 2002, 2004, 2005
    Free Software Foundation, Inc.
 
@@ -18,8 +18,8 @@
 
    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., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   Foundation, Inc., 51 Franklin Street, Fifth Floor,
+   Boston, MA 02110-1301, USA.  */
 
 #include "defs.h"
 #include "command.h"
 static struct target_ops *ptrace_ops_hack;
 \f
 
+#ifdef PT_GET_PROCESS_STATE
+
+static int
+inf_ptrace_follow_fork (struct target_ops *ops, int follow_child)
+{
+  pid_t pid, fpid;
+  ptrace_state_t pe;
+
+  /* FIXME: kettenis/20050720: This stuff should really be passed as
+     an argument by our caller.  */
+  {
+    ptid_t ptid;
+    struct target_waitstatus status;
+
+    get_last_target_status (&ptid, &status);
+    gdb_assert (status.kind == TARGET_WAITKIND_FORKED);
+
+    pid = ptid_get_pid (ptid);
+  }
+
+  if (ptrace (PT_GET_PROCESS_STATE, pid,
+              (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+    perror_with_name (("ptrace"));
+
+  gdb_assert (pe.pe_report_event == PTRACE_FORK);
+  fpid = pe.pe_other_pid;
+
+  if (follow_child)
+    {
+      inferior_ptid = pid_to_ptid (fpid);
+      detach_breakpoints (pid);
+
+      /* 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
+    {
+      inferior_ptid = pid_to_ptid (pid);
+      detach_breakpoints (fpid);
+
+      if (ptrace (PT_DETACH, fpid, (PTRACE_TYPE_ARG3)1, 0) == -1)
+       perror_with_name (("ptrace"));
+    }
+
+  return 0;
+}
+
+#endif /* PT_GET_PROCESS_STATE */
+\f
+
 /* Prepare to be traced.  */
 
 static void
@@ -93,6 +146,23 @@ inf_ptrace_create_inferior (char *exec_file, char *allargs, char **env,
   proceed ((CORE_ADDR) -1, TARGET_SIGNAL_0, 0);
 }
 
+#ifdef PT_GET_PROCESS_STATE
+
+static void
+inf_ptrace_post_startup_inferior (ptid_t pid)
+{
+  ptrace_event_t pe;
+
+  /* Set the initial event mask.  */
+  memset (&pe, 0, sizeof pe);
+  pe.pe_set_event |= PTRACE_FORK;
+  if (ptrace (PT_SET_EVENT_MASK, ptid_get_pid (pid),
+             (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+    perror_with_name (("ptrace"));
+}
+
+#endif
+
 /* Clean up a rotting corpse of an inferior after it died.  */
 
 static void
@@ -101,9 +171,9 @@ inf_ptrace_mourn_inferior (void)
   int status;
 
   /* Wait just one more time to collect the inferior's exit status.
-     Don not check whether this succeeds though, since we may be
+     Do not check whether this succeeds though, since we may be
      dealing with a process that we attached to.  Such a process will
-     only report its exit status to its origional parent.  */
+     only report its exit status to its original parent.  */
   waitpid (ptid_get_pid (inferior_ptid), &status, 0);
 
   unpush_target (ptrace_ops_hack);
@@ -164,8 +234,25 @@ inf_ptrace_attach (char *args, int from_tty)
   observer_notify_inferior_created (&current_target, from_tty);
 }
 
+#ifdef PT_GET_PROCESS_STATE
+
+void
+inf_ptrace_post_attach (int pid)
+{
+  ptrace_event_t pe;
+
+  /* Set the initial event mask.  */
+  memset (&pe, 0, sizeof pe);
+  pe.pe_set_event |= PTRACE_FORK;
+  if (ptrace (PT_SET_EVENT_MASK, pid,
+             (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+    perror_with_name (("ptrace"));
+}
+
+#endif
+
 /* Detach from the inferior, optionally passing it the signal
-   specified ARGS.  If FROM_TTY is non-zero, be chatty about it.  */
+   specified by ARGS.  If FROM_TTY is non-zero, be chatty about it.  */
 
 static void
 inf_ptrace_detach (char *args, int from_tty)
@@ -187,7 +274,7 @@ inf_ptrace_detach (char *args, int from_tty)
 
 #ifdef PT_DETACH
   /* We'd better not have left any breakpoints in the program or it'll
-     die when it hits one.  Alsno note that this may only work if we
+     die when it hits one.  Also note that this may only work if we
      previously attached to the inferior.  It *might* work if we
      started the process ourselves.  */
   errno = 0;
@@ -310,6 +397,44 @@ inf_ptrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
     }
   while (pid == -1);
 
+#ifdef PT_GET_PROCESS_STATE
+  if (WIFSTOPPED (status))
+    {
+      ptrace_state_t pe;
+      pid_t fpid;
+
+      if (ptrace (PT_GET_PROCESS_STATE, pid,
+                 (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+       perror_with_name (("ptrace"));
+
+      switch (pe.pe_report_event)
+       {
+       case PTRACE_FORK:
+         ourstatus->kind = TARGET_WAITKIND_FORKED;
+         ourstatus->value.related_pid = pe.pe_other_pid;
+
+         /* Make sure the other end of the fork is stopped too.  */
+         fpid = waitpid (pe.pe_other_pid, &status, 0);
+         if (fpid == -1)
+           perror_with_name (("waitpid"));
+
+         if (ptrace (PT_GET_PROCESS_STATE, fpid,
+                     (PTRACE_TYPE_ARG3)&pe, sizeof pe) == -1)
+           perror_with_name (("ptrace"));
+
+         gdb_assert (pe.pe_report_event == PTRACE_FORK);
+         gdb_assert (pe.pe_other_pid == pid);
+         if (fpid == ptid_get_pid (inferior_ptid))
+           {
+             ourstatus->value.related_pid = pe.pe_other_pid;
+             return pid_to_ptid (fpid);
+           }
+
+         return pid_to_ptid (pid);
+       }
+    }
+#endif
+
   store_waitstatus (ourstatus, status);
   return pid_to_ptid (pid);
 }
@@ -337,8 +462,12 @@ inf_ptrace_xfer_partial (struct target_ops *ops, enum target_object object,
        struct ptrace_io_desc piod;
 
        /* NOTE: We assume that there are no distinct address spaces
-          for instruction and data.  */
-       piod.piod_op = writebuf ? PIOD_WRITE_D : PIOD_READ_D;
+          for instruction and data.  However, on OpenBSD 3.9 and
+          later, PIOD_WRITE_D doesn't allow changing memory that's
+          mapped read-only.  Since most code segments will be
+          read-only, using PIOD_WRITE_D will prevent us from
+          inserting breakpoints, so we use PIOD_WRITE_I instead.  */
+       piod.piod_op = writebuf ? PIOD_WRITE_I : PIOD_READ_D;
        piod.piod_addr = writebuf ? (void *) writebuf : readbuf;
        piod.piod_offs = (void *) (long) offset;
        piod.piod_len = len;
@@ -471,6 +600,11 @@ inf_ptrace_target (void)
   t->to_files_info = inf_ptrace_files_info;
   t->to_kill = inf_ptrace_kill;
   t->to_create_inferior = inf_ptrace_create_inferior;
+#ifdef PT_GET_PROCESS_STATE
+  t->to_follow_fork = inf_ptrace_follow_fork;
+  t->to_post_startup_inferior = inf_ptrace_post_startup_inferior;
+  t->to_post_attach = inf_ptrace_post_attach;
+#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;
@@ -496,8 +630,14 @@ inf_ptrace_fetch_register (int regnum)
   PTRACE_TYPE_RET *buf;
   int pid, i;
 
+  if (CANNOT_FETCH_REGISTER (regnum))
+    {
+      regcache_raw_supply (current_regcache, regnum, NULL);
+      return;
+    }
+
   /* Cater for systems like GNU/Linux, that implement threads as
-     seperate processes.  */
+     separate processes.  */
   pid = ptid_get_lwp (inferior_ptid);
   if (pid == 0)
     pid = ptid_get_pid (inferior_ptid);
@@ -509,7 +649,7 @@ inf_ptrace_fetch_register (int regnum)
   gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
   buf = alloca (size);
 
-  /* Read the register contents from the inferior a chuck at the time.  */
+  /* Read the register contents from the inferior a chunk at a time.  */
   for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
     {
       errno = 0;
@@ -546,8 +686,11 @@ inf_ptrace_store_register (int regnum)
   PTRACE_TYPE_RET *buf;
   int pid, i;
 
+  if (CANNOT_STORE_REGISTER (regnum))
+    return;
+
   /* Cater for systems like GNU/Linux, that implement threads as
-     seperate processes.  */
+     separate processes.  */
   pid = ptid_get_lwp (inferior_ptid);
   if (pid == 0)
     pid = ptid_get_pid (inferior_ptid);
@@ -559,7 +702,7 @@ inf_ptrace_store_register (int regnum)
   gdb_assert ((size % sizeof (PTRACE_TYPE_RET)) == 0);
   buf = alloca (size);
 
-  /* Write the register contents into the inferior a chunk at the time.  */
+  /* Write the register contents into the inferior a chunk at a time.  */
   regcache_raw_collect (current_regcache, regnum, buf);
   for (i = 0; i < size / sizeof (PTRACE_TYPE_RET); i++)
     {
This page took 0.027288 seconds and 4 git commands to generate.