-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.
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,
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. */
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. */
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
}
}
- 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
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. */
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
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);