Home | History | Annotate | Line # | Download | only in gdb.base
      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