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