mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2024-11-27 14:00:30 +00:00
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.
This commit is contained in:
parent
bf67003b45
commit
e5f8a7cc2d
@ -1,3 +1,9 @@
|
||||
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.
|
||||
|
||||
2014-10-27 Luis Machado <lgustavo@codesourcery.com>
|
||||
|
||||
* arm-tdep.c (INSN_S_L_BIT_NUM): Document.
|
||||
|
@ -1,3 +1,10 @@
|
||||
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.
|
||||
|
||||
2014-10-20 Simon Marchi <simon.marchi@ericsson.com>
|
||||
|
||||
* python.texi (Breakpoints In Python): Add parenthesis after
|
||||
|
@ -5079,7 +5079,9 @@ line of source code, or one machine instruction (depending on what
|
||||
particular command you use). Either when continuing or when stepping,
|
||||
your program may stop even sooner, due to a breakpoint or a signal. (If
|
||||
it stops due to a signal, you may want to use @code{handle}, or use
|
||||
@samp{signal 0} to resume execution. @xref{Signals, ,Signals}.)
|
||||
@samp{signal 0} to resume execution (@pxref{Signals, ,Signals}),
|
||||
or you may step into the signal's handler (@pxref{stepping and signal
|
||||
handlers}).)
|
||||
|
||||
@table @code
|
||||
@kindex continue
|
||||
@ -5573,6 +5575,66 @@ a result of the fatal signal once it saw the signal. To prevent this,
|
||||
you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your
|
||||
Program a Signal}.
|
||||
|
||||
@cindex stepping and signal handlers
|
||||
@anchor{stepping and signal handlers}
|
||||
|
||||
@value{GDBN} optimizes for stepping the mainline code. If a signal
|
||||
that has @code{handle nostop} and @code{handle pass} set arrives while
|
||||
a stepping command (e.g., @code{stepi}, @code{step}, @code{next}) is
|
||||
in progress, @value{GDBN} lets the signal handler run and then resumes
|
||||
stepping the mainline code once the signal handler returns. In other
|
||||
words, @value{GDBN} steps over the signal handler. This prevents
|
||||
signals that you've specified as not interesting (with @code{handle
|
||||
nostop}) from changing the focus of debugging unexpectedly. Note that
|
||||
the signal handler itself may still hit a breakpoint, stop for another
|
||||
signal that has @code{handle stop} in effect, or for any other event
|
||||
that normally results in stopping the stepping command sooner. Also
|
||||
note that @value{GDBN} still informs you that the program received a
|
||||
signal if @code{handle print} is set.
|
||||
|
||||
@anchor{stepping into signal handlers}
|
||||
|
||||
If you set @code{handle pass} for a signal, and your program sets up a
|
||||
handler for it, then issuing a stepping command, such as @code{step}
|
||||
or @code{stepi}, when your program is stopped due to the signal will
|
||||
step @emph{into} the signal handler (if the target supports that).
|
||||
|
||||
Likewise, if you use the @code{queue-signal} command to queue a signal
|
||||
to be delivered to the current thread when execution of the thread
|
||||
resumes (@pxref{Signaling, ,Giving your Program a Signal}), then a
|
||||
stepping command will step into the signal handler.
|
||||
|
||||
Here's an example, using @code{stepi} to step to the first instruction
|
||||
of @code{SIGUSR1}'s handler:
|
||||
|
||||
@smallexample
|
||||
(@value{GDBP}) handle SIGUSR1
|
||||
Signal Stop Print Pass to program Description
|
||||
SIGUSR1 Yes Yes Yes User defined signal 1
|
||||
(@value{GDBP}) c
|
||||
Continuing.
|
||||
|
||||
Program received signal SIGUSR1, User defined signal 1.
|
||||
main () sigusr1.c:28
|
||||
28 p = 0;
|
||||
(@value{GDBP}) si
|
||||
sigusr1_handler () at sigusr1.c:9
|
||||
9 @{
|
||||
@end smallexample
|
||||
|
||||
The same, but using @code{queue-signal} instead of waiting for the
|
||||
program to receive the signal first:
|
||||
|
||||
@smallexample
|
||||
(@value{GDBP}) n
|
||||
28 p = 0;
|
||||
(@value{GDBP}) queue-signal SIGUSR1
|
||||
(@value{GDBP}) si
|
||||
sigusr1_handler () at sigusr1.c:9
|
||||
9 @{
|
||||
(@value{GDBP})
|
||||
@end smallexample
|
||||
|
||||
@cindex extra signal information
|
||||
@anchor{extra signal information}
|
||||
|
||||
@ -16654,6 +16716,9 @@ be used to pass a signal whose handling state has been set to @code{nopass}
|
||||
@end table
|
||||
@c @end group
|
||||
|
||||
@xref{stepping into signal handlers}, for information on how stepping
|
||||
commands behave when the thread has a signal queued.
|
||||
|
||||
@node Returning
|
||||
@section Returning from a Function
|
||||
|
||||
|
@ -4463,9 +4463,9 @@ handle_signal_stop (struct execution_control_state *ecs)
|
||||
return;
|
||||
}
|
||||
|
||||
if (ecs->event_thread->control.step_range_end != 0
|
||||
&& ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
|
||||
&& pc_in_thread_step_range (stop_pc, ecs->event_thread)
|
||||
if (ecs->event_thread->suspend.stop_signal != GDB_SIGNAL_0
|
||||
&& (pc_in_thread_step_range (stop_pc, ecs->event_thread)
|
||||
|| ecs->event_thread->control.step_range_end == 1)
|
||||
&& frame_id_eq (get_stack_frame_id (frame),
|
||||
ecs->event_thread->control.step_stack_frame_id)
|
||||
&& ecs->event_thread->control.step_resume_breakpoint == NULL)
|
||||
@ -4485,6 +4485,7 @@ handle_signal_stop (struct execution_control_state *ecs)
|
||||
"single-step range\n");
|
||||
|
||||
insert_hp_step_resume_breakpoint_at_frame (frame);
|
||||
ecs->event_thread->step_after_step_resume_breakpoint = 1;
|
||||
/* Reset trap_expected to ensure breakpoints are re-inserted. */
|
||||
ecs->event_thread->control.trap_expected = 0;
|
||||
keep_going (ecs);
|
||||
|
@ -1,3 +1,14 @@
|
||||
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.
|
||||
|
||||
2014-10-27 Yao Qi <yao@codesourcery.com>
|
||||
|
||||
* gdb.trace/tfile.c (adjust_function_address)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user