summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.base/infcall-failure.exp
blob: 2dcdda34b4d0d9e5cde265b64d21e510de3d2b2b (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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# Copyright 2022 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/>.

# Some simple tests of inferior function calls from breakpoint
# conditions, in a single-threaded inferior.
#
# Test what happens when the inferior function (from a breakpoint
# condition) either hits a nested breakpoint, or segfaults.

standard_testfile

if { [build_executable "failed to prepare" ${binfile} "${srcfile}" \
	  {debug}] == -1 } {
    return
}

set bp_1_line [gdb_get_line_number "First breakpoint"]
set bp_2_line [gdb_get_line_number "Second breakpoint"]
set segv_line [gdb_get_line_number "Segfault here"]

# Start GDB based on TARGET_ASYNC and TARGET_NON_STOP, and then runto
# main.
proc start_gdb_and_runto_main { target_async target_non_stop } {
    save_vars { ::GDBFLAGS } {
	append ::GDBFLAGS \
	    " -ex \"maint set target-non-stop $target_non_stop\""
	append ::GDBFLAGS \
	    " -ex \"maintenance set target-async ${target_async}\""

	clean_restart ${::binfile}
    }

    if {![runto_main]} {
	fail "run to main"
	return -1
    }

    return 0
}

# Start GDB according to ASYNC_P and NON_STOP_P, then setup a
# conditional breakpoint.  The breakpoint condition includes an
# inferior function call that will itself hit a breakpoint.  Check how
# GDB reports this to the user.
proc_with_prefix run_cond_hits_breakpoint_test { async_p non_stop_p } {
    if { [start_gdb_and_runto_main $async_p $non_stop_p] == -1 } {
	return
    }

    # Setup the conditional breakpoint and record its number.
    gdb_breakpoint "${::srcfile}:${::bp_1_line} if (func_bp ())"
    set bp_1_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
		     "get number of first breakpoint"]

    # Setup a breakpoint inside func_bp.
    gdb_breakpoint "${::srcfile}:${::bp_2_line}"
    set bp_2_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
		     "get number of second breakpoint"]

    gdb_test "continue" \
	[multi_line \
	     "Continuing\\." \
	     "" \
	     "Breakpoint ${bp_2_num}, func_bp \\(\\) at \[^\r\n\]+:${::bp_2_line}" \
	     "${::decimal}\\s+\[^\r\n\]+Second breakpoint\[^\r\n\]+" \
	     "Error in testing condition for breakpoint ${bp_1_num}:" \
	     "The program being debugged stopped while in a function called from GDB\\." \
	     "Evaluation of the expression containing the function" \
	     "\\(func_bp\\) will be abandoned\\." \
	     "When the function is done executing, GDB will silently stop\\." \
	     "" \
	     "Breakpoint ${bp_1_num}, \[^\r\n\]+" \
	     "${::decimal}\\s+\[^\r\n\]+Second breakpoint\[^\r\n\]+"]
}

# Start GDB according to ASYNC_P and NON_STOP_P, then call an inferior
# function.  The inferior function being called will itself have a
# breakpoint within it.  Check how GDB reports this to the user.
proc_with_prefix run_call_hits_breakpoint_test { async_p non_stop_p } {
    if { [start_gdb_and_runto_main $async_p $non_stop_p] == -1 } {
	return
    }

    # Setup a breakpoint inside func_bp.
    gdb_breakpoint "${::srcfile}:${::bp_2_line}"
    set bp_2_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
		      "get number of second breakpoint"]


    gdb_test "call func_bp ()" \
	[multi_line \
	     "" \
	     "Breakpoint ${bp_2_num}, func_bp \\(\\) at \[^\r\n\]+:${::bp_2_line}" \
	     "${::decimal}\\s+\[^\r\n\]+Second breakpoint\[^\r\n\]+" \
	     "The program being debugged stopped while in a function called from GDB\\." \
	     "Evaluation of the expression containing the function" \
	     "\\(func_bp\\) will be abandoned\\." \
	     "When the function is done executing, GDB will silently stop\\."]
}

# Start GDB according to ASYNC_P and NON_STOP_P, then setup a
# conditional breakpoint.  The breakpoint condition includes an
# inferior function call that segfaults.  Check how GDB reports this
# to the user.
proc_with_prefix run_cond_hits_segfault_test { async_p non_stop_p } {
    if { [start_gdb_and_runto_main $async_p $non_stop_p] == -1 } {
	return
    }

    # This test relies on the inferior segfaulting when trying to
    # access address zero.
    if { [is_address_zero_readable] } {
	return
    }

    # Setup the conditional breakpoint and record its number.
    gdb_breakpoint "${::srcfile}:${::bp_1_line} if (func_segfault ())"
    set bp_1_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
		     "get number of first breakpoint"]

    gdb_test "continue" \
	[multi_line \
	     "Continuing\\." \
	     "" \
	     "Program received signal SIGSEGV, Segmentation fault\\." \
	     "${::hex} in func_segfault \\(\\) at \[^\r\n\]+:${::segv_line}" \
	     "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+" \
	     "Error in testing condition for breakpoint ${bp_1_num}:" \
	     "The program being debugged stopped while in a function called from GDB\\." \
	     "Evaluation of the expression containing the function" \
	     "\\(func_segfault\\) will be abandoned\\." \
	     "When the function is done executing, GDB will silently stop\\." \
	     "" \
	     "Breakpoint ${bp_1_num}, \[^\r\n\]+" \
	     "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+"]
}

# Start GDB according to ASYNC_P and NON_STOP_P, then call an inferior
# function.  The inferior function will segfault.  Check how GDB
# reports this to the user.
proc_with_prefix run_call_hits_segfault_test { async_p non_stop_p } {
    if { [start_gdb_and_runto_main $async_p $non_stop_p] == -1 } {
	return
    }

    # This test relies on the inferior segfaulting when trying to
    # access address zero.
    if { [is_address_zero_readable] } {
	return
    }

    gdb_test "call func_segfault ()" \
	[multi_line \
	     "" \
	     "Program received signal SIGSEGV, Segmentation fault\\." \
	     "${::hex} in func_segfault \\(\\) at \[^\r\n\]+:${::segv_line}" \
	     "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+" \
	     "The program being debugged stopped while in a function called from GDB\\." \
	     "Evaluation of the expression containing the function" \
	     "\\(func_segfault\\) will be abandoned\\." \
	     "When the function is done executing, GDB will silently stop\\."]
}

foreach_with_prefix target_async { "on" "off" } {
    foreach_with_prefix target_non_stop { "on" "off" } {
	run_cond_hits_breakpoint_test $target_async $target_non_stop
	run_call_hits_breakpoint_test $target_async $target_non_stop

	run_cond_hits_segfault_test $target_async $target_non_stop
	run_call_hits_segfault_test $target_async $target_non_stop
    }
}