diff options
author | Pedro Alves <palves@redhat.com> | 2014-10-27 20:24:59 +0000 |
---|---|---|
committer | Pedro Alves <palves@redhat.com> | 2014-10-27 20:26:12 +0000 |
commit | e5f8a7cc2d376c81749b6e4a4efc034201cf683c (patch) | |
tree | dde215ef253ca851fe7fa3ee9e2d849a1e211b06 /gdb/testsuite/gdb.base | |
parent | bf67003b4567600ed3022a439207ac8f26454f91 (diff) | |
download | gdb-e5f8a7cc2d376c81749b6e4a4efc034201cf683c.zip gdb-e5f8a7cc2d376c81749b6e4a4efc034201cf683c.tar.gz gdb-e5f8a7cc2d376c81749b6e4a4efc034201cf683c.tar.bz2 |
stepi/nexti: skip signal handler if "handle nostop" signal arrives
I noticed that "si" behaves differently when a "handle nostop" signal
arrives while the step is in progress, depending on whether the
program was stopped at a breakpoint when "si" was entered.
Specifically, in case GDB needs to step off a breakpoint, the handler
is skipped and the program stops in the next "mainline" instruction.
Otherwise, the "si" stops in the first instruction of the signal
handler.
I was surprised the testsuite doesn't catch this difference. Turns
out gdb.base/sigstep.exp covers a bunch of cases related to stepping
and signal handlers, but does not test stepi nor nexti, only
step/next/continue.
My first reaction was that stopping in the signal handler was the
correct thing to do, as it's where the next user-visible instruction
that is executed is. I considered then "nexti" -- a signal handler
could be reasonably considered a subroutine call to step over, it'd
seem intuitive to me that "nexti" would skip it.
But then, I realized that signals that arrive while a plain/line
"step" is in progress _also_ have their handler skipped. A user might
well be excused for being confused by this, given:
(gdb) help step
Step program until it reaches a different source line.
And the signal handler's sources will be in different source lines,
after all.
I think that having to explain that "stepi" steps into handlers, (and
that "nexti" wouldn't according to my reasoning above), while "step"
does not, is a sign of an awkward interface.
E.g., if a user truly is interested in stepping into signal handlers,
then it's odd that she has to either force the signal to "handle
stop", or recall to do "stepi" whenever such a signal might be
delivered. For that use case, it'd seem nicer to me if "step" also
stepped into handlers.
This suggests to me that we either need a global "step-into-handlers"
setting, or perhaps better, make "handle pass/nopass stop/nostop
print/noprint" have have an additional axis - "handle
stepinto/nostepinto", so that the user could configure whether
handlers for specific signals should be stepped into.
In any case, I think it's simpler (and thus better) for all step
commands to behave the same. This commit thus makes "si/ni" skip
handlers for "handle nostop" signals that arrive while the command was
already in progress, like step/next do.
To be clear, nothing changes if the program was stopped for a signal,
and the user enters a stepping command _then_ -- GDB still steps into
the handler. The change concerns signals that don't cause a stop and
that arrive while the step is in progress.
Tested on x86_64 Fedora 20, native and gdbserver.
gdb/
2014-10-27 Pedro Alves <palves@redhat.com>
* infrun.c (handle_signal_stop): Also skip handlers when a random
signal arrives while handling a "stepi" or a "nexti". Set the
thread's 'step_after_step_resume_breakpoint' flag.
gdb/doc/
2014-10-27 Pedro Alves <palves@redhat.com>
* gdb.texinfo (Continuing and Stepping): Add cross reference to
info on stepping and signal handlers.
(Signals): Explain stepping and signal handlers. Add context
index entry, and cross references.
gdb/testsuite/
2014-10-27 Pedro Alves <palves@redhat.com>
* gdb.base/sigstep.c (dummy): New global.
(main): Issue a couple writes to the new global.
* gdb.base/sigstep.exp (get_next_pc, test_skip_handler): New
procedures.
(skip_over_handler): Use test_skip_handler.
(top level): Call skip_over_handler for stepi and nexti too.
(breakpoint_over_handler): Use test_skip_handler.
(top level): Call breakpoint_over_handler for stepi and nexti too.
Diffstat (limited to 'gdb/testsuite/gdb.base')
-rw-r--r-- | gdb/testsuite/gdb.base/sigstep.c | 7 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/sigstep.exp | 55 |
2 files changed, 47 insertions, 15 deletions
diff --git a/gdb/testsuite/gdb.base/sigstep.c b/gdb/testsuite/gdb.base/sigstep.c index aa2384a..cc69184 100644 --- a/gdb/testsuite/gdb.base/sigstep.c +++ b/gdb/testsuite/gdb.base/sigstep.c @@ -24,6 +24,7 @@ #include <errno.h> static volatile int done; +static volatile int dummy; static void handler (int sig) @@ -74,8 +75,10 @@ main () return 1; } } - /* Wait. */ - while (!done); + /* Wait. Issue a couple writes to a dummy volatile var to be + reasonably sure our simple "get-next-pc" logic doesn't + stumble on branches. */ + dummy = 0; dummy = 0; while (!done); done = 0; } return 0; diff --git a/gdb/testsuite/gdb.base/sigstep.exp b/gdb/testsuite/gdb.base/sigstep.exp index 184d46e..53152b8 100644 --- a/gdb/testsuite/gdb.base/sigstep.exp +++ b/gdb/testsuite/gdb.base/sigstep.exp @@ -269,9 +269,38 @@ proc skip_to_handler_entry { i } { gdb_test "clear *handler" ".*" "$prefix; clear handler" } -skip_to_handler_entry step -skip_to_handler_entry next -skip_to_handler_entry continue +foreach cmd {"stepi" "nexti" "step" "next" "continue"} { + skip_to_handler_entry $cmd +} + +# Get the address of where a single-step should land. + +proc get_next_pc {test} { + global gdb_prompt + global hex + + set next "" + gdb_test_multiple "x/2i \$pc" $test { + -re "$hex .*:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" { + set next $expect_out(1,string) + pass $test + } + } + + return $next +} + +# Test that the command skipped over the handler. + +proc test_skip_handler {prefix i} { + if {$i == "stepi" || $i == "nexti"} { + set next_pc [get_next_pc "$prefix; get next PC"] + gdb_test "$i" "dummy = 0.*" "$prefix; performing $i" + gdb_test "p /x \$pc" " = $next_pc" "$prefix; advanced" + } else { + gdb_test "$i" "done = 0.*" "$prefix; performing $i" + } +} # Try stepping when there's a signal pending but no breakpoints. # Should skip the handler advancing to the next line. @@ -295,13 +324,13 @@ proc skip_over_handler { i } { # Make the signal pending sleep 1 - - gdb_test "$i" "done = 0.*" "$prefix; performing $i" + + test_skip_handler $prefix $i } -skip_over_handler step -skip_over_handler next -skip_over_handler continue +foreach cmd {"stepi" "nexti" "step" "next" "continue"} { + skip_over_handler $cmd +} # Try stepping when there's a signal pending, a pre-existing # breakpoint at the current instruction, and a breakpoint in the @@ -385,7 +414,7 @@ breakpoint_to_handler_entry continue # Try stepping when there's a signal pending, and a pre-existing # breakpoint at the current instruction, and no breakpoint in the -# handler. Should advance to the next line. +# handler. Should advance to the next line/instruction. proc breakpoint_over_handler { i } { global gdb_prompt @@ -409,10 +438,10 @@ proc breakpoint_over_handler { i } { # Make the signal pending sleep 1 - gdb_test "$i" "done = 0.*" "$prefix; performing $i" + test_skip_handler $prefix $i gdb_test "clear $infinite_loop" ".*" "$prefix; clear infinite loop" } -breakpoint_over_handler step -breakpoint_over_handler next -breakpoint_over_handler continue +foreach cmd {"stepi" "nexti" "step" "next" "continue"} { + breakpoint_over_handler $cmd +} |