Commit | Line | Data |
---|---|---|
9c317b71 YQ |
1 | # This testcase is part of GDB, the GNU debugger. |
2 | ||
88b9d363 | 3 | # Copyright 2011-2022 Free Software Foundation, Inc. |
9c317b71 YQ |
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 | ||
9c317b71 | 18 | set syscall_insn "" |
16b10d6e LM |
19 | set syscall_register "" |
20 | array set syscall_number {} | |
9c317b71 | 21 | |
16b10d6e | 22 | # Define the syscall instructions, registers and numbers for each target. |
9c317b71 YQ |
23 | |
24 | if { [istarget "i\[34567\]86-*-linux*"] || [istarget "x86_64-*-linux*"] } { | |
9a7f938f | 25 | set syscall_insn "\[ \t\](int|syscall|sysenter)\[ \t\]" |
16b10d6e LM |
26 | set syscall_register "eax" |
27 | array set syscall_number {fork "(56|120)" vfork "(58|190)" \ | |
28 | clone "(56|120)"} | |
99fd02d9 | 29 | } elseif { [istarget "aarch64*-*-linux*"] || [istarget "arm*-*-linux*"] } { |
5d0a3b53 | 30 | set syscall_insn "\[ \t\](swi|svc)\[ \t\]" |
16b10d6e LM |
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)"} | |
9c317b71 YQ |
40 | } else { |
41 | return -1 | |
42 | } | |
43 | ||
2b74ba5a | 44 | proc_with_prefix check_pc_after_cross_syscall { syscall syscall_insn_next_addr } { |
0b47da9f YQ |
45 | set syscall_insn_next_addr_found [get_hexadecimal_valueof "\$pc" "0"] |
46 | ||
16b10d6e LM |
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 | |
0b47da9f | 63 | } |
9c317b71 | 64 | |
0b47da9f YQ |
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. | |
9c317b71 | 69 | |
0b47da9f YQ |
70 | proc setup { syscall } { |
71 | global gdb_prompt syscall_insn | |
9c317b71 | 72 | |
16b10d6e LM |
73 | global hex |
74 | set next_insn_addr -1 | |
8fc8cbda | 75 | set testfile "step-over-$syscall" |
9c317b71 | 76 | |
0b47da9f | 77 | clean_restart $testfile |
9c317b71 | 78 | |
50441f0f | 79 | if { ![runto_main] } then { |
0b47da9f YQ |
80 | fail "run to main ($syscall)" |
81 | return -1 | |
82 | } | |
9c317b71 | 83 | |
0b47da9f YQ |
84 | # Delete the breakpoint on main. |
85 | gdb_test_no_output "delete break 1" | |
9c317b71 | 86 | |
2b74ba5a AB |
87 | gdb_test_no_output "set displaced-stepping off" \ |
88 | "set displaced-stepping off during test setup" | |
9c317b71 | 89 | |
16b10d6e | 90 | gdb_test "break \*$syscall" "Breakpoint \[0-9\]* at .*" |
9c317b71 | 91 | |
0b47da9f YQ |
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. | |
9c317b71 | 97 | |
0b47da9f YQ |
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. | |
9c317b71 | 102 | |
16b10d6e LM |
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) | |
0b47da9f | 108 | |
16b10d6e LM |
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 | |
0b47da9f | 117 | } |
16b10d6e LM |
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 | } | |
9c317b71 | 135 | } |
16b10d6e LM |
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 } | |
9c317b71 | 149 | } |
0b47da9f YQ |
150 | } |
151 | ||
16b10d6e LM |
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) | |
14852123 | 158 | set actual_syscall_insn $expect_out(2,string) |
16b10d6e LM |
159 | set next_insn_addr $expect_out(3,string) |
160 | pass $gdb_test_name | |
161 | } | |
0b47da9f YQ |
162 | } |
163 | ||
14852123 TV |
164 | # If we encounter a sequence: |
165 | # 0xf7fd5155 <__kernel_vsyscall+5>: sysenter | |
166 | # 0xf7fd5157 <__kernel_vsyscall+7>: int $0x80 | |
167 | # 0xf7fd5159 <__kernel_vsyscall+9>: pop %ebp | |
168 | # then a stepi at sysenter will step over the int insn, so make sure | |
169 | # next_insn_addr points after the int insn. | |
170 | if { $actual_syscall_insn == "sysenter" } { | |
171 | set test "pc after sysenter instruction" | |
172 | set re_int_insn "\[ \t\]*int\[ \t\]\[^\r\n\]*" | |
173 | set re [multi_line \ | |
174 | "x/2i $hex" \ | |
175 | "\[^\r\n\]* $hex \[^\r\n\]*:$re_int_insn" \ | |
176 | "\[^\r\n\]* ($hex) \[^\r\n\]*:\[^\r\n\]*"] | |
177 | gdb_test_multiple "x/2i $next_insn_addr" $test { | |
178 | -re -wrap $re { | |
179 | set next_insn_addr $expect_out(1,string) | |
180 | } | |
181 | -re -wrap "" { | |
182 | } | |
183 | } | |
184 | } | |
185 | ||
0b47da9f YQ |
186 | if {[gdb_test "stepi" "x/i .*=>.*" "stepi $syscall insn"] != 0} { |
187 | return { -1, -1 } | |
188 | } | |
16b10d6e LM |
189 | |
190 | set pc_after_stepi [get_hexadecimal_valueof "\$pc" "0" \ | |
191 | "pc after stepi"] | |
192 | ||
193 | gdb_assert {$next_insn_addr == $pc_after_stepi} \ | |
194 | "pc after stepi matches insn addr after syscall" | |
195 | ||
196 | return [list $syscall_insn_addr $pc_after_stepi] | |
0b47da9f | 197 | } |
9c317b71 | 198 | |
8fc8cbda | 199 | proc step_over_syscall { syscall } { |
0b47da9f YQ |
200 | with_test_prefix "$syscall" { |
201 | global syscall_insn | |
202 | global gdb_prompt | |
203 | ||
8fc8cbda | 204 | set testfile "step-over-$syscall" |
0b47da9f YQ |
205 | |
206 | if [build_executable ${testfile}.exp ${testfile} ${testfile}.c {debug}] { | |
5b362f04 | 207 | untested "failed to compile" |
0a251e08 YQ |
208 | return -1 |
209 | } | |
9c317b71 | 210 | |
e197ad3c YQ |
211 | foreach_with_prefix displaced {"off" "on"} { |
212 | if {$displaced == "on" && ![support_displaced_stepping]} { | |
213 | continue | |
214 | } | |
215 | ||
4719d415 YQ |
216 | if { $displaced == "on" && $syscall == "clone" } { |
217 | # GDB doesn't support stepping over clone syscall with | |
218 | # displaced stepping. | |
219 | kfail "gdb/19675" "single step over clone" | |
220 | continue | |
221 | } | |
222 | ||
ea507862 | 223 | set ret [setup $syscall] |
0b47da9f | 224 | |
ea507862 YQ |
225 | set syscall_insn_addr [lindex $ret 0] |
226 | set syscall_insn_next_addr [lindex $ret 1] | |
227 | if { $syscall_insn_addr == -1 } { | |
228 | return -1 | |
229 | } | |
9c317b71 | 230 | |
ea507862 YQ |
231 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \ |
232 | "continue to $syscall (3rd time)" | |
9c317b71 | 233 | |
ea507862 YQ |
234 | # Hit the breakpoint on $syscall for the third time. In this time, we'll set |
235 | # breakpoint on the syscall insn we recorded previously, and single step over it. | |
9c317b71 | 236 | |
ea507862 YQ |
237 | set syscall_insn_bp 0 |
238 | gdb_test_multiple "break \*$syscall_insn_addr" "break on syscall insn" { | |
239 | -re "Breakpoint (\[0-9\]*) at .*$gdb_prompt $" { | |
240 | set syscall_insn_bp $expect_out(1,string) | |
241 | pass "break on syscall insns" | |
242 | } | |
0a251e08 | 243 | } |
9c317b71 | 244 | |
16b10d6e LM |
245 | # Check if the syscall breakpoint is at the syscall instruction |
246 | # address. If so, no need to continue, otherwise we will run the | |
247 | # inferior to completion. | |
248 | if {$syscall_insn_addr != [get_hexadecimal_valueof "\$pc" "0"]} { | |
249 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, .*" \ | |
250 | "continue to syscall insn $syscall" | |
251 | } | |
9c317b71 | 252 | |
ea507862 | 253 | gdb_test_no_output "set displaced-stepping $displaced" |
9c317b71 | 254 | |
ea507862 YQ |
255 | # Check the address of next instruction of syscall. |
256 | if {[gdb_test "stepi" "x/i .*=>.*" "single step over $syscall"] != 0} { | |
257 | return -1 | |
258 | } | |
259 | check_pc_after_cross_syscall $syscall $syscall_insn_next_addr | |
dfe2ac14 | 260 | |
ea507862 YQ |
261 | # Delete breakpoint syscall insns to avoid interference to other syscalls. |
262 | delete_breakpoints | |
9a7f938f | 263 | |
ea507862 YQ |
264 | gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" |
265 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \ | |
266 | "continue to marker ($syscall)" | |
e197ad3c | 267 | } |
9a7f938f | 268 | } |
0a251e08 | 269 | } |
9c317b71 | 270 | |
92fa70b0 YQ |
271 | # Set a breakpoint with a condition that evals false on syscall |
272 | # instruction. In fact, it tests GDBserver steps over syscall | |
21a77091 YQ |
273 | # instruction. SYSCALL is the syscall the program calls. |
274 | # FOLLOW_FORK is either "parent" or "child". DETACH_ON_FORK is | |
275 | # "on" or "off". | |
92fa70b0 | 276 | |
21a77091 | 277 | proc break_cond_on_syscall { syscall follow_fork detach_on_fork } { |
92fa70b0 | 278 | with_test_prefix "break cond on target : $syscall" { |
8fc8cbda | 279 | set testfile "step-over-$syscall" |
92fa70b0 YQ |
280 | |
281 | set ret [setup $syscall] | |
282 | ||
283 | set syscall_insn_addr [lindex $ret 0] | |
284 | set syscall_insn_next_addr [lindex $ret 1] | |
285 | if { $syscall_insn_addr == -1 } { | |
286 | return -1 | |
287 | } | |
288 | ||
289 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \ | |
290 | "continue to $syscall" | |
291 | # Delete breakpoint syscall insns to avoid interference with other syscalls. | |
292 | delete_breakpoints | |
293 | ||
21a77091 YQ |
294 | gdb_test "set follow-fork-mode $follow_fork" |
295 | gdb_test "set detach-on-fork $detach_on_fork" | |
92fa70b0 YQ |
296 | |
297 | # Create a breakpoint with a condition that evals false. | |
298 | gdb_test "break \*$syscall_insn_addr if main == 0" \ | |
299 | "Breakpoint \[0-9\]* at .*" | |
300 | ||
4719d415 YQ |
301 | if { $syscall == "clone" } { |
302 | # Create a breakpoint in the child with the condition that | |
303 | # evals false, so that GDBserver can get the event from the | |
304 | # child but GDB doesn't see it. In this way, we don't have | |
305 | # to adjust the test flow for "clone". | |
306 | # This is a regression test for PR server/19736. In this way, | |
307 | # we can test that GDBserver gets an event from the child and | |
308 | # set suspend count correctly while the parent is stepping over | |
309 | # the breakpoint. | |
310 | gdb_test "break clone_fn if main == 0" | |
311 | } | |
312 | ||
21a77091 YQ |
313 | if { $syscall == "clone" } { |
314 | # follow-fork and detach-on-fork only make sense to | |
315 | # fork and vfork. | |
316 | gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" | |
317 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \ | |
318 | "continue to marker" | |
319 | } else { | |
320 | if { $follow_fork == "child" } { | |
321 | gdb_test "continue" "exited normally.*" "continue to end of inf 2" | |
322 | if { $detach_on_fork == "off" } { | |
323 | gdb_test "inferior 1" | |
324 | gdb_test "break marker" "Breakpoint.*at.*" | |
325 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \ | |
326 | "continue to marker" | |
327 | } | |
328 | } else { | |
329 | gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" | |
330 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \ | |
331 | "continue to marker" | |
332 | } | |
333 | } | |
92fa70b0 YQ |
334 | } |
335 | } | |
336 | ||
8fc8cbda YQ |
337 | step_over_syscall "fork" |
338 | step_over_syscall "vfork" | |
4719d415 | 339 | step_over_syscall "clone" |
92fa70b0 | 340 | |
8fc8cbda | 341 | set testfile "step-over-fork" |
92fa70b0 | 342 | clean_restart $testfile |
50441f0f | 343 | if { ![runto_main] } then { |
92fa70b0 YQ |
344 | fail "run to main" |
345 | return -1 | |
346 | } | |
347 | ||
348 | set cond_bp_target 1 | |
349 | ||
350 | set test "set breakpoint condition-evaluation target" | |
351 | gdb_test_multiple $test $test { | |
352 | -re "warning: Target does not support breakpoint condition evaluation.\r\nUsing host evaluation mode instead.\r\n$gdb_prompt $" { | |
353 | # Target doesn't support breakpoint condition | |
354 | # evaluation on its side. | |
355 | set cond_bp_target 0 | |
356 | } | |
357 | -re "^$test\r\n$gdb_prompt $" { | |
358 | } | |
359 | } | |
360 | ||
361 | if { $cond_bp_target } { | |
21a77091 YQ |
362 | |
363 | foreach_with_prefix detach-on-fork {"on" "off"} { | |
364 | foreach_with_prefix follow-fork {"parent" "child"} { | |
365 | foreach syscall { "fork" "vfork" "clone" } { | |
366 | ||
367 | if { $syscall == "vfork" | |
368 | && ${follow-fork} == "parent" | |
369 | && ${detach-on-fork} == "off" } { | |
370 | # Both vforked child process and parent process are | |
371 | # under GDB's control, but GDB follows the parent | |
372 | # process only, which can't be run until vforked child | |
373 | # finishes. Skip the test in this scenario. | |
374 | continue | |
375 | } | |
376 | break_cond_on_syscall $syscall ${follow-fork} ${detach-on-fork} | |
377 | } | |
378 | } | |
379 | } | |
92fa70b0 | 380 | } |