mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-30 12:44:10 +08:00
* config/pa/nm-hppah.h (CHILD_POST_FOLLOW_VFORK): Change to
CHILD_FOLLOW_FORK. * hppah-nat.c (saved_vfork_pid): Add. (child_post_follow_vfork): Remove. (child_follow_fork): New function. (child_wait): Call detach_breakpoints after receiving the child vfork. Call child_resume directly instead of going through resume (). Make sure we have the exec before reporting the vfork. * inferior.h (follow_inferior_reset_breakpoints): Add prototype. * infrun.c (follow_fork, follow_vfork, follow_inferior_fork): Remove. (follow_fork): New function. Call target_follow_fork. (follow_inferior_reset_breakpoints): New function broken out from old follow_inferior_fork. (resume): Remove hack to follow exec after vfork. * inftarg.c (child_post_follow_vfork): Remove. (child_follow_fork): New function. (init_child_ops): Replace to_post_follow_vfork with to_follow_fork. * target.c (cleanup_target): Replace to_post_follow_vfork with to_follow_fork. (update_current_target): Likewise. (setup_target_debug): Likewise. (debug_to_post_follow_vfork): Remove. (debug_to_follow_fork): New function. * target.h (struct target_ops): Replace to_post_folow_vfork with to_follow_fork. (child_post_follow_vfork): Remove prototype. (child_follow_fork): Add prototype. (target_post_follow_vfork): Remove macro. (target_follow_fork): Add macro. testsuite/ * gdb.base/foll-vfork.exp: Re-enable test on HP/UX.
This commit is contained in:
parent
7d2830a309
commit
6604731ba7
@ -1,3 +1,35 @@
|
||||
2002-12-10 Daniel Jacobowitz <drow@mvista.com>
|
||||
|
||||
* config/pa/nm-hppah.h (CHILD_POST_FOLLOW_VFORK): Change to
|
||||
CHILD_FOLLOW_FORK.
|
||||
* hppah-nat.c (saved_vfork_pid): Add.
|
||||
(child_post_follow_vfork): Remove.
|
||||
(child_follow_fork): New function.
|
||||
(child_wait): Call detach_breakpoints after receiving the child vfork.
|
||||
Call child_resume directly instead of going through resume ().
|
||||
Make sure we have the exec before reporting the vfork.
|
||||
* inferior.h (follow_inferior_reset_breakpoints): Add prototype.
|
||||
* infrun.c (follow_fork, follow_vfork, follow_inferior_fork): Remove.
|
||||
(follow_fork): New function. Call target_follow_fork.
|
||||
(follow_inferior_reset_breakpoints): New function broken out from
|
||||
old follow_inferior_fork.
|
||||
(resume): Remove hack to follow exec after vfork.
|
||||
* inftarg.c (child_post_follow_vfork): Remove.
|
||||
(child_follow_fork): New function.
|
||||
(init_child_ops): Replace to_post_follow_vfork with to_follow_fork.
|
||||
* target.c (cleanup_target): Replace to_post_follow_vfork with
|
||||
to_follow_fork.
|
||||
(update_current_target): Likewise.
|
||||
(setup_target_debug): Likewise.
|
||||
(debug_to_post_follow_vfork): Remove.
|
||||
(debug_to_follow_fork): New function.
|
||||
* target.h (struct target_ops): Replace to_post_folow_vfork with
|
||||
to_follow_fork.
|
||||
(child_post_follow_vfork): Remove prototype.
|
||||
(child_follow_fork): Add prototype.
|
||||
(target_post_follow_vfork): Remove macro.
|
||||
(target_follow_fork): Add macro.
|
||||
|
||||
2002-12-10 Daniel Jacobowitz <drow@mvista.com>
|
||||
|
||||
* hppah-nat.c (saved_child_execd_pathname, saved_vfork_state): New.
|
||||
|
@ -65,7 +65,7 @@
|
||||
/* In hppah-nat.c: */
|
||||
#define FETCH_INFERIOR_REGISTERS
|
||||
#define CHILD_XFER_MEMORY
|
||||
#define CHILD_POST_FOLLOW_VFORK
|
||||
#define CHILD_FOLLOW_FORK
|
||||
|
||||
/* While this is for use by threaded programs, it doesn't appear
|
||||
* to hurt non-threaded ones. This is used in infrun.c: */
|
||||
|
200
gdb/hppah-nat.c
200
gdb/hppah-nat.c
@ -385,6 +385,7 @@ child_xfer_memory (CORE_ADDR memaddr, char *myaddr, int len, int write,
|
||||
}
|
||||
|
||||
char *saved_child_execd_pathname = NULL;
|
||||
int saved_vfork_pid;
|
||||
enum {
|
||||
STATE_NONE,
|
||||
STATE_GOT_CHILD,
|
||||
@ -393,48 +394,121 @@ enum {
|
||||
STATE_FAKE_EXEC
|
||||
} saved_vfork_state = STATE_NONE;
|
||||
|
||||
void
|
||||
child_post_follow_vfork (int parent_pid, int followed_parent, int child_pid,
|
||||
int followed_child)
|
||||
int
|
||||
child_follow_fork (int follow_child)
|
||||
{
|
||||
/* Are we a debugger that followed the parent of a vfork? If so,
|
||||
then recall that the child's vfork event was delivered to us
|
||||
first. And, that the parent was suspended by the OS until the
|
||||
child's exec or exit events were received.
|
||||
ptid_t last_ptid;
|
||||
struct target_waitstatus last_status;
|
||||
int has_vforked;
|
||||
int parent_pid, child_pid;
|
||||
|
||||
Upon receiving that child vfork, then, we were forced to remove
|
||||
all breakpoints in the child and continue it so that it could
|
||||
reach the exec or exit point.
|
||||
get_last_target_status (&last_ptid, &last_status);
|
||||
has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
|
||||
parent_pid = ptid_get_pid (last_ptid);
|
||||
child_pid = last_status.value.related_pid;
|
||||
|
||||
But also recall that the parent and child of a vfork share the
|
||||
same address space. Thus, removing bp's in the child also
|
||||
removed them from the parent.
|
||||
/* At this point, if we are vforking, breakpoints were already
|
||||
detached from the child in child_wait; and the child has already
|
||||
called execve(). If we are forking, both the parent and child
|
||||
have breakpoints inserted. */
|
||||
|
||||
Now that the child has safely exec'd or exited, we must restore
|
||||
the parent's breakpoints before we continue it. Else, we may
|
||||
cause it run past expected stopping points. */
|
||||
if (followed_parent)
|
||||
if (! follow_child)
|
||||
{
|
||||
reattach_breakpoints (parent_pid);
|
||||
if (! has_vforked)
|
||||
{
|
||||
detach_breakpoints (child_pid);
|
||||
#ifdef SOLIB_REMOVE_INFERIOR_HOOK
|
||||
SOLIB_REMOVE_INFERIOR_HOOK (child_pid);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Detach from the child. */
|
||||
target_require_detach (child_pid, "", 1);
|
||||
|
||||
/* The parent and child of a vfork share the same address space.
|
||||
Also, on some targets the order in which vfork and exec events
|
||||
are received for parent in child requires some delicate handling
|
||||
of the events.
|
||||
|
||||
For instance, on ptrace-based HPUX we receive the child's vfork
|
||||
event first, at which time the parent has been suspended by the
|
||||
OS and is essentially untouchable until the child's exit or second
|
||||
exec event arrives. At that time, the parent's vfork event is
|
||||
delivered to us, and that's when we see and decide how to follow
|
||||
the vfork. But to get to that point, we must continue the child
|
||||
until it execs or exits. To do that smoothly, all breakpoints
|
||||
must be removed from the child, in case there are any set between
|
||||
the vfork() and exec() calls. But removing them from the child
|
||||
also removes them from the parent, due to the shared-address-space
|
||||
nature of a vfork'd parent and child. On HPUX, therefore, we must
|
||||
take care to restore the bp's to the parent before we continue it.
|
||||
Else, it's likely that we may not stop in the expected place. (The
|
||||
worst scenario is when the user tries to step over a vfork() call;
|
||||
the step-resume bp must be restored for the step to properly stop
|
||||
in the parent after the call completes!)
|
||||
|
||||
Sequence of events, as reported to gdb from HPUX:
|
||||
|
||||
Parent Child Action for gdb to take
|
||||
-------------------------------------------------------
|
||||
1 VFORK Continue child
|
||||
2 EXEC
|
||||
3 EXEC or EXIT
|
||||
4 VFORK
|
||||
|
||||
Now that the child has safely exec'd or exited, we must restore
|
||||
the parent's breakpoints before we continue it. Else, we may
|
||||
cause it run past expected stopping points. */
|
||||
|
||||
if (has_vforked)
|
||||
reattach_breakpoints (parent_pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
char child_pid_spelling[40];
|
||||
|
||||
/* Needed to keep the breakpoint lists in sync. */
|
||||
if (! has_vforked)
|
||||
detach_breakpoints (child_pid);
|
||||
|
||||
/* Before detaching from the parent, remove all breakpoints from it. */
|
||||
remove_breakpoints ();
|
||||
|
||||
/* Also reset the solib inferior hook from the parent. */
|
||||
#ifdef SOLIB_REMOVE_INFERIOR_HOOK
|
||||
SOLIB_REMOVE_INFERIOR_HOOK (PIDGET (inferior_ptid));
|
||||
#endif
|
||||
|
||||
/* Detach from the parent. */
|
||||
target_detach (NULL, 1);
|
||||
|
||||
/* Attach to the child. */
|
||||
inferior_ptid = pid_to_ptid (child_pid);
|
||||
sprintf (child_pid_spelling, "%d", child_pid);
|
||||
|
||||
target_require_attach (child_pid_spelling, 1);
|
||||
|
||||
/* If we vforked, then we've also execed by now. The exec will be
|
||||
reported momentarily. follow_exec () will handle breakpoints, so
|
||||
we don't have to.. */
|
||||
if (!has_vforked)
|
||||
follow_inferior_reset_breakpoints ();
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
if (followed_child)
|
||||
if (has_vforked)
|
||||
{
|
||||
/* If the child has exited, then there's nothing for us to do.
|
||||
In the case of an exec event, we'll let that be handled by
|
||||
the normal mechanism that notices and handles exec events, in
|
||||
resume(). */
|
||||
/* 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 (! follow_child || saved_vfork_state == STATE_GOT_PARENT)
|
||||
saved_vfork_state = STATE_NONE;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Format a process id, given PID. Be sure to terminate
|
||||
@ -592,13 +666,26 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||
if (saved_vfork_state == STATE_GOT_CHILD)
|
||||
{
|
||||
child_post_startup_inferior (pid_to_ptid (pid));
|
||||
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
|
||||
detach_breakpoints (pid);
|
||||
#ifdef SOLIB_REMOVE_INFERIOR_HOOK
|
||||
SOLIB_REMOVE_INFERIOR_HOOK (pid);
|
||||
#endif
|
||||
child_resume (pid_to_ptid (pid), 0, TARGET_SIGNAL_0);
|
||||
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
||||
return pid_to_ptid (related_pid);
|
||||
}
|
||||
else if (saved_vfork_state == STATE_FAKE_EXEC)
|
||||
{
|
||||
ourstatus->kind = TARGET_WAITKIND_VFORKED;
|
||||
ourstatus->value.related_pid = related_pid;
|
||||
return pid_to_ptid (pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
ourstatus->kind = TARGET_WAITKIND_VFORKED;
|
||||
ourstatus->value.related_pid = related_pid;
|
||||
/* We saw the parent's vfork, but we haven't seen the exec yet.
|
||||
Wait for it, for simplicity's sake. It should be pending. */
|
||||
saved_vfork_pid = related_pid;
|
||||
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
||||
return pid_to_ptid (pid);
|
||||
}
|
||||
}
|
||||
@ -608,27 +695,32 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||
/* 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)
|
||||
The latter two can come in either order. Make sure we get
|
||||
both. */
|
||||
if (saved_vfork_state != STATE_NONE)
|
||||
{
|
||||
if (saved_vfork_state == STATE_GOT_CHILD)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else if (saved_vfork_state == STATE_GOT_PARENT)
|
||||
{
|
||||
saved_vfork_state = STATE_FAKE_EXEC;
|
||||
ourstatus->kind = TARGET_WAITKIND_VFORKED;
|
||||
ourstatus->value.related_pid = saved_vfork_pid;
|
||||
}
|
||||
else
|
||||
fprintf_unfiltered (gdb_stdout,
|
||||
"hppa: exec: unexpected state\n");
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -304,6 +304,8 @@ extern int signal_pass_update (int, int);
|
||||
extern void get_last_target_status(ptid_t *ptid,
|
||||
struct target_waitstatus *status);
|
||||
|
||||
extern void follow_inferior_reset_breakpoints (void);
|
||||
|
||||
/* From infcmd.c */
|
||||
|
||||
extern void tty_command (char *, int);
|
||||
|
196
gdb/infrun.c
196
gdb/infrun.c
@ -66,12 +66,7 @@ static int restore_selected_frame (void *);
|
||||
|
||||
static void build_infrun (void);
|
||||
|
||||
static void follow_inferior_fork (int parent_pid, int child_pid,
|
||||
int has_forked, int has_vforked);
|
||||
|
||||
static void follow_fork (int parent_pid, int child_pid);
|
||||
|
||||
static void follow_vfork (int parent_pid, int child_pid);
|
||||
static int follow_fork ();
|
||||
|
||||
static void set_schedlock_func (char *args, int from_tty,
|
||||
struct cmd_list_element *c);
|
||||
@ -384,15 +379,11 @@ static const char *follow_fork_mode_kind_names[] = {
|
||||
static const char *follow_fork_mode_string = follow_fork_mode_parent;
|
||||
|
||||
|
||||
static void
|
||||
follow_inferior_fork (int parent_pid, int child_pid, int has_forked,
|
||||
int has_vforked)
|
||||
static int
|
||||
follow_fork ()
|
||||
{
|
||||
int followed_parent = 0;
|
||||
int followed_child = 0;
|
||||
|
||||
/* Which process did the user want us to follow? */
|
||||
const char *follow_mode = follow_fork_mode_string;
|
||||
int follow_child = (follow_mode == follow_fork_mode_child);
|
||||
|
||||
/* Or, did the user not know, and want us to ask? */
|
||||
if (follow_fork_mode_string == follow_fork_mode_ask)
|
||||
@ -402,138 +393,36 @@ follow_inferior_fork (int parent_pid, int child_pid, int has_forked,
|
||||
/* follow_mode = follow_fork_mode_...; */
|
||||
}
|
||||
|
||||
/* If we're to be following the parent, then detach from child_pid.
|
||||
We're already following the parent, so need do nothing explicit
|
||||
for it. */
|
||||
if (follow_mode == follow_fork_mode_parent)
|
||||
{
|
||||
followed_parent = 1;
|
||||
|
||||
/* We're already attached to the parent, by default. */
|
||||
|
||||
/* Before detaching from the child, remove all breakpoints from
|
||||
it. (This won't actually modify the breakpoint list, but will
|
||||
physically remove the breakpoints from the child.) */
|
||||
detach_breakpoints (child_pid);
|
||||
#ifdef SOLIB_REMOVE_INFERIOR_HOOK
|
||||
SOLIB_REMOVE_INFERIOR_HOOK (child_pid);
|
||||
#endif
|
||||
|
||||
/* Detach from the child. */
|
||||
dont_repeat ();
|
||||
|
||||
target_require_detach (child_pid, "", 1);
|
||||
}
|
||||
|
||||
/* If we're to be following the child, then attach to it, detach
|
||||
from inferior_ptid, and set inferior_ptid to child_pid. */
|
||||
else if (follow_mode == follow_fork_mode_child)
|
||||
{
|
||||
char child_pid_spelling[100]; /* Arbitrary length. */
|
||||
|
||||
followed_child = 1;
|
||||
|
||||
/* Before detaching from the parent, detach all breakpoints from
|
||||
the child. Note that this only works if we're following vforks
|
||||
right away; if we've exec'd then the breakpoints are already detached
|
||||
and the shadow contents are out of date. */
|
||||
detach_breakpoints (child_pid);
|
||||
|
||||
/* Before detaching from the parent, remove all breakpoints from it. */
|
||||
remove_breakpoints ();
|
||||
|
||||
/* Also reset the solib inferior hook from the parent. */
|
||||
#ifdef SOLIB_REMOVE_INFERIOR_HOOK
|
||||
SOLIB_REMOVE_INFERIOR_HOOK (PIDGET (inferior_ptid));
|
||||
#endif
|
||||
|
||||
/* Detach from the parent. */
|
||||
dont_repeat ();
|
||||
target_detach (NULL, 1);
|
||||
|
||||
/* Attach to the child. */
|
||||
inferior_ptid = pid_to_ptid (child_pid);
|
||||
sprintf (child_pid_spelling, "%d", child_pid);
|
||||
dont_repeat ();
|
||||
|
||||
target_require_attach (child_pid_spelling, 1);
|
||||
|
||||
/* Was there a step_resume breakpoint? (There was if the user
|
||||
did a "next" at the fork() call.) If so, explicitly reset its
|
||||
thread number.
|
||||
|
||||
step_resumes are a form of bp that are made to be per-thread.
|
||||
Since we created the step_resume bp when the parent process
|
||||
was being debugged, and now are switching to the child process,
|
||||
from the breakpoint package's viewpoint, that's a switch of
|
||||
"threads". We must update the bp's notion of which thread
|
||||
it is for, or it'll be ignored when it triggers... */
|
||||
/* As above, if we're following vforks at exec time then resetting the
|
||||
step resume breakpoint is probably wrong. */
|
||||
if (step_resume_breakpoint)
|
||||
breakpoint_re_set_thread (step_resume_breakpoint);
|
||||
|
||||
/* Reinsert all breakpoints in the child. (The user may've set
|
||||
breakpoints after catching the fork, in which case those
|
||||
actually didn't get set in the child, but only in the parent.) */
|
||||
breakpoint_re_set ();
|
||||
insert_breakpoints ();
|
||||
}
|
||||
|
||||
/* The parent and child of a vfork share the same address space.
|
||||
Also, on some targets the order in which vfork and exec events
|
||||
are received for parent in child requires some delicate handling
|
||||
of the events.
|
||||
|
||||
For instance, on ptrace-based HPUX we receive the child's vfork
|
||||
event first, at which time the parent has been suspended by the
|
||||
OS and is essentially untouchable until the child's exit or second
|
||||
exec event arrives. At that time, the parent's vfork event is
|
||||
delivered to us, and that's when we see and decide how to follow
|
||||
the vfork. But to get to that point, we must continue the child
|
||||
until it execs or exits. To do that smoothly, all breakpoints
|
||||
must be removed from the child, in case there are any set between
|
||||
the vfork() and exec() calls. But removing them from the child
|
||||
also removes them from the parent, due to the shared-address-space
|
||||
nature of a vfork'd parent and child. On HPUX, therefore, we must
|
||||
take care to restore the bp's to the parent before we continue it.
|
||||
Else, it's likely that we may not stop in the expected place. (The
|
||||
worst scenario is when the user tries to step over a vfork() call;
|
||||
the step-resume bp must be restored for the step to properly stop
|
||||
in the parent after the call completes!)
|
||||
|
||||
Sequence of events, as reported to gdb from HPUX:
|
||||
|
||||
Parent Child Action for gdb to take
|
||||
-------------------------------------------------------
|
||||
1 VFORK Continue child
|
||||
2 EXEC
|
||||
3 EXEC or EXIT
|
||||
4 VFORK */
|
||||
if (has_vforked)
|
||||
{
|
||||
target_post_follow_vfork (parent_pid,
|
||||
followed_parent, child_pid, followed_child);
|
||||
}
|
||||
|
||||
pending_follow.fork_event.saw_parent_fork = 0;
|
||||
pending_follow.fork_event.saw_child_fork = 0;
|
||||
|
||||
return target_follow_fork (follow_child);
|
||||
}
|
||||
|
||||
static void
|
||||
follow_fork (int parent_pid, int child_pid)
|
||||
void
|
||||
follow_inferior_reset_breakpoints (void)
|
||||
{
|
||||
follow_inferior_fork (parent_pid, child_pid, 1, 0);
|
||||
}
|
||||
/* Was there a step_resume breakpoint? (There was if the user
|
||||
did a "next" at the fork() call.) If so, explicitly reset its
|
||||
thread number.
|
||||
|
||||
step_resumes are a form of bp that are made to be per-thread.
|
||||
Since we created the step_resume bp when the parent process
|
||||
was being debugged, and now are switching to the child process,
|
||||
from the breakpoint package's viewpoint, that's a switch of
|
||||
"threads". We must update the bp's notion of which thread
|
||||
it is for, or it'll be ignored when it triggers. */
|
||||
|
||||
/* Forward declaration. */
|
||||
static void follow_exec (int, char *);
|
||||
if (step_resume_breakpoint)
|
||||
breakpoint_re_set_thread (step_resume_breakpoint);
|
||||
|
||||
static void
|
||||
follow_vfork (int parent_pid, int child_pid)
|
||||
{
|
||||
follow_inferior_fork (parent_pid, child_pid, 0, 1);
|
||||
/* Reinsert all breakpoints in the child. The user may have set
|
||||
breakpoints after catching the fork, in which case those
|
||||
were never set in the child, but only in the parent. This makes
|
||||
sure the inserted breakpoints match the breakpoint list. */
|
||||
|
||||
breakpoint_re_set ();
|
||||
insert_breakpoints ();
|
||||
}
|
||||
|
||||
/* EXECD_PATHNAME is assumed to be non-NULL. */
|
||||
@ -722,38 +611,19 @@ resume (int step, enum target_signal sig)
|
||||
#endif
|
||||
|
||||
/* If there were any forks/vforks/execs that were caught and are
|
||||
now to be followed, then do so. */
|
||||
now to be followed, then do so. */
|
||||
switch (pending_follow.kind)
|
||||
{
|
||||
case (TARGET_WAITKIND_FORKED):
|
||||
case TARGET_WAITKIND_FORKED:
|
||||
case TARGET_WAITKIND_VFORKED:
|
||||
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
|
||||
follow_fork (PIDGET (inferior_ptid),
|
||||
pending_follow.fork_event.child_pid);
|
||||
if (follow_fork ())
|
||||
should_resume = 0;
|
||||
break;
|
||||
|
||||
case (TARGET_WAITKIND_VFORKED):
|
||||
{
|
||||
int saw_child_exec = pending_follow.fork_event.saw_child_exec;
|
||||
|
||||
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
|
||||
follow_vfork (PIDGET (inferior_ptid),
|
||||
pending_follow.fork_event.child_pid);
|
||||
|
||||
/* Did we follow the child, but not yet see the child's exec event?
|
||||
If so, then it actually ought to be waiting for us; we respond to
|
||||
parent vfork events. We don't actually want to resume the child
|
||||
in this situation; we want to just get its exec event. */
|
||||
if (!saw_child_exec &&
|
||||
(PIDGET (inferior_ptid) == pending_follow.fork_event.child_pid))
|
||||
should_resume = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case (TARGET_WAITKIND_EXECD):
|
||||
/* If we saw a vfork event but couldn't follow it until we saw
|
||||
an exec, then now might be the time! */
|
||||
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
|
||||
case TARGET_WAITKIND_EXECD:
|
||||
/* follow_exec is called as soon as the exec event is seen. */
|
||||
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -469,14 +469,12 @@ child_remove_vfork_catchpoint (int pid)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(CHILD_POST_FOLLOW_VFORK)
|
||||
void
|
||||
child_post_follow_vfork (int parent_pid, int followed_parent, int child_pid,
|
||||
int followed_child)
|
||||
#if !defined(CHILD_FOLLOW_FORK)
|
||||
int
|
||||
child_follow_fork (int follow_child)
|
||||
{
|
||||
/* This version of Unix doesn't require a meaningful "post follow vfork"
|
||||
operation by a clone debugger.
|
||||
*/
|
||||
/* This version of Unix doesn't support following fork or vfork events. */
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -645,7 +643,7 @@ init_child_ops (void)
|
||||
child_ops.to_remove_fork_catchpoint = child_remove_fork_catchpoint;
|
||||
child_ops.to_insert_vfork_catchpoint = child_insert_vfork_catchpoint;
|
||||
child_ops.to_remove_vfork_catchpoint = child_remove_vfork_catchpoint;
|
||||
child_ops.to_post_follow_vfork = child_post_follow_vfork;
|
||||
child_ops.to_follow_fork = child_follow_fork;
|
||||
child_ops.to_insert_exec_catchpoint = child_insert_exec_catchpoint;
|
||||
child_ops.to_remove_exec_catchpoint = child_remove_exec_catchpoint;
|
||||
child_ops.to_reported_exec_events_per_exec_call = child_reported_exec_events_per_exec_call;
|
||||
|
22
gdb/target.c
22
gdb/target.c
@ -473,8 +473,8 @@ cleanup_target (struct target_ops *t)
|
||||
de_fault (to_remove_vfork_catchpoint,
|
||||
(int (*) (int))
|
||||
tcomplain);
|
||||
de_fault (to_post_follow_vfork,
|
||||
(void (*) (int, int, int, int))
|
||||
de_fault (to_follow_fork,
|
||||
(int (*) (int))
|
||||
target_ignore);
|
||||
de_fault (to_insert_exec_catchpoint,
|
||||
(int (*) (int))
|
||||
@ -597,7 +597,7 @@ update_current_target (void)
|
||||
INHERIT (to_remove_fork_catchpoint, t);
|
||||
INHERIT (to_insert_vfork_catchpoint, t);
|
||||
INHERIT (to_remove_vfork_catchpoint, t);
|
||||
INHERIT (to_post_follow_vfork, t);
|
||||
INHERIT (to_follow_fork, t);
|
||||
INHERIT (to_insert_exec_catchpoint, t);
|
||||
INHERIT (to_remove_exec_catchpoint, t);
|
||||
INHERIT (to_reported_exec_events_per_exec_call, t);
|
||||
@ -2064,15 +2064,15 @@ debug_to_remove_vfork_catchpoint (int pid)
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void
|
||||
debug_to_post_follow_vfork (int parent_pid, int followed_parent, int child_pid,
|
||||
int followed_child)
|
||||
static int
|
||||
debug_to_follow_fork (int follow_child)
|
||||
{
|
||||
debug_target.to_post_follow_vfork (parent_pid, followed_parent, child_pid, followed_child);
|
||||
int retval = debug_target.to_follow_fork (follow_child);
|
||||
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
"target_post_follow_vfork (%d, %d, %d, %d)\n",
|
||||
parent_pid, followed_parent, child_pid, followed_child);
|
||||
fprintf_unfiltered (gdb_stdlog, "target_follow_fork (%d) = %d\n",
|
||||
follow_child, retval);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -2285,7 +2285,7 @@ setup_target_debug (void)
|
||||
current_target.to_remove_fork_catchpoint = debug_to_remove_fork_catchpoint;
|
||||
current_target.to_insert_vfork_catchpoint = debug_to_insert_vfork_catchpoint;
|
||||
current_target.to_remove_vfork_catchpoint = debug_to_remove_vfork_catchpoint;
|
||||
current_target.to_post_follow_vfork = debug_to_post_follow_vfork;
|
||||
current_target.to_follow_fork = debug_to_follow_fork;
|
||||
current_target.to_insert_exec_catchpoint = debug_to_insert_exec_catchpoint;
|
||||
current_target.to_remove_exec_catchpoint = debug_to_remove_exec_catchpoint;
|
||||
current_target.to_reported_exec_events_per_exec_call = debug_to_reported_exec_events_per_exec_call;
|
||||
|
22
gdb/target.h
22
gdb/target.h
@ -276,7 +276,7 @@ struct target_ops
|
||||
int (*to_remove_fork_catchpoint) (int);
|
||||
int (*to_insert_vfork_catchpoint) (int);
|
||||
int (*to_remove_vfork_catchpoint) (int);
|
||||
void (*to_post_follow_vfork) (int, int, int, int);
|
||||
int (*to_follow_fork) (int);
|
||||
int (*to_insert_exec_catchpoint) (int);
|
||||
int (*to_remove_exec_catchpoint) (int);
|
||||
int (*to_reported_exec_events_per_exec_call) (void);
|
||||
@ -548,7 +548,7 @@ extern int child_remove_vfork_catchpoint (int);
|
||||
|
||||
extern void child_acknowledge_created_inferior (int);
|
||||
|
||||
extern void child_post_follow_vfork (int, int, int, int);
|
||||
extern int child_follow_fork (int);
|
||||
|
||||
extern int child_insert_exec_catchpoint (int);
|
||||
|
||||
@ -705,16 +705,16 @@ extern void target_load (char *arg, int from_tty);
|
||||
#define target_remove_vfork_catchpoint(pid) \
|
||||
(*current_target.to_remove_vfork_catchpoint) (pid)
|
||||
|
||||
/* An inferior process has been created via a vfork() system call.
|
||||
The debugger has followed the parent, the child, or both. The
|
||||
process of setting up for that follow may have required some
|
||||
target-specific trickery to track the sequence of reported events.
|
||||
If so, this function should be defined by those targets that
|
||||
require the debugger to perform cleanup or initialization after
|
||||
the vfork follow. */
|
||||
/* If the inferior forks or vforks, this function will be called at
|
||||
the next resume in order to perform any bookkeeping and fiddling
|
||||
necessary to continue debugging either the parent or child, as
|
||||
requested, and releasing the other. Information about the fork
|
||||
or vfork event is available via get_last_target_status ().
|
||||
This function returns 1 if the inferior should not be resumed
|
||||
(i.e. there is another event pending). */
|
||||
|
||||
#define target_post_follow_vfork(parent_pid,followed_parent,child_pid,followed_child) \
|
||||
(*current_target.to_post_follow_vfork) (parent_pid,followed_parent,child_pid,followed_child)
|
||||
#define target_follow_fork(follow_child) \
|
||||
(*current_target.to_follow_fork) (follow_child)
|
||||
|
||||
/* On some targets, we can catch an inferior exec event when it
|
||||
occurs. These functions insert/remove an already-created
|
||||
|
@ -1,3 +1,7 @@
|
||||
2002-12-10 Daniel Jacobowitz <drow@mvista.com>
|
||||
|
||||
* gdb.base/foll-vfork.exp: Re-enable test on HP/UX.
|
||||
|
||||
2002-12-06 David Carlton <carlton@math.stanford.edu>
|
||||
|
||||
* gdb.base/store.c: Don't declare functions static.
|
||||
|
@ -28,10 +28,13 @@ if { ![isnative] } then {
|
||||
set prms_id 0
|
||||
set bug_id 0
|
||||
|
||||
if [istarget "hppa2.0w-hp-hpux*"] {
|
||||
warning "Don't run gdb.base/foll-vfork.exp until JAGaa43495 kernel problem is fixed."
|
||||
return 0
|
||||
}
|
||||
# NOTE drow/2002-12-06: I don't know what the referenced kernel problem
|
||||
# is, but it appears to be fixed in recent HP/UX versions.
|
||||
|
||||
##if [istarget "hppa2.0w-hp-hpux*"] {
|
||||
## warning "Don't run gdb.base/foll-vfork.exp until JAGaa43495 kernel problem is fixed."
|
||||
## return 0
|
||||
##}
|
||||
|
||||
set testfile "foll-vfork"
|
||||
set testfile2 "vforked-prog"
|
||||
|
Loading…
Reference in New Issue
Block a user