From d303a6c766567886ef8ad122d6fcd4947a7a5954 Mon Sep 17 00:00:00 2001 From: Andrew Cagney Date: Mon, 10 May 2004 18:36:07 +0000 Subject: [PATCH] 2004-05-10 Andrew Cagney * infrun.c (check_sigtramp2): Delete function. (handle_inferior_event): When single stepping, and taking a signal, set a breakpoint at the signal return address. Delete redundant calls to check_sigtramp2. (insert_step_resume_breakpoint): New function. (through_sigtramp_breakpoint, handle_inferior_event) (follow_exec, wait_for_inferior, fetch_inferior_event) (currently_stepping, keep_going): Delete most uses of through_sigtramp_breakpoint, not that it should be deleted. (delete_breakpoint_current_contents): Delete function. Index: testsuite/ChangeLog 2004-05-10 Andrew Cagney * gdb.base/signals.exp (signal_tests_1): Simplify "continue to func1" and "next to 2nd alarm", kernel bug avoided. --- gdb/ChangeLog | 13 ++ gdb/infrun.c | 191 +++++++++-------------------- gdb/testsuite/ChangeLog | 5 + gdb/testsuite/gdb.base/signals.exp | 177 +++++++------------------- 4 files changed, 126 insertions(+), 260 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 8f7be5e6450..5e77fcf06b1 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2004-05-10 Andrew Cagney + + * infrun.c (check_sigtramp2): Delete function. + (handle_inferior_event): When single stepping, and taking a + signal, set a breakpoint at the signal return address. Delete + redundant calls to check_sigtramp2. + (insert_step_resume_breakpoint): New function. + (through_sigtramp_breakpoint, handle_inferior_event) + (follow_exec, wait_for_inferior, fetch_inferior_event) + (currently_stepping, keep_going): Delete most uses of + through_sigtramp_breakpoint, not that it should be deleted. + (delete_breakpoint_current_contents): Delete function. + 2004-05-10 Randolph Chung * config/pa/linux.mt (TM_FILE): Use new tm-linux.h for hppa-linux diff --git a/gdb/infrun.c b/gdb/infrun.c index 88c429ae6a5..79e681c944d 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -60,8 +60,6 @@ static void resume_cleanups (void *); static int hook_stop_stub (void *); -static void delete_breakpoint_current_contents (void *); - static int restore_selected_frame (void *); static void build_infrun (void); @@ -305,6 +303,8 @@ static int breakpoints_failed; 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 @@ -423,9 +423,6 @@ follow_exec (int pid, char *execd_pathname) 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); @@ -905,17 +902,6 @@ init_wait_for_inferior (void) 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; - } -} /* 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 @@ -984,9 +970,10 @@ void init_execution_control_state (struct execution_control_state *ecs); 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); @@ -1008,8 +995,6 @@ wait_for_inferior (void) 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. */ @@ -1070,8 +1055,6 @@ fetch_inferior_event (void *client_data) { 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); @@ -1989,15 +1972,9 @@ handle_inferior_event (struct execution_control_state *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 { @@ -2080,39 +2057,22 @@ process_event_stop_test: 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; } @@ -2153,13 +2113,6 @@ process_event_stop_test: { 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 */ @@ -2207,9 +2160,8 @@ process_event_stop_test: 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; @@ -2217,9 +2169,8 @@ process_event_stop_test: 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; @@ -2251,10 +2202,6 @@ process_event_stop_test: 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) @@ -2398,9 +2345,6 @@ process_event_stop_test: /* 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; } @@ -2408,9 +2352,6 @@ process_event_stop_test: 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; } @@ -2422,9 +2363,6 @@ process_event_stop_test: 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; } @@ -2688,50 +2626,13 @@ process_event_stop_test: 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. */ @@ -2809,6 +2710,38 @@ step_into_function (struct execution_control_state *ecs) 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. @@ -2933,15 +2866,13 @@ keep_going (struct execution_control_state *ecs) /* 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) diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 5276de71d7c..29a29cbc591 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2004-05-10 Andrew Cagney + + * gdb.base/signals.exp (signal_tests_1): Simplify "continue to + func1" and "next to 2nd alarm", kernel bug avoided. + 2004-05-10 Daniel Jacobowitz PR external/1568 diff --git a/gdb/testsuite/gdb.base/signals.exp b/gdb/testsuite/gdb.base/signals.exp index a07e3a8500a..46ae2144c4e 100644 --- a/gdb/testsuite/gdb.base/signals.exp +++ b/gdb/testsuite/gdb.base/signals.exp @@ -60,102 +60,47 @@ proc signal_tests_1 {} { # 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 \\*/" \ @@ -191,41 +136,13 @@ proc signal_tests_1 {} { 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" -- 2.30.2