]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.base/gnu-ifunc.exp
Automatic Copyright Year update after running gdb/copyright.py
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.base / gnu-ifunc.exp
1 # Copyright (C) 2009-2022 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 if {[skip_shlib_tests]} {
17 return 0
18 }
19
20 if {[skip_ifunc_tests]} {
21 return 0
22 }
23
24 standard_testfile .c
25 set staticexecutable ${testfile}-static
26 set staticbinfile [standard_output_file ${staticexecutable}]
27
28 set libfile "${testfile}-lib"
29 set libsrc ${libfile}.c
30
31 set final_file "${testfile}-final"
32 set final_src ${final_file}.c
33
34 if [get_compiler_info] {
35 return -1
36 }
37
38 # Return the binary suffix appended to program and library names to
39 # make each testcase variant unique.
40 proc make_binsuffix {resolver_attr resolver_debug final_debug} {
41 return "$resolver_attr-$resolver_debug-$final_debug"
42 }
43
44 # Compile the testcase. RESOLVER_ATTR is true if we're testing with
45 # an ifunc resolver that has a different name from the user symbol,
46 # specified with GCC's __attribute__ ifunc. RESOLVER_DEBUG is true
47 # iff the resolver was compiled with debug info. FINAL_DEBUG is true
48 # iff the target function was compiled with debug info.
49 proc build {resolver_attr resolver_debug final_debug} {
50 global srcdir subdir srcfile binfile
51 global libsrc lib_so libfile
52 global exec_opts executable
53 global hex gdb_prompt
54 global final_file final_src
55
56 set suffix [make_binsuffix $resolver_attr $resolver_debug $final_debug]
57
58 set lib_so [standard_output_file ${libfile}-$suffix.so]
59 # $lib_o must not have {debug}, it would override the STT_GNU_IFUNC ELF markers.
60 set lib_o [standard_output_file ${libfile}-$suffix.o]
61
62 set exec_opts [list debug shlib=$lib_so]
63
64 set lib_opts {}
65 set final_opts {}
66
67 # Force lazy binding so we don't resolve everything at process startup.
68 lappend exec_opts "additional_flags=-Wl,-z,lazy"
69 lappend lib_opts "additional_flags=-Wl,-z,lazy"
70
71 if {$resolver_attr} {
72 lappend lib_opts "additional_flags=-DIFUNC_RESOLVER_ATTR"
73 }
74
75 if {$resolver_debug} {
76 lappend lib_opts "debug"
77 }
78
79 if {$final_debug} {
80 lappend final_opts "debug"
81 }
82
83 set final_o [standard_output_file $final_file-$suffix.o]
84
85 if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc \
86 $lib_so $lib_opts] != ""
87 || [gdb_compile ${srcdir}/${subdir}/$final_src \
88 $final_o object $final_opts] != ""
89 || [gdb_compile [list ${srcdir}/${subdir}/$srcfile $final_o] \
90 $binfile-$suffix executable $exec_opts] != ""} {
91 untested "failed to compile testcase"
92 return 0
93 }
94
95 return 1
96 }
97
98 # Test setting a breakpoint on a ifunc function before and after the
99 # ifunc is resolved. For the description of RESOLVER_ATTR,
100 # RESOLVER_DEBUG and FINAL_DEBUG, see the "build" procedure above.
101 proc_with_prefix set-break {resolver_attr resolver_debug final_debug} {
102 global binfile libfile lib_so
103 global hex decimal
104 global gdb_prompt
105
106 set suffix [make_binsuffix $resolver_attr $resolver_debug $final_debug]
107
108 set lib_so [standard_output_file ${libfile}-$suffix.so]
109 clean_restart $binfile-$suffix
110 gdb_load_shlib ${lib_so}
111
112 if ![runto_main] then {
113 return 1
114 }
115
116 gdb_breakpoint [gdb_get_line_number "break-at-call"]
117 gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
118
119 set ws "\[ \t\]+"
120 set dot "\\.?"
121
122 if {$resolver_attr} {
123 set gnu_ifunc_resolver "gnu_ifunc_resolver"
124 } else {
125 set gnu_ifunc_resolver "gnu_ifunc"
126 }
127
128 if {!$resolver_debug} {
129 set gnu_ifunc_resolver "${dot}${gnu_ifunc_resolver}"
130 }
131
132 if {!$final_debug} {
133 set final "${dot}final"
134 } else {
135 set final "final"
136 }
137
138 with_test_prefix "before resolving" {
139 delete_breakpoints
140 gdb_test "break gnu_ifunc" \
141 "Breakpoint $decimal at gnu-indirect-function resolver at $hex"
142 gdb_test "info breakpoints" \
143 "$decimal${ws}STT_GNU_IFUNC resolver${ws}keep${ws}y${ws}$hex <${gnu_ifunc_resolver}>"
144
145 # Make the breakpoint conditional on a condition that always
146 # fails. This is so that when the ifunc-resolver breakpoint
147 # triggers, GDB resumes the program immediately.
148 gdb_test_no_output "condition \$bpnum 0"
149 }
150
151 global final_src
152
153 with_test_prefix "resolve" {
154 gdb_breakpoint [gdb_get_line_number "break-at-exit"]
155 gdb_continue_to_breakpoint "break-at-exit" ".*break-at-exit.*"
156 }
157
158 with_test_prefix "after resolving" {
159 if {!$final_debug} {
160 # Set a breakpoint both at the ifunc, and at the ifunc's
161 # target. GDB should resolve both to the same address.
162 # Start with the ifunc's target.
163 set addr "-"
164 set test "break final"
165 # Extract the address without the leading "0x", because
166 # addresses in "info break" output include leading 0s
167 # (like "0x0000ADDR").
168 set hex_number {[0-9a-fA-F][0-9a-fA-F]*}
169 gdb_test_multiple $test $test {
170 -re "Breakpoint .* at 0x($hex_number)\r\n$gdb_prompt $" {
171 set addr $expect_out(1,string)
172 pass $test
173 }
174 }
175
176 # Now set a break at the ifunc.
177 gdb_test "break gnu_ifunc" "Breakpoint .* at 0x$addr"
178 set location "$decimal${ws}breakpoint${ws}keep${ws}y${ws}0x0*$addr${ws}<${final}\\+.*>"
179 } else {
180 set lineno -1
181 set test "break final"
182 gdb_test_multiple $test $test {
183 -re "Breakpoint .* at $hex: file .*$final_src, line ($decimal)\\.\r\n$gdb_prompt $" {
184 set lineno $expect_out(1,string)
185 pass $test
186 }
187 }
188 gdb_test "break gnu_ifunc" "Breakpoint .* at $hex: file .*$final_src, line $lineno\\."
189 set location "$decimal${ws}breakpoint${ws}keep${ws}y${ws}$hex in final at .*$final_src:$lineno"
190 }
191
192 # The first location here is for the breakpoint that was set
193 # before the ifunc was resolved. It should be resolved by
194 # now, and it should have the exact same address/line as the
195 # other two locations.
196 gdb_test "info breakpoints" "$location\r\n.*$location\r\n$location"
197 }
198 }
199
200 # Misc GNU ifunc tests. For the description of RESOLVER_ATTR,
201 # RESOLVER_DEBUG and FINAL_DEBUG, see the "build" procedure above.
202 proc misc_tests {resolver_attr resolver_debug final_debug} {
203 global srcdir subdir srcfile binfile
204 global libsrc lib_so libfile
205 global exec_opts executable
206 global hex gdb_prompt
207 global final_file final_src
208
209 set suffix [make_binsuffix $resolver_attr $resolver_debug $final_debug]
210
211 if {$resolver_attr} {
212 set gnu_ifunc_resolver "gnu_ifunc_resolver"
213 } else {
214 set gnu_ifunc_resolver "gnu_ifunc"
215 }
216
217 set dot "\\.?"
218
219 if {!$resolver_debug} {
220 set gnu_ifunc_resolver "${dot}${gnu_ifunc_resolver}"
221 }
222
223 if {!$final_debug} {
224 set final "${dot}final"
225 } else {
226 set final "final"
227 }
228
229 # Start with a fresh gdb.
230
231 clean_restart $binfile-$suffix
232 gdb_load_shlib ${lib_so}
233
234 if ![runto_main] then {
235 return 1
236 }
237
238 # The "if" condition is artifical to test regression of a former patch.
239 gdb_breakpoint "[gdb_get_line_number "break-at-nextcall"] if i && (int) gnu_ifunc (i) != 42"
240
241 gdb_breakpoint [gdb_get_line_number "break-at-call"]
242 gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
243
244 # Test GDB will automatically indirect the call.
245
246 if {!$resolver_debug && !$final_debug} {
247 gdb_test "p gnu_ifunc()" \
248 "'${dot}final' has unknown return type; cast the call to its declared return type"
249 gdb_test "p gnu_ifunc (3)" \
250 "'${dot}final' has unknown return type; cast the call to its declared return type"
251 gdb_test "p (int) gnu_ifunc (3)" " = 4"
252 } else {
253 gdb_test "p gnu_ifunc()" "Too few arguments in function call\\."
254 gdb_test "p gnu_ifunc (3)" " = 4"
255 }
256
257 # Test that the resolver received its argument.
258
259 set actual_hwcap "0x0"
260 set test "info auxv"
261 gdb_test_multiple $test $test {
262 -re "\r\n\\d+\\s+AT_HWCAP\[^\r\n\]+($hex)\r\n.*$gdb_prompt $" {
263 set actual_hwcap $expect_out(1,string)
264 }
265 -re ".*$gdb_prompt $" {
266 pass "$test (no HWCAP)"
267 }
268 }
269
270 gdb_test "p/x resolver_hwcap" "= $actual_hwcap" "resolver received HWCAP"
271
272 # Test GDB will skip the gnu_ifunc resolver on first call.
273
274 # Even if the resolver has debug info, stepping into an ifunc call
275 # should skip the resolver.
276 if {!$final_debug} {
277 # Make GDB stop stepping even if it steps into a function with
278 # no debug info.
279 gdb_test_no_output "set step-mode on"
280 gdb_test "step" "$hex in ${dot}final \\\(\\\)"
281 } else {
282 gdb_test "step" "\r\nfinal .*"
283 }
284
285 # Test GDB will not break before the final chosen implementation.
286
287 # Also test a former patch regression:
288 # Continuing.
289 # Error in testing breakpoint condition:
290 # Attempt to take address of value not located in memory.
291 #
292 # Breakpoint 2, main () at ./gdb.base/gnu-ifunc.c:33
293
294 gdb_test "continue" \
295 "Continuing.\r\n\r\nBreakpoint .* (at|in) .*break-at-nextcall.*" \
296 "continue to break-at-nextcall"
297
298 gdb_breakpoint "gnu_ifunc"
299
300 gdb_continue_to_breakpoint "nextcall gnu_ifunc"
301
302 gdb_test "frame" \
303 "#0 +(0x\[0-9a-f\]+ in +)?${final} \\(.*" "nextcall gnu_ifunc skipped"
304
305 # Check any commands not doing an inferior call access the address of the
306 # STT_GNU_IFUNC resolver, not the target function.
307
308 if {[istarget powerpc64-*] && [is_lp64_target]} {
309 # With only minimal symbols GDB provides the function descriptors. With
310 # full debug info the function code would be displayed.
311 }
312
313 gdb_test "p gnu_ifunc" \
314 " = {<text gnu-indirect-function variable, no debug info>} 0x\[0-9a-f\]+ <${gnu_ifunc_resolver}>" \
315 "p gnu_ifunc executing"
316 gdb_test "info sym gnu_ifunc" \
317 "${gnu_ifunc_resolver} in section .*" \
318 "info sym gnu_ifunc executing"
319
320 set test "info addr gnu_ifunc"
321 if {!$resolver_attr && $resolver_debug} {
322 gdb_test_multiple $test $test {
323 -re "Symbol \"gnu_ifunc\" is a function at address (0x\[0-9a-f\]+).*$gdb_prompt $" {
324 pass $test
325 }
326 }
327 } else {
328 gdb_test_multiple $test $test {
329 -re "Symbol \"gnu_ifunc\" is at (0x\[0-9a-f\]+) in .*$gdb_prompt $" {
330 pass $test
331 }
332 }
333 }
334 gdb_test "info sym $expect_out(1,string)" \
335 "${gnu_ifunc_resolver} in section .*" \
336 "info sym <gnu_ifunc-address>"
337
338 # Test calling the resolver directly instead of the ifunc symbol.
339 # Can only do that if the ifunc and the ifunc resolver have
340 # different names.
341 if {$resolver_attr} {
342 if {$resolver_debug} {
343 if {[istarget powerpc64-*] && [is_lp64_target]} {
344 gdb_test "p gnu_ifunc_resolver(0)" \
345 " = \\(int \\(\\*\\)\\(int\\)\\) @$hex: $hex <${final}>"
346 } else {
347 gdb_test "p gnu_ifunc_resolver(0)" \
348 " = \\(int \\(\\*\\)\\(int\\)\\) $hex <final>"
349 }
350 } else {
351 gdb_test "p gnu_ifunc_resolver(0)" \
352 "'${gnu_ifunc_resolver}' has unknown return type; cast the call to its declared return type"
353 gdb_test "p (void *) gnu_ifunc_resolver(0)" \
354 " = \\(void \\*\\) $hex <${final}>"
355 }
356 }
357 }
358
359 # Test all the combinations of:
360 #
361 # - An ifunc resolver with the same name as the ifunc symbol vs an
362 # ifunc resolver with a different name as the ifunc symbol.
363 #
364 # - ifunc resolver compiled with and without debug info. This ensures
365 # that GDB understands that a function not a regular function by
366 # looking at the STT_GNU_IFUNC type in the elf symbols. DWARF has
367 # no way to express the STT_GNU_IFUNC type.
368 #
369 # - ifunc target function (resolved) compiled with and without debug
370 # info.
371 foreach_with_prefix resolver_attr {0 1} {
372 foreach_with_prefix resolver_debug {0 1} {
373 foreach_with_prefix final_debug {0 1} {
374 if { [build $resolver_attr $resolver_debug $final_debug] != 0 } {
375 misc_tests $resolver_attr $resolver_debug $final_debug
376 set-break $resolver_attr $resolver_debug $final_debug
377 }
378 }
379 }
380 }
381
382 # Test statically linked ifunc resolving during inferior start.
383 # https://bugzilla.redhat.com/show_bug.cgi?id=624967
384
385 with_test_prefix "static" {
386 # Compile $staticbinfile separately as it may exit on error
387 # (ld/12595).
388
389 set lib_o [standard_output_file ${libfile}.o]
390 set final_o [standard_output_file ${final_file}.o]
391 if { [gdb_compile ${srcdir}/${subdir}/$libsrc $lib_o object {}] != ""
392 || [gdb_compile ${srcdir}/${subdir}/$final_src $final_o object {}] != ""
393 || [gdb_compile "${srcdir}/${subdir}/$srcfile $lib_o $final_o" \
394 $staticbinfile executable {debug}] != "" } {
395 untested "failed to compile second testcase"
396 return -1
397 }
398
399 clean_restart $staticexecutable
400
401 gdb_breakpoint "gnu_ifunc"
402 gdb_breakpoint "main"
403 gdb_run_cmd
404 gdb_test "" "Breakpoint \[0-9\]*, main .*" "static gnu_ifunc"
405 }