183 lines
5.7 KiB
Plaintext
183 lines
5.7 KiB
Plaintext
# Copyright 2014-2016 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 that the Zx breakpoint/watchpoint packets are idempotent.
|
|
|
|
# GDBserver used to not treat Zx breakpoints other than Z0 as
|
|
# idempotent, although it must, to avoid problems with
|
|
# retransmissions. Even without spurious transport problems, if the
|
|
# target supports target conditions or commands, GDB re-inserts Zx
|
|
# breakpoints even if they are already inserted, to update the
|
|
# target-side condition/commands. E.g., simply when a duplicate
|
|
# breakpoint is created, or when a shared library load causes a
|
|
# re-set, which creates duplicate locations while breakpoints are
|
|
# inserted, or when the condition is really changed while breakpoints
|
|
# are inserted. To make the test not depend on shared library support
|
|
# or on details of the breakpoint re-set implementation, or on GDB
|
|
# optimizing out re-sends if the condition hasn't actually changed, we
|
|
# force always-inserted on, and really change the breakpoint's
|
|
# condition. For good measure, test with both always-inserted "on"
|
|
# and "off" modes.
|
|
|
|
# The test is written in black-box style, and doesn't actually use
|
|
# anything target remote specific, so let it run on all targets.
|
|
|
|
standard_testfile
|
|
|
|
if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} {
|
|
return -1
|
|
}
|
|
|
|
if ![runto_main] then {
|
|
fail "can't run to main"
|
|
return 0
|
|
}
|
|
|
|
if [is_remote host] {
|
|
set arg [remote_download host $binfile]
|
|
if { $arg == "" } {
|
|
perror "download failed"
|
|
return -1
|
|
}
|
|
}
|
|
|
|
# Force a breakpoint re-set in GDB. Currently this is done by
|
|
# reloading symbols with the "file" command.
|
|
|
|
proc force_breakpoint_re_set {} {
|
|
global binfile gdb_prompt
|
|
|
|
set test "file \$binfile"
|
|
gdb_test_multiple "file $binfile" $test {
|
|
-re "Are you sure you want to change the file. .*y or n. $" {
|
|
send_gdb "y\n"
|
|
exp_continue
|
|
}
|
|
-re "Load new symbol table from \".*\".*y or n. $" {
|
|
send_gdb "y\n"
|
|
exp_continue
|
|
}
|
|
-re "Reading symbols from.*done.*$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
}
|
|
|
|
# Set a break/hbreak/watch/rwatch/awatch.
|
|
|
|
proc set_breakpoint { break_command } {
|
|
global gdb_prompt srcfile
|
|
|
|
if { $break_command == "break" } {
|
|
gdb_test "$break_command foo" "Breakpoint.*at.* file .*$srcfile, line.*"
|
|
} elseif { $break_command == "hbreak" } {
|
|
set test "$break_command foo"
|
|
gdb_test_multiple $test $test {
|
|
-re "No hardware breakpoint support in the target.*$gdb_prompt $" {
|
|
unsupported $test
|
|
}
|
|
-re "Hardware breakpoints used exceeds limit.*$gdb_prompt $" {
|
|
unsupported $test
|
|
}
|
|
-re "Cannot insert hardware breakpoint.*$gdb_prompt $" {
|
|
unsupported $test
|
|
}
|
|
-re "Hardware assisted breakpoint.*at.* file .*$srcfile, line.*$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
} elseif { [string first "watch" $break_command] != -1 } {
|
|
set test "$break_command global"
|
|
gdb_test_multiple $test $test {
|
|
-re "Target does not support this type of hardware watchpoint\\.\r\n$gdb_prompt $" {
|
|
unsupported $test
|
|
}
|
|
-re "Could not insert hardware watchpoint.*$gdb_prompt $" {
|
|
unsupported $test
|
|
}
|
|
-re "atchpoint \[0-9\]+: global\r\n$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
} else {
|
|
error "unhandled command: $break_command"
|
|
}
|
|
}
|
|
|
|
# Run the test proper. ALWAYS_INSERT determines whether
|
|
# always-inserted mode is on/off, and BREAK_COMMAND is the
|
|
# break/watch/etc. command being tested.
|
|
#
|
|
proc test_break { always_inserted break_command } {
|
|
set cmd [lindex [split "$break_command"] 0]
|
|
|
|
with_test_prefix "always-inserted $always_inserted: $cmd" {
|
|
delete_breakpoints
|
|
|
|
if ![runto_main] then {
|
|
fail "can't run to main"
|
|
return
|
|
}
|
|
|
|
gdb_test_no_output "set breakpoint always-inserted $always_inserted"
|
|
|
|
# Set breakpoints/watchpoints twice. With always-inserted on,
|
|
# GDB reinserts the exact same Z breakpoint twice... Do this
|
|
# to make sure the stub pays attention to idempotency even
|
|
# when the condition doesn't change. If GDB end up optimizing
|
|
# out exact duplicate packets, we should come up with a way to
|
|
# keep testing this case.
|
|
foreach iter { "once" "twice" } {
|
|
with_test_prefix $iter {
|
|
set_breakpoint $break_command
|
|
}
|
|
}
|
|
|
|
# Force a breakpoint re-set. In always-inserted mode, this
|
|
# makes GDB re-send Z packets too...
|
|
force_breakpoint_re_set
|
|
|
|
# Now really change the condition, which forces a reinsert by
|
|
# design.
|
|
gdb_test "condition \$bpnum cond_global == 0" ".*"
|
|
|
|
# Now delete breakpoints, and let the program execute the
|
|
# address where the breakpoint used to be set. If the target
|
|
# doesn't treat insertions an idempotent way, we'll get a
|
|
# spurious SIGTRAP.
|
|
delete_breakpoints
|
|
gdb_test "b bar" "Breakpoint .* at .*"
|
|
gdb_test "continue" "Breakpoint .*, bar .*"
|
|
}
|
|
}
|
|
|
|
foreach always_inserted { "off" "on" } {
|
|
test_break $always_inserted "break"
|
|
|
|
if {![skip_hw_breakpoint_tests]} {
|
|
test_break $always_inserted "hbreak"
|
|
}
|
|
|
|
if {![skip_hw_watchpoint_tests]} {
|
|
test_break $always_inserted "watch"
|
|
}
|
|
|
|
if {![skip_hw_watchpoint_access_tests]
|
|
&& ![skip_hw_watchpoint_multi_tests]} {
|
|
test_break $always_inserted "rwatch"
|
|
test_break $always_inserted "awatch"
|
|
}
|
|
}
|