1# Copyright 2013-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
16load_lib "range-stepping-support.exp"
17
18standard_testfile
19set executable $testfile
20
21if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug}] } {
22    return -1
23}
24
25if ![runto_main] {
26    fail "can't run to main"
27    return -1
28}
29
30if ![gdb_range_stepping_enabled] {
31    unsupported "range stepping not supported by the target"
32    return -1
33}
34
35# Check that range stepping can step a range of multiple instructions.
36
37with_test_prefix "multi insns" {
38
39    gdb_breakpoint [gdb_get_line_number "location 1"]
40    gdb_continue_to_breakpoint "location 1"
41
42    set pc_before_stepping ""
43    set test "pc before stepping"
44    gdb_test_multiple "print/x \$pc" $test {
45	-re "\\\$$decimal = (\[^\r\n\]*)\r\n$gdb_prompt $" {
46	    set pc_before_stepping $expect_out(1,string)
47	    pass $test
48	}
49    }
50
51    # When "next" is executed, GDB should send one vCont;s and vCont;r
52    # and receive two stop replies:
53    #
54    # --> vCont;s  (step over breakpoint)
55    # <-- T05
56    # --> vCont;rSTART,END  (range step)
57    # <-- T05
58    set result [exec_cmd_expect_vCont_count "next" 1]
59    if { $result } {
60	# This is the first range-stepping test, and the simplest
61	# one.  If it fails, probably the rest of the tests would
62	# fail too, and the huge number of rsp packets in the test
63	# with the time-consuming loop would blow up the gdb.log file.
64	# Skip the rest of the tests.
65	return
66    }
67
68    set pc_after_stepping ""
69    set msg "pc after stepping"
70    gdb_test_multiple "print/x \$pc" $msg {
71	-re "\\\$$decimal = (\[^\r\n\]*)\r\n$gdb_prompt $" {
72	    set pc_after_stepping $expect_out(1,string)
73	    pass $msg
74	}
75    }
76
77    # There should be at least two instructions between
78    # PC_BEFORE_STEPPING and PC_AFTER_STEPPING.
79    gdb_test "disassemble ${pc_before_stepping},${pc_after_stepping}" \
80	"${hex} <main\\+${decimal}>:.*${hex} <main\\+${decimal}>:.*" \
81	"stepped multiple insns"
82}
83
84# Check that range stepping can step over a function.
85
86with_test_prefix "step over func" {
87
88    set line_num [gdb_get_line_number "location 2"]
89    gdb_test "where" "main \\(\\) at .*${srcfile}:${line_num}.*"
90
91    # It's expected to get three stops and two 'vCont;r's.  In the C
92    # code, the line of C source produces roughly the following
93    # instructions:
94    #
95    # addr1:
96    #  insn1
97    #  insn2
98    #  ...
99    #  call func1
100    # addr2:
101    #  ...
102    #  insn3
103    # addr3:
104    #  insn4
105    #
106    # Something like this will happen:
107    # --> vCont;rADDR1,ADDR3  (range step from ADDR1 to ADDR3)
108    # <-- T05  (target single-stepped to func, which is out of the step range)
109    # --> $Z0,ADDR2  (place step-resume breakpoint at ADDR2)
110    # --> vCont;c  (resume)
111    # <-- T05  (target stops at ADDR2)
112    # --> vCont;rADDR1,ADDR3  (continues range stepping)
113    # <-- T05
114    exec_cmd_expect_vCont_count "next" 2
115}
116
117# Check that breakpoints interrupt range stepping correctly.
118
119with_test_prefix "breakpoint" {
120    gdb_breakpoint "func1"
121    # Something like this will happen:
122    # --> vCont;rADDR1,ADDR3
123    # <-- T05  (target single-steps to func1, which is out of the step range)
124    # --> $Z0,ADDR2  (step-resume breakpoint at ADDR2)
125    # --> vCont;c  (resume)
126    # <-- T05  (target hits the breakpoint at func1)
127    exec_cmd_expect_vCont_count "next" 1
128
129    gdb_test "backtrace" "#0 .* func1 .*#1 .* main .*" \
130	"backtrace from func1"
131
132    # A cancelled range step should not confuse the following
133    # execution commands.
134    exec_cmd_expect_vCont_count "stepi" 0
135    gdb_test "finish" ".*"
136    gdb_test "next" ".*"
137    delete_breakpoints
138}
139
140# Check that range stepping works well even when there's a loop in the
141# step range.
142
143with_test_prefix "loop" {
144
145    # GDB should send one vCont;r and receive one stop reply:
146    # --> vCont;rSTART,END  (range step)
147    # <-- T05
148    exec_cmd_expect_vCont_count "next" 1
149
150    # Confirm the loop completed.
151    gdb_test "print a" " = 15"
152    gdb_test "print e" " = 105"
153}
154
155# Check that range stepping works well even when the target's PC was
156# already within the loop's body.
157
158with_test_prefix "loop 2" {
159    # Stepi into the loop body.  15 should be large enough to make
160    # sure the program stops within the loop's body.
161    gdb_test "stepi 15" ".*"
162    # GDB should send one vCont;r and receive one stop reply:
163    # --> vCont;rSTART,END  (range step)
164    # <-- T05
165    exec_cmd_expect_vCont_count "next" 1
166
167    # Confirm the loop completed.
168    gdb_test "print a" " = 15"
169    gdb_test "print e" " = 105"
170}
171
172# Check that range stepping works well even when it is interrupted by
173# ctrl-c.
174
175if ![target_info exists gdb,nointerrupts] {
176    with_test_prefix "interrupt" {
177	gdb_test_no_output "set debug remote 1"
178
179	send_gdb "next\n"
180	sleep 1
181	send_gdb "\003"
182
183	# GDB should send one vCont;r and receive one stop reply for
184	# SIGINT:
185	# --> vCont;rSTART,END  (range step)
186	# <-- T02  (SIGINT)
187
188	set vcont_r_counter 0
189
190	set test "send ctrl-c to GDB"
191	gdb_test_multiple "" $test {
192	    -re "vCont;r\[^\r\n\]*\.\.\." {
193		incr vcont_r_counter
194		exp_continue
195	    }
196	    -re "Program received signal SIGINT.*$gdb_prompt $" {
197		pass $test
198	    }
199	}
200	gdb_test_no_output "set debug remote 0"
201
202	# Check the number of 'vCont;r' packets.
203	if { $vcont_r_counter == 1 } {
204	    pass "${test}: 1 vCont;r"
205	} else {
206	    fail "${test}: 1 vCont;r"
207	}
208
209	# Break the loop earlier and continue range stepping.
210	gdb_test "set variable c = 0"
211	exec_cmd_expect_vCont_count "next" 1
212    }
213}
214
215# Check that range stepping doesn't break software watchpoints.  With
216# those, GDB needs to be notified of all single-steps, to evaluate
217# whether the watched value changes at each step.
218with_test_prefix "software watchpoint" {
219    gdb_test "step" "soft-watch.*" "step into multiple instruction line"
220    # A software watchpoint at PC makes the thread stop before the
221    # whole line range is over (after one single-step, actually).
222    gdb_test "watch \$pc" ".*" "set watchpoint"
223    gdb_test "step" "soft-watch.*" "step still in same line"
224}
225
226return 0
227