old-cross-binutils/gdb/testsuite/gdb.threads/stepi-random-signal.exp
Pedro Alves b5ee5a50d4 Fix gdb.threads/stepi-random-signal.exp on software single-step targets.
Currently on software single-step Linux targets we get:

 (gdb) PASS: gdb.threads/stepi-random-signal.exp: before stepi: get hexadecimal valueof "$pc"
 stepi
 infrun: clear_proceed_status_thread (Thread 0x7ffff7fca700 (LWP 7073))
 infrun: clear_proceed_status_thread (Thread 0x7ffff7fcb740 (LWP 7069))
 infrun: proceed (addr=0xffffffffffffffff, signal=GDB_SIGNAL_DEFAULT, step=1)
 infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=0, current thread [Thread 0x7ffff7fcb740 (LWP 7069)] at 0x400700
 infrun: wait_for_inferior ()
 infrun: target_wait (-1, status) =
 infrun:   7069 [Thread 0x7ffff7fcb740 (LWP 7069)],
 infrun:   status->kind = stopped, signal = GDB_SIGNAL_TRAP
 infrun: infwait_normal_state
 infrun: TARGET_WAITKIND_STOPPED
 infrun: stop_pc = 0x400704
 infrun: software single step trap for Thread 0x7ffff7fcb740 (LWP 7069)
 infrun: stepi/nexti
 infrun: stop_stepping
 44        while (counter != 0)
 (gdb) FAIL: gdb.threads/stepi-random-signal.exp: stepi (no random signal)

Vs hardware-step targets:

 (gdb) PASS: gdb.threads/stepi-random-signal.exp: before stepi: get hexadecimal valueof "$pc"
 stepi
 infrun: clear_proceed_status_thread (Thread 0x7ffff7fca700 (LWP 9565))
 infrun: clear_proceed_status_thread (Thread 0x7ffff7fcb740 (LWP 9561))
 infrun: proceed (addr=0xffffffffffffffff, signal=GDB_SIGNAL_DEFAULT, step=1)
 infrun: resume (step=1, signal=GDB_SIGNAL_0), trap_expected=0, current thread [Thread 0x7ffff7fcb740 (LWP 9561)] at 0x400700
 infrun: wait_for_inferior ()
 infrun: target_wait (-1, status) =
 infrun:   9561 [Thread 0x7ffff7fcb740 (LWP 9561)],
 infrun:   status->kind = stopped, signal = GDB_SIGNAL_CHLD
 infrun: infwait_normal_state
 infrun: TARGET_WAITKIND_STOPPED
 infrun: stop_pc = 0x400700
 infrun: random signal (GDB_SIGNAL_CHLD)
 infrun: random signal, keep going
 infrun: resume (step=1, signal=GDB_SIGNAL_CHLD), trap_expected=0, current thread [Thread 0x7ffff7fcb740 (LWP 9561)] at 0x400700
 infrun: prepare_to_wait
 infrun: target_wait (-1, status) =
 infrun:   9561 [Thread 0x7ffff7fcb740 (LWP 9561)],
 infrun:   status->kind = stopped, signal = GDB_SIGNAL_TRAP
 infrun: infwait_normal_state
 infrun: TARGET_WAITKIND_STOPPED
 infrun: stop_pc = 0x400704
 infrun: stepi/nexti
 infrun: stop_stepping
 44        while (counter != 0)
 (gdb) PASS: gdb.threads/stepi-random-signal.exp: stepi

The test turns on infrun debug, does a stepi while a SIGCHLD is
pending, and checks whether the "random signal" paths in infrun.c are
taken.

On the software single-step variant above, those paths were not taken.

This is a test bug.

The Linux backend short-circuits reporting signals that are set to
pass/nostop/noprint.  But _only_ if the thread is _not_
single-stepping.  So on hardware-step targets, even though the signal
is set to pass/nostop/noprint by default, the thread is indeed told to
single-step, and so the core sees the signal.  On the other hand, on
software single-step architectures, the backend never actually gets a
single-step request (steps are emulated by setting a breakpoint at the
next pc, and then the target told to continue, not step).  So the
short-circuiting code triggers and the core doesn't see the signal.

The fix is to make the test be sure the target doesn't bypass
reporting the signal to the core.

Tested on x86_64 Fedora 17, both with and without a series that
implements software single-step for x86_64.

gdb/testsuite/
2014-02-07  Pedro Alves  <palves@redhat.com>

	* gdb.threads/stepi-random-signal.exp: Set SIGCHLD to print.
2014-02-07 19:04:10 +00:00

109 lines
3 KiB
Text

# Copyright 2013-2014 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/>.
standard_testfile
set executable ${testfile}
if { [gdb_compile_pthreads \
"${srcdir}/${subdir}/${srcfile}" \
"${binfile}" \
executable {debug}] != "" } {
untested "Couldn't compile test program."
return -1
}
clean_restart $executable
# Start the second thread.
if ![runto start] {
return -1
}
# Go back to the main thread, and leave it in the loop, where we're
# reasonably sure we don't have 'conditional jmp $pc'-like
# instructions. We wouldn't be able to detect whether a stepi makes
# progress over those.
gdb_test_no_output "set scheduler-locking on"
gdb_test "thread 1" "Switching to .*"
gdb_breakpoint $srcfile:[gdb_get_line_number "set break 2 here"]
gdb_continue_to_breakpoint "loop" ".* set break 2 here .*"
# Now back to thread 2, and let it queue a signal in thread 1.
gdb_test "thread 2" "Switching to .*"
gdb_breakpoint $srcfile:[gdb_get_line_number "set break here"]
gdb_continue_to_breakpoint "after pthread_kill" ".* set break here .*"
# We're now ready to stepi thread 1. It should immediately dequeue
# the signal.
gdb_test "thread 1" "Switching to .*" "thread 1 again"
# No longer need these.
delete_breakpoints
# Turn on infrun debugging, so we can tell whether the signal is
# really dequeued and that GDB sees it.
gdb_test_no_output "set debug infrun 1"
# Make sure the target backend reports the signal to GDB core. Some
# backends (like Linux) skip reporting a signal if set to
# pass/nostop/noprint, resuming the thread immediately instead.
gdb_test "handle SIGCHLD print"
# Helper to extract the current PC. PREFIX is used to make each call
# have its own unique test name.
proc get_pc { prefix } {
with_test_prefix "$prefix" {
return [get_hexadecimal_valueof "\$pc" ""]
}
}
set prev_addr [get_pc "before stepi"]
if {$prev_addr == ""} {
return
}
# True if we saw the infrun path we want to test be exercised.
set seen 0
set test "stepi"
if {[gdb_test_multiple "stepi" "$test" {
-re "infrun: random signal" {
set seen 1
exp_continue
}
-re "$gdb_prompt $" {
}
}] != 0} {
return
}
if {$seen} {
pass "$test"
} else {
fail "$test (no random signal)"
}
set addr [get_pc "after stepi"]
if {$addr == ""} {
return
}
set test "stepi interfered by signal makes progress"
if {$addr == $prev_addr} {
fail "$test"
} else {
pass "$test"
}