]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.base/longjmp.exp
f74891aa7caa90c15c11774dab4079ba9bdbf227
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.base / longjmp.exp
1 # Copyright 2008-2023 Free Software Foundation, Inc.
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 3 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 #
17 # Test support for stepping over longjmp.
18 #
19
20
21 standard_testfile .c
22
23 if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug nowarnings}] != "" } {
24 untested "failed to compile"
25 return -1
26 }
27
28 proc do_test { with_probes } {
29 clean_restart ${::binfile}
30
31 if { !$with_probes } {
32 gdb_test "maint ignore-probes libc ^longjmp$"
33 }
34
35 if {![runto_main]} {
36 return 0
37 }
38
39 # With a libc with probes, all tests should pass.
40 #
41 # Without probes, we can still set a break on longjmp, but getting the longjmp
42 # target may not work, in the following cases:
43 # - gdbarch_get_longjmp_target_p (gdbarch) == 0: not implemented.
44 # - gdbarch_get_longjmp_target (gdbarch) == 0: for instance on amd64 if
45 # tdep->jb_pc_offset == -1.
46 # - gdbarch_get_longjmp_target (gdbarch) != 0: if we have a glibc with
47 # pointer mangling ( https://sourceware.org/glibc/wiki/PointerEncryption )
48 # then we retrieve a mangled longjmp target that needs to be demangled.
49 # For instance on amd64 with target board unix/-m32.
50 #
51 # Pointer demangling is currently not implemented for any target.
52 # For the amd64 case, this would require copying for instance this:
53 # 48 c1 ca 11 ror $0x11,%rdx
54 # 64 48 33 14 25 30 00 xor %fs:0x30,%rdx
55 # into a scratch space, save the register set, set %rdx to the mangled
56 # longjmp target, displaced-step through the two insn and read the
57 # demangled longjmp target from %rdx, and restore the register set.
58 #
59 # The failure mode in the first two cases is that the next degrades into a
60 # continue. The failure mode in the latter case is a failure to set a
61 # breakpoint (matched by re_cannot_insert_bp) and a stop in longjmp.
62 #
63 # We detect the different failure modes and kfail these.
64
65 set have_longjmp_probe 0
66 gdb_test_multiple "info probes stap libc ^longjmp$" "" {
67 -re -wrap "No probes matched\\." {
68 pass $gdb_test_name
69 }
70 -re -wrap "\r\nstap\[ \t\]+libc\[ \t\]+longjmp\[ \t\]+.*" {
71 pass $gdb_test_name
72 set have_longjmp_probe 1
73 }
74 }
75
76 if { $with_probes } {
77 if { !$have_longjmp_probe } {
78 unsupported "longjmp probe required"
79 return
80 }
81 } else {
82 gdb_assert { !$have_longjmp_probe }
83 }
84
85 # When using these line numbers in break linespecs, prefix each of these
86 # with "$subdir/$srcfile:" to avoid referring to a glibc file when stopped
87 # in __libc_siglongjmp or similar.
88 set bp_miss_step_1 [gdb_get_line_number "miss_step_1"]
89 set bp_miss_step_2 [gdb_get_line_number "miss_step_2"]
90
91 set bp_start_test_1 [gdb_get_line_number "patt1"]
92 set bp_start_test_2 [gdb_get_line_number "patt2"]
93 set bp_start_test_3 [gdb_get_line_number "patt3"]
94
95 set re_cannot_insert_bp \
96 [multi_line \
97 "Warning:" \
98 "Cannot insert breakpoint $::decimal\\." \
99 "Cannot access memory at address $::hex"]
100
101 #
102 # Pattern 1 - simple longjmp.
103 #
104
105 with_test_prefix "pattern 1" {
106
107 with_test_prefix setup {
108 delete_breakpoints
109
110 gdb_test "break $::subdir/$::srcfile:$bp_start_test_1" \
111 "Breakpoint.*at.* file .*$::srcfile, line.*$bp_start_test_1.*" \
112 "breakpoint at pattern start"
113 gdb_test "continue" "patt1.*" "continue to breakpoint at pattern start"
114
115 # set safe-net break
116 gdb_test "break $::subdir/$::srcfile:$bp_miss_step_1" \
117 "Breakpoint.*at.* file .*$::srcfile, line.*$bp_miss_step_1.*" \
118 "breakpoint at safety net"
119 }
120
121 gdb_test "next" "longjmps\\+\\+;.*" "next over setjmp"
122 gdb_test "next" "longjmp \\(env, 1\\);.*" "next to longjmp"
123
124 set msg "next over longjmp"
125 gdb_test_multiple "next" $msg {
126 -re ".*patt1.*$::gdb_prompt $" {
127 pass $msg
128 gdb_test "next" "resumes\\+\\+.*" "next into else block"
129 gdb_test "next" "miss_step_1.*" "next into safety net"
130 }
131 -re "miss_step_1.*$::gdb_prompt $" {
132 if { $have_longjmp_probe } {
133 fail $gdb_test_name
134 } else {
135 kfail $gdb_test_name "gdb/26967"
136 }
137 }
138 -re -wrap "\r\n$re_cannot_insert_bp\r\n.*" {
139 if { $have_longjmp_probe } {
140 fail $gdb_test_name
141 } else {
142 kfail $gdb_test_name "gdb/26967"
143 }
144 }
145 }
146 }
147
148 #
149 # Pattern 2 - longjmp from an inner function.
150 #
151
152 with_test_prefix "pattern 2" {
153
154 with_test_prefix setup {
155 delete_breakpoints
156
157 gdb_test "break $::subdir/$::srcfile:$bp_start_test_2" \
158 "Breakpoint.*at.* file .*$::srcfile, line.*$bp_start_test_2.*" \
159 "breakpoint at pattern start"
160 gdb_test "continue" "patt2.*" "continue to breakpoint at pattern start"
161
162 # set safe-net break
163 gdb_test "break $::subdir/$::srcfile:$bp_miss_step_2" \
164 "Breakpoint.*at.* file .*$::srcfile, line.*$bp_miss_step_2.*" \
165 "breakpoint at safety net"
166 }
167
168 gdb_test "next" "call_longjmp.*" "next over setjmp"
169
170 set msg "next over call_longjmp"
171 gdb_test_multiple "next" $msg {
172 -re ".*patt2.*$::gdb_prompt $" {
173 pass $msg
174
175 gdb_test "next" "resumes\\+\\+.*" "next into else block"
176 gdb_test "next" "miss_step_2.*" "next into safety net"
177 }
178 -re "miss_step_2.*$::gdb_prompt $" {
179 if { $have_longjmp_probe } {
180 fail $gdb_test_name
181 } else {
182 kfail $gdb_test_name "gdb/26967"
183 }
184 }
185 -re -wrap "\r\n$re_cannot_insert_bp\r\n.*" {
186 if { $have_longjmp_probe } {
187 fail $gdb_test_name
188 } else {
189 kfail $gdb_test_name "gdb/26967"
190 }
191 }
192 }
193 }
194
195 #
196 # Pattern 3 - setjmp/longjmp inside stepped-over function.
197 #
198
199 with_test_prefix "pattern 3" {
200
201 with_test_prefix setup {
202 delete_breakpoints
203
204 gdb_test "break $::subdir/$::srcfile:$bp_start_test_3" \
205 "Breakpoint.*at.* file .*$::srcfile, line.*$bp_start_test_3.*" \
206 "breakpoint at pattern start"
207 gdb_test "continue" "patt3.*" "continue to breakpoint at pattern start"
208 }
209
210 gdb_test_multiple "next" "next over pattern" {
211 -re -wrap "longjmp caught.*" {
212 pass $gdb_test_name
213 }
214 -re -wrap "\r\n$re_cannot_insert_bp\r\n.*" {
215 if { $have_longjmp_probe } {
216 fail $gdb_test_name
217 } else {
218 kfail $gdb_test_name "gdb/26967"
219 }
220 }
221 }
222 }
223 }
224
225 foreach_with_prefix with_probes { 0 1 } {
226 do_test $with_probes
227 }