* inf-ptrace.c [PT_GET_PROCESS_STATE] (inf_ptrace_follow_fork):
authorMark Kettenis <kettenis@gnu.org>
Mon, 25 Jul 2005 21:11:02 +0000 (21:11 +0000)
committerMark Kettenis <kettenis@gnu.org>
Mon, 25 Jul 2005 21:11:02 +0000 (21:11 +0000)
New function.
(inf_ptrace_him, inf_ptrace_attach) [PT_GET_PROCESS_STATE]: Set
PTRACE_FORK event flag.
(inf_ptrace_wait) [PT_GET_PROCESS_STATE]: Handle PTRACE_FORK
event.
(inf_ptrace_target) [PT_GET_PROCESS_STATE]: Set to_follow_fork.

gdb/ChangeLog
gdb/inf-ptrace.c

index 348dd8deeccb09c3f3b090476df3c29148e7b172..77d4be8f9a4d60f40c0b2a9cd6058fa3a9219e09 100644 (file)
@@ -1,3 +1,13 @@
+2005-07-25  Mark Kettenis  <kettenis@gnu.org>
+
+       * inf-ptrace.c [PT_GET_PROCESS_STATE] (inf_ptrace_follow_fork):
+       New function.
+       (inf_ptrace_him, inf_ptrace_attach) [PT_GET_PROCESS_STATE]: Set
+       PTRACE_FORK event flag.
+       (inf_ptrace_wait) [PT_GET_PROCESS_STATE]: Handle PTRACE_FORK
+       event.
+       (inf_ptrace_target) [PT_GET_PROCESS_STATE]: Set to_follow_fork.
+
 2005-07-25  Mark Kettenis  <kettenis@gnu.org>
 
        * gdb_ptrace.h (PT_TRACE_ME): Define to zero if not already
index 9c4a77fcb3b60e0ad723995893cf860a7d24801a..033840a067ccc373ca932d3cc4184163099be8d2 100644 (file)
 static struct target_ops *ptrace_ops_hack;
 \f
 
+#ifdef PT_GET_PROCESS_STATE
+
+static int
+inf_ptrace_follow_fork (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
@@ -55,6 +108,19 @@ inf_ptrace_me (void)
 static void
 inf_ptrace_him (int pid)
 {
+#ifdef PT_GET_PROCESS_STATE
+  {
+    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
+
   push_target (ptrace_ops_hack);
 
   /* On some targets, there must be some explicit synchronization
@@ -156,6 +222,19 @@ inf_ptrace_attach (char *args, int from_tty)
   error (_("This system does not support attaching to a process"));
 #endif
 
+#ifdef PT_GET_PROCESS_STATE
+  {
+    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
+
   inferior_ptid = pid_to_ptid (pid);
   push_target (ptrace_ops_hack);
 
@@ -310,6 +389,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);
 }
@@ -471,6 +588,9 @@ 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;
+#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;