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