* 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.
This commit is contained in:
Daniel Jacobowitz 2002-12-11 02:02:03 +00:00
parent 8e7d2c1695
commit 7d2830a309
4 changed files with 113 additions and 49 deletions

View 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.

View 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

View 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);

View 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)