gdb/
* infrun.c (proceed): Revert previous change. (resume): Instead, handle the case of signal delivery while stepping off a breakpoint location here, and only if software single-stepping is used. Handle nested signals. gdb/testsuite/ * gdb.base/signest.exp: New file. * gdb.base/signest.c: Likewise.
This commit is contained in:
parent
e0605dbe1c
commit
3085278312
5 changed files with 195 additions and 36 deletions
|
@ -1,3 +1,10 @@
|
||||||
|
2011-04-28 Ulrich Weigand <ulrich.weigand@linaro.org>
|
||||||
|
|
||||||
|
* infrun.c (proceed): Revert previous change.
|
||||||
|
(resume): Instead, handle the case of signal delivery while stepping
|
||||||
|
off a breakpoint location here, and only if software single-stepping
|
||||||
|
is used. Handle nested signals.
|
||||||
|
|
||||||
2011-04-28 Yao Qi <yao@codesourcery.com>
|
2011-04-28 Yao Qi <yao@codesourcery.com>
|
||||||
|
|
||||||
* arm-tdep.c (copy_unmodified): Rename to ...
|
* arm-tdep.c (copy_unmodified): Rename to ...
|
||||||
|
|
99
gdb/infrun.c
99
gdb/infrun.c
|
@ -1703,6 +1703,51 @@ a command like `return' or `jump' to continue execution."));
|
||||||
else if (step)
|
else if (step)
|
||||||
step = maybe_software_singlestep (gdbarch, pc);
|
step = maybe_software_singlestep (gdbarch, pc);
|
||||||
|
|
||||||
|
/* Currently, our software single-step implementation leads to different
|
||||||
|
results than hardware single-stepping in one situation: when stepping
|
||||||
|
into delivering a signal which has an associated signal handler,
|
||||||
|
hardware single-step will stop at the first instruction of the handler,
|
||||||
|
while software single-step will simply skip execution of the handler.
|
||||||
|
|
||||||
|
For now, this difference in behavior is accepted since there is no
|
||||||
|
easy way to actually implement single-stepping into a signal handler
|
||||||
|
without kernel support.
|
||||||
|
|
||||||
|
However, there is one scenario where this difference leads to follow-on
|
||||||
|
problems: if we're stepping off a breakpoint by removing all breakpoints
|
||||||
|
and then single-stepping. In this case, the software single-step
|
||||||
|
behavior means that even if there is a *breakpoint* in the signal
|
||||||
|
handler, GDB still would not stop.
|
||||||
|
|
||||||
|
Fortunately, we can at least fix this particular issue. We detect
|
||||||
|
here the case where we are about to deliver a signal while software
|
||||||
|
single-stepping with breakpoints removed. In this situation, we
|
||||||
|
revert the decisions to remove all breakpoints and insert single-
|
||||||
|
step breakpoints, and instead we install a step-resume breakpoint
|
||||||
|
at the current address, deliver the signal without stepping, and
|
||||||
|
once we arrive back at the step-resume breakpoint, actually step
|
||||||
|
over the breakpoint we originally wanted to step over. */
|
||||||
|
if (singlestep_breakpoints_inserted_p
|
||||||
|
&& tp->control.trap_expected && sig != TARGET_SIGNAL_0)
|
||||||
|
{
|
||||||
|
/* If we have nested signals or a pending signal is delivered
|
||||||
|
immediately after a handler returns, might might already have
|
||||||
|
a step-resume breakpoint set on the earlier handler. We cannot
|
||||||
|
set another step-resume breakpoint; just continue on until the
|
||||||
|
original breakpoint is hit. */
|
||||||
|
if (tp->control.step_resume_breakpoint == NULL)
|
||||||
|
{
|
||||||
|
insert_step_resume_breakpoint_at_frame (get_current_frame ());
|
||||||
|
tp->step_after_step_resume_breakpoint = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_single_step_breakpoints ();
|
||||||
|
singlestep_breakpoints_inserted_p = 0;
|
||||||
|
|
||||||
|
insert_breakpoints ();
|
||||||
|
tp->control.trap_expected = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (should_resume)
|
if (should_resume)
|
||||||
{
|
{
|
||||||
ptid_t resume_ptid;
|
ptid_t resume_ptid;
|
||||||
|
@ -2064,6 +2109,24 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
|
||||||
/* prepare_to_proceed may change the current thread. */
|
/* prepare_to_proceed may change the current thread. */
|
||||||
tp = inferior_thread ();
|
tp = inferior_thread ();
|
||||||
|
|
||||||
|
if (oneproc)
|
||||||
|
{
|
||||||
|
tp->control.trap_expected = 1;
|
||||||
|
/* If displaced stepping is enabled, we can step over the
|
||||||
|
breakpoint without hitting it, so leave all breakpoints
|
||||||
|
inserted. Otherwise we need to disable all breakpoints, step
|
||||||
|
one instruction, and then re-add them when that step is
|
||||||
|
finished. */
|
||||||
|
if (!use_displaced_stepping (gdbarch))
|
||||||
|
remove_breakpoints ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can insert breakpoints if we're not trying to step over one,
|
||||||
|
or if we are stepping over one but we're using displaced stepping
|
||||||
|
to do so. */
|
||||||
|
if (! tp->control.trap_expected || use_displaced_stepping (gdbarch))
|
||||||
|
insert_breakpoints ();
|
||||||
|
|
||||||
if (!non_stop)
|
if (!non_stop)
|
||||||
{
|
{
|
||||||
/* Pass the last stop signal to the thread we're resuming,
|
/* Pass the last stop signal to the thread we're resuming,
|
||||||
|
@ -2133,42 +2196,6 @@ proceed (CORE_ADDR addr, enum target_signal siggnal, int step)
|
||||||
/* Reset to normal state. */
|
/* Reset to normal state. */
|
||||||
init_infwait_state ();
|
init_infwait_state ();
|
||||||
|
|
||||||
/* Stepping over a breakpoint while at the same time delivering a signal
|
|
||||||
has a problem: we cannot use displaced stepping, but we also cannot
|
|
||||||
use software single-stepping, because we do not know where execution
|
|
||||||
will continue if a signal handler is installed.
|
|
||||||
|
|
||||||
On the other hand, if there is a signal handler we'd have to step
|
|
||||||
over it anyway. So what we do instead is to install a step-resume
|
|
||||||
handler at the current address right away, deliver the signal without
|
|
||||||
stepping, and once we arrive back at the step-resume breakpoint, step
|
|
||||||
once more over the original breakpoint we wanted to step over. */
|
|
||||||
if (oneproc && tp->suspend.stop_signal != TARGET_SIGNAL_0
|
|
||||||
&& execution_direction != EXEC_REVERSE)
|
|
||||||
{
|
|
||||||
insert_step_resume_breakpoint_at_frame (get_current_frame ());
|
|
||||||
tp->step_after_step_resume_breakpoint = 1;
|
|
||||||
oneproc = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oneproc)
|
|
||||||
{
|
|
||||||
tp->control.trap_expected = 1;
|
|
||||||
/* If displaced stepping is enabled, we can step over the
|
|
||||||
breakpoint without hitting it, so leave all breakpoints
|
|
||||||
inserted. Otherwise we need to disable all breakpoints, step
|
|
||||||
one instruction, and then re-add them when that step is
|
|
||||||
finished. */
|
|
||||||
if (!use_displaced_stepping (gdbarch))
|
|
||||||
remove_breakpoints ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We can insert breakpoints if we're not trying to step over one,
|
|
||||||
or if we are stepping over one but we're using displaced stepping
|
|
||||||
to do so. */
|
|
||||||
if (! tp->control.trap_expected || use_displaced_stepping (gdbarch))
|
|
||||||
insert_breakpoints ();
|
|
||||||
|
|
||||||
/* Resume inferior. */
|
/* Resume inferior. */
|
||||||
resume (oneproc || step || bpstat_should_step (), tp->suspend.stop_signal);
|
resume (oneproc || step || bpstat_should_step (), tp->suspend.stop_signal);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2011-04-28 Ulrich Weigand <ulrich.weigand@linaro.org>
|
||||||
|
|
||||||
|
* gdb.base/signest.exp: New file.
|
||||||
|
* gdb.base/signest.c: Likewise.
|
||||||
|
|
||||||
2011-04-28 Jan Kratochvil <jan.kratochvil@redhat.com>
|
2011-04-28 Jan Kratochvil <jan.kratochvil@redhat.com>
|
||||||
|
|
||||||
* lib/mi-support.exp (mi_expect_stop) <stopped at wrong place>: Accept
|
* lib/mi-support.exp (mi_expect_stop) <stopped at wrong place>: Accept
|
||||||
|
|
53
gdb/testsuite/gdb.base/signest.c
Normal file
53
gdb/testsuite/gdb.base/signest.c
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/* This testcase is part of GDB, the GNU debugger.
|
||||||
|
|
||||||
|
Copyright 2011 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
volatile char *p = NULL;
|
||||||
|
|
||||||
|
extern long
|
||||||
|
bowler (void)
|
||||||
|
{
|
||||||
|
return *p;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void
|
||||||
|
keeper (int sig)
|
||||||
|
{
|
||||||
|
static int recurse = 0;
|
||||||
|
if (++recurse < 3)
|
||||||
|
bowler ();
|
||||||
|
|
||||||
|
_exit (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main (void)
|
||||||
|
{
|
||||||
|
struct sigaction act;
|
||||||
|
memset (&act, 0, sizeof act);
|
||||||
|
act.sa_handler = keeper;
|
||||||
|
act.sa_flags = SA_NODEFER;
|
||||||
|
sigaction (SIGSEGV, &act, NULL);
|
||||||
|
sigaction (SIGBUS, &act, NULL);
|
||||||
|
|
||||||
|
bowler ();
|
||||||
|
return 0;
|
||||||
|
}
|
67
gdb/testsuite/gdb.base/signest.exp
Normal file
67
gdb/testsuite/gdb.base/signest.exp
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# This testcase is part of GDB, the GNU debugger.
|
||||||
|
|
||||||
|
# Copyright 2011 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
set testfile "signest"
|
||||||
|
set srcfile ${testfile}.c
|
||||||
|
|
||||||
|
if [target_info exists gdb,nosignals] {
|
||||||
|
verbose "Skipping ${testfile}.exp because of nosignals."
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} {debug}] {
|
||||||
|
untested ${testfile}.exp
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
if ![runto_main] then {
|
||||||
|
untested ${testfile}.exp
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
# If we can examine what's at memory address 0, it is possible that we
|
||||||
|
# could also execute it. This could probably make us run away,
|
||||||
|
# executing random code, which could have all sorts of ill effects,
|
||||||
|
# especially on targets without an MMU. Don't run the tests in that
|
||||||
|
# case.
|
||||||
|
|
||||||
|
gdb_test_multiple "x 0" "memory at address 0" {
|
||||||
|
-re "0x0:.*Cannot access memory at address 0x0.*$gdb_prompt $" { }
|
||||||
|
-re "0x0:.*Error accessing memory address 0x0.*$gdb_prompt $" { }
|
||||||
|
-re ".*$gdb_prompt $" {
|
||||||
|
untested "Memory at address 0 is possibly executable"
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run until we hit the SIGSEGV (or SIGBUS on some platforms).
|
||||||
|
gdb_test "continue" \
|
||||||
|
".*Program received signal (SIGBUS|SIGSEGV).*bowler.*" \
|
||||||
|
"continue to fault"
|
||||||
|
|
||||||
|
# Insert conditional breakpoint at faulting instruction
|
||||||
|
gdb_test "break if 0" ".*" "set conditional breakpoint"
|
||||||
|
|
||||||
|
# Set SIGSEGV/SIGBUS to pass+nostop
|
||||||
|
gdb_test "handle SIGSEGV nostop print pass" ".*" "pass SIGSEGV"
|
||||||
|
gdb_test "handle SIGBUS nostop print pass" ".*" "pass SIGBUS"
|
||||||
|
|
||||||
|
# Step off the faulting instruction into the handler, triggering nested faults
|
||||||
|
gdb_test "continue" \
|
||||||
|
".*Program received signal (SIGBUS|SIGSEGV).*Program received signal (SIGBUS|SIGSEGV).*exited normally.*" \
|
||||||
|
"run through nested faults"
|
||||||
|
|
Loading…
Add table
Reference in a new issue