]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.base/step-over-syscall.exp
6f67aea12ef03d08f1ff89fbce3abf9c44a9fbaa
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.base / step-over-syscall.exp
1 # This testcase is part of GDB, the GNU debugger.
2
3 # Copyright 2011-2020 Free Software Foundation, Inc.
4
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 set syscall_insn ""
19 set syscall_register ""
20 array set syscall_number {}
21
22 # Define the syscall instructions, registers and numbers for each target.
23
24 if { [istarget "i\[34567\]86-*-linux*"] || [istarget "x86_64-*-linux*"] } {
25 set syscall_insn "\[ \t\](int|syscall|sysenter)\[ \t\]"
26 set syscall_register "eax"
27 array set syscall_number {fork "(56|120)" vfork "(58|190)" \
28 clone "(56|120)"}
29 } elseif { [istarget "aarch64*-*-linux*"] || [istarget "arm*-*-linux*"] } {
30 set syscall_insn "\[ \t\](swi|svc)\[ \t\]"
31
32 if { [istarget "aarch64*-*-linux*"] } {
33 set syscall_register "x8"
34 } else {
35 set syscall_register "r7"
36 }
37
38 array set syscall_number {fork "(120|220)" vfork "(190|220)" \
39 clone "(120|220)"}
40 } else {
41 return -1
42 }
43
44 proc_with_prefix check_pc_after_cross_syscall { syscall syscall_insn_next_addr } {
45 set syscall_insn_next_addr_found [get_hexadecimal_valueof "\$pc" "0"]
46
47 gdb_assert {$syscall_insn_next_addr != 0 \
48 && $syscall_insn_next_addr == $syscall_insn_next_addr_found} \
49 "single step over $syscall final pc"
50 }
51
52 # Verify the syscall number is the correct one.
53
54 proc syscall_number_matches { syscall } {
55 global syscall_register syscall_number
56
57 if {[gdb_test "p \$$syscall_register" ".*= $syscall_number($syscall)" \
58 "syscall number matches"] != 0} {
59 return 0
60 }
61
62 return 1
63 }
64
65 # Restart GDB and set up the test. Return a list in which the first one
66 # is the address of syscall instruction and the second one is the address
67 # of the next instruction address of syscall instruction. If anything
68 # wrong, the two elements of list are -1.
69
70 proc setup { syscall } {
71 global gdb_prompt syscall_insn
72
73 global hex
74 set next_insn_addr -1
75 set testfile "step-over-$syscall"
76
77 clean_restart $testfile
78
79 if { ![runto_main] } then {
80 fail "run to main ($syscall)"
81 return -1
82 }
83
84 # Delete the breakpoint on main.
85 gdb_test_no_output "delete break 1"
86
87 gdb_test_no_output "set displaced-stepping off" \
88 "set displaced-stepping off during test setup"
89
90 gdb_test "break \*$syscall" "Breakpoint \[0-9\]* at .*"
91
92 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \
93 "continue to $syscall (1st time)"
94 # Hit the breakpoint on $syscall for the first time. In this time,
95 # we will let PLT resolution done, and the number single steps we will
96 # do later will be reduced.
97
98 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \
99 "continue to $syscall (2nd time)"
100 # Hit the breakpoint on $syscall for the second time. In this time,
101 # the address of syscall insn and next insn of syscall are recorded.
102
103 # Check if the first instruction we stopped at is the syscall one.
104 set syscall_insn_addr -1
105 gdb_test_multiple "display/i \$pc" "fetch first stop pc" {
106 -re "display/i .*: x/i .*=> ($hex) .*:.*$syscall_insn.*$gdb_prompt $" {
107 set insn_addr $expect_out(1,string)
108
109 # Is the syscall number the correct one?
110 if {[syscall_number_matches $syscall]} {
111 set syscall_insn_addr $insn_addr
112 }
113 pass $gdb_test_name
114 }
115 -re ".*$gdb_prompt $" {
116 pass $gdb_test_name
117 }
118 }
119
120 # If we are not at the syscall instruction yet, keep looking for it with
121 # stepi commands.
122 if {$syscall_insn_addr == -1} {
123 # Single step until we see a syscall insn or we reach the
124 # upper bound of loop iterations.
125 set steps 0
126 set max_steps 1000
127 gdb_test_multiple "stepi" "find syscall insn in $syscall" {
128 -re ".*$syscall_insn.*$gdb_prompt $" {
129 # Is the syscall number the correct one?
130 if {[syscall_number_matches $syscall]} {
131 pass $gdb_test_name
132 } else {
133 exp_continue
134 }
135 }
136 -re "x/i .*=>.*\r\n$gdb_prompt $" {
137 incr steps
138 if {$steps == $max_steps} {
139 fail $gdb_test_name
140 } else {
141 send_gdb "stepi\n"
142 exp_continue
143 }
144 }
145 }
146
147 if {$steps == $max_steps} {
148 return { -1, -1 }
149 }
150 }
151
152 # We have found the syscall instruction. Now record the next instruction.
153 # Use the X command instead of stepi since we can't guarantee
154 # stepi is working properly.
155 gdb_test_multiple "x/2i \$pc" "pc before/after syscall instruction" {
156 -re "x/2i .*=> ($hex) .*:.*$syscall_insn.* ($hex) .*:.*$gdb_prompt $" {
157 set syscall_insn_addr $expect_out(1,string)
158 set next_insn_addr $expect_out(3,string)
159 pass $gdb_test_name
160 }
161 }
162
163 if {[gdb_test "stepi" "x/i .*=>.*" "stepi $syscall insn"] != 0} {
164 return { -1, -1 }
165 }
166
167 set pc_after_stepi [get_hexadecimal_valueof "\$pc" "0" \
168 "pc after stepi"]
169
170 gdb_assert {$next_insn_addr == $pc_after_stepi} \
171 "pc after stepi matches insn addr after syscall"
172
173 return [list $syscall_insn_addr $pc_after_stepi]
174 }
175
176 proc step_over_syscall { syscall } {
177 with_test_prefix "$syscall" {
178 global syscall_insn
179 global gdb_prompt
180
181 set testfile "step-over-$syscall"
182
183 if [build_executable ${testfile}.exp ${testfile} ${testfile}.c {debug}] {
184 untested "failed to compile"
185 return -1
186 }
187
188 foreach_with_prefix displaced {"off" "on"} {
189 if {$displaced == "on" && ![support_displaced_stepping]} {
190 continue
191 }
192
193 if { $displaced == "on" && $syscall == "clone" } {
194 # GDB doesn't support stepping over clone syscall with
195 # displaced stepping.
196 kfail "gdb/19675" "single step over clone"
197 continue
198 }
199
200 set ret [setup $syscall]
201
202 set syscall_insn_addr [lindex $ret 0]
203 set syscall_insn_next_addr [lindex $ret 1]
204 if { $syscall_insn_addr == -1 } {
205 return -1
206 }
207
208 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \
209 "continue to $syscall (3rd time)"
210
211 # Hit the breakpoint on $syscall for the third time. In this time, we'll set
212 # breakpoint on the syscall insn we recorded previously, and single step over it.
213
214 set syscall_insn_bp 0
215 gdb_test_multiple "break \*$syscall_insn_addr" "break on syscall insn" {
216 -re "Breakpoint (\[0-9\]*) at .*$gdb_prompt $" {
217 set syscall_insn_bp $expect_out(1,string)
218 pass "break on syscall insns"
219 }
220 }
221
222 # Check if the syscall breakpoint is at the syscall instruction
223 # address. If so, no need to continue, otherwise we will run the
224 # inferior to completion.
225 if {$syscall_insn_addr != [get_hexadecimal_valueof "\$pc" "0"]} {
226 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, .*" \
227 "continue to syscall insn $syscall"
228 }
229
230 gdb_test_no_output "set displaced-stepping $displaced"
231
232 # Check the address of next instruction of syscall.
233 if {[gdb_test "stepi" "x/i .*=>.*" "single step over $syscall"] != 0} {
234 return -1
235 }
236 check_pc_after_cross_syscall $syscall $syscall_insn_next_addr
237
238 # Delete breakpoint syscall insns to avoid interference to other syscalls.
239 delete_breakpoints
240
241 gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*"
242 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \
243 "continue to marker ($syscall)"
244 }
245 }
246 }
247
248 # Set a breakpoint with a condition that evals false on syscall
249 # instruction. In fact, it tests GDBserver steps over syscall
250 # instruction. SYSCALL is the syscall the program calls.
251 # FOLLOW_FORK is either "parent" or "child". DETACH_ON_FORK is
252 # "on" or "off".
253
254 proc break_cond_on_syscall { syscall follow_fork detach_on_fork } {
255 with_test_prefix "break cond on target : $syscall" {
256 set testfile "step-over-$syscall"
257
258 set ret [setup $syscall]
259
260 set syscall_insn_addr [lindex $ret 0]
261 set syscall_insn_next_addr [lindex $ret 1]
262 if { $syscall_insn_addr == -1 } {
263 return -1
264 }
265
266 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \
267 "continue to $syscall"
268 # Delete breakpoint syscall insns to avoid interference with other syscalls.
269 delete_breakpoints
270
271 gdb_test "set follow-fork-mode $follow_fork"
272 gdb_test "set detach-on-fork $detach_on_fork"
273
274 # Create a breakpoint with a condition that evals false.
275 gdb_test "break \*$syscall_insn_addr if main == 0" \
276 "Breakpoint \[0-9\]* at .*"
277
278 if { $syscall == "clone" } {
279 # Create a breakpoint in the child with the condition that
280 # evals false, so that GDBserver can get the event from the
281 # child but GDB doesn't see it. In this way, we don't have
282 # to adjust the test flow for "clone".
283 # This is a regression test for PR server/19736. In this way,
284 # we can test that GDBserver gets an event from the child and
285 # set suspend count correctly while the parent is stepping over
286 # the breakpoint.
287 gdb_test "break clone_fn if main == 0"
288 }
289
290 if { $syscall == "clone" } {
291 # follow-fork and detach-on-fork only make sense to
292 # fork and vfork.
293 gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*"
294 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \
295 "continue to marker"
296 } else {
297 if { $follow_fork == "child" } {
298 gdb_test "continue" "exited normally.*" "continue to end of inf 2"
299 if { $detach_on_fork == "off" } {
300 gdb_test "inferior 1"
301 gdb_test "break marker" "Breakpoint.*at.*"
302 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \
303 "continue to marker"
304 }
305 } else {
306 gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*"
307 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \
308 "continue to marker"
309 }
310 }
311 }
312 }
313
314 step_over_syscall "fork"
315 step_over_syscall "vfork"
316 step_over_syscall "clone"
317
318 set testfile "step-over-fork"
319 clean_restart $testfile
320 if { ![runto_main] } then {
321 fail "run to main"
322 return -1
323 }
324
325 set cond_bp_target 1
326
327 set test "set breakpoint condition-evaluation target"
328 gdb_test_multiple $test $test {
329 -re "warning: Target does not support breakpoint condition evaluation.\r\nUsing host evaluation mode instead.\r\n$gdb_prompt $" {
330 # Target doesn't support breakpoint condition
331 # evaluation on its side.
332 set cond_bp_target 0
333 }
334 -re "^$test\r\n$gdb_prompt $" {
335 }
336 }
337
338 if { $cond_bp_target } {
339
340 foreach_with_prefix detach-on-fork {"on" "off"} {
341 foreach_with_prefix follow-fork {"parent" "child"} {
342 foreach syscall { "fork" "vfork" "clone" } {
343
344 if { $syscall == "vfork"
345 && ${follow-fork} == "parent"
346 && ${detach-on-fork} == "off" } {
347 # Both vforked child process and parent process are
348 # under GDB's control, but GDB follows the parent
349 # process only, which can't be run until vforked child
350 # finishes. Skip the test in this scenario.
351 continue
352 }
353 break_cond_on_syscall $syscall ${follow-fork} ${detach-on-fork}
354 }
355 }
356 }
357 }