1# Copyright (C) 2009-2020 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
16if {[skip_shlib_tests]} {
17    return 0
18}
19
20if {[skip_ifunc_tests]} {
21    return 0
22}
23
24standard_testfile .c
25set staticexecutable ${testfile}-static
26set staticbinfile [standard_output_file ${staticexecutable}]
27
28set libfile "${testfile}-lib"
29set libsrc ${libfile}.c
30
31set final_file "${testfile}-final"
32set final_src ${final_file}.c
33
34if [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.
40proc 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.
49proc 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 [standard_output_file $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.
97proc_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.
199proc 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.
369foreach_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
383with_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}
404