summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.base/gnu-ifunc.exp
blob: 1d0d0401c3717498cca09b0a323874a067c84b45 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# Copyright (C) 2009-2018 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
}

standard_testfile .c
set executable ${testfile}
set staticexecutable ${executable}-static
set staticbinfile [standard_output_file ${staticexecutable}]

set libfile "${testfile}-lib"
set libsrc ${libfile}.c
set lib_so [standard_output_file ${libfile}.so]
# $lib_o must not have {debug}, it would override the STT_GNU_IFUNC ELF markers.
set lib_o [standard_output_file ${libfile}.o]

# We need DWARF for the "final" function as we "step" into the function and GDB
# would step-over the "final" function if there would be no line number debug
# information (DWARF) available.
#
# We must not have DWARF for the "gnu_ifunc" function as DWARF has no way to
# express the STT_GNU_IFUNC type and it would be considered as a regular
# function due to DWARF by GDB.  In ELF gnu-ifunc is expressed by the
# STT_GNU_IFUNC type.
#
# Both functions need to be in the same shared library file but
# gdb_compile_shlib has no way to specify source-specific compilation options.
#
# Therefore $libfile contains only the STT_GNU_IFUNC function with no DWARF
# referencing all the other parts from the main executable with DWARF.

set lib_opts {}
set exec_opts [list debug shlib=$lib_so]

if [get_compiler_info] {
    return -1
}

if { [gdb_compile_shlib ${srcdir}/${subdir}/$libsrc $lib_so $lib_opts] != ""
     || [gdb_compile ${srcdir}/${subdir}/$srcfile $binfile executable $exec_opts] != ""} {
    untested "failed to compile first testcase"
    return -1
}

# Start with a fresh gdb.

clean_restart $executable
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 && 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.

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.

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.
    set func_prefix {\.}
} else {
    set func_prefix {}
}

gdb_test "p gnu_ifunc" " = {<text gnu-indirect-function variable, no debug info>} 0x\[0-9a-f\]+ <${func_prefix}gnu_ifunc>" "p gnu_ifunc executing"
gdb_test "info sym gnu_ifunc" "gnu_ifunc in section .*" "info sym gnu_ifunc executing"

set test "info addr gnu_ifunc"
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 in section .*" "info sym <gnu_ifunc-address>"


# Test statically linked ifunc resolving during inferior start.
# https://bugzilla.redhat.com/show_bug.cgi?id=624967

# Compile $staticbinfile separately as it may exit on error (ld/12595).

if { [gdb_compile ${srcdir}/${subdir}/$libsrc $lib_o object {}] != ""
     || [gdb_compile "${srcdir}/${subdir}/$srcfile $lib_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"