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