static int hook_stop_stub (void *);
-static void delete_breakpoint_current_contents (void *);
-
static int restore_selected_frame (void *);
static void build_infrun (void);
static int stop_print_frame;
static struct breakpoint *step_resume_breakpoint = NULL;
+/* NOTE: cagney/2004-05-08: This variable needs to be garbage
+ collected, it isn't used. */
static struct breakpoint *through_sigtramp_breakpoint = NULL;
/* On some platforms (e.g., HP-UX), hardware watchpoints have bad
step_range_start = 0;
step_range_end = 0;
- /* If there was one, it's gone now. */
- through_sigtramp_breakpoint = NULL;
-
/* What is this a.out's name? */
printf_unfiltered ("Executing new program: %s\n", execd_pathname);
stepping_past_singlestep_breakpoint = 0;
}
-
-static void
-delete_breakpoint_current_contents (void *arg)
-{
- struct breakpoint **breakpointp = (struct breakpoint **) arg;
- if (*breakpointp != NULL)
- {
- delete_breakpoint (*breakpointp);
- *breakpointp = NULL;
- }
-}
\f
/* This enum encodes possible reasons for doing a target_wait, so that
wfi can call target_wait in one place. (Ultimately the call will be
static void handle_step_into_function (struct execution_control_state *ecs);
void handle_inferior_event (struct execution_control_state *ecs);
-static void check_sigtramp2 (struct execution_control_state *ecs);
static void step_into_function (struct execution_control_state *ecs);
static void step_over_function (struct execution_control_state *ecs);
+static void insert_step_resume_breakpoint (struct frame_info *step_frame,
+ struct execution_control_state *ecs);
static void stop_stepping (struct execution_control_state *ecs);
static void prepare_to_wait (struct execution_control_state *ecs);
static void keep_going (struct execution_control_state *ecs);
old_cleanups = make_cleanup (delete_step_resume_breakpoint,
&step_resume_breakpoint);
- make_cleanup (delete_breakpoint_current_contents,
- &through_sigtramp_breakpoint);
/* wfi still stays in a loop, so it's OK just to take the address of
a local to get the ecs pointer. */
{
old_cleanups = make_exec_cleanup (delete_step_resume_breakpoint,
&step_resume_breakpoint);
- make_exec_cleanup (delete_breakpoint_current_contents,
- &through_sigtramp_breakpoint);
/* Fill in with reasonable starting values. */
init_execution_control_state (async_ecs);
return;
}
- /* Don't even think about breakpoints
- if just proceeded over a breakpoint.
-
- However, if we are trying to proceed over a breakpoint
- and end up in sigtramp, then through_sigtramp_breakpoint
- will be set and we should check whether we've hit the
- step breakpoint. */
- if (stop_signal == TARGET_SIGNAL_TRAP && trap_expected
- && through_sigtramp_breakpoint == NULL)
+ /* Don't even think about breakpoints if just proceeded over a
+ breakpoint. */
+ if (stop_signal == TARGET_SIGNAL_TRAP && trap_expected)
bpstat_clear (&stop_bpstat);
else
{
if (signal_program[stop_signal] == 0)
stop_signal = TARGET_SIGNAL_0;
- /* I'm not sure whether this needs to be check_sigtramp2 or
- whether it could/should be keep_going.
-
- This used to jump to step_over_function if we are stepping,
- which is wrong.
-
- Suppose the user does a `next' over a function call, and while
- that call is in progress, the inferior receives a signal for
- which GDB does not stop (i.e., signal_stop[SIG] is false). In
- that case, when we reach this point, there is already a
- step-resume breakpoint established, right where it should be:
- immediately after the function call the user is "next"-ing
- over. If we call step_over_function now, two bad things
- happen:
-
- - we'll create a new breakpoint, at wherever the current
- frame's return address happens to be. That could be
- anywhere, depending on what function call happens to be on
- the top of the stack at that point. Point is, it's probably
- not where we need it.
-
- - the existing step-resume breakpoint (which is at the correct
- address) will get orphaned: step_resume_breakpoint will point
- to the new breakpoint, and the old step-resume breakpoint
- will never be cleaned up.
-
- The old behavior was meant to help HP-UX single-step out of
- sigtramps. It would place the new breakpoint at prev_pc, which
- was certainly wrong. I don't know the details there, so fixing
- this probably breaks that. As with anything else, it's up to
- the HP-UX maintainer to furnish a fix that doesn't break other
- platforms. --JimB, 20 May 1999 */
- check_sigtramp2 (ecs);
+ if (step_range_end != 0
+ && stop_signal != TARGET_SIGNAL_0
+ && stop_pc >= step_range_start && stop_pc < step_range_end
+ && frame_id_eq (get_frame_id (get_current_frame ()), step_frame_id))
+ {
+ /* The inferior is about to take a signal that will take it
+ out of the single step range. Set a breakpoint at the
+ current PC (which is presumably where the signal handler
+ will eventually return) and then allow the inferior to
+ run free.
+
+ Note that this is only needed for a signal delivered
+ while in the single-step range. Nested signals aren't a
+ problem as they eventually all return. */
+ insert_step_resume_breakpoint (get_current_frame (), ecs);
+ }
keep_going (ecs);
return;
}
{
delete_step_resume_breakpoint (&step_resume_breakpoint);
}
- /* Not sure whether we need to blow this away too, but probably
- it is like the step-resume breakpoint. */
- if (through_sigtramp_breakpoint != NULL)
- {
- delete_breakpoint (through_sigtramp_breakpoint);
- through_sigtramp_breakpoint = NULL;
- }
#if 0
/* FIXME - Need to implement nested temporary breakpoints */
case BPSTAT_WHAT_STOP_NOISY:
stop_print_frame = 1;
- /* We are about to nuke the step_resume_breakpoint and
- through_sigtramp_breakpoint via the cleanup chain, so
- no need to worry about it here. */
+ /* We are about to nuke the step_resume_breakpointt via the
+ cleanup chain, so no need to worry about it here. */
stop_stepping (ecs);
return;
case BPSTAT_WHAT_STOP_SILENT:
stop_print_frame = 0;
- /* We are about to nuke the step_resume_breakpoint and
- through_sigtramp_breakpoint via the cleanup chain, so
- no need to worry about it here. */
+ /* We are about to nuke the step_resume_breakpoin via the
+ cleanup chain, so no need to worry about it here. */
stop_stepping (ecs);
return;
break;
case BPSTAT_WHAT_THROUGH_SIGTRAMP:
- if (through_sigtramp_breakpoint)
- delete_breakpoint (through_sigtramp_breakpoint);
- through_sigtramp_breakpoint = NULL;
-
/* If were waiting for a trap, hitting the step_resume_break
doesn't count as getting it. */
if (trap_expected)
/* Having a step-resume breakpoint overrides anything
else having to do with stepping commands until
that breakpoint is reached. */
- /* I'm not sure whether this needs to be check_sigtramp2 or
- whether it could/should be keep_going. */
- check_sigtramp2 (ecs);
keep_going (ecs);
return;
}
if (step_range_end == 0)
{
/* Likewise if we aren't even stepping. */
- /* I'm not sure whether this needs to be check_sigtramp2 or
- whether it could/should be keep_going. */
- check_sigtramp2 (ecs);
keep_going (ecs);
return;
}
within it! */
if (stop_pc >= step_range_start && stop_pc < step_range_end)
{
- /* We might be doing a BPSTAT_WHAT_SINGLE and getting a signal.
- So definately need to check for sigtramp here. */
- check_sigtramp2 (ecs);
keep_going (ecs);
return;
}
static int
currently_stepping (struct execution_control_state *ecs)
{
- return ((through_sigtramp_breakpoint == NULL
- && !ecs->handling_longjmp
+ return ((!ecs->handling_longjmp
&& ((step_range_end && step_resume_breakpoint == NULL)
|| trap_expected))
|| ecs->stepping_through_solib_after_catch
|| bpstat_should_step ());
}
-static void
-check_sigtramp2 (struct execution_control_state *ecs)
-{
- char *name;
- struct symtab_and_line sr_sal;
-
- /* Check that what has happened here is that we have just stepped
- the inferior with a signal (because it is a signal which
- shouldn't make us stop), thus stepping into sigtramp. */
-
- if (!trap_expected)
- return;
- if (get_frame_type (get_current_frame ()) != SIGTRAMP_FRAME)
- return;
-
- /* So we need to set a step_resume_break_address breakpoint and
- continue until we hit it, and then step. FIXME: This should be
- more enduring than a step_resume breakpoint; we should know that
- we will later need to keep going rather than re-hitting the
- breakpoint here (see the testsuite, gdb.base/signals.exp where it
- says "exceedingly difficult"). */
-
- init_sal (&sr_sal); /* initialize to zeroes */
- sr_sal.pc = prev_pc;
- sr_sal.section = find_pc_overlay (sr_sal.pc);
- /* We perhaps could set the frame if we kept track of what the frame
- corresponding to prev_pc was. But we don't, so don't. */
- through_sigtramp_breakpoint =
- set_momentary_breakpoint (sr_sal, null_frame_id, bp_through_sigtramp);
- if (breakpoints_inserted)
- insert_breakpoints ();
-
- ecs->remove_breakpoints_on_following_step = 1;
- ecs->another_trap = 1;
-}
-
/* Subroutine call with source code we should not step over. Do step
to the first line of code in it. */
keep_going (ecs);
}
+/* The inferior, as a result of a function call (has left) or signal
+ (about to leave) the single-step range. Set a momentary breakpoint
+ within the step range where the inferior is expected to later
+ return. */
+
+static void
+insert_step_resume_breakpoint (struct frame_info *step_frame,
+ struct execution_control_state *ecs)
+{
+ struct symtab_and_line sr_sal;
+
+ /* This is only used within the step-resume range/frame. */
+ gdb_assert (frame_id_eq (step_frame_id, get_frame_id (step_frame)));
+ gdb_assert (step_range_end != 0);
+ gdb_assert (get_frame_pc (step_frame) >= step_range_start
+ && get_frame_pc (step_frame) < step_range_end);
+
+ init_sal (&sr_sal); /* initialize to zeros */
+
+ sr_sal.pc = ADDR_BITS_REMOVE (get_frame_pc (step_frame));
+ sr_sal.section = find_pc_overlay (sr_sal.pc);
+
+ check_for_old_step_resume_breakpoint ();
+
+ step_resume_breakpoint
+ = set_momentary_breakpoint (sr_sal, get_frame_id (step_frame),
+ bp_step_resume);
+
+ if (breakpoints_inserted)
+ insert_breakpoints ();
+}
+
/* We've just entered a callee, and we wish to resume until it returns
to the caller. Setting a step_resume breakpoint on the return
address will catch a return from the callee.
/* If we've just finished a special step resume and we don't
want to hit a breakpoint, pull em out. */
if (step_resume_breakpoint == NULL
- && through_sigtramp_breakpoint == NULL
&& ecs->remove_breakpoints_on_following_step)
{
ecs->remove_breakpoints_on_following_step = 0;
remove_breakpoints ();
breakpoints_inserted = 0;
}
- else if (!breakpoints_inserted &&
- (through_sigtramp_breakpoint != NULL || !ecs->another_trap))
+ else if (!breakpoints_inserted && !ecs->another_trap)
{
breakpoints_failed = insert_breakpoints ();
if (breakpoints_failed)
# An alarm has been signaled, give the signal time to get delivered.
sleep 2
- # i386 BSD currently fails the next test with a SIGTRAP.
- setup_xfail "i*86-*-bsd*"
- # But Dynix has a DECR_PC_AFTER_BREAK of zero, so the failure
- # is shadowed by hitting the through_sigtramp_breakpoint.
- clear_xfail "i*86-sequent-bsd*"
- # Univel SVR4 i386 continues instead of stepping.
- setup_xfail "i*86-univel-sysv4*"
- # lynx fails with "next" acting like "continue"
- setup_xfail "*-*-*lynx*"
- # linux (aout versions) also fails with "next" acting like "continue"
- # this is probably more dependant on the kernel version than on the
- # object file format or utils. (sigh)
- setup_xfail "i*86-pc-linuxaout-gnu" "i*86-pc-linuxoldld-gnu"
- send_gdb "next\n"
- gdb_expect {
- -re "alarm .*$gdb_prompt $" { pass "next to 2nd alarm (1)" }
- -re "Program received signal SIGTRAP.*first.*$gdb_prompt $" {
-
- # This can happen on machines that have a trace flag
- # in their PS register.
- # The trace flag in the PS register will be set due to
- # the `next' command.
- # Before calling the signal handler, the PS register
- # is pushed along with the context on the user stack.
- # When the signal handler has finished, it reenters the
- # the kernel via a sigreturn syscall, which restores the
- # PS register along with the context.
- # If the kernel erroneously does not clear the trace flag
- # in the pushed context, gdb will receive a SIGTRAP from
- # the set trace flag in the restored context after the
- # signal handler has finished.
-
- # I do not yet understand why the SIGTRAP does not occur
- # after stepping the instruction at the restored PC on
- # i386 BSDI 1.0 systems.
-
- # Note that the vax under Ultrix also exhibits
- # this behaviour (it is uncovered by the `continue from
- # a break in a signal handler' test below).
- # With this test the failure is shadowed by hitting the
- # through_sigtramp_breakpoint upon return from the signal
- # handler.
-
- # SVR4 and Linux based i*86 systems exhibit this behaviour
- # as well (it is uncovered by the `continue from a break
- # in a signal handler' test below).
- # As these systems use procfs, where we tell the kernel not
- # to tell gdb about `pass' signals, and the trace flag is
- # cleared by the kernel before entering the sigtramp
- # routine, GDB will not notice the execution of the signal
- # handler.
- # Upon return from the signal handler, GDB will receive
- # a SIGTRAP from the set trace flag in the restored context.
- # The SIGTRAP marks the end of a (albeit long winded)
- # single step for GDB, causing this test to pass.
-
- fail "next to 2nd alarm (1) (probably kernel bug)"
- gdb_test "next" "alarm.*" "next to 2nd alarm (1)"
- }
- -re "Program exited with code.*$gdb_prompt $" {
-
- # This is apparently a bug in the UnixWare kernel (but
- # has not been investigated beyond the
- # resume/target_wait level, and has not been reported
- # to Univel). If it steps when a signal is pending,
- # it does a continue instead. I don't know whether
- # there is a workaround.
-
- # Perhaps this problem exists on other SVR4 systems;
- # but (a) we have no reason to think so, and (b) if we
- # put a wrong xfail here, we never get an XPASS to let
- # us know that it was incorrect (and then if such a
- # configuration regresses we have no way of knowing).
- # Solaris is not a relevant data point either way
- # because it lacks single stepping.
-
- # fnf: I don't agree with the above philosophy. We
- # can never be sure that any particular XFAIL is
- # specified 100% correctly in that no systems with
- # the bug are missed and all systems without the bug
- # are excluded. If we include an XFAIL that isn't
- # appropriate for a particular system, then when that
- # system gets tested it will XPASS, and someone should
- # investigate and fix the setup_xfail as appropriate,
- # or more preferably, the actual bug. Each such case
- # adds more data to narrowing down the scope of the
- # problem and ultimately fixing it.
-
- setup_xfail "i*86-*-sysv4*"
- fail "'next' behaved as 'continue (known SVR4 bug)'"
- return 0
- }
- -re ".*$gdb_prompt $" { fail "next to 2nd alarm (1)" }
- timeout { fail "next to 2nd alarm (1); (timeout)" }
- eof { fail "next to 2nd alarm (1); (eof)" }
- }
+ # NOTE: cagney/2004-05-09: The following is retained as an
+ # historical reference. Because signal delivery when doing a
+ # next has been changed to use a continue, and not a
+ # single-step, the kernel bug of a stuck trace-bit in the
+ # trampoline's saved PS register is avoided.
+
+ # This can happen on machines that have a trace flag in their
+ # PS register. The trace flag in the PS register will be set
+ # due to the `next' command. Before calling the signal
+ # handler, the PS register is pushed along with the context on
+ # the user stack. When the signal handler has finished, it
+ # reenters the the kernel via a sigreturn syscall, which
+ # restores the PS register along with the context. If the
+ # kernel erroneously does not clear the trace flag in the
+ # pushed context, gdb will receive a SIGTRAP from the set
+ # trace flag in the restored context after the signal handler
+ # has finished.
+
+ # I do not yet understand why the SIGTRAP does not occur after
+ # stepping the instruction at the restored PC on i386 BSDI 1.0
+ # systems.
+
+ # Note that the vax under Ultrix also exhibits this behaviour
+ # (it is uncovered by the `continue from a break in a signal
+ # handler' test below). With this test the failure is
+ # shadowed by hitting the through_sigtramp_breakpoint upon
+ # return from the signal handler.
+
+ # SVR4 and Linux based i*86 systems exhibit this behaviour as
+ # well (it is uncovered by the `continue from a break in a
+ # signal handler' test below). As these systems use procfs,
+ # where we tell the kernel not to tell gdb about `pass'
+ # signals, and the trace flag is cleared by the kernel before
+ # entering the sigtramp routine, GDB will not notice the
+ # execution of the signal handler. Upon return from the
+ # signal handler, GDB will receive a SIGTRAP from the set
+ # trace flag in the restored context. The SIGTRAP marks the
+ # end of a (albeit long winded) single step for GDB, causing
+ # this test to pass.
+
+ gdb_test "next" "alarm .*" "next to 2nd alarm"
gdb_test "break handler" "Breakpoint \[0-9\]+ .*"
gdb_test "next" "\\+\\+count; /\\* second \\*/" \
gdb_test "break func1" "Breakpoint \[0-9\]+ .*"
gdb_test "break func2" "Breakpoint \[0-9\]+ .*"
- # Vax Ultrix and i386 BSD currently fail the next test with
- # a SIGTRAP, but with different symptoms.
- setup_xfail "vax-*-ultrix*"
- setup_xfail "i*86-*-bsd*"
- setup_xfail "i*86-*-freebsd*"
- setup_xfail "i*86-pc-linux-gnu*"
- setup_xfail "i*86-*-solaris2*"
- send_gdb "continue\n"
- gdb_expect {
- -re "Breakpoint.*func1.*$gdb_prompt $" { pass "continue to func1" }
- -re "Program received signal SIGTRAP.*second.*$gdb_prompt $" {
-
- # See explanation for `next to 2nd alarm (1)' fail above.
- # We did step into the signal handler, hit a breakpoint
- # in the handler and continued from the breakpoint.
- # The set trace flag in the restored context is causing
- # the SIGTRAP, without stepping an instruction.
-
- fail "continue to func1 (probably kernel bug)"
- gdb_test "continue" "Breakpoint.*func1.*" \
- "extra continue to func1"
- }
- -re "Program received signal SIGTRAP.*func1 ..;.*$gdb_prompt $" {
+ # NOTE: cagney/2004-05-09: Ref "next to 2nd alarm" above.
+ # Because signal delivery when doing a next has been changed
+ # to use a continue, and not a single-step, the kernel bug of
+ # a stuck trace-bit in the trampoline's saved PS register is
+ # avoided.
- # On the vax under Ultrix the set trace flag in the restored
- # context is causing the SIGTRAP, but after stepping one
- # instruction, as expected.
-
- fail "continue to func1 (probably kernel bug)"
- gdb_test "continue" "Breakpoint.*func1.*" \
- "extra continue to func1"
- }
- -re ".*$gdb_prompt $" { fail "continue to func1" }
- default { fail "continue to func1" }
- }
+ gdb_test "continue" "Breakpoint.*func1.*" "continue to func1"
setup_xfail "*-*-irix*"
send_gdb "signal SIGUSR1\n"