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