1 # Copyright 2022-2024 Free Software Foundation, Inc.
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.
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.
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/>.
16 # Tests inferior calls executed from a breakpoint condition in
17 # a multi-threaded program.
19 # This test has the inferior function call timeout, and checks how GDB
20 # handles this situation.
24 if { [build_executable "failed to prepare" ${binfile} "${srcfile}" \
29 set cond_bp_line [gdb_get_line_number "Conditional breakpoint here"]
30 set final_bp_line [gdb_get_line_number "Stop marker"]
31 set segfault_line [gdb_get_line_number "Segfault here"]
33 # Setup GDB based on TARGET_ASYNC, TARGET_NON_STOP, and NON_STOP.
34 # Setup some breakpoints in the inferior, one of which has an inferior
35 # call within its condition.
37 # Continue GDB, the breakpoint with inferior call will be hit, but the
38 # inferior call will never return. We expect GDB to timeout.
40 # The reason that the inferior call never completes is that a second
41 # thread, on which the inferior call relies, either hits a breakpoint
42 # (when OTHER_THREAD_BP is true), or crashes (when OTHER_THREAD_BP is
45 # When UNWIND is "on" GDB will unwind the thread which performed the
46 # inferior function call back to the state where the inferior call was
47 # made (when the inferior call times out). Otherwise, when UNWIND is
48 # "off", the inferior is left in the frame where the timeout occurred.
49 proc run_test { target_async target_non_stop non_stop other_thread_bp unwind } {
50 save_vars { ::GDBFLAGS } {
51 append ::GDBFLAGS " -ex \"maint set target-non-stop $target_non_stop\""
52 append ::GDBFLAGS " -ex \"maint non-stop $non_stop\""
53 append ::GDBFLAGS " -ex \"maintenance set target-async ${target_async}\""
55 clean_restart ${::binfile}
62 # The default timeout for indirect inferior calls (e.g. inferior
63 # calls for conditional breakpoint expressions) is pretty high.
64 # We don't want the test to take too long, so reduce this.
66 # However, the test relies on a second thread hitting some event
67 # (either a breakpoint or signal) before this timeout expires.
69 # There is a chance that on a really slow system this might not
70 # happen, in which case the test might fail.
72 # However, we still allocate 5 seconds, which feels like it should
73 # be enough time in most cases, but maybe we need to do something
74 # smarter here? Possibly we could have some initial run where the
75 # inferior doesn't timeout, but does perform the same interaction
76 # between threads, we could time that, and use that as the basis
77 # for this timeout. For now though, we just hope 5 seconds is
79 gdb_test_no_output "set indirect-call-timeout 5"
80 gdb_test_no_output "set unwind-on-timeout $unwind"
83 "${::srcfile}:${::cond_bp_line} if (condition_func ())"
84 set bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
85 "get number for conditional breakpoint"]
87 gdb_breakpoint "${::srcfile}:${::final_bp_line}"
88 set final_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
89 "get number for final breakpoint"]
91 # The thread performing an inferior call relies on a second
92 # thread. The second thread will segfault unless it hits a
93 # breakpoint first. In either case the initial thread will not
94 # complete its inferior call.
95 if { $other_thread_bp } {
96 gdb_breakpoint "${::srcfile}:${::segfault_line}"
97 set segfault_bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
98 "get number for segfault breakpoint"]
102 gdb_test "continue" \
104 "Error in testing condition for breakpoint ${bp_num}:" \
105 "The program being debugged timed out while in a function called from GDB\\." \
106 "GDB has restored the context to what it was before the call\\." \
107 "To change this behavior use \"set unwind-on-timeout off\"\\." \
108 "Evaluation of the expression containing the function" \
109 "\\(condition_func\\) will be abandoned\\." \
111 "Thread ${::decimal}\[^\r\n\]*hit Breakpoint ${bp_num}, \[^\r\n\]+" \
112 "\[^\r\n\]+ Conditional breakpoint here\\. \[^\r\n\]+"] \
113 "expected timeout waiting for inferior call to complete"
115 # When non-stop mode is off we get slightly different output from GDB.
116 if { ([target_info gdb_protocol] == "remote"
117 || [target_info gdb_protocol] == "extended-remote")
118 && !$target_non_stop} {
119 set stopped_line_pattern \
120 "Thread ${::decimal} \"\[^\r\n\"\]+\" received signal SIGINT, Interrupt\\."
122 set stopped_line_pattern "Thread ${::decimal} \"\[^\r\n\"\]+\" stopped\\."
125 gdb_test "continue" \
127 "$stopped_line_pattern" \
129 "Error in testing condition for breakpoint ${bp_num}:" \
130 "The program being debugged timed out while in a function called from GDB\\." \
131 "GDB remains in the frame where the timeout occurred\\." \
132 "To change this behavior use \"set unwind-on-timeout on\"\\." \
133 "Evaluation of the expression containing the function" \
134 "\\(condition_func\\) will be abandoned\\." \
135 "When the function is done executing, GDB will silently stop\\."] \
136 "expected timeout waiting for inferior call to complete"
139 # Remember that other thread that either crashed (with a segfault)
140 # or hit a breakpoint? Now that the inferior call has timed out,
141 # if we try to resume then we should see the pending event from
143 if { $other_thread_bp } {
144 gdb_test "continue" \
149 "Thread ${::decimal} \"\[^\"\r\n\]+\" hit Breakpoint ${segfault_bp_num}, do_segfault \[^\r\n\]+:${::segfault_line}" \
150 "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+"] \
151 "hit the segfault breakpoint"
153 gdb_test "continue" \
157 "Thread ${::decimal} \"infcall-from-bp\" received signal SIGSEGV, Segmentation fault\\." \
158 "\\\[Switching to Thread \[^\r\n\]+\\\]" \
159 "${::hex} in do_segfault \\(\\) at \[^\r\n\]+:${::segfault_line}" \
160 "${::decimal}\\s+\[^\r\n\]+Segfault here\[^\r\n\]+"] \
165 foreach_with_prefix target_async {"on" "off" } {
167 if { !$target_async } {
168 # GDB can't timeout while waiting for a thread if the target
169 # runs with async-mode turned off; once the target is running
170 # GDB is effectively blocked until the target stops for some
175 foreach_with_prefix target_non_stop {"off" "on"} {
176 foreach_with_prefix non_stop {"off" "on"} {
177 if { $non_stop && !$target_non_stop } {
178 # It doesn't make sense to operate GDB in non-stop
179 # mode when the target has (in theory) non-stop mode
183 foreach_with_prefix unwind {"off" "on"} {
184 foreach_with_prefix other_thread_bp { true false } {
185 run_test $target_async $target_non_stop $non_stop \
186 $other_thread_bp $unwind