mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-21 04:42:53 +08:00
f489207efd
This patch fixes a problem on nios2-linux-gnu with stepping past the kernel helper __kuser_cmpxchg, which was exposed by the testcase gdb.threads/watchpoint-fork.exp. The kernel maps this function into user space on an unwritable page. In this testcase, the cmpxchg helper is invoked indirectly from the setbuf call in the test program. Since this target lacks hardware breakpoint/watchpoint support, GDB tries to single-step through the program by setting software breakpoints, and was just giving an error when it reached the function on the unwritable page. The solution here is to always step over the call instead of stepping into it; cmpxchg is supposed to be an atomic operation so this behavior seems reasonable. The hook in nios2_get_next_pc is somewhat generic, but at present cmpxchg is the only helper provided by the Linux kernel that is invoked by an ordinary function call. (Signal return trampolines also go through the unwritable page but not by a function call.) Fixing this issue also revealed that the testcase needs a much larger timeout factor when software single-stepping is used. That has also been fixed in this patch. gdb/ChangeLog 2019-03-28 Sandra Loosemore <sandra@codesourcery.com> * nios2-tdep.h (struct gdbarch_tdep): Add is_kernel_helper. * nios2-tdep.c (nios2_get_next_pc): Skip over kernel helpers. * nios2-linux-tdep.c (nios2_linux_is_kernel_helper): New. (nios2_linux_init_abi): Install it. gdb/testsuite/ChangeLog 2019-03-28 Sandra Loosemore <sandra@codesourcery.com> * gdb.threads/watchpoint-fork.exp (test): Use large timeout factor when no hardware watchpoint support.
153 lines
5.7 KiB
Plaintext
153 lines
5.7 KiB
Plaintext
# Copyright 2012-2019 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/>.
|
|
|
|
# Test case for forgotten hw-watchpoints after fork()-off of a process.
|
|
|
|
set testfile watchpoint-fork
|
|
|
|
proc test {type symbol} {
|
|
with_test_prefix "$type" {
|
|
global testfile subdir srcdir gdb_prompt
|
|
|
|
set srcfile_type ${srcdir}/${subdir}/${testfile}-${type}.c
|
|
|
|
# no threads
|
|
|
|
with_test_prefix "singlethreaded" {
|
|
set executable ${testfile}-${type}-st
|
|
set srcfile_main ${testfile}-st.c
|
|
if {[build_executable $testfile.exp $executable \
|
|
[list $srcfile_main ${testfile}-${type}.c] \
|
|
[list debug additional_flags=-D$symbol]] == -1} {
|
|
return -1
|
|
}
|
|
|
|
clean_restart $executable
|
|
|
|
if [target_info exists gdb,no_hardware_watchpoints] {
|
|
# The software watchpoint functionality is in GDB an unrelated test.
|
|
gdb_test_no_output "set can-use-hw-watchpoints 0"
|
|
# Software watchpoints can be quite slow on remote targets
|
|
# on this test because it ends up single-stepping through
|
|
# code to initialize dynamic libraries, etc.
|
|
set factor 20
|
|
} else {
|
|
set factor 1
|
|
}
|
|
|
|
gdb_test "show detach-on-fork" "Whether gdb will detach the child of a fork is on\\."
|
|
gdb_test_no_output "set follow-fork-mode $type"
|
|
gdb_test "show follow-fork-mode" "Debugger response to a program call of fork or vfork is \"$type\"\\."
|
|
# Testcase uses it for the `follow-fork-mode child' type.
|
|
gdb_test "handle SIGUSR1 nostop noprint pass" "No\[ \t\]+No\[ \t\]+Yes.*"
|
|
|
|
if ![runto_main] {
|
|
return
|
|
}
|
|
|
|
gdb_test "watch var" "atchpoint \[0-9\]+: var" "set the watchpoint"
|
|
|
|
# It is never hit but it should not be left over in the fork()ed-off child.
|
|
if [skip_hw_breakpoint_tests] {
|
|
set hbreak "break"
|
|
} else {
|
|
set hbreak "hbreak"
|
|
}
|
|
gdb_test "$hbreak marker"
|
|
|
|
gdb_breakpoint "mark_exit"
|
|
|
|
with_timeout_factor $factor {
|
|
gdb_test "continue" \
|
|
"reakpoint \[0-9\]+, marker.*" "hardware breakpoints work"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 0.*New value = 1.*forkoff *\\(1\\).*" "watchpoints work"
|
|
gdb_test "continue" \
|
|
"reakpoint \[0-9\]+, marker.*" "breakpoint after the first fork"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 1.*New value = 2.*forkoff *\\(2\\).*" "watchpoint after the first fork"
|
|
gdb_test "continue" \
|
|
"reakpoint \[0-9\]+, marker.*" "breakpoint after the second fork"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 2.*New value = 3.*mark_exit \\(\\);" "watchpoint after the second fork"
|
|
gdb_test "continue" "Continuing\\..*\r\n(Thread .* hit )?Breakpoint \[0-9\]+, mark_exit .*" "finish"
|
|
}
|
|
}
|
|
|
|
# threads
|
|
|
|
if [target_info exists gdb,no_hardware_watchpoints] {
|
|
# Watchpoint hits would get detected in unexpected threads.
|
|
return
|
|
}
|
|
|
|
with_test_prefix "multithreaded" {
|
|
set executable ${testfile}-${type}-mt
|
|
set srcfile_main ${srcdir}/${subdir}/${testfile}-mt.c
|
|
if { [gdb_compile_pthreads "${srcfile_main} ${srcfile_type}" [standard_output_file ${executable}] executable [list debug "additional_flags=-D$symbol -DTHREAD"]] != "" } {
|
|
untested "failed to compile"
|
|
return
|
|
}
|
|
clean_restart $executable
|
|
|
|
gdb_test_no_output "set follow-fork-mode $type"
|
|
# Testcase uses it for the `follow-fork-mode child' type.
|
|
gdb_test "handle SIGUSR1 nostop noprint pass" "No\[ \t\]+No\[ \t\]+Yes.*"
|
|
|
|
if ![runto_main] {
|
|
return
|
|
}
|
|
|
|
gdb_test "watch var" "atchpoint \[0-9\]+: var" "set the watchpoint"
|
|
|
|
# It should not be left over in the fork()ed-off child.
|
|
gdb_test "$hbreak marker" {reakpoint [0-9]+.*}
|
|
|
|
gdb_breakpoint "mark_exit"
|
|
|
|
gdb_test "continue" \
|
|
"reakpoint \[0-9\]+, marker.*" "hardware breakpoints work"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 0.*New value = 1.*validity-first.*" "singlethread watchpoints work"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 1.*New value = 2.*validity-thread-A.*" "multithreaded watchpoints work at A"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 2.*New value = 3.*validity-thread-B.*" "multithreaded watchpoints work at B"
|
|
gdb_test "continue" \
|
|
"reakpoint \[0-9\]+, marker.*" "breakpoint (A) after the first fork"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 3.*New value = 4.*after-fork1-A.*" "watchpoint A after the first fork"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 4.*New value = 5.*after-fork1-B.*" "watchpoint B after the first fork"
|
|
gdb_test "continue" \
|
|
"reakpoint \[0-9\]+, marker.*" "breakpoint (A) after the second fork"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 5.*New value = 6.*after-fork2-A.*" "watchpoint A after the second fork"
|
|
gdb_test "continue" \
|
|
"atchpoint \[0-9\]+: var.*Old value = 6.*New value = 7.*after-fork2-B.*" "watchpoint B after the second fork"
|
|
gdb_test "continue" "Continuing\\..*\r\nThread .* hit Breakpoint \[0-9\]+, mark_exit .*" "finish"
|
|
}
|
|
}
|
|
}
|
|
|
|
test parent FOLLOW_PARENT
|
|
|
|
# Only GNU/Linux is known to support `set follow-fork-mode child'.
|
|
if [istarget "*-*-linux*"] {
|
|
test child FOLLOW_CHILD
|
|
} else {
|
|
untested "${testfile}: child"
|
|
}
|