]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.mi/mi-thread-bp-deleted.exp
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.mi / mi-thread-bp-deleted.exp
1 # Copyright 2023-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
16 # Check that the =breakpoint-deleted notification for a thread-specific
17 # breakpoint is sent as soon as the related thread exits, and not when the
18 # inferior next stops.
19 #
20 # This test is based on gdb.threads/thread-bp-deleted.exp.
21
22 load_lib mi-support.exp
23 set MIFLAGS "-i=mi"
24
25 # We need to do things a little differently when using the remote protocol.
26 set is_remote \
27 [expr [target_info exists gdb_protocol] \
28 && ([string equal [target_info gdb_protocol] "remote"] \
29 || [string equal [target_info gdb_protocol] "extended-remote"])]
30
31 standard_testfile
32
33 if { [build_executable "failed to prepare" $testfile $srcfile \
34 {debug pthreads}] } {
35 return -1
36 }
37
38 foreach_mi_ui_mode mode {
39 mi_gdb_exit
40
41 if {$mode eq "separate"} {
42 set start_ops "separate-mi-tty"
43 } else {
44 set start_ops ""
45 }
46
47 # Restart, but enable non-stop mode, we need it for background
48 # execution.
49 save_vars { GDBFLAGS } {
50 append GDBFLAGS " -ex \"maint set target-non-stop on\""
51 append GDBFLAGS " -ex \"set mi-async on\""
52 mi_clean_restart $binfile $start_ops
53 }
54
55 mi_runto_main
56
57 if {![mi_detect_async]} {
58 unsupported "async-mode is required"
59 continue
60 }
61
62 mi_delete_breakpoints
63
64 # Place a breakpoint on 'breakpt' and run to this breakpoint.
65 mi_create_breakpoint "breakpt" "place breakpoint on breakpt"
66 set breakpt_num [mi_get_valueof "/d" "\$bpnum" "INVALID" \
67 "get number for breakpt breakpoint"]
68 mi_execute_to "exec-continue" "breakpoint-hit" "breakpt" "" \
69 ".*" ".*" {"" "disp=\"keep\""} \
70 "continue to breakpoint in breakpt"
71
72 # Now drain all the pending output from the CLI if we are using a separate
73 # UI.
74 if {$mode eq "separate"} {
75 with_spawn_id $gdb_main_spawn_id {
76 gdb_test_multiple "" "drain CLI output upto breakpoint" {
77 -re "Thread 1 \[^\r\n\]+ hit Breakpoint $decimal,\
78 breakpt \\(\\) at\
79 \[^\r\n\]+\r\n$decimal\\s+\[^\r\n\]+\r\n" {
80 pass $gdb_test_name
81 }
82 }
83 }
84 }
85
86 # This is just for convenience, this refers to the second thread the
87 # inferior spawns.
88 set worker_thread 2
89
90 # Create a thread-specific breakpoint.
91 mi_create_breakpoint "-p $worker_thread main" \
92 "place thread breakpoint on main" \
93 -thread "$worker_thread"
94 set bpnum [mi_get_valueof "/d" "\$bpnum" "INVALID" \
95 "get number for thread-specific breakpoint"]
96
97 set loc1 [mi_make_breakpoint -number "$breakpt_num"]
98 set loc2 [mi_make_breakpoint -number "$bpnum" -thread "$worker_thread"]
99 set table_2_locs [mi_make_breakpoint_table [list $loc1 $loc2]]
100 set table_1_locs [mi_make_breakpoint_table [list $loc1]]
101
102 mi_gdb_test "-break-info" \
103 "\\^done,$table_2_locs" \
104 "-break-info, expecting two locations"
105
106 # Resume the inferior, at this point the inferior will spin while
107 # we interact with it.
108 mi_send_resuming_command "exec-continue" "continue"
109
110 # Look for the thread-exited notification and the breakpoint-deleted
111 # notification. When using a single UI we see both the MI and CLI
112 # messages. When using a separate MI UI we only see the MI messages.
113 set saw_cli_thread_exited false
114 set saw_mi_thread_exited false
115 set saw_cli_bp_deleted false
116 set saw_mi_bp_deleted false
117
118 # When running with a remote target, the thread-exited event doesn't
119 # appear to be pushed from the target to GDB; instead GDB has to fetch the
120 # thread list from the target and spot that a thread exited.
121 #
122 # In order to achieve this, when running with a remote target we run the
123 # '-thread-info 99' command. There isn't a thread 99, but GDB doesn't
124 # know that until it fetches the thread list. By fetching the thread list
125 # GDB will spot that the thread we are interested in has exited.
126 if {$is_remote} {
127 set cmd "-thread-info 99"
128 set attempt_count 5
129 } else {
130 set cmd ""
131 set attempt_count 0
132 }
133
134
135 gdb_test_multiple $cmd "collect thread exited output" \
136 -prompt "$::mi_gdb_prompt$" {
137
138 -re "^~\"\\\[Thread \[^\r\n\]+ exited\\\]\\\\n\"\r\n" {
139 set saw_cli_thread_exited true
140 exp_continue
141 }
142
143 -re "^~\"Thread-specific breakpoint $bpnum deleted -\
144 thread $worker_thread no longer in the thread list\\.\\\\n\"\r\n" {
145 set saw_cli_bp_deleted true
146 exp_continue
147 }
148
149 -re "^=thread-exited,id=\"$worker_thread\",group-id=\"i1\"\r\n" {
150 set saw_mi_thread_exited true
151
152 # The order of the MI notifications depends on the order in which
153 # the observers where registered within GDB. If we have not seen
154 # the other MI notification yet then keep looking.
155 #
156 # Additionally, for remote targets, we're going to wait for the
157 # output of the '-thread-info 99' command before we check the
158 # results.
159 if {!$saw_mi_bp_deleted || $is_remote} {
160 exp_continue
161 }
162
163 # We get here with a native target; check we saw all the output
164 # that we expected.
165 if {$mode eq "separate"} {
166 gdb_assert { $saw_mi_thread_exited && $saw_mi_bp_deleted \
167 && !$saw_cli_thread_exited \
168 && !$saw_cli_bp_deleted } \
169 $gdb_test_name
170 } else {
171 gdb_assert { $saw_mi_thread_exited && $saw_mi_bp_deleted \
172 && $saw_cli_thread_exited \
173 && $saw_cli_bp_deleted } \
174 $gdb_test_name
175 }
176 }
177
178 -re "^=breakpoint-deleted,id=\"3\"\r\n" {
179 set saw_mi_bp_deleted true
180
181 # The order of the MI notifications depends on the order in which
182 # the observers where registered within GDB. If we have not seen
183 # the other MI notification yet then keep looking.
184 #
185 # Additionally, for remote targets, we're going to wait for the
186 # output of the '-thread-info 99' command before we check the
187 # results.
188 if {!$saw_mi_thread_exited || $is_remote} {
189 exp_continue
190 }
191
192 # We get here with a native target; check we saw all the output
193 # that we expected.
194 if {$mode eq "separate"} {
195 gdb_assert { $saw_mi_thread_exited && $saw_mi_bp_deleted \
196 && !$saw_cli_thread_exited \
197 && !$saw_cli_bp_deleted } \
198 $gdb_test_name
199 } else {
200 gdb_assert { $saw_mi_thread_exited && $saw_mi_bp_deleted \
201 && $saw_cli_thread_exited \
202 && $saw_cli_bp_deleted } \
203 $gdb_test_name
204 }
205 }
206
207 -re "^-thread-info 99\r\n" {
208 if {!$is_remote} {
209 fail "$gdb_test_name (unexpected output)"
210 }
211 # This is the command being echoed back, ignore it.
212 exp_continue
213 }
214
215 -re "^\\^done,threads=\\\[\\\]\r\n$::mi_gdb_prompt$" {
216
217 # This is the result of the '-thread-info 99' trick, which is only
218 # used in remote mode. If we see this in native mode then
219 # something has gone wrong.
220 if {!$is_remote} {
221 fail "$gdb_test_name (unexpected output)"
222 }
223
224 # If we've not seen any of the expected output yet then maybe the
225 # remote thread just hasn't exited yet. Wait a short while and
226 # try again.
227 if { !$saw_mi_thread_exited && !$saw_mi_bp_deleted \
228 && !$saw_cli_thread_exited && !$saw_cli_bp_deleted \
229 && $attempt_count > 0 } {
230 sleep 1
231 incr attempt_count -1
232 send_gdb "$cmd\n"
233 exp_continue
234 }
235
236 # The output has arrived! Check how we did. There are other bugs
237 # that come into play here which change what output we'll see.
238 gdb_assert { $saw_mi_thread_exited && $saw_mi_bp_deleted \
239 && $saw_cli_thread_exited \
240 && $saw_cli_bp_deleted } $gdb_test_name
241 }
242 }
243
244 # When the MI is running on a separate UI the CLI message will be seen
245 # over there, but only if we are not running remote. When we are running
246 # remote then the thread-exited event will only be triggered as a result
247 # of user triggering a refresh of the thread list (hence the '-thread-info
248 # 99' trick above). By typing a command we change the current UI to the
249 # terminal we are typing at, as a result these CLI style message will
250 # actually appear on the MI when using a remote target.
251 if {$mode eq "separate" && !$is_remote} {
252 with_spawn_id $gdb_main_spawn_id {
253 set saw_thread_exited false
254 gdb_test_multiple "" "collect cli thread exited output" {
255 -re "\\\[Thread \[^\r\n\]+ exited\\\]\r\n" {
256 set saw_thread_exited true
257 exp_continue
258 }
259
260 -re "^Thread-specific breakpoint $bpnum deleted -\
261 thread $worker_thread no longer in the thread list\\.\r\n" {
262 gdb_assert { $saw_thread_exited } \
263 $gdb_test_name
264 }
265 }
266 }
267 }
268
269 mi_gdb_test "-break-info" \
270 "\\^done,$table_1_locs" \
271 "-break-info, expecting one location"
272
273 # Set 'do_spin' to zero, this allows the inferior to progress again; we
274 # should then hit the breakpoint in 'breakpt' again.
275 mi_gdb_test "set var do_spin = 0" \
276 [multi_line \
277 ".*=memory-changed,thread-group=\"i${decimal}\".addr=\"${hex}\",len=\"${hex}\"" \
278 "\\^done"] \
279 "set do_spin variable in inferior, inferior should now finish"
280 mi_expect_stop "breakpoint-hit" "breakpt" ".*" ".*" "$::decimal" \
281 {"" "disp=\"keep\""} "stop in breakpt at the end of the test"
282 }