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 | ||
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 | } | |
e4620230 | 78 | |
f9e48344 | 79 | set final_o [standard_output_file $final_file-$suffix.o] |
c7075ad5 PA |
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 | } | |
e4620230 | 90 | |
ae59b1da | 91 | return 1 |
e4620230 JK |
92 | } |
93 | ||
c7075ad5 PA |
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 | ||
79188d8d PA |
113 | gdb_breakpoint [gdb_get_line_number "break-at-call"] |
114 | gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*" | |
115 | ||
c7075ad5 PA |
116 | set ws "\[ \t\]+" |
117 | set dot "\\.?" | |
e4620230 | 118 | |
c7075ad5 PA |
119 | if {$resolver_attr} { |
120 | set gnu_ifunc_resolver "gnu_ifunc_resolver" | |
121 | } else { | |
122 | set gnu_ifunc_resolver "gnu_ifunc" | |
123 | } | |
e4620230 | 124 | |
c7075ad5 PA |
125 | if {!$resolver_debug} { |
126 | set gnu_ifunc_resolver "${dot}${gnu_ifunc_resolver}" | |
127 | } | |
e4620230 | 128 | |
c7075ad5 PA |
129 | if {!$final_debug} { |
130 | set final "${dot}final" | |
131 | } else { | |
132 | set final "final" | |
133 | } | |
e4620230 | 134 | |
c7075ad5 PA |
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}>" | |
79188d8d PA |
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" | |
c7075ad5 | 146 | } |
e1b2624a | 147 | |
c7075ad5 PA |
148 | global final_src |
149 | ||
150 | with_test_prefix "resolve" { | |
c7075ad5 PA |
151 | gdb_breakpoint [gdb_get_line_number "break-at-exit"] |
152 | gdb_continue_to_breakpoint "break-at-exit" ".*break-at-exit.*" | |
e1b2624a | 153 | } |
c7075ad5 PA |
154 | |
155 | with_test_prefix "after resolving" { | |
c7075ad5 PA |
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 | } | |
79188d8d PA |
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" | |
e1b2624a AA |
194 | } |
195 | } | |
196 | ||
c7075ad5 PA |
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 "\\.?" | |
e1b2624a | 215 | |
c7075ad5 PA |
216 | if {!$resolver_debug} { |
217 | set gnu_ifunc_resolver "${dot}${gnu_ifunc_resolver}" | |
218 | } | |
e4620230 | 219 | |
c7075ad5 PA |
220 | if {!$final_debug} { |
221 | set final "${dot}final" | |
222 | } else { | |
223 | set final "final" | |
224 | } | |
e4620230 | 225 | |
c7075ad5 | 226 | # Start with a fresh gdb. |
e4620230 | 227 | |
c7075ad5 PA |
228 | clean_restart $binfile-$suffix |
229 | gdb_load_shlib ${lib_so} | |
e4620230 | 230 | |
c7075ad5 PA |
231 | if ![runto_main] then { |
232 | fail "can't run to main" | |
233 | return 1 | |
234 | } | |
e4620230 | 235 | |
c7075ad5 PA |
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" | |
e4620230 | 238 | |
c7075ad5 PA |
239 | gdb_breakpoint [gdb_get_line_number "break-at-call"] |
240 | gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*" | |
e4620230 | 241 | |
c7075ad5 | 242 | # Test GDB will automatically indirect the call. |
e4620230 | 243 | |
c7075ad5 PA |
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 | } | |
e4620230 | 254 | |
c7075ad5 PA |
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 | } | |
e4620230 | 267 | |
c7075ad5 | 268 | gdb_test "p/x resolver_hwcap" "= $actual_hwcap" "resolver received HWCAP" |
e4620230 | 269 | |
c7075ad5 | 270 | # Test GDB will skip the gnu_ifunc resolver on first call. |
e4620230 | 271 | |
c7075ad5 PA |
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 | } | |
e4620230 JK |
354 | } |
355 | } | |
e4620230 | 356 | |
c7075ad5 PA |
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} { | |
ca98345e SL |
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 | } | |
c7075ad5 PA |
376 | } |
377 | } | |
378 | } | |
e4620230 JK |
379 | |
380 | # Test statically linked ifunc resolving during inferior start. | |
381 | # https://bugzilla.redhat.com/show_bug.cgi?id=624967 | |
382 | ||
c7075ad5 PA |
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 | } | |
e4620230 | 396 | |
c7075ad5 | 397 | clean_restart $staticexecutable |
e4620230 | 398 | |
c7075ad5 PA |
399 | gdb_breakpoint "gnu_ifunc" |
400 | gdb_breakpoint "main" | |
401 | gdb_run_cmd | |
402 | gdb_test "" "Breakpoint \[0-9\]*, main .*" "static gnu_ifunc" | |
403 | } |