# This testcase is part of GDB, the GNU debugger. # Copyright 2011-2012 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . if { ![support_displaced_stepping] } { unsupported "displaced stepping" return -1 } set syscall_insn "" # Define the syscall instruction for each target. if { [istarget "i\[34567\]86-*-linux*"] || [istarget "x86_64-*-linux*"] } { set syscall_insn "(int|syscall|sysenter)" } else { return -1 } proc disp_step_cross_syscall { syscall } { global syscall_insn global gdb_prompt global pf_prefix set testfile "disp-step-$syscall" if [prepare_for_testing ${testfile}.exp ${testfile} ${testfile}.c {debug}] { untested ${testfile}.exp return -1 } if { ![runto main] } then { fail "run to main ($syscall)" return } set old_pf_prefix $pf_prefix lappend pf_prefix "$syscall:" # Delete the breakpoint on main. gdb_test_no_output "delete break 1" gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*" gdb_test_no_output "set displaced-stepping off" set syscall_bp 0 gdb_test_multiple "break $syscall" "break $syscall" { -re "Breakpoint (\[0-9\]*) at .*$gdb_prompt $" { set syscall_bp $expect_out(1,string) pass "break $syscall" } } gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \ "continue to $syscall (1st time)" # Hit the breakpoint on $syscall for the first time. In this time, we will let PLT # resolution done, and the number single steps we will do later will be # reduced. gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \ "continue to $syscall (2nd time)" # Hit the breakpoint on $syscall for the second time. In this time, the address # of syscall insn and next insn of syscall are recorded. gdb_test "display/i \$pc" ".*" # Single step until we see sysall insn or we reach the upper bound of loop # iterations. set see_syscall_insn 0 for {set i 0} {$i < 1000 && $see_syscall_insn == 0} {incr i} { send_gdb "stepi\n" gdb_expect { -re ".*$syscall_insn.*$gdb_prompt $" { set see_syscall_insn 1 } -re ".*$gdb_prompt $" {} } } if {$see_syscall_insn == 0} then { fail "find syscall insn in $syscall" set pf_prefix $old_pf_prefix return -1 } set syscall_insn_addr [get_hexadecimal_valueof "\$pc" "0"] gdb_test "stepi" ".*" "stepi $syscall insn" set syscall_insn_next_addr [get_hexadecimal_valueof "\$pc" "0"] gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \ "continue to $syscall (3rd time)" # Hit the breakpoint on $syscall for the third time. In this time, we'll set # breakpoint on the syscall insn we recorded previously, and single step over it. set syscall_insn_bp 0 gdb_test_multiple "break \*$syscall_insn_addr" "break on syscall insn" { -re "Breakpoint (\[0-9\]*) at .*$gdb_prompt $" { set syscall_insn_bp $expect_out(1,string) pass "break on syscall insns" } } gdb_test_no_output "delete $syscall_bp" "delete break $syscall" gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, .*" \ "continue to syscall insn $syscall" gdb_test_no_output "set displaced-stepping on" # Check the address of next instruction of syscall. gdb_test "stepi" ".*$syscall_insn_next_addr.*" "single step over $syscall" # Delete breakpoint syscall insns to avoid interference to other syscalls. gdb_test_no_output "delete $syscall_insn_bp" "delete break $syscall insn" gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \ "continue to marker ($syscall)" set pf_prefix $old_pf_prefix } disp_step_cross_syscall "fork" disp_step_cross_syscall "vfork"