This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

PATCH: Fork event updates, part the fifth


Next in the series.  This one holds TARGET_WAITKIND_VFORKED in hppah-nat
until both the parent and child vfork have been received.  It's just another
step in pushing HP-specific gunk from infrun back down into the target code. 
Corresponding hacks can be deleted from infrun now.

Also contains the ttrace fix alluded to in my last message.  Following vfork
on HP/UX 11 "sort of" works after this patch.  Don't try it, wait for the
next one :)

This'll also go in early next week unless comments.

-- 
Daniel Jacobowitz
MontaVista Software                         Debian GNU/Linux Developer

2002-12-06  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.

diff -Nurp gdb.work1/hppah-nat.c gdb.work2/hppah-nat.c
--- gdb.work1/hppah-nat.c	2002-12-05 14:36:53.000000000 -0500
+++ gdb.work2/hppah-nat.c	2002-12-06 17:11:28.000000000 -0500
@@ -384,6 +384,14 @@ child_xfer_memory (CORE_ADDR memaddr, ch
   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,
       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_w
   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_w
 	    }
 	}
 
-      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
diff -Nurp gdb.work1/infrun.c gdb.work2/infrun.c
--- gdb.work1/infrun.c	2002-12-05 14:36:53.000000000 -0500
+++ gdb.work2/infrun.c	2002-12-06 17:14:19.000000000 -0500
@@ -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_
     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_
 	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);
diff -Nurp gdb.work1/infttrace.c gdb.work2/infttrace.c
--- gdb.work1/infttrace.c	2002-12-06 00:49:38.000000000 -0500
+++ gdb.work2/infttrace.c	2002-12-05 16:00:49.000000000 -0500
@@ -4523,7 +4523,15 @@ child_resume (ptid_t ptid, int step, enu
 	 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)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]