1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
|
# Copyright 2014-2024 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
# The allow_hw_watchpoint_tests starts GDB on a small test program to
# check if HW watchpoints are supported. We do not want to restart
# GDB after this test script has itself started GDB, so call
# allow_hw_watchpoint_tests first and cache the result.
set allow_hw_watchpoint_tests_p [allow_hw_watchpoint_tests]
# 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" optional
exp_continue
}
-re "Load new symbol table from \".*\".*y or n. $" {
send_gdb "y\n" optional
exp_continue
}
-re "Reading symbols from.*$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 "$cmd" {
delete_breakpoints
if {![runto_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 .*"
}
}
# The testcase uses the "file" command to force breakpoint re-set in
# GDB. Test both with and without PIE, as GDB used to mishandle
# breakpoint re-set when reloading PIEs.
foreach_with_prefix pie { "nopie" "pie" } {
set opts {debug}
lappend opts $pie
set binfile [standard_output_file $testfile-$pie]
if {[prepare_for_testing "failed to prepare" $binfile $srcfile $opts]} {
continue
}
if [is_remote host] {
set arg [remote_download host $binfile]
if { $arg == "" } {
untested "download failed"
continue
}
}
foreach_with_prefix always_inserted { "off" "on" } {
test_break $always_inserted "break"
if {[allow_hw_breakpoint_tests]} {
test_break $always_inserted "hbreak"
}
if {$allow_hw_watchpoint_tests_p} {
test_break $always_inserted "watch"
}
if {[allow_hw_watchpoint_access_tests]
&& [allow_hw_watchpoint_multi_tests]} {
test_break $always_inserted "rwatch"
test_break $always_inserted "awatch"
}
}
}
|