Commit | Line | Data |
---|---|---|
9c317b71 YQ |
1 | # This testcase is part of GDB, the GNU debugger. |
2 | ||
3666a048 | 3 | # Copyright 2011-2021 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) | |
158 | set next_insn_addr $expect_out(3,string) | |
159 | pass $gdb_test_name | |
160 | } | |
0b47da9f YQ |
161 | } |
162 | ||
0b47da9f YQ |
163 | if {[gdb_test "stepi" "x/i .*=>.*" "stepi $syscall insn"] != 0} { |
164 | return { -1, -1 } | |
165 | } | |
16b10d6e LM |
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] | |
0b47da9f | 174 | } |
9c317b71 | 175 | |
8fc8cbda | 176 | proc step_over_syscall { syscall } { |
0b47da9f YQ |
177 | with_test_prefix "$syscall" { |
178 | global syscall_insn | |
179 | global gdb_prompt | |
180 | ||
8fc8cbda | 181 | set testfile "step-over-$syscall" |
0b47da9f YQ |
182 | |
183 | if [build_executable ${testfile}.exp ${testfile} ${testfile}.c {debug}] { | |
5b362f04 | 184 | untested "failed to compile" |
0a251e08 YQ |
185 | return -1 |
186 | } | |
9c317b71 | 187 | |
e197ad3c YQ |
188 | foreach_with_prefix displaced {"off" "on"} { |
189 | if {$displaced == "on" && ![support_displaced_stepping]} { | |
190 | continue | |
191 | } | |
192 | ||
4719d415 YQ |
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 | ||
ea507862 | 200 | set ret [setup $syscall] |
0b47da9f | 201 | |
ea507862 YQ |
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 | } | |
9c317b71 | 207 | |
ea507862 YQ |
208 | gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \ |
209 | "continue to $syscall (3rd time)" | |
9c317b71 | 210 | |
ea507862 YQ |
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. | |
9c317b71 | 213 | |
ea507862 YQ |
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 | } | |
0a251e08 | 220 | } |
9c317b71 | 221 | |
16b10d6e LM |
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 | } | |
9c317b71 | 229 | |
ea507862 | 230 | gdb_test_no_output "set displaced-stepping $displaced" |
9c317b71 | 231 | |
ea507862 YQ |
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 | |
dfe2ac14 | 237 | |
ea507862 YQ |
238 | # Delete breakpoint syscall insns to avoid interference to other syscalls. |
239 | delete_breakpoints | |
9a7f938f | 240 | |
ea507862 YQ |
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)" | |
e197ad3c | 244 | } |
9a7f938f | 245 | } |
0a251e08 | 246 | } |
9c317b71 | 247 | |
92fa70b0 YQ |
248 | # Set a breakpoint with a condition that evals false on syscall |
249 | # instruction. In fact, it tests GDBserver steps over syscall | |
21a77091 YQ |
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". | |
92fa70b0 | 253 | |
21a77091 | 254 | proc break_cond_on_syscall { syscall follow_fork detach_on_fork } { |
92fa70b0 | 255 | with_test_prefix "break cond on target : $syscall" { |
8fc8cbda | 256 | set testfile "step-over-$syscall" |
92fa70b0 YQ |
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 | ||
21a77091 YQ |
271 | gdb_test "set follow-fork-mode $follow_fork" |
272 | gdb_test "set detach-on-fork $detach_on_fork" | |
92fa70b0 YQ |
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 | ||
4719d415 YQ |
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 | ||
21a77091 YQ |
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 | } | |
92fa70b0 YQ |
311 | } |
312 | } | |
313 | ||
8fc8cbda YQ |
314 | step_over_syscall "fork" |
315 | step_over_syscall "vfork" | |
4719d415 | 316 | step_over_syscall "clone" |
92fa70b0 | 317 | |
8fc8cbda | 318 | set testfile "step-over-fork" |
92fa70b0 | 319 | clean_restart $testfile |
50441f0f | 320 | if { ![runto_main] } then { |
92fa70b0 YQ |
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 } { | |
21a77091 YQ |
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 | } | |
92fa70b0 | 357 | } |