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 18set syscall_insn "" 19set syscall_register "" 20array set syscall_number {} 21 22# Define the syscall instructions, registers and numbers for each target. 23 24if { [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 44proc_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 54proc 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 70proc 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 176proc 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 254proc 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 314step_over_syscall "fork" 315step_over_syscall "vfork" 316step_over_syscall "clone" 317 318set testfile "step-over-fork" 319clean_restart $testfile 320if { ![runto main] } then { 321 fail "run to main" 322 return -1 323} 324 325set cond_bp_target 1 326 327set test "set breakpoint condition-evaluation target" 328gdb_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 338if { $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} 358