* hppah-nat.c (saved_child_execd_pathname, saved_vfork_state): New.
authorDaniel Jacobowitz <drow@false.org>
Wed, 11 Dec 2002 02:02:03 +0000 (02:02 +0000)
committerDaniel Jacobowitz <drow@false.org>
Wed, 11 Dec 2002 02:02:03 +0000 (02:02 +0000)
(child_post_follow_vfork): Cancel pending exec event if we follow
the parent.
(child_wait): Only return TARGET_WAITKIND_VFORKED when all necessary
events have been processed.  Return a fake TARGET_WAITKIND_EXECD
event at the following wait call if necessary.
* infrun.c (follow_vfork): Don't follow_exec here.
(handle_inferior_event): Add comment to TARGET_WAITKIND_EXECD
case about HP/UX 10.20.  Remove code pushed down to
hppah-nat.c:child_wait.
* infttrace.c (child_resume): Use TT_PROC_CONTINUE if
vfork_in_flight is set.

gdb/ChangeLog
gdb/hppah-nat.c
gdb/infrun.c
gdb/infttrace.c

index a83927b6897c5e57cda06ccf1e82866da9fe0126..c427bf0f405cab5c042fd3286da5e4de7caf8bbd 100644 (file)
@@ -1,4 +1,19 @@
-2002-12-06  Daniel Jacobowitz  <drow@mvista.com>
+2002-12-10  Daniel Jacobowitz  <drow@mvista.com>
+
+       * hppah-nat.c (saved_child_execd_pathname, saved_vfork_state): New.
+       (child_post_follow_vfork): Cancel pending exec event if we follow
+       the parent.
+       (child_wait): Only return TARGET_WAITKIND_VFORKED when all necessary
+       events have been processed.  Return a fake TARGET_WAITKIND_EXECD
+       event at the following wait call if necessary.
+       * infrun.c (follow_vfork): Don't follow_exec here.
+       (handle_inferior_event): Add comment to TARGET_WAITKIND_EXECD
+       case about HP/UX 10.20.  Remove code pushed down to
+       hppah-nat.c:child_wait.
+       * infttrace.c (child_resume): Use TT_PROC_CONTINUE if
+       vfork_in_flight is set.
+
+2002-12-10  Daniel Jacobowitz  <drow@mvista.com>
 
        * hppah-nat.c (child_wait): Return TARGET_WAITKIND_IGNORE
        for the parent's fork event.
index 17614073e22f7c9fb76fb5f95e261c42b018a1ae..d7919e6cef891c5c2dd38c3ae90a69eb9559ab33 100644 (file)
@@ -384,6 +384,14 @@ child_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
   return len;
 }
 
