Refactor gdb.base/disp-step-syscall.exp for general step over test
[external/binutils.git] / gdb / testsuite / gdb.base / disp-step-syscall.exp
1 # This testcase is part of GDB, the GNU debugger.
2
3 # Copyright 2011-2016 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 if { ![support_displaced_stepping] } {
19     unsupported "displaced stepping"
20     return -1
21 }
22
23 set syscall_insn ""
24
25 # Define the syscall instruction for each target.
26
27 if { [istarget "i\[34567\]86-*-linux*"] || [istarget "x86_64-*-linux*"] } {
28     set syscall_insn "\[ \t\](int|syscall|sysenter)\[ \t\]"
29 } elseif { [istarget "aarch64*-*-linux*"] || [istarget "arm*-*-linux*"] } {
30     set syscall_insn "\[ \t\](swi|svc)\[ \t\]"
31 } else {
32     return -1
33 }
34
35 proc check_pc_after_cross_syscall { syscall syscall_insn_next_addr } {
36     set syscall_insn_next_addr_found [get_hexadecimal_valueof "\$pc" "0"]
37
38     set test "single step over $syscall final pc"
39     if {$syscall_insn_next_addr != 0
40         && $syscall_insn_next_addr == $syscall_insn_next_addr_found} {
41         pass $test
42     } else {
43         fail $test
44     }
45 }
46
47 # Restart GDB and set up the test.  Return a list in which the first one
48 # is the address of syscall instruction and the second one is the address
49 # of the next instruction address of syscall instruction.  If anything
50 # wrong, the two elements of list are -1.
51
52 proc setup { syscall } {
53     global gdb_prompt syscall_insn
54
55     set testfile "disp-step-$syscall"
56
57     clean_restart $testfile
58
59     if { ![runto main] } then {
60         fail "run to main ($syscall)"
61         return -1
62     }
63
64     # Delete the breakpoint on main.
65     gdb_test_no_output "delete break 1"
66
67     gdb_test_no_output "set displaced-stepping off"
68
69     gdb_test "break $syscall" "Breakpoint \[0-9\]* at .*"
70
71     gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \
72         "continue to $syscall (1st time)"
73     # Hit the breakpoint on $syscall for the first time.  In this time,
74     # we will let PLT resolution done, and the number single steps we will
75     # do later will be reduced.
76
77     gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \
78         "continue to $syscall (2nd time)"
79     # Hit the breakpoint on $syscall for the second time.  In this time,
80     # the address of syscall insn and next insn of syscall are recorded.
81
82     gdb_test "display/i \$pc" ".*"
83
84     # Single step until we see a syscall insn or we reach the
85     # upper bound of loop iterations.
86     set msg "find syscall insn in $syscall"
87     set steps 0
88     set max_steps 1000
89     gdb_test_multiple "stepi" $msg {
90         -re ".*$syscall_insn.*$gdb_prompt $" {
91             pass $msg
92         }
93         -re "x/i .*=>.*\r\n$gdb_prompt $" {
94             incr steps
95             if {$steps == $max_steps} {
96                 fail $msg
97             } else {
98                 send_gdb "stepi\n"
99                 exp_continue
100             }
101         }
102     }
103
104     if {$steps == $max_steps} {
105         return { -1, -1 }
106     }
107
108     set syscall_insn_addr [get_hexadecimal_valueof "\$pc" "0"]
109     if {[gdb_test "stepi" "x/i .*=>.*" "stepi $syscall insn"] != 0} {
110         return { -1, -1 }
111     }
112     return [list $syscall_insn_addr [get_hexadecimal_valueof "\$pc" "0"]]
113 }
114
115 proc disp_step_cross_syscall { syscall } {
116     with_test_prefix "$syscall" {
117         global syscall_insn
118         global gdb_prompt
119
120         set testfile "disp-step-$syscall"
121
122         if [build_executable ${testfile}.exp ${testfile} ${testfile}.c {debug}] {
123             untested ${testfile}.exp
124             return -1
125         }
126
127         set ret [setup $syscall]
128
129         set syscall_insn_addr [lindex $ret 0]
130         set syscall_insn_next_addr [lindex $ret 1]
131         if { $syscall_insn_addr == -1 } {
132             return -1
133         }
134
135         gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, (.* in |__libc_|)$syscall \\(\\).*" \
136             "continue to $syscall (3rd time)"
137
138         # Hit the breakpoint on $syscall for the third time.  In this time, we'll set
139         # breakpoint on the syscall insn we recorded previously, and single step over it.
140
141         set syscall_insn_bp 0
142         gdb_test_multiple "break \*$syscall_insn_addr"  "break on syscall insn" {
143             -re "Breakpoint (\[0-9\]*) at .*$gdb_prompt $" {
144                 set syscall_insn_bp $expect_out(1,string)
145                 pass "break on syscall insns"
146             }
147         }
148
149         gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, .*" \
150             "continue to syscall insn $syscall"
151
152         gdb_test_no_output "set displaced-stepping on"
153
154         # Check the address of next instruction of syscall.
155         if {[gdb_test "stepi" "x/i .*=>.*" "single step over $syscall"] != 0} {
156             return -1
157         }
158
159         check_pc_after_cross_syscall $syscall $syscall_insn_next_addr
160
161         # Delete breakpoint syscall insns to avoid interference to other syscalls.
162         delete_breakpoints
163
164         gdb_test "break marker" "Breakpoint.*at.* file .*${testfile}.c, line.*"
165         gdb_test "continue" "Continuing\\..*Breakpoint \[0-9\]+, marker \\(\\) at.*" \
166             "continue to marker ($syscall)"
167     }
168 }
169
170 disp_step_cross_syscall "fork"
171 disp_step_cross_syscall "vfork"