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