b5ee5a50d4
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.
109 lines
3 KiB
Text
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"
|
|
}
|