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