1# Copyright 2015-2019 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# Test thread ID parsing and display. 17 18load_lib gdb-python.exp 19 20standard_testfile 21 22# Multiple inferiors are needed, therefore both native and extended 23# gdbserver modes are supported. Only non-extended gdbserver is not 24# supported. 25if [use_gdb_stub] { 26 untested "using gdb stub" 27 return 28} 29 30if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {pthreads debug}] } { 31 return -1 32} 33 34clean_restart ${testfile} 35 36if { ![runto_main] } then { 37 return -1 38} 39 40# Issue "thread apply TID_LIST p 1234" and expect EXP_TID_LIST (a list 41# of thread ids) to be displayed. 42proc thread_apply {tid_list exp_tid_list {message ""}} { 43 global decimal 44 set any "\[^\r\n\]*" 45 set expected [string_to_regexp $exp_tid_list] 46 47 set r "" 48 foreach tid $expected { 49 append r "\[\r\n\]+" 50 append r "Thread $tid $any:\r\n" 51 append r "\\$$decimal = 1234" 52 } 53 54 set cmd "thread apply $tid_list" 55 if {$message == ""} { 56 set message $cmd 57 } 58 gdb_test "$cmd p 1234" $r $message 59} 60 61# Issue "info threads TID_LIST" and expect EXP_TID_LIST (a list of 62# thread ids) to be displayed. 63proc info_threads {tid_list exp_tid_list {message ""}} { 64 set any "\[^\r\n\]*" 65 set expected [string_to_regexp $exp_tid_list] 66 set r [join $expected " ${any}\r\n${any} "] 67 set r "${any} $r ${any}" 68 set cmd "info threads $tid_list" 69 if {$message == ""} { 70 set message $cmd 71 } 72 gdb_test $cmd $r $message 73} 74 75# Issue "info threads TID_LIST" and expect INFO_THR output. Then 76# issue "thread apply TID_LIST" and expect THR_APPLY output. If 77# THR_APPLY is omitted, INFO_THR is expected instead. 78proc thr_apply_info_thr {tid_list info_thr {thr_apply ""}} { 79 if {$thr_apply == ""} { 80 set thr_apply $info_thr 81 } 82 83 info_threads $tid_list $info_thr 84 thread_apply $tid_list $thr_apply 85} 86 87# Issue both "info threads TID_LIST" and "thread apply TID_LIST" and 88# expect both commands to error out with EXP_ERROR. 89proc thr_apply_info_thr_error {tid_list exp_error} { 90 gdb_test "info threads $tid_list" \ 91 $exp_error 92 93 gdb_test "thread apply $tid_list" \ 94 $exp_error \ 95 "thread apply $tid_list" 96} 97 98# Issue both "info threads TID_LIST" and "thread apply TID_LIST" and 99# expect the command to error out with "Invalid thread ID: $EXPECTED". 100# EXPECTED is a literal string, not a regexp. If EXPECTED is omitted, 101# TID_LIST is expected instead. 102proc thr_apply_info_thr_invalid {tid_list {expected ""}} { 103 if {$expected == ""} { 104 set expected $tid_list 105 } 106 set expected [string_to_regexp $expected] 107 gdb_test "info threads $tid_list" \ 108 "Invalid thread ID: $expected" 109 110 gdb_test "thread apply $tid_list p 1234" \ 111 "Invalid thread ID: $expected p 1234" \ 112 "thread apply $tid_list" 113} 114 115# "info threads" while there's only inferior 1 should show 116# single-number thread IDs. 117with_test_prefix "single inferior" { 118 info_threads "" "1" 119 120 gdb_test "thread" "Current thread is 1 .*" 121} 122 123# "info threads" while there are multiple inferiors should show 124# qualified thread IDs. 125with_test_prefix "two inferiors" { 126 # Add another inferior. 127 gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2" 128 129 # Now that we've added another inferior, thread IDs now show the 130 # inferior number. 131 info_threads "" "1.1" 132 133 gdb_test "thread" "Current thread is 1\.1 .*" 134 135 gdb_test "inferior 2" "Switching to inferior 2 .*" "switch to inferior 2" 136 gdb_test "file ${binfile}" ".*" "load file in inferior 2" 137 138 runto_main 139 140 # Now that we've added another inferior, thread IDs now show the 141 # inferior number. 142 info_threads "" "1.1 2.1" \ 143 "info threads show inferior numbers" 144 145 gdb_test "thread" "Current thread is 2\.1 .*" \ 146 "switch to thread using extended thread ID" 147 148 gdb_breakpoint "thread_function1" 149 150 gdb_continue_to_breakpoint "once" 151 gdb_test "inferior 1" "Switching to inferior 1 .*" 152 gdb_continue_to_breakpoint "twice" 153 154 info_threads "" "1.1 1.2 2.1 2.2" \ 155 "info threads again" 156 157 # Same, but show the global ID. 158 gdb_test "info threads -gid" \ 159 [multi_line \ 160 " 1\.1 +1 +.*" \ 161 "\\* 1\.2 +4 +.* thread_function1 .* at .*$srcfile:.*" \ 162 " 2\.1 +2 +.*" \ 163 " 2\.2 +3 +.* thread_function1 .* at .*$srcfile:.*"] 164 165 # Confirm the convenience variables show the expected numbers. 166 gdb_test "p \$_thread == 2" " = 1" 167 gdb_test "p \$_gthread == 4" " = 1" 168 169 # Without an explicit inferior component, GDB defaults to the 170 # current inferior. Make sure we don't refer to a thread by 171 # global ID by mistake. 172 gdb_test "thread 4" "Unknown thread 1.4\\." 173 174 # Test thread ID list parsing. Test qualified and unqualified 175 # IDs; qualified and unqualified ranges; invalid IDs and invalid 176 # ranges. 177 178 # First spawn a couple more threads so ranges includes more than 179 # two threads. 180 with_test_prefix "more threads" { 181 gdb_breakpoint "thread_function2" 182 183 gdb_test "inferior 2" "Switching to inferior 2 .*" 184 gdb_continue_to_breakpoint "once" 185 186 gdb_test "inferior 1" "Switching to inferior 1 .*" 187 gdb_continue_to_breakpoint "twice" 188 } 189 190 thr_apply_info_thr "1" \ 191 "1.1" 192 193 thr_apply_info_thr "1.1" \ 194 "1.1" 195 196 thr_apply_info_thr "1 2 3" \ 197 "1.1 1.2 1.3" 198 199 # Same, but with qualified thread IDs. 200 thr_apply_info_thr "1.1 1.2 1.3 2.1 2.2" \ 201 "1.1 1.2 1.3 2.1 2.2" 202 203 # Test a thread number range. 204 thr_apply_info_thr "1-3" \ 205 "1.1 1.2 1.3" 206 207 # Same, but using a qualified range. 208 thr_apply_info_thr "1.1-3" \ 209 "1.1 1.2 1.3" 210 211 # A mix of qualified and unqualified thread IDs/ranges. 212 thr_apply_info_thr "1.1 2-3" \ 213 "1.1 1.2 1.3" 214 215 thr_apply_info_thr "1 1.2-3" \ 216 "1.1 1.2 1.3" 217 218 # Likewise, but mix inferiors too. 219 thr_apply_info_thr "2.1 2-3" \ 220 "1.2 1.3 2.1" \ 221 "2.1 1.2 1.3" 222 223 # Multiple ranges with mixed explicit inferiors. 224 thr_apply_info_thr "1.1-2 2.2-3" \ 225 "1.1 1.2 2.2 2.3" 226 227 # All threads. 228 thread_apply "all" \ 229 "2.3 2.2 2.1 1.3 1.2 1.1" 230 thread_apply "all -ascending" \ 231 "1.1 1.2 1.3 2.1 2.2 2.3" 232 233 # Now test using GDB convenience variables. 234 235 gdb_test "p \$inf = 1" " = 1" 236 gdb_test "p \$thr_start = 2" " = 2" 237 gdb_test "p \$thr_end = 3" " = 3" 238 239 # Convenience variable for the inferior number, only. 240 thr_apply_info_thr "\$inf.2" \ 241 "1.2" 242 thr_apply_info_thr "\$inf.2-3" \ 243 "1.2 1.3" 244 245 # Convenience variables for thread numbers as well. 246 foreach prefix {"" "1." "\$inf."} { 247 thr_apply_info_thr "${prefix}\$thr_start" \ 248 "1.2" 249 thr_apply_info_thr "${prefix}\$thr_start-\$thr_end" \ 250 "1.2 1.3" 251 thr_apply_info_thr "${prefix}2-\$thr_end" \ 252 "1.2 1.3" 253 thr_apply_info_thr "${prefix}\$thr_start-3" \ 254 "1.2 1.3" 255 256 # Undefined convenience variable. 257 set prefix_re [string_to_regexp $prefix] 258 thr_apply_info_thr_error "${prefix}\$conv123" \ 259 [multi_line \ 260 "Convenience variable must have integer value\." \ 261 "Invalid thread ID: ${prefix_re}\\\$conv123"] 262 } 263 264 # Convenience variables pointing at an inexisting thread and/or 265 # inferior. 266 gdb_test "p \$inf = 30" " = 30" 267 gdb_test "p \$thr = 20" " = 20" 268 # Try both the convenience variable and the literal number. 269 foreach thr {"\$thr" "20" "1.20" "\$inf.1" "30.1" } { 270 set expected [string_to_regexp $thr] 271 gdb_test "info threads $thr" "No threads match '${expected}'." 272 # "info threads" works like a filter. If there's any other 273 # valid thread in the list, there's no error. 274 info_threads "$thr 1.1" "1.1" 275 info_threads "1.1 $thr" "1.1" 276 } 277 278 gdb_test "thread apply \$thr p 1234" \ 279 "warning: Unknown thread 1.20" \ 280 "thread apply \$thr" 281 282 gdb_test "thread apply \$inf.1 p 1234" \ 283 "warning: Unknown thread 30.1" \ 284 "thread apply \$inf.1" 285 286 # Star ranges. 287 288 thr_apply_info_thr "1.*" \ 289 "1.1 1.2 1.3" 290 291 thr_apply_info_thr "*" \ 292 "1.1 1.2 1.3" 293 294 thr_apply_info_thr "1.* 2.1" \ 295 "1.1 1.2 1.3 2.1" 296 297 thr_apply_info_thr "2.1 1.*" \ 298 "1.1 1.2 1.3 2.1" \ 299 "2.1 1.1 1.2 1.3" 300 301 thr_apply_info_thr "1.* 2.*" \ 302 "1.1 1.2 1.3 2.1 2.2 2.3" 303 304 thr_apply_info_thr "2.* 1.*" \ 305 "1.1 1.2 1.3 2.1 2.2 2.3" \ 306 "2.1 2.2 2.3 1.1 1.2 1.3" 307 308 # There's no inferior 3, but "info threads" treats the thread list 309 # as a filter, so it's OK. "thread apply" complains about the 310 # unknown inferior through. 311 info_threads "1.1 3.*" \ 312 "1.1" 313 gdb_test "thread apply 1.1 3.* p 1" \ 314 "Thread 1.1.*warning: Unknown inferior 3" 315 316 # Now test a set of invalid thread IDs/ranges. 317 318 thr_apply_info_thr_invalid "1." \ 319 "1." 320 321 thr_apply_info_thr_invalid "1-3 1." \ 322 "1." 323 324 thr_apply_info_thr_invalid "1.1.1" \ 325 "1.1.1" 326 327 thr_apply_info_thr_invalid "2 1.1.1" \ 328 "1.1.1" 329 330 thr_apply_info_thr_invalid "1.1.1 2" \ 331 "1.1.1 2" 332 333 thr_apply_info_thr_invalid "1-2.1" \ 334 "1-2.1" 335 336 gdb_test "p \$zero = 0" " = 0" 337 gdb_test "p \$one = 1" " = 1" 338 gdb_test "p \$minus_one = -11" " = -11" 339 foreach prefix {"" "1." "$one."} { 340 set prefix_re [string_to_regexp $prefix] 341 342 thr_apply_info_thr_invalid "${prefix}foo" 343 thr_apply_info_thr_invalid "${prefix}1foo" 344 thr_apply_info_thr_invalid "${prefix}foo1" 345 346 thr_apply_info_thr_error "${prefix}1-0" "inverted range" 347 thr_apply_info_thr_error "${prefix}1-\$zero" "inverted range" 348 thr_apply_info_thr_error "${prefix}\$one-0" "inverted range" 349 thr_apply_info_thr_error "${prefix}\$one-\$zero" "inverted range" 350 thr_apply_info_thr_error "${prefix}1-" "inverted range" 351 thr_apply_info_thr_error "${prefix}2-1" "inverted range" 352 thr_apply_info_thr_error "${prefix}2-\$one" "inverted range" 353 thr_apply_info_thr_error "${prefix}-1" "negative value" 354 thr_apply_info_thr_error "${prefix}-\$one" "negative value" 355 thr_apply_info_thr_error "${prefix}\$minus_one" \ 356 "negative value: ${prefix_re}\\\$minus_one" 357 358 thr_apply_info_thr_error "${prefix}1-*" "inverted range" 359 thr_apply_info_thr_invalid "${prefix}*1" 360 thr_apply_info_thr_invalid "${prefix}*foo" 361 thr_apply_info_thr_invalid "${prefix}foo*" 362 } 363 364 # Check that a valid thread ID list with a missing command errors 365 # out. 366 with_test_prefix "missing command" { 367 set output "Please specify a command following the thread ID list" 368 gdb_test "thread apply 1" $output 369 gdb_test "thread apply 1.1" $output 370 gdb_test "thread apply 1.1 1.2" $output 371 gdb_test "thread apply 1-2" $output 372 gdb_test "thread apply 1.1-2" $output 373 gdb_test "thread apply $thr" $output 374 gdb_test "thread apply 1.*" $output 375 } 376 377 # Check that we do parse the inferior number and don't confuse it. 378 gdb_test "info threads 3.1" \ 379 "No threads match '3.1'\." 380} 381 382if { ![skip_python_tests] } { 383 with_test_prefix "python" { 384 # Check that InferiorThread.num and InferiorThread.global_num 385 # return the expected numbers. 386 gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" \ 387 "test gdb.selected_thread" 1 388 gdb_test "python print ('result = %s' % t0.num)" " = 3" \ 389 "test InferiorThread.num" 390 gdb_test "python print ('result = %s' % t0.global_num)" " = 6" \ 391 "test InferiorThread.global_num" 392 393 # Breakpoint.thread expects global IDs. Confirm that that 394 # works as expected. 395 delete_breakpoints 396 gdb_breakpoint "thread_function1" 397 398 gdb_py_test_silent_cmd "python bp = gdb.breakpoints()\[0\]" \ 399 "get python breakpoint" 0 400 gdb_test "python bp.thread = 6" "thread = 6" \ 401 "make breakpoint thread-specific with python" 402 # Check that the inferior-qualified ID is correct. 403 gdb_test "info breakpoint" \ 404 "stop only in thread 1.3\r\n.*" \ 405 "thread specific breakpoint right thread" 406 } 407} 408 409# Remove the second inferior and confirm that GDB goes back to showing 410# single-number thread IDs. 411with_test_prefix "back to one inferior" { 412 gdb_test "kill inferior 2" "" "kill inferior 2" "Kill the program being debugged.*" "y" 413 gdb_test "thread 1.1" "Switching to thread 1\.1 .*" 414 gdb_test "remove-inferior 2" ".*" "remove inferior 2" 415 416 # "info threads" while there's only inferior 1 should show 417 # single-number thread IDs. 418 info_threads "" "1 2 3" 419 420 gdb_test "thread" "Current thread is 1 .*" 421} 422 423# Add another inferior and remove inferior 1. Since even though 424# there's a single inferior, its number is not 1, GDB should show 425# inferior-qualified thread IDs. 426with_test_prefix "single-inferior but not initial" { 427 # Add another inferior. 428 gdb_test "add-inferior" "Added inferior 3.*" "add empty inferior" 429 430 # Now that we'd added another inferior, thread IDs should show the 431 # inferior number. 432 info_threads "" "1.1 1.2 1.3" \ 433 "info threads with multiple inferiors" 434 435 gdb_test "thread" "Current thread is 1\.1 .*" 436 437 gdb_test "inferior 3" "Switching to inferior 3 .*" "switch to inferior 3" 438 gdb_test "file ${binfile}" ".*" "load file in inferior 3" 439 440 runto_main 441 442 gdb_test "remove-inferior 1" ".*" "remove inferior 1" 443 444 # Even though we have a single inferior, its number is > 1, so 445 # thread IDs should include the inferior number. 446 info_threads "" "3.1" \ 447 "info threads with single inferior" 448 449 gdb_test "thread" "Current thread is 3\.1 .*" "thread again" 450} 451