mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-15 04:31:49 +08:00
b811d2c292
gdb/ChangeLog: Update copyright year range in all GDB files.
404 lines
12 KiB
Plaintext
404 lines
12 KiB
Plaintext
# Copyright (C) 2009-2020 Free Software Foundation, Inc.
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
if {[skip_shlib_tests]} {
|
|
return 0
|
|
}
|
|
|
|
if {[skip_ifunc_tests]} {
|
|
return 0
|
|
}
|
|
|
|
standard_testfile .c
|
|
set staticexecutable ${testfile}-static
|
|
set staticbinfile [standard_output_file ${staticexecutable}]
|
|
|
|
set libfile "${testfile}-lib"
|
|
set libsrc ${libfile}.c
|
|
|
|
set final_file "${testfile}-final"
|
|
set final_src ${final_file}.c
|
|
|
|
if [get_compiler_info] {
|
|
return -1
|
|
}
|
|
|
|
# Return the binary suffix appended to program and library names to
|
|
# make each testcase variant unique.
|
|
proc make_binsuffix {resolver_attr resolver_debug final_debug} {
|
|
return "$resolver_attr-$resolver_debug-$final_debug"
|
|
}
|
|
|
|
# Compile the testcase. RESOLVER_ATTR is true if we're testing with
|
|
# an ifunc resolver that has a different name from the user symbol,
|
|
# specified with GCC's __attribute__ ifunc. RESOLVER_DEBUG is true
|
|
# iff the resolver was compiled with debug info. FINAL_DEBUG is true
|
|
# iff the target function was compiled with debug info.
|
|
proc build {resolver_attr resolver_debug final_debug} {
|
|
global srcdir subdir srcfile binfile
|
|
global libsrc lib_so libfile
|
|
global exec_opts executable
|
|
global hex gdb_prompt
|
|
global final_file final_src
|
|
|
|
set suffix [make_binsuffix $resolver_attr $resolver_debug $final_debug]
|
|
|
|
set lib_so [standard_output_file ${libfile}-$suffix.so]
|
|
# $lib_o must not have {debug}, it would override the STT_GNU_IFUNC ELF markers.
|
|
set lib_o [standard_output_file ${libfile}-$suffix.o]
|
|
|
|
set exec_opts [list debug shlib=$lib_so]
|
|
|
|
set lib_opts {}
|
|
set final_opts {}
|
|
|
|
if {$resolver_attr} {
|
|
lappend lib_opts "additional_flags=-DIFUNC_RESOLVER_ATTR"
|
|
}
|
|
|
|
if {$resolver_debug} {
|
|
lappend lib_opts "debug"
|
|
}
|
|
|
|
if {$final_debug} {
|
|
lappend final_opts "debug"
|
|
}
|
|
|
|
set final_o [standard_output_file $final_file-$suffix.o]
|
|
|
|
if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc \
|
|
$lib_so $lib_opts] != ""
|
|
|| [gdb_compile ${srcdir}/${subdir}/$final_src \
|
|
$final_o object $final_opts] != ""
|
|
|| [gdb_compile [list ${srcdir}/${subdir}/$srcfile $final_o] \
|
|
$binfile-$suffix executable $exec_opts] != ""} {
|
|
untested "failed to compile testcase"
|
|
return 0
|
|
}
|
|
|
|
return 1
|
|
}
|
|
|
|
# Test setting a breakpoint on a ifunc function before and after the
|
|
# ifunc is resolved. For the description of RESOLVER_ATTR,
|
|
# RESOLVER_DEBUG and FINAL_DEBUG, see the "build" procedure above.
|
|
proc_with_prefix set-break {resolver_attr resolver_debug final_debug} {
|
|
global binfile libfile lib_so
|
|
global hex decimal
|
|
global gdb_prompt
|
|
|
|
set suffix [make_binsuffix $resolver_attr $resolver_debug $final_debug]
|
|
|
|
set lib_so [standard_output_file ${libfile}-$suffix.so]
|
|
clean_restart $binfile-$suffix
|
|
gdb_load_shlib ${lib_so}
|
|
|
|
if ![runto_main] then {
|
|
fail "can't run to main"
|
|
return 1
|
|
}
|
|
|
|
gdb_breakpoint [gdb_get_line_number "break-at-call"]
|
|
gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
|
|
|
|
set ws "\[ \t\]+"
|
|
set dot "\\.?"
|
|
|
|
if {$resolver_attr} {
|
|
set gnu_ifunc_resolver "gnu_ifunc_resolver"
|
|
} else {
|
|
set gnu_ifunc_resolver "gnu_ifunc"
|
|
}
|
|
|
|
if {!$resolver_debug} {
|
|
set gnu_ifunc_resolver "${dot}${gnu_ifunc_resolver}"
|
|
}
|
|
|
|
if {!$final_debug} {
|
|
set final "${dot}final"
|
|
} else {
|
|
set final "final"
|
|
}
|
|
|
|
with_test_prefix "before resolving" {
|
|
delete_breakpoints
|
|
gdb_test "break gnu_ifunc" \
|
|
"Breakpoint $decimal at gnu-indirect-function resolver at $hex"
|
|
gdb_test "info breakpoints" \
|
|
"$decimal${ws}STT_GNU_IFUNC resolver${ws}keep${ws}y${ws}$hex <${gnu_ifunc_resolver}>"
|
|
|
|
# Make the breakpoint conditional on a condition that always
|
|
# fails. This is so that when the ifunc-resolver breakpoint
|
|
# triggers, GDB resumes the program immediately.
|
|
gdb_test_no_output "condition \$bpnum 0"
|
|
}
|
|
|
|
global final_src
|
|
|
|
with_test_prefix "resolve" {
|
|
gdb_breakpoint [gdb_get_line_number "break-at-exit"]
|
|
gdb_continue_to_breakpoint "break-at-exit" ".*break-at-exit.*"
|
|
}
|
|
|
|
with_test_prefix "after resolving" {
|
|
if {!$final_debug} {
|
|
# Set a breakpoint both at the ifunc, and at the ifunc's
|
|
# target. GDB should resolve both to the same address.
|
|
# Start with the ifunc's target.
|
|
set addr "-"
|
|
set test "break final"
|
|
# Extract the address without the leading "0x", because
|
|
# addresses in "info break" output include leading 0s
|
|
# (like "0x0000ADDR").
|
|
set hex_number {[0-9a-fA-F][0-9a-fA-F]*}
|
|
gdb_test_multiple $test $test {
|
|
-re "Breakpoint .* at 0x($hex_number)\r\n$gdb_prompt $" {
|
|
set addr $expect_out(1,string)
|
|
pass $test
|
|
}
|
|
}
|
|
|
|
# Now set a break at the ifunc.
|
|
gdb_test "break gnu_ifunc" "Breakpoint .* at 0x$addr"
|
|
set location "$decimal${ws}breakpoint${ws}keep${ws}y${ws}0x0*$addr${ws}<${final}\\+.*>"
|
|
} else {
|
|
set lineno -1
|
|
set test "break final"
|
|
gdb_test_multiple $test $test {
|
|
-re "Breakpoint .* at $hex: file .*$final_src, line ($decimal)\\.\r\n$gdb_prompt $" {
|
|
set lineno $expect_out(1,string)
|
|
pass $test
|
|
}
|
|
}
|
|
gdb_test "break gnu_ifunc" "Breakpoint .* at $hex: file .*$final_src, line $lineno\\."
|
|
set location "$decimal${ws}breakpoint${ws}keep${ws}y${ws}$hex in final at .*$final_src:$lineno"
|
|
}
|
|
|
|
# The first location here is for the breakpoint that was set
|
|
# before the ifunc was resolved. It should be resolved by
|
|
# now, and it should have the exact same address/line as the
|
|
# other two locations.
|
|
gdb_test "info breakpoints" "$location\r\n.*$location\r\n$location"
|
|
}
|
|
}
|
|
|
|
# Misc GNU ifunc tests. For the description of RESOLVER_ATTR,
|
|
# RESOLVER_DEBUG and FINAL_DEBUG, see the "build" procedure above.
|
|
proc misc_tests {resolver_attr resolver_debug final_debug} {
|
|
global srcdir subdir srcfile binfile
|
|
global libsrc lib_so libfile
|
|
global exec_opts executable
|
|
global hex gdb_prompt
|
|
global final_file final_src
|
|
|
|
set suffix [make_binsuffix $resolver_attr $resolver_debug $final_debug]
|
|
|
|
if {$resolver_attr} {
|
|
set gnu_ifunc_resolver "gnu_ifunc_resolver"
|
|
} else {
|
|
set gnu_ifunc_resolver "gnu_ifunc"
|
|
}
|
|
|
|
set dot "\\.?"
|
|
|
|
if {!$resolver_debug} {
|
|
set gnu_ifunc_resolver "${dot}${gnu_ifunc_resolver}"
|
|
}
|
|
|
|
if {!$final_debug} {
|
|
set final "${dot}final"
|
|
} else {
|
|
set final "final"
|
|
}
|
|
|
|
# Start with a fresh gdb.
|
|
|
|
clean_restart $binfile-$suffix
|
|
gdb_load_shlib ${lib_so}
|
|
|
|
if ![runto_main] then {
|
|
fail "can't run to main"
|
|
return 1
|
|
}
|
|
|
|
# The "if" condition is artifical to test regression of a former patch.
|
|
gdb_breakpoint "[gdb_get_line_number "break-at-nextcall"] if i && (int) gnu_ifunc (i) != 42"
|
|
|
|
gdb_breakpoint [gdb_get_line_number "break-at-call"]
|
|
gdb_continue_to_breakpoint "break-at-call" ".*break-at-call.*"
|
|
|
|
# Test GDB will automatically indirect the call.
|
|
|
|
if {!$resolver_debug && !$final_debug} {
|
|
gdb_test "p gnu_ifunc()" \
|
|
"'${dot}final' has unknown return type; cast the call to its declared return type"
|
|
gdb_test "p gnu_ifunc (3)" \
|
|
"'${dot}final' has unknown return type; cast the call to its declared return type"
|
|
gdb_test "p (int) gnu_ifunc (3)" " = 4"
|
|
} else {
|
|
gdb_test "p gnu_ifunc()" "Too few arguments in function call\\."
|
|
gdb_test "p gnu_ifunc (3)" " = 4"
|
|
}
|
|
|
|
# Test that the resolver received its argument.
|
|
|
|
set actual_hwcap "0x0"
|
|
set test "info auxv"
|
|
gdb_test_multiple $test $test {
|
|
-re "\r\n\\d+\\s+AT_HWCAP\[^\r\n\]+($hex)\r\n.*$gdb_prompt $" {
|
|
set actual_hwcap $expect_out(1,string)
|
|
}
|
|
-re ".*$gdb_prompt $" {
|
|
pass "$test (no HWCAP)"
|
|
}
|
|
}
|
|
|
|
gdb_test "p/x resolver_hwcap" "= $actual_hwcap" "resolver received HWCAP"
|
|
|
|
# Test GDB will skip the gnu_ifunc resolver on first call.
|
|
|
|
# Even if the resolver has debug info, stepping into an ifunc call
|
|
# should skip the resolver.
|
|
if {!$final_debug} {
|
|
# Make GDB stop stepping even if it steps into a function with
|
|
# no debug info.
|
|
gdb_test_no_output "set step-mode on"
|
|
gdb_test "step" "$hex in ${dot}final \\\(\\\)"
|
|
} else {
|
|
gdb_test "step" "\r\nfinal .*"
|
|
}
|
|
|
|
# Test GDB will not break before the final chosen implementation.
|
|
|
|
# Also test a former patch regression:
|
|
# Continuing.
|
|
# Error in testing breakpoint condition:
|
|
# Attempt to take address of value not located in memory.
|
|
#
|
|
# Breakpoint 2, main () at ./gdb.base/gnu-ifunc.c:33
|
|
|
|
gdb_test "continue" \
|
|
"Continuing.\r\n\r\nBreakpoint .* (at|in) .*break-at-nextcall.*" \
|
|
"continue to break-at-nextcall"
|
|
|
|
gdb_breakpoint "gnu_ifunc"
|
|
|
|
gdb_continue_to_breakpoint "nextcall gnu_ifunc"
|
|
|
|
gdb_test "frame" \
|
|
"#0 +(0x\[0-9a-f\]+ in +)?${final} \\(.*" "nextcall gnu_ifunc skipped"
|
|
|
|
# Check any commands not doing an inferior call access the address of the
|
|
# STT_GNU_IFUNC resolver, not the target function.
|
|
|
|
if {[istarget powerpc64-*] && [is_lp64_target]} {
|
|
# With only minimal symbols GDB provides the function descriptors. With
|
|
# full debug info the function code would be displayed.
|
|
}
|
|
|
|
gdb_test "p gnu_ifunc" \
|
|
" = {<text gnu-indirect-function variable, no debug info>} 0x\[0-9a-f\]+ <${gnu_ifunc_resolver}>" \
|
|
"p gnu_ifunc executing"
|
|
gdb_test "info sym gnu_ifunc" \
|
|
"${gnu_ifunc_resolver} in section .*" \
|
|
"info sym gnu_ifunc executing"
|
|
|
|
set test "info addr gnu_ifunc"
|
|
if {!$resolver_attr && $resolver_debug} {
|
|
gdb_test_multiple $test $test {
|
|
-re "Symbol \"gnu_ifunc\" is a function at address (0x\[0-9a-f\]+).*$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
} else {
|
|
gdb_test_multiple $test $test {
|
|
-re "Symbol \"gnu_ifunc\" is at (0x\[0-9a-f\]+) in .*$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
}
|
|
gdb_test "info sym $expect_out(1,string)" \
|
|
"${gnu_ifunc_resolver} in section .*" \
|
|
"info sym <gnu_ifunc-address>"
|
|
|
|
# Test calling the resolver directly instead of the ifunc symbol.
|
|
# Can only do that if the ifunc and the ifunc resolver have
|
|
# different names.
|
|
if {$resolver_attr} {
|
|
if {$resolver_debug} {
|
|
if {[istarget powerpc64-*] && [is_lp64_target]} {
|
|
gdb_test "p gnu_ifunc_resolver(0)" \
|
|
" = \\(int \\(\\*\\)\\(int\\)\\) @$hex: $hex <${final}>"
|
|
} else {
|
|
gdb_test "p gnu_ifunc_resolver(0)" \
|
|
" = \\(int \\(\\*\\)\\(int\\)\\) $hex <final>"
|
|
}
|
|
} else {
|
|
gdb_test "p gnu_ifunc_resolver(0)" \
|
|
"'${gnu_ifunc_resolver}' has unknown return type; cast the call to its declared return type"
|
|
gdb_test "p (void *) gnu_ifunc_resolver(0)" \
|
|
" = \\(void \\*\\) $hex <${final}>"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Test all the combinations of:
|
|
#
|
|
# - An ifunc resolver with the same name as the ifunc symbol vs an
|
|
# ifunc resolver with a different name as the ifunc symbol.
|
|
#
|
|
# - ifunc resolver compiled with and without debug info. This ensures
|
|
# that GDB understands that a function not a regular function by
|
|
# looking at the STT_GNU_IFUNC type in the elf symbols. DWARF has
|
|
# no way to express the STT_GNU_IFUNC type.
|
|
#
|
|
# - ifunc target function (resolved) compiled with and without debug
|
|
# info.
|
|
foreach_with_prefix resolver_attr {0 1} {
|
|
foreach_with_prefix resolver_debug {0 1} {
|
|
foreach_with_prefix final_debug {0 1} {
|
|
if { [build $resolver_attr $resolver_debug $final_debug] != 0 } {
|
|
misc_tests $resolver_attr $resolver_debug $final_debug
|
|
set-break $resolver_attr $resolver_debug $final_debug
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Test statically linked ifunc resolving during inferior start.
|
|
# https://bugzilla.redhat.com/show_bug.cgi?id=624967
|
|
|
|
with_test_prefix "static" {
|
|
# Compile $staticbinfile separately as it may exit on error
|
|
# (ld/12595).
|
|
|
|
set lib_o [standard_output_file ${libfile}.o]
|
|
set final_o [standard_output_file ${final_file}.o]
|
|
if { [gdb_compile ${srcdir}/${subdir}/$libsrc $lib_o object {}] != ""
|
|
|| [gdb_compile ${srcdir}/${subdir}/$final_src $final_o object {}] != ""
|
|
|| [gdb_compile "${srcdir}/${subdir}/$srcfile $lib_o $final_o" \
|
|
$staticbinfile executable {debug}] != "" } {
|
|
untested "failed to compile second testcase"
|
|
return -1
|
|
}
|
|
|
|
clean_restart $staticexecutable
|
|
|
|
gdb_breakpoint "gnu_ifunc"
|
|
gdb_breakpoint "main"
|
|
gdb_run_cmd
|
|
gdb_test "" "Breakpoint \[0-9\]*, main .*" "static gnu_ifunc"
|
|
}
|