diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index a64289ea009..cada90d15ea 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,15 @@ +2014-10-28 Pedro Alves <palves@redhat.com> + + PR gdb/17511 + * gdb.base/sigstep.c (handler): Add a few more writes to 'done'. + * gdb.base/sigstep.exp (other_handler_location): New global. + (advance): Support stepping into the signal handler, and running + commands while in the handler. + (in_handler_map): New global. + (top level): In the advance test, add combinations for getting + into the handler with stepping commands, and for running commands + in the handler. Add comment descripting the advancei tests. + 2014-10-28 Pedro Alves <palves@redhat.com> * gdb.base/sigstep.exp: Use build_executable instead of diff --git a/gdb/testsuite/gdb.base/sigstep.c b/gdb/testsuite/gdb.base/sigstep.c index cc691843abb..38dd1fb1c2e 100644 --- a/gdb/testsuite/gdb.base/sigstep.c +++ b/gdb/testsuite/gdb.base/sigstep.c @@ -29,7 +29,12 @@ static volatile int dummy; static void handler (int sig) { + /* This is more than one write so that the breakpoint location below + is more than one instruction away. */ done = 1; + done = 1; + done = 1; + done = 1; /* other handler location */ } /* handler */ struct itimerval itime; diff --git a/gdb/testsuite/gdb.base/sigstep.exp b/gdb/testsuite/gdb.base/sigstep.exp index ef98b3d0e11..08ad828f121 100644 --- a/gdb/testsuite/gdb.base/sigstep.exp +++ b/gdb/testsuite/gdb.base/sigstep.exp @@ -36,6 +36,7 @@ if {[build_executable $testfile.exp $testfile $srcfile debug]} { set clear_done [gdb_get_line_number {done = 0}] set infinite_loop [gdb_get_line_number {while (!done)}] +set other_handler_location [gdb_get_line_number "other handler location"] # Restart GDB, set a display showing $PC, and run to main. @@ -72,29 +73,48 @@ proc validate_backtrace {} { validate_backtrace -proc advance { cmd } { - global gdb_prompt inferior_exited_re +# Goes to handler using ENTER_CMD, runs IN_HANDLER while in the signal +# hander, and then steps out of the signal handler using EXIT_CMD. - with_test_prefix "$cmd from handler" { +proc advance { enter_cmd in_handler_prefix in_handler exit_cmd } { + global gdb_prompt inferior_exited_re + global clear_done other_handler_location + + set prefix "$enter_cmd to handler, $in_handler_prefix in handler, $exit_cmd from handler" + + with_test_prefix $prefix { restart - gdb_test "break handler" - # Get us into the handler - gdb_test "continue" ".* handler .*" "continue to handler" + if { $enter_cmd == "continue" } { + gdb_test "break handler" + } else { + gdb_test "handle SIGALRM print pass stop" + gdb_test "handle SIGVTALRM print pass stop" + gdb_test "continue" "Program received signal.*" "continue to signal" + } + gdb_test "$enter_cmd" ".*handler .*" "$enter_cmd to handler" + + delete_breakpoints + + uplevel 1 $in_handler + + if { $exit_cmd == "continue" } { + gdb_test "break $clear_done" ".*" "break clear done" + } set test "leave handler" - gdb_test_multiple "$cmd" "${test}" { + gdb_test_multiple "$exit_cmd" "${test}" { -re "Could not insert single-step breakpoint.*$gdb_prompt $" { setup_kfail gdb/8841 "sparc*-*-openbsd*" fail "$test (could not insert single-step breakpoint)" } -re "done = 1;.*${gdb_prompt} $" { - send_gdb "$cmd\n" + send_gdb "$exit_cmd\n" exp_continue -continue_timer } -re "\} .. handler .*${gdb_prompt} $" { - send_gdb "$cmd\n" + send_gdb "$exit_cmd\n" exp_continue -continue_timer } -re "$inferior_exited_re normally.*${gdb_prompt} $" { @@ -114,6 +134,55 @@ proc advance { cmd } { } } +# Map of PREFIX => "things to do within the signal handler", for the +# advance tests. + +set in_handler_map { + "nothing" { + } + "si+advance" { + # Advance to the second location in handler. + gdb_test "si" "handler.*" "si in handler" + + set test "advance in handler" + gdb_test_multiple "advance $other_handler_location" $test { + -re "Program received signal SIGTRAP.*$gdb_prompt $" { + # On some versions of Linux (observed on + # 3.16.4-200.fc20.x86_64), using PTRACE_SINGLESTEP+sig + # to step into a signal handler, and then issuing + # another PTRACE_SINGLESTEP within the handler ends up + # with $eflags.TF mistakenly set, which results in + # subsequent PTRACE_CONTINUEs trapping after each + # insn. + if {$enter_cmd != "continue"} { + setup_xfail "x86_64-*-linux*" gdb/17511 + } + fail "$test (spurious SIGTRAP)" + return + } + -re "other handler location.*$gdb_prompt $" { + pass $test + } + } + } +} + +# Check that we can step/next/continue, etc. our way in and out of a +# signal handler. Also test that we can step, and run to a breakpoint +# within the handler. + +foreach enter_cmd { "stepi" "nexti" "step" "next" "continue" } { + if { $enter_cmd != "continue" && ![can_single_step_to_signal_handler] } { + continue + } + + foreach exit_cmd { "step" "next" "continue" } { + foreach {in_handler_prefix in_handler} $in_handler_map { + advance $enter_cmd $in_handler_prefix $in_handler $exit_cmd + } + } +} + proc advancei { cmd } { global gdb_prompt inferior_exited_re @@ -199,11 +268,9 @@ proc advancei { cmd } { } } -# Check that we can step/next our way out of a signal handler. - -foreach cmd {"step" "next"} { - advance $cmd -} +# Check that we can step our way out of a signal handler, using +# commands that first step out to the signal trampoline, and then out +# to the mainline code. foreach cmd {"stepi" "nexti" "finish" "return"} { advancei $cmd