1 # This testcase is part of GDB, the GNU debugger. 2 3 # Copyright 2011-2024 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 { displaced syscall syscall_insn_next_addr } { 45 set syscall_insn_next_addr_found [get_hexadecimal_valueof "\$pc" "0"] 46 47 # After the 'stepi' we expect thread 1 to still be selected. 48 set curr_thread "unknown" 49 gdb_test_multiple "thread" "" { 50 -re -wrap "Current thread is (\\d+) .*" { 51 set curr_thread $expect_out(1,string) 52 pass $gdb_test_name 53 } 54 } 55 56 gdb_assert {$syscall_insn_next_addr != 0 \ 57 && $syscall_insn_next_addr == $syscall_insn_next_addr_found \ 58 && $curr_thread == 1} \ 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 73 } 74 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. 79 80 proc setup { syscall } { 81 global gdb_prompt syscall_insn 82 83 global hex 84 set next_insn_addr -1 85 set testfile "step-over-$syscall" 86 87 clean_restart $testfile 88 89 if {![runto_main]} { 90 return -1 91 } 92 93 # Delete the breakpoint on main. 94 gdb_test_no_output "delete break 1" 95 96 gdb_test_no_output "set displaced-stepping off" \ 97 "set displaced-stepping off during test setup" 98 99 gdb_test "break \*$syscall" "Breakpoint \[0-9\]* at .*" 100 101 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in )?(__libc_)?$syscall \\(\\).*" \ 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. 106 107 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in )?(__libc_)?$syscall \\(\\).*" \ 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. 111 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) 117 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 126 } 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 } 144 } 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 } 158 } 159 } 160 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) 167 set actual_syscall_insn $expect_out(2,string) 168 set next_insn_addr $expect_out(3,string) 169 pass $gdb_test_name 170 } 171 } 172 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 195 if {[gdb_test "stepi" "x/i .*=>.*" "stepi $syscall insn"] != 0} { 196 return { -1, -1 } 197 } 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] 206 } 207 208 proc step_over_syscall { syscall } { 209 with_test_prefix "$syscall" { 210 global syscall_insn 211 global gdb_prompt 212 213 set testfile "step-over-$syscall" 214 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] { 221 untested "failed to compile" 222 return -1 223 } 224 225 foreach_with_prefix displaced {"off" "on"} { 226 if {$displaced == "on" && ![support_displaced_stepping]} { 227 continue 228 } 229 230 set ret [setup $syscall] 231 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 } 237 238 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in )?(__libc_)?$syscall \\(\\).*" \ 239 "continue to $syscall, 3rd time" 240 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. 243 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 } 250 } 251 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 } 259 260 gdb_test_no_output "set displaced-stepping $displaced" 261 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 } 266 check_pc_after_cross_syscall $displaced $syscall $syscall_insn_next_addr 267 268 # Delete breakpoint syscall insns to avoid interference to other syscalls. 269 delete_breakpoints 270 271 gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" 272 273 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \ 274 "continue to marker ($syscall)" 275 } 276 } 277 } 278 279 # Set a breakpoint with a condition that evals false on syscall 280 # instruction. In fact, it tests GDBserver steps over syscall 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". 284 285 proc break_cond_on_syscall { syscall follow_fork detach_on_fork } { 286 with_test_prefix "break cond on target : $syscall" { 287 set testfile "step-over-$syscall" 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 297 gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in )?(__libc_)?$syscall \\(\\).*" \ 298 "continue to $syscall" 299 # Delete breakpoint syscall insns to avoid interference with other syscalls. 300 delete_breakpoints 301 302 gdb_test "set follow-fork-mode $follow_fork" 303 gdb_test "set detach-on-fork $detach_on_fork" 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 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 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.*" 333 gdb_test "continue" "Continuing\\..*Breakpoint $::bkptno_numopt_re, marker \\(\\) at.*" \ 334 "continue to marker" 335 } 336 } else { 337 gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" 338 gdb_test "continue" "Continuing\\..*Breakpoint $::bkptno_numopt_re, marker \\(\\) at.*" \ 339 "continue to marker" 340 } 341 } 342 } 343 } 344 345 step_over_syscall "fork" 346 step_over_syscall "vfork" 347 step_over_syscall "clone" 348 349 set testfile "step-over-fork" 350 clean_restart $testfile 351 if {![runto_main]} { 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 } { 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 } 387 } 388