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# This file is part of the gdb testsuite 17 18# Test relies on checking gdb debug output. Do not run if gdb debug is 19# enabled as any debug will be redirected to the log. 20if [gdb_debug_enabled] { 21 untested "debug is enabled" 22 return 0 23} 24 25standard_testfile 26 27if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } { 28 return -1 29} 30 31if ![runto main] { 32 return -1 33} 34 35# Delete all target-supplied memory regions. 36delete_memory_regions 37 38delete_breakpoints 39 40# Probe for hardware stepping. 41 42proc probe_target_hardware_step {} { 43 global gdb_prompt 44 45 set hw_step 0 46 47 gdb_test_no_output "set debug target 1" 48 set test "probe target hardware step" 49 gdb_test_multiple "si" $test { 50 -re "resume \\(\[^\r\n\]+, step, .*$gdb_prompt $" { 51 set hw_step 1 52 pass $test 53 } 54 -re "$gdb_prompt $" { 55 pass $test 56 } 57 } 58 gdb_test "set debug target 0" "->log_command.*\\).*" 59 return $hw_step 60} 61 62# Get the bounds of a function, and write them to FUNC_LO (inclusive), 63# FUNC_HI (exclusive). Return true on success and false on failure. 64proc get_function_bounds {function func_lo func_hi} { 65 global gdb_prompt 66 global hex decimal 67 68 upvar $func_lo lo 69 upvar $func_hi hi 70 71 set lo "" 72 set size "" 73 74 set test "get lo address of $function" 75 gdb_test_multiple "disassemble $function" $test { 76 -re "($hex) .*$hex <\\+($decimal)>:\[^\r\n\]+\r\nEnd of assembler dump\.\r\n$gdb_prompt $" { 77 set lo $expect_out(1,string) 78 set size $expect_out(2,string) 79 pass $test 80 } 81 } 82 83 if { $lo == "" || $size == "" } { 84 return false 85 } 86 87 # Account for the size of the last instruction. 88 set test "get hi address of $function" 89 gdb_test_multiple "x/2i $function+$size" $test { 90 -re ".*$hex <$function\\+$size>:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" { 91 set hi $expect_out(1,string) 92 pass $test 93 } 94 } 95 96 if { $hi == "" } { 97 return false 98 } 99 100 # Remove unnecessary leading 0's (0x00000ADDR => 0xADDR) so we can 101 # easily do matches. Disassemble includes leading zeros, while 102 # x/i doesn't. 103 regsub -all "0x0\+" $lo "0x" lo 104 regsub -all "0x0\+" $hi "0x" hi 105 106 return true 107} 108 109# Get the address where the thread is currently stopped. 110proc get_curr_insn {} { 111 global gdb_prompt 112 global hex 113 114 set pc "" 115 set test "get current insn" 116 gdb_test_multiple "p /x \$pc" $test { 117 -re " = ($hex)\r\n$gdb_prompt $" { 118 set pc $expect_out(1,string) 119 pass $test 120 } 121 } 122 123 return $pc 124} 125 126# Get the address of where a single-step should land. 127proc get_next_insn {} { 128 global gdb_prompt 129 global hex 130 131 set next "" 132 set test "get next insn" 133 gdb_test_multiple "x/2i \$pc" $test { 134 -re "$hex .*:\[^\r\n\]+\r\n\[ \]+($hex).*\.\r\n$gdb_prompt $" { 135 set next $expect_out(1,string) 136 pass $test 137 } 138 } 139 140 return $next 141} 142 143set hw_step [probe_target_hardware_step] 144 145if ![get_function_bounds "main" main_lo main_hi] { 146 # Can't do the following tests if main's bounds are unknown. 147 return -1 148} 149 150# Manually create a read-only memory region that covers 'main'. 151gdb_test_no_output "mem $main_lo $main_hi ro" \ 152 "create read-only mem region covering main" 153 154# So that we don't fail inserting breakpoints on addresses outside 155# main, like the internal event breakpoints. 156gdb_test_no_output "set mem inaccessible-by-default off" 157 158# So we get an immediate warning/error without needing to resume the 159# target. 160gdb_test_no_output "set breakpoint always-inserted on" 161 162# Disable the automatic fallback to HW breakpoints. We want a 163# software breakpoint to be attempted, and to fail. 164gdb_test_no_output "set breakpoint auto-hw off" 165 166# Confirm manual writes to the read-only memory region fail. 167gdb_test "p /x *(char *) $main_lo = 1" \ 168 "Cannot access memory at address $main_lo" \ 169 "writing to read-only memory fails" 170 171# Ensure that inserting a software breakpoint in a known-read-only 172# region fails. 173gdb_test "break *$main_lo" \ 174 "Cannot insert breakpoint .*Cannot set software breakpoint at read-only address $main_lo.*" \ 175 "inserting software breakpoint in read-only memory fails" 176 177delete_breakpoints 178 179set supports_hbreak 0 180set test "probe hbreak support" 181gdb_test_multiple "hbreak *$main_lo" $test { 182 -re "You may have requested too many.*$gdb_prompt $" { 183 pass "$test (no support)" 184 } 185 -re "No hardware breakpoint support.*$gdb_prompt $" { 186 pass "$test (no support)" 187 } 188 -re "$gdb_prompt $" { 189 pass "$test (support)" 190 set supports_hbreak 1 191 } 192} 193 194delete_breakpoints 195 196# Check that the "auto-hw on/off" setting affects single-step 197# breakpoints as expected, by stepping through the read-only region. 198# If the target does hardware stepping, we won't exercise that aspect, 199# but we should be able to step through the region without seeing the 200# hardware breakpoint or read-only address errors. 201proc test_single_step { always_inserted auto_hw } { 202 global gdb_prompt 203 global decimal 204 global hex 205 global supports_hbreak 206 global hw_step 207 208 gdb_test_no_output "set breakpoint always-inserted $always_inserted" 209 gdb_test_no_output "set breakpoint auto-hw $auto_hw" 210 211 # Get the address of the current instruction so we know where SI is 212 # starting from. 213 set curr_insn [get_curr_insn] 214 215 # Get the address of the next instruction so we know where SI should 216 # land. 217 set next_insn [get_next_insn] 218 219 set test "step in ro region" 220 gdb_test_multiple "si" $test { 221 -re "Could not insert hardware breakpoints.*$gdb_prompt $" { 222 gdb_assert {!$hw_step && $auto_hw == "on" && !$supports_hbreak} \ 223 "$test (cannot insert hw break)" 224 } 225 -re "Cannot set software breakpoint at read-only address $next_insn.*$gdb_prompt $" { 226 gdb_assert {!$hw_step && $auto_hw == "off"} \ 227 "$test (cannot insert sw break)" 228 } 229 -re "^si\r\nNote: automatically using hardware breakpoints for read-only addresses\.\r\n\(\?\:${hex}\[ \t\]\)\?${decimal}\[ \t\]+i = 0;\r\n$gdb_prompt $" { 230 gdb_assert {!$hw_step && $auto_hw == "on" && $supports_hbreak} \ 231 "$test (auto-hw)" 232 } 233 -re "^si\r\n\(\?\:${hex}\[ \t\]\)\?${decimal}\[ \t\]+i = 0;\r\n$gdb_prompt $" { 234 gdb_assert {$hw_step || ($auto_hw == "on" && $supports_hbreak)} \ 235 "$test (no error)" 236 } 237 } 238 239 gdb_test "maint info breakpoints 0" \ 240 "No breakpoint or watchpoint matching '0'\." \ 241 "single-step breakpoint is not left behind" 242 243 # Confirm the thread really advanced. 244 if {$hw_step || ($auto_hw == "on" && $supports_hbreak)} { 245 gdb_test "p /x \$pc" " = $next_insn" "thread advanced" 246 } else { 247 gdb_test "p /x \$pc" " = $curr_insn" "thread did not advance" 248 } 249} 250 251foreach always_inserted {"off" "on"} { 252 foreach auto_hw {"off" "on"} { 253 with_test_prefix "always-inserted $always_inserted: auto-hw $auto_hw" { 254 test_single_step $always_inserted $auto_hw 255 } 256 } 257} 258