]>
Commit | Line | Data |
---|---|---|
9c317b71 YQ |
1 | # This testcase is part of GDB, the GNU debugger. |
2 | ||
1d506c26 | 3 | # Copyright 2011-2024 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*"] } { | |
202be274 | 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 | ||
99ba4b64 | 44 | proc_with_prefix check_pc_after_cross_syscall { displaced syscall syscall_insn_next_addr } { |
0b47da9f YQ |
45 | set syscall_insn_next_addr_found [get_hexadecimal_valueof "\$pc" "0"] |
46 | ||
99ba4b64 | 47 | # After the 'stepi' we expect thread 1 to still be selected. |
99ba4b64 | 48 | set curr_thread "unknown" |
6bd50ebd PA |
49 | gdb_test_multiple "thread" "" { |
50 | -re -wrap "Current thread is (\\d+) .*" { | |
99ba4b64 | 51 | set curr_thread $expect_out(1,string) |
6bd50ebd | 52 | pass $gdb_test_name |
99ba4b64 AB |
53 | } |
54 | } | |
55 | ||
16b10d6e | 56 | gdb_assert {$syscall_insn_next_addr != 0 \ |
99ba4b64 AB |
57 | && $syscall_insn_next_addr == $syscall_insn_next_addr_found \ |
58 | && $curr_thread == 1} \ | |
16b10d6e LM |
59 | "single step over $syscall final pc" |
60 | } | |
61 | ||
62 | # Verify the syscall number is the correct one. | |
63 | ||
64 | proc syscall_number_matches { syscall } { | |
65 | global syscall_register syscall_number | |
66 | ||
67 | if {[gdb_test "p \$$syscall_register" ".*= $syscall_number($syscall)" \ | |
68 | "syscall number matches"] != 0} { | |
69 | return 0 | |
70 | } | |
71 | ||
72 | return 1 | |
0b47da9f | 73 | } |
9c317b71 | 74 | |
0b47da9f YQ |
75 | # Restart GDB and set up the test. Return a list in which the first one |
76 | # is the address of syscall instruction and the second one is the address | |
77 | # of the next instruction address of syscall instruction. If anything | |
78 | # wrong, the two elements of list are -1. | |
9c317b71 | 79 | |
0b47da9f YQ |
80 | proc setup { syscall } { |
81 | global gdb_prompt syscall_insn | |
9c317b71 | 82 | |
16b10d6e LM |
83 | global hex |
84 | set next_insn_addr -1 | |
8fc8cbda | 85 | set testfile "step-over-$syscall" |
9c317b71 | 86 | |
0b47da9f | 87 | clean_restart $testfile |
9c317b71 | 88 | |
65a33d75 | 89 | if {![runto_main]} { |
0b47da9f YQ |
90 | return -1 |
91 | } | |
9c317b71 | 92 | |
0b47da9f YQ |
93 | # Delete the breakpoint on main. |
94 | gdb_test_no_output "delete break 1" | |
9c317b71 | 95 | |
2b74ba5a AB |
96 | gdb_test_no_output "set displaced-stepping off" \ |
97 | "set displaced-stepping off during test setup" | |
9c317b71 | 98 | |
16b10d6e | 99 | gdb_test "break \*$syscall" "Breakpoint \[0-9\]* at .*" |
9c317b71 | 100 | |
906c2c65 | 101 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in )?(__libc_)?$syscall \\(\\).*" \ |
0b47da9f YQ |
102 | "continue to $syscall (1st time)" |
103 | # Hit the breakpoint on $syscall for the first time. In this time, | |
104 | # we will let PLT resolution done, and the number single steps we will | |
105 | # do later will be reduced. | |
9c317b71 | 106 | |
906c2c65 | 107 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in )?(__libc_)?$syscall \\(\\).*" \ |
0b47da9f YQ |
108 | "continue to $syscall (2nd time)" |
109 | # Hit the breakpoint on $syscall for the second time. In this time, | |
110 | # the address of syscall insn and next insn of syscall are recorded. | |
9c317b71 | 111 | |
16b10d6e LM |
112 | # Check if the first instruction we stopped at is the syscall one. |
113 | set syscall_insn_addr -1 | |
114 | gdb_test_multiple "display/i \$pc" "fetch first stop pc" { | |
115 | -re "display/i .*: x/i .*=> ($hex) .*:.*$syscall_insn.*$gdb_prompt $" { | |
116 | set insn_addr $expect_out(1,string) | |
0b47da9f | 117 | |
16b10d6e LM |
118 | # Is the syscall number the correct one? |
119 | if {[syscall_number_matches $syscall]} { | |
120 | set syscall_insn_addr $insn_addr | |
121 | } | |
122 | pass $gdb_test_name | |
123 | } | |
124 | -re ".*$gdb_prompt $" { | |
125 | pass $gdb_test_name | |
0b47da9f | 126 | } |
16b10d6e LM |
127 | } |
128 | ||
129 | # If we are not at the syscall instruction yet, keep looking for it with | |
130 | # stepi commands. | |
131 | if {$syscall_insn_addr == -1} { | |
132 | # Single step until we see a syscall insn or we reach the | |
133 | # upper bound of loop iterations. | |
134 | set steps 0 | |
135 | set max_steps 1000 | |
136 | gdb_test_multiple "stepi" "find syscall insn in $syscall" { | |
137 | -re ".*$syscall_insn.*$gdb_prompt $" { | |
138 | # Is the syscall number the correct one? | |
139 | if {[syscall_number_matches $syscall]} { | |
140 | pass $gdb_test_name | |
141 | } else { | |
142 | exp_continue | |
143 | } | |
9c317b71 | 144 | } |
16b10d6e LM |
145 | -re "x/i .*=>.*\r\n$gdb_prompt $" { |
146 | incr steps | |
147 | if {$steps == $max_steps} { | |
148 | fail $gdb_test_name | |
149 | } else { | |
150 | send_gdb "stepi\n" | |
151 | exp_continue | |
152 | } | |
153 | } | |
154 | } | |
155 | ||
156 | if {$steps == $max_steps} { | |
157 | return { -1, -1 } | |
9c317b71 | 158 | } |
0b47da9f YQ |
159 | } |
160 | ||
16b10d6e LM |
161 | # We have found the syscall instruction. Now record the next instruction. |
162 | # Use the X command instead of stepi since we can't guarantee | |
163 | # stepi is working properly. | |
164 | gdb_test_multiple "x/2i \$pc" "pc before/after syscall instruction" { | |
165 | -re "x/2i .*=> ($hex) .*:.*$syscall_insn.* ($hex) .*:.*$gdb_prompt $" { | |
166 | set syscall_insn_addr $expect_out(1,string) | |
14852123 | 167 | set actual_syscall_insn $expect_out(2,string) |
16b10d6e LM |
168 | set next_insn_addr $expect_out(3,string) |
169 | pass $gdb_test_name | |
170 | } | |
0b47da9f YQ |
171 | } |
172 | ||
14852123 TV |
173 | # If we encounter a sequence: |
174 | # 0xf7fd5155 <__kernel_vsyscall+5>: sysenter | |
175 | # 0xf7fd5157 <__kernel_vsyscall+7>: int $0x80 | |
176 | # 0xf7fd5159 <__kernel_vsyscall+9>: pop %ebp | |
177 | # then a stepi at sysenter will step over the int insn, so make sure | |
178 | # next_insn_addr points after the int insn. | |
179 | if { $actual_syscall_insn == "sysenter" } { | |
180 | set test "pc after sysenter instruction" | |
181 | set re_int_insn "\[ \t\]*int\[ \t\]\[^\r\n\]*" | |
182 | set re [multi_line \ | |
183 | "x/2i $hex" \ | |
184 | "\[^\r\n\]* $hex \[^\r\n\]*:$re_int_insn" \ | |
185 | "\[^\r\n\]* ($hex) \[^\r\n\]*:\[^\r\n\]*"] | |
186 | gdb_test_multiple "x/2i $next_insn_addr" $test { | |
187 | -re -wrap $re { | |
188 | set next_insn_addr $expect_out(1,string) | |
189 | } | |
190 | -re -wrap "" { | |
191 | } | |
192 | } | |
193 | } | |
194 | ||
0b47da9f YQ |
195 | if {[gdb_test "stepi" "x/i .*=>.*" "stepi $syscall insn"] != 0} { |
196 | return { -1, -1 } | |
197 | } | |
16b10d6e LM |
198 | |
199 | set pc_after_stepi [get_hexadecimal_valueof "\$pc" "0" \ | |
200 | "pc after stepi"] | |
201 | ||
202 | gdb_assert {$next_insn_addr == $pc_after_stepi} \ | |
203 | "pc after stepi matches insn addr after syscall" | |
204 | ||
205 | return [list $syscall_insn_addr $pc_after_stepi] | |
0b47da9f | 206 | } |
9c317b71 | 207 | |
8fc8cbda | 208 | proc step_over_syscall { syscall } { |
0b47da9f YQ |
209 | with_test_prefix "$syscall" { |
210 | global syscall_insn | |
211 | global gdb_prompt | |
212 | ||
8fc8cbda | 213 | set testfile "step-over-$syscall" |
0b47da9f | 214 | |
99ba4b64 AB |
215 | set options [list debug] |
216 | if { $syscall == "clone" } { | |
217 | lappend options "pthreads" | |
218 | } | |
219 | ||
220 | if [build_executable ${testfile}.exp ${testfile} ${testfile}.c $options] { | |
5b362f04 | 221 | untested "failed to compile" |
0a251e08 YQ |
222 | return -1 |
223 | } | |
9c317b71 | 224 | |
e197ad3c YQ |
225 | foreach_with_prefix displaced {"off" "on"} { |
226 | if {$displaced == "on" && ![support_displaced_stepping]} { | |
227 | continue | |
228 | } | |
229 | ||
ea507862 | 230 | set ret [setup $syscall] |
0b47da9f | 231 | |
ea507862 YQ |
232 | set syscall_insn_addr [lindex $ret 0] |
233 | set syscall_insn_next_addr [lindex $ret 1] | |
234 | if { $syscall_insn_addr == -1 } { | |
235 | return -1 | |
236 | } | |
9c317b71 | 237 | |
906c2c65 | 238 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in )?(__libc_)?$syscall \\(\\).*" \ |
ea507862 | 239 | "continue to $syscall (3rd time)" |
9c317b71 | 240 | |
ea507862 YQ |
241 | # Hit the breakpoint on $syscall for the third time. In this time, we'll set |
242 | # breakpoint on the syscall insn we recorded previously, and single step over it. | |
9c317b71 | 243 | |
ea507862 YQ |
244 | set syscall_insn_bp 0 |
245 | gdb_test_multiple "break \*$syscall_insn_addr" "break on syscall insn" { | |
246 | -re "Breakpoint (\[0-9\]*) at .*$gdb_prompt $" { | |
247 | set syscall_insn_bp $expect_out(1,string) | |
248 | pass "break on syscall insns" | |
249 | } | |
0a251e08 | 250 | } |
9c317b71 | 251 | |
16b10d6e LM |
252 | # Check if the syscall breakpoint is at the syscall instruction |
253 | # address. If so, no need to continue, otherwise we will run the | |
254 | # inferior to completion. | |
255 | if {$syscall_insn_addr != [get_hexadecimal_valueof "\$pc" "0"]} { | |
256 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, .*" \ | |
257 | "continue to syscall insn $syscall" | |
258 | } | |
9c317b71 | 259 | |
ea507862 | 260 | gdb_test_no_output "set displaced-stepping $displaced" |
9c317b71 | 261 | |
ea507862 YQ |
262 | # Check the address of next instruction of syscall. |
263 | if {[gdb_test "stepi" "x/i .*=>.*" "single step over $syscall"] != 0} { | |
264 | return -1 | |
265 | } | |
99ba4b64 | 266 | check_pc_after_cross_syscall $displaced $syscall $syscall_insn_next_addr |
dfe2ac14 | 267 | |
ea507862 YQ |
268 | # Delete breakpoint syscall insns to avoid interference to other syscalls. |
269 | delete_breakpoints | |
9a7f938f | 270 | |
ea507862 | 271 | gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" |
99ba4b64 | 272 | |
ea507862 YQ |
273 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \ |
274 | "continue to marker ($syscall)" | |
e197ad3c | 275 | } |
9a7f938f | 276 | } |
0a251e08 | 277 | } |
9c317b71 | 278 | |
92fa70b0 YQ |
279 | # Set a breakpoint with a condition that evals false on syscall |
280 | # instruction. In fact, it tests GDBserver steps over syscall | |
21a77091 YQ |
281 | # instruction. SYSCALL is the syscall the program calls. |
282 | # FOLLOW_FORK is either "parent" or "child". DETACH_ON_FORK is | |
283 | # "on" or "off". | |
92fa70b0 | 284 | |
21a77091 | 285 | proc break_cond_on_syscall { syscall follow_fork detach_on_fork } { |
92fa70b0 | 286 | with_test_prefix "break cond on target : $syscall" { |
8fc8cbda | 287 | set testfile "step-over-$syscall" |
92fa70b0 YQ |
288 | |
289 | set ret [setup $syscall] | |
290 | ||
291 | set syscall_insn_addr [lindex $ret 0] | |
292 | set syscall_insn_next_addr [lindex $ret 1] | |
293 | if { $syscall_insn_addr == -1 } { | |
294 | return -1 | |
295 | } | |
296 | ||
906c2c65 | 297 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in )?(__libc_)?$syscall \\(\\).*" \ |
92fa70b0 YQ |
298 | "continue to $syscall" |
299 | # Delete breakpoint syscall insns to avoid interference with other syscalls. | |
300 | delete_breakpoints | |
301 | ||
21a77091 YQ |
302 | gdb_test "set follow-fork-mode $follow_fork" |
303 | gdb_test "set detach-on-fork $detach_on_fork" | |
92fa70b0 YQ |
304 | |
305 | # Create a breakpoint with a condition that evals false. | |
306 | gdb_test "break \*$syscall_insn_addr if main == 0" \ | |
307 | "Breakpoint \[0-9\]* at .*" | |
308 | ||
4719d415 YQ |
309 | if { $syscall == "clone" } { |
310 | # Create a breakpoint in the child with the condition that | |
311 | # evals false, so that GDBserver can get the event from the | |
312 | # child but GDB doesn't see it. In this way, we don't have | |
313 | # to adjust the test flow for "clone". | |
314 | # This is a regression test for PR server/19736. In this way, | |
315 | # we can test that GDBserver gets an event from the child and | |
316 | # set suspend count correctly while the parent is stepping over | |
317 | # the breakpoint. | |
318 | gdb_test "break clone_fn if main == 0" | |
319 | } | |
320 | ||
21a77091 YQ |
321 | if { $syscall == "clone" } { |
322 | # follow-fork and detach-on-fork only make sense to | |
323 | # fork and vfork. | |
324 | gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" | |
325 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \ | |
326 | "continue to marker" | |
327 | } else { | |
328 | if { $follow_fork == "child" } { | |
329 | gdb_test "continue" "exited normally.*" "continue to end of inf 2" | |
330 | if { $detach_on_fork == "off" } { | |
331 | gdb_test "inferior 1" | |
332 | gdb_test "break marker" "Breakpoint.*at.*" | |
e66c9ede | 333 | gdb_test "continue" "Continuing\\..*Breakpoint $::bkptno_numopt_re, marker \\(\\) at.*" \ |
21a77091 YQ |
334 | "continue to marker" |
335 | } | |
336 | } else { | |
337 | gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" | |
e66c9ede | 338 | gdb_test "continue" "Continuing\\..*Breakpoint $::bkptno_numopt_re, marker \\(\\) at.*" \ |
21a77091 YQ |
339 | "continue to marker" |
340 | } | |
341 | } | |
92fa70b0 YQ |
342 | } |
343 | } | |
344 | ||
8fc8cbda YQ |
345 | step_over_syscall "fork" |
346 | step_over_syscall "vfork" | |
4719d415 | 347 | step_over_syscall "clone" |
92fa70b0 | 348 | |
8fc8cbda | 349 | set testfile "step-over-fork" |
92fa70b0 | 350 | clean_restart $testfile |
65a33d75 | 351 | if {![runto_main]} { |
92fa70b0 YQ |
352 | return -1 |
353 | } | |
354 | ||
355 | set cond_bp_target 1 | |
356 | ||
357 | set test "set breakpoint condition-evaluation target" | |
358 | gdb_test_multiple $test $test { | |
359 | -re "warning: Target does not support breakpoint condition evaluation.\r\nUsing host evaluation mode instead.\r\n$gdb_prompt $" { | |
360 | # Target doesn't support breakpoint condition | |
361 | # evaluation on its side. | |
362 | set cond_bp_target 0 | |
363 | } | |
364 | -re "^$test\r\n$gdb_prompt $" { | |
365 | } | |
366 | } | |
367 | ||
368 | if { $cond_bp_target } { | |
21a77091 YQ |
369 | |
370 | foreach_with_prefix detach-on-fork {"on" "off"} { | |
371 | foreach_with_prefix follow-fork {"parent" "child"} { | |
372 | foreach syscall { "fork" "vfork" "clone" } { | |
373 | ||
374 | if { $syscall == "vfork" | |
375 | && ${follow-fork} == "parent" | |
376 | && ${detach-on-fork} == "off" } { | |
377 | # Both vforked child process and parent process are | |
378 | # under GDB's control, but GDB follows the parent | |
379 | # process only, which can't be run until vforked child | |
380 | # finishes. Skip the test in this scenario. | |
381 | continue | |
382 | } | |
383 | break_cond_on_syscall $syscall ${follow-fork} ${detach-on-fork} | |
384 | } | |
385 | } | |
386 | } | |
92fa70b0 | 387 | } |