+char *saved_child_execd_pathname = NULL;
+enum {
+  STATE_NONE,
+  STATE_GOT_CHILD,
+  STATE_GOT_EXEC,
+  STATE_GOT_PARENT,
+  STATE_FAKE_EXEC
+} saved_vfork_state = STATE_NONE;
 
 void
 child_post_follow_vfork (int parent_pid, int followed_parent, int child_pid,
@@ -410,6 +418,13 @@ child_post_follow_vfork (int parent_pid, int followed_parent, int child_pid,
       reattach_breakpoints (parent_pid);
     }
 
+  /* If we followed the parent, don't try to follow the child's exec.  */
+  if (saved_vfork_state != STATE_GOT_PARENT && saved_vfork_state != STATE_FAKE_EXEC)
+    fprintf_unfiltered (gdb_stdout, "hppa: post follow vfork: confused state\n");
+
+  if (followed_parent || saved_vfork_state == STATE_GOT_PARENT)
+    saved_vfork_state = STATE_NONE;
+
   /* Are we a debugger that followed the child of a vfork?  If so,
      then recall that we don't actually acquire control of the child
      until after it has exec'd or exited.  */
@@ -466,7 +481,6 @@ hppa_tid_to_str (ptid_t ptid)
 int not_same_real_pid = 1;
 /*## */
 
-
 /* Wait for child to do something.  Return pid of child, or -1 in case
    of error; store status through argument pointer OURSTATUS.  */
 
@@ -482,6 +496,14 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   enum target_waitkind kind;
   int pid;
 
+  if (saved_vfork_state == STATE_FAKE_EXEC)
+    {
+      saved_vfork_state = STATE_NONE;
+      ourstatus->kind = TARGET_WAITKIND_EXECD;
+      ourstatus->value.execd_pathname = saved_child_execd_pathname;
+      return inferior_ptid;
+    }
+
   do
     {
       set_sigint_trap ();      /* Causes SIGINT to be passed on to the
@@ -543,17 +565,73 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
            }
        }
 
-      if (hpux_has_vforked (pid, &related_pid)
-         && ((pid == PIDGET (inferior_ptid))
-             || (related_pid == PIDGET (inferior_ptid))))
+      if (hpux_has_vforked (pid, &related_pid))
        {
-         ourstatus->kind = TARGET_WAITKIND_VFORKED;
-         ourstatus->value.related_pid = related_pid;
-         return pid_to_ptid (pid);
+         if (pid == PIDGET (inferior_ptid))
+           {
+             if (saved_vfork_state == STATE_GOT_CHILD)
+               saved_vfork_state = STATE_GOT_PARENT;
+             else if (saved_vfork_state == STATE_GOT_EXEC)
+               saved_vfork_state = STATE_FAKE_EXEC;
+             else
+               fprintf_unfiltered (gdb_stdout,
+                                   "hppah: parent vfork: confused\n");
+           }
+         else if (related_pid == PIDGET (inferior_ptid))
+           {
+             if (saved_vfork_state == STATE_NONE)
+               saved_vfork_state = STATE_GOT_CHILD;
+             else
+               fprintf_unfiltered (gdb_stdout,
+                                   "hppah: child vfork: confused\n");
+           }
+         else
+           fprintf_unfiltered (gdb_stdout,
+                               "hppah: unknown vfork: confused\n");
+
+         if (saved_vfork_state == STATE_GOT_CHILD)
+           {
+             child_post_startup_inferior (pid_to_ptid (pid));
+             ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
+             return pid_to_ptid (pid);
+           }
+         else
+           {
+             ourstatus->kind = TARGET_WAITKIND_VFORKED;
+             ourstatus->value.related_pid = related_pid;
+             return pid_to_ptid (pid);
+           }
        }
 
       if (hpux_has_execd (pid, &execd_pathname))
        {
+         /* On HP-UX, events associated with a vforking inferior come in
+            threes: a vfork event for the child (always first), followed
+            a vfork event for the parent and an exec event for the child.
+            The latter two can come in either order.
+
+            If we get the parent vfork event first, life's good: We follow
+            either the parent or child, and then the child's exec event is
+            a "don't care".
+
+            But if we get the child's exec event first, then we delay
+            responding to it until we handle the parent's vfork.  Because,
+            otherwise we can't satisfy a "catch vfork".  */
+         if (saved_vfork_state == STATE_GOT_CHILD)
+           {
+             saved_child_execd_pathname = execd_pathname;
+             saved_vfork_state = STATE_GOT_EXEC;
+
+             /* On HP/UX with ptrace, the child must be resumed before
+                the parent vfork event is delivered.  A single-step
+                suffices.  */
+             if (RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK ())
+               target_resume (pid_to_ptid (pid), 1, TARGET_SIGNAL_0);
+
+             ourstatus->kind = TARGET_WAITKIND_IGNORE;
+             return inferior_ptid;
+           }
+         
          /* Are we ignoring initial exec events?  (This is likely because
             we're in the process of starting up the inferior, and another
             (older) mechanism handles those.)  If so, we'll report this
index 7cb9f3338ea4c3697ed81eaa337d306f42dea34b..b96e1c7a254c00edc78625307fd94b5a42887035 100644 (file)
@@ -534,16 +534,6 @@ static void
 follow_vfork (int parent_pid, int child_pid)
 {
   follow_inferior_fork (parent_pid, child_pid, 0, 1);
-
-  /* Did we follow the child?  Had it exec'd before we saw the parent vfork? */
-  if (pending_follow.fork_event.saw_child_exec
-      && (PIDGET (inferior_ptid) == child_pid))
-    {
-      pending_follow.fork_event.saw_child_exec = 0;
-      pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
-      follow_exec (PIDGET (inferior_ptid), pending_follow.execd_pathname);
-      xfree (pending_follow.execd_pathname);
-    }
 }
 
 /* EXECD_PATHNAME is assumed to be non-NULL. */
@@ -1555,6 +1545,9 @@ handle_inferior_event (struct execution_control_state *ecs)
     case TARGET_WAITKIND_EXECD:
       stop_signal = TARGET_SIGNAL_TRAP;
 
+      /* NOTE drow/2002-12-05: This code should be pushed down into the
+        target_wait function.  Until then following vfork on HP/UX 10.20
+        is probably broken by this.  Of course, it's broken anyway.  */
       /* Is this a target which reports multiple exec events per actual
          call to exec()?  (HP-UX using ptrace does, for example.)  If so,
          ignore all but the last one.  Just resume the exec'r, and wait
@@ -1576,36 +1569,6 @@ handle_inferior_event (struct execution_control_state *ecs)
        savestring (ecs->ws.value.execd_pathname,
                    strlen (ecs->ws.value.execd_pathname));
 
-      /* Did inferior_ptid exec, or did a (possibly not-yet-followed)
-         child of a vfork exec?
-
-         ??rehrauer: This is unabashedly an HP-UX specific thing.  On
-         HP-UX, events associated with a vforking inferior come in
-         threes: a vfork event for the child (always first), followed
-         a vfork event for the parent and an exec event for the child.
-         The latter two can come in either order.
-
-         If we get the parent vfork event first, life's good: We follow
-         either the parent or child, and then the child's exec event is
-         a "don't care".
-
-         But if we get the child's exec event first, then we delay
-         responding to it until we handle the parent's vfork.  Because,
-         otherwise we can't satisfy a "catch vfork". */
-      if (pending_follow.kind == TARGET_WAITKIND_VFORKED)
-       {
-         pending_follow.fork_event.saw_child_exec = 1;
-
-         /* On some targets, the child must be resumed before
-            the parent vfork event is delivered.  A single-step
-            suffices. */
-         if (RESUME_EXECD_VFORKING_CHILD_TO_GET_PARENT_VFORK ())
-           target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
-         /* We expect the parent vfork event to be available now. */
-         prepare_to_wait (ecs);
-         return;
-       }
-
       /* This causes the eventpoints and symbol table to be reset.  Must
          do this now, before trying to determine whether to stop. */
       follow_exec (PIDGET (inferior_ptid), pending_follow.execd_pathname);
index 7f0910f5711c83337181216402fad17c1f58f0b0..69a67dfa1b497b05fe64738bfa12421118e53c48 100644 (file)
@@ -4523,7 +4523,15 @@ child_resume (ptid_t ptid, int step, enum target_signal signal)
         pending signal will be passed to the inferior.  interrupt.exp
         in the testsuite does this precise thing and fails due to the
         unwanted signal delivery to the inferior.  */
-      if (resume_all_threads)
+      /* drow/2002-12-05: However, note that we must use TT_PROC_CONTINUE
+        if we are tracing a vfork.  */
+      if (vfork_in_flight)
+       {
+         call_ttrace (TT_PROC_CONTINUE, tid, TT_NIL, TT_NIL, TT_NIL);
+         clear_all_handled ();
+         clear_all_stepping_mode ();
+       }
+      else if (resume_all_threads)
        {
 #ifdef THREAD_DEBUG
          if (debug_on)