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