1# Copyright 2014-2020 Free Software Foundation, Inc. 2 3# This program is free software; you can redistribute it and/or modify 4# it under the terms of the GNU General Public License as published by 5# the Free Software Foundation; either version 3 of the License, or 6# (at your option) any later version. 7# 8# This program is distributed in the hope that it will be useful, 9# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# GNU General Public License for more details. 12# 13# You should have received a copy of the GNU General Public License 14# along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16# Test that the Zx breakpoint/watchpoint packets are idempotent. 17 18# GDBserver used to not treat Zx breakpoints other than Z0 as 19# idempotent, although it must, to avoid problems with 20# retransmissions. Even without spurious transport problems, if the 21# target supports target conditions or commands, GDB re-inserts Zx 22# breakpoints even if they are already inserted, to update the 23# target-side condition/commands. E.g., simply when a duplicate 24# breakpoint is created, or when a shared library load causes a 25# re-set, which creates duplicate locations while breakpoints are 26# inserted, or when the condition is really changed while breakpoints 27# are inserted. To make the test not depend on shared library support 28# or on details of the breakpoint re-set implementation, or on GDB 29# optimizing out re-sends if the condition hasn't actually changed, we 30# force always-inserted on, and really change the breakpoint's 31# condition. For good measure, test with both always-inserted "on" 32# and "off" modes. 33 34# The test is written in black-box style, and doesn't actually use 35# anything target remote specific, so let it run on all targets. 36 37standard_testfile 38 39# Force a breakpoint re-set in GDB. Currently this is done by 40# reloading symbols with the "file" command. 41 42proc force_breakpoint_re_set {} { 43 global binfile gdb_prompt 44 45 set test "file \$binfile" 46 gdb_test_multiple "file $binfile" $test { 47 -re "Are you sure you want to change the file. .*y or n. $" { 48 send_gdb "y\n" optional 49 exp_continue 50 } 51 -re "Load new symbol table from \".*\".*y or n. $" { 52 send_gdb "y\n" optional 53 exp_continue 54 } 55 -re "Reading symbols from.*$gdb_prompt $" { 56 pass $test 57 } 58 } 59} 60 61# Set a break/hbreak/watch/rwatch/awatch. 62 63proc set_breakpoint { break_command } { 64 global gdb_prompt srcfile 65 66 if { $break_command == "break" } { 67 gdb_test "$break_command foo" "Breakpoint.*at.* file .*$srcfile, line.*" 68 } elseif { $break_command == "hbreak" } { 69 set test "$break_command foo" 70 gdb_test_multiple $test $test { 71 -re "No hardware breakpoint support in the target.*$gdb_prompt $" { 72 unsupported $test 73 } 74 -re "Hardware breakpoints used exceeds limit.*$gdb_prompt $" { 75 unsupported $test 76 } 77 -re "Cannot insert hardware breakpoint.*$gdb_prompt $" { 78 unsupported $test 79 } 80 -re "Hardware assisted breakpoint.*at.* file .*$srcfile, line.*$gdb_prompt $" { 81 pass $test 82 } 83 } 84 } elseif { [string first "watch" $break_command] != -1 } { 85 set test "$break_command global" 86 gdb_test_multiple $test $test { 87 -re "Target does not support this type of hardware watchpoint\\.\r\n$gdb_prompt $" { 88 unsupported $test 89 } 90 -re "Could not insert hardware watchpoint.*$gdb_prompt $" { 91 unsupported $test 92 } 93 -re "atchpoint \[0-9\]+: global\r\n$gdb_prompt $" { 94 pass $test 95 } 96 } 97 } else { 98 error "unhandled command: $break_command" 99 } 100} 101 102# Run the test proper. ALWAYS_INSERT determines whether 103# always-inserted mode is on/off, and BREAK_COMMAND is the 104# break/watch/etc. command being tested. 105# 106proc test_break { always_inserted break_command } { 107 set cmd [lindex [split "$break_command"] 0] 108 109 with_test_prefix "$cmd" { 110 delete_breakpoints 111 112 if ![runto_main] then { 113 fail "can't run to main" 114 return 115 } 116 117 gdb_test_no_output "set breakpoint always-inserted $always_inserted" 118 119 # Set breakpoints/watchpoints twice. With always-inserted on, 120 # GDB reinserts the exact same Z breakpoint twice... Do this 121 # to make sure the stub pays attention to idempotency even 122 # when the condition doesn't change. If GDB end up optimizing 123 # out exact duplicate packets, we should come up with a way to 124 # keep testing this case. 125 foreach iter { "once" "twice" } { 126 with_test_prefix $iter { 127 set_breakpoint $break_command 128 } 129 } 130 131 # Force a breakpoint re-set. In always-inserted mode, this 132 # makes GDB re-send Z packets too... 133 force_breakpoint_re_set 134 135 # Now really change the condition, which forces a reinsert by 136 # design. 137 gdb_test "condition \$bpnum cond_global == 0" ".*" 138 139 # Now delete breakpoints, and let the program execute the 140 # address where the breakpoint used to be set. If the target 141 # doesn't treat insertions an idempotent way, we'll get a 142 # spurious SIGTRAP. 143 delete_breakpoints 144 gdb_test "b bar" "Breakpoint .* at .*" 145 gdb_test "continue" "Breakpoint .*, bar .*" 146 } 147} 148 149# The testcase uses the "file" command to force breakpoint re-set in 150# GDB. Test both with and without PIE, as GDB used to mishandle 151# breakpoint re-set when reloading PIEs. 152foreach_with_prefix pie { "nopie" "pie" } { 153 154 set opts {debug} 155 lappend opts $pie 156 157 set binfile [standard_output_file $testfile-$pie] 158 159 if {[prepare_for_testing "failed to prepare" $binfile $srcfile $opts]} { 160 continue 161 } 162 163 if [is_remote host] { 164 set arg [remote_download host $binfile] 165 if { $arg == "" } { 166 untested "download failed" 167 continue 168 } 169 } 170 171 foreach_with_prefix always_inserted { "off" "on" } { 172 test_break $always_inserted "break" 173 174 if {![skip_hw_breakpoint_tests]} { 175 test_break $always_inserted "hbreak" 176 } 177 178 if {![skip_hw_watchpoint_tests]} { 179 test_break $always_inserted "watch" 180 } 181 182 if {![skip_hw_watchpoint_access_tests] 183 && ![skip_hw_watchpoint_multi_tests]} { 184 test_break $always_inserted "rwatch" 185 test_break $always_inserted "awatch" 186 } 187 } 188} 189