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