| 1 | # Copyright 2015-2016 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 | |
| 18 | load_lib gdb-python.exp |
| 19 | |
| 20 | standard_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. |
| 25 | if [target_info exists use_gdb_stub] { |
| 26 | untested ${testfile}.exp |
| 27 | return |
| 28 | } |
| 29 | |
| 30 | if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {pthreads debug}] } { |
| 31 | return -1 |
| 32 | } |
| 33 | |
| 34 | clean_restart ${testfile} |
| 35 | |
| 36 | if { ![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. |
| 42 | proc 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. |
| 63 | proc 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. |
| 78 | proc 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. |
| 89 | proc 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. |
| 102 | proc 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. |
| 117 | with_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. |
| 125 | with_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 | # Now test using GDB convenience variables. |
| 228 | |
| 229 | gdb_test "p \$inf = 1" " = 1" |
| 230 | gdb_test "p \$thr_start = 2" " = 2" |
| 231 | gdb_test "p \$thr_end = 3" " = 3" |
| 232 | |
| 233 | # Convenience variable for the inferior number, only. |
| 234 | thr_apply_info_thr "\$inf.2" \ |
| 235 | "1.2" |
| 236 | thr_apply_info_thr "\$inf.2-3" \ |
| 237 | "1.2 1.3" |
| 238 | |
| 239 | # Convenience variables for thread numbers as well. |
| 240 | foreach prefix {"" "1." "\$inf."} { |
| 241 | thr_apply_info_thr "${prefix}\$thr_start" \ |
| 242 | "1.2" |
| 243 | thr_apply_info_thr "${prefix}\$thr_start-\$thr_end" \ |
| 244 | "1.2 1.3" |
| 245 | thr_apply_info_thr "${prefix}2-\$thr_end" \ |
| 246 | "1.2 1.3" |
| 247 | thr_apply_info_thr "${prefix}\$thr_start-3" \ |
| 248 | "1.2 1.3" |
| 249 | |
| 250 | # Undefined convenience variable. |
| 251 | set prefix_re [string_to_regexp $prefix] |
| 252 | thr_apply_info_thr_error "${prefix}\$conv123" \ |
| 253 | [multi_line \ |
| 254 | "Convenience variable must have integer value\." \ |
| 255 | "Invalid thread ID: ${prefix_re}\\\$conv123"] |
| 256 | } |
| 257 | |
| 258 | # Convenience variables pointing at an inexisting thread and/or |
| 259 | # inferior. |
| 260 | gdb_test "p \$inf = 30" " = 30" |
| 261 | gdb_test "p \$thr = 20" " = 20" |
| 262 | # Try both the convenience variable and the literal number. |
| 263 | foreach thr {"\$thr" "20" "1.20" "\$inf.1" "30.1" } { |
| 264 | set expected [string_to_regexp $thr] |
| 265 | gdb_test "info threads $thr" "No threads match '${expected}'." |
| 266 | # "info threads" works like a filter. If there's any other |
| 267 | # valid thread in the list, there's no error. |
| 268 | info_threads "$thr 1.1" "1.1" |
| 269 | info_threads "1.1 $thr" "1.1" |
| 270 | } |
| 271 | |
| 272 | gdb_test "thread apply \$thr p 1234" \ |
| 273 | "warning: Unknown thread 1.20" \ |
| 274 | "thread apply \$thr" |
| 275 | |
| 276 | gdb_test "thread apply \$inf.1 p 1234" \ |
| 277 | "warning: Unknown thread 30.1" \ |
| 278 | "thread apply \$inf.1" |
| 279 | |
| 280 | # Star ranges. |
| 281 | |
| 282 | thr_apply_info_thr "1.*" \ |
| 283 | "1.1 1.2 1.3" |
| 284 | |
| 285 | thr_apply_info_thr "*" \ |
| 286 | "1.1 1.2 1.3" |
| 287 | |
| 288 | thr_apply_info_thr "1.* 2.1" \ |
| 289 | "1.1 1.2 1.3 2.1" |
| 290 | |
| 291 | thr_apply_info_thr "2.1 1.*" \ |
| 292 | "1.1 1.2 1.3 2.1" \ |
| 293 | "2.1 1.1 1.2 1.3" |
| 294 | |
| 295 | thr_apply_info_thr "1.* 2.*" \ |
| 296 | "1.1 1.2 1.3 2.1 2.2 2.3" |
| 297 | |
| 298 | thr_apply_info_thr "2.* 1.*" \ |
| 299 | "1.1 1.2 1.3 2.1 2.2 2.3" \ |
| 300 | "2.1 2.2 2.3 1.1 1.2 1.3" |
| 301 | |
| 302 | # There's no inferior 3, but "info threads" treats the thread list |
| 303 | # as a filter, so it's OK. "thread apply" complains about the |
| 304 | # unknown inferior through. |
| 305 | info_threads "1.1 3.*" \ |
| 306 | "1.1" |
| 307 | gdb_test "thread apply 1.1 3.* p 1" \ |
| 308 | "Thread 1.1.*warning: Unknown inferior 3" |
| 309 | |
| 310 | # Now test a set of invalid thread IDs/ranges. |
| 311 | |
| 312 | thr_apply_info_thr_invalid "1." \ |
| 313 | "1." |
| 314 | |
| 315 | thr_apply_info_thr_invalid "1-3 1." \ |
| 316 | "1." |
| 317 | |
| 318 | thr_apply_info_thr_invalid "1.1.1" \ |
| 319 | "1.1.1" |
| 320 | |
| 321 | thr_apply_info_thr_invalid "2 1.1.1" \ |
| 322 | "1.1.1" |
| 323 | |
| 324 | thr_apply_info_thr_invalid "1.1.1 2" \ |
| 325 | "1.1.1 2" |
| 326 | |
| 327 | thr_apply_info_thr_invalid "1-2.1" \ |
| 328 | "1-2.1" |
| 329 | |
| 330 | gdb_test "p \$zero = 0" " = 0" |
| 331 | gdb_test "p \$one = 1" " = 1" |
| 332 | gdb_test "p \$minus_one = -11" " = -11" |
| 333 | foreach prefix {"" "1." "$one."} { |
| 334 | set prefix_re [string_to_regexp $prefix] |
| 335 | |
| 336 | thr_apply_info_thr_invalid "${prefix}foo" |
| 337 | thr_apply_info_thr_invalid "${prefix}1foo" |
| 338 | thr_apply_info_thr_invalid "${prefix}foo1" |
| 339 | |
| 340 | thr_apply_info_thr_error "${prefix}1-0" "inverted range" |
| 341 | thr_apply_info_thr_error "${prefix}1-\$zero" "inverted range" |
| 342 | thr_apply_info_thr_error "${prefix}\$one-0" "inverted range" |
| 343 | thr_apply_info_thr_error "${prefix}\$one-\$zero" "inverted range" |
| 344 | thr_apply_info_thr_error "${prefix}1-" "inverted range" |
| 345 | thr_apply_info_thr_error "${prefix}2-1" "inverted range" |
| 346 | thr_apply_info_thr_error "${prefix}2-\$one" "inverted range" |
| 347 | thr_apply_info_thr_error "${prefix}-1" "negative value" |
| 348 | thr_apply_info_thr_error "${prefix}-\$one" "negative value" |
| 349 | thr_apply_info_thr_error "${prefix}\$minus_one" \ |
| 350 | "negative value: ${prefix_re}\\\$minus_one" |
| 351 | |
| 352 | thr_apply_info_thr_error "${prefix}1-*" "inverted range" |
| 353 | thr_apply_info_thr_invalid "${prefix}*1" |
| 354 | thr_apply_info_thr_invalid "${prefix}*foo" |
| 355 | thr_apply_info_thr_invalid "${prefix}foo*" |
| 356 | } |
| 357 | |
| 358 | # Check that a valid thread ID list with a missing command errors |
| 359 | # out. |
| 360 | with_test_prefix "missing command" { |
| 361 | set output "Please specify a command following the thread ID list" |
| 362 | gdb_test "thread apply 1" $output |
| 363 | gdb_test "thread apply 1.1" $output |
| 364 | gdb_test "thread apply 1.1 1.2" $output |
| 365 | gdb_test "thread apply 1-2" $output |
| 366 | gdb_test "thread apply 1.1-2" $output |
| 367 | gdb_test "thread apply $thr" $output |
| 368 | gdb_test "thread apply 1.*" $output |
| 369 | } |
| 370 | |
| 371 | # Check that we do parse the inferior number and don't confuse it. |
| 372 | gdb_test "info threads 3.1" \ |
| 373 | "No threads match '3.1'\." |
| 374 | } |
| 375 | |
| 376 | if { ![skip_python_tests] } { |
| 377 | with_test_prefix "python" { |
| 378 | # Check that InferiorThread.num and InferiorThread.global_num |
| 379 | # return the expected numbers. |
| 380 | gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" \ |
| 381 | "test gdb.selected_thread" 1 |
| 382 | gdb_test "python print ('result = %s' % t0.num)" " = 3" \ |
| 383 | "test InferiorThread.num" |
| 384 | gdb_test "python print ('result = %s' % t0.global_num)" " = 6" \ |
| 385 | "test InferiorThread.global_num" |
| 386 | |
| 387 | # Breakpoint.thread expects global IDs. Confirm that that |
| 388 | # works as expected. |
| 389 | delete_breakpoints |
| 390 | gdb_breakpoint "thread_function1" |
| 391 | |
| 392 | gdb_py_test_silent_cmd "python bp = gdb.breakpoints()\[0\]" \ |
| 393 | "get python breakpoint" 0 |
| 394 | gdb_test "python bp.thread = 6" "thread = 6" \ |
| 395 | "make breakpoint thread-specific with python" |
| 396 | # Check that the inferior-qualified ID is correct. |
| 397 | gdb_test "info breakpoint" \ |
| 398 | "stop only in thread 1.3\r\n.*" \ |
| 399 | "thread specific breakpoint right thread" |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | # Remove the second inferior and confirm that GDB goes back to showing |
| 404 | # single-number thread IDs. |
| 405 | with_test_prefix "back to one inferior" { |
| 406 | gdb_test "kill inferior 2" "" "kill inferior 2" "Kill the program being debugged.*" "y" |
| 407 | gdb_test "thread 1.1" "Switching to thread 1\.1 .*" |
| 408 | gdb_test "remove-inferior 2" ".*" "remove inferior 2" |
| 409 | |
| 410 | # "info threads" while there's only inferior 1 should show |
| 411 | # single-number thread IDs. |
| 412 | info_threads "" "1 2 3" |
| 413 | |
| 414 | gdb_test "thread" "Current thread is 1 .*" |
| 415 | } |
| 416 | |
| 417 | # Add another inferior and remove inferior 1. Since even though |
| 418 | # there's a single inferior, its number is not 1, GDB should show |
| 419 | # inferior-qualified thread IDs. |
| 420 | with_test_prefix "single-inferior but not initial" { |
| 421 | # Add another inferior. |
| 422 | gdb_test "add-inferior" "Added inferior 3.*" "add empty inferior" |
| 423 | |
| 424 | # Now that we'd added another inferior, thread IDs should show the |
| 425 | # inferior number. |
| 426 | info_threads "" "1.1 1.2 1.3" \ |
| 427 | "info threads with multiple inferiors" |
| 428 | |
| 429 | gdb_test "thread" "Current thread is 1\.1 .*" |
| 430 | |
| 431 | gdb_test "inferior 3" "Switching to inferior 3 .*" "switch to inferior 3" |
| 432 | gdb_test "file ${binfile}" ".*" "load file in inferior 3" |
| 433 | |
| 434 | runto_main |
| 435 | |
| 436 | gdb_test "remove-inferior 1" ".*" "remove inferior 1" |
| 437 | |
| 438 | # Even though we have a single inferior, its number is > 1, so |
| 439 | # thread IDs should include the inferior number. |
| 440 | info_threads "" "3.1" \ |
| 441 | "info threads with single inferior" |
| 442 | |
| 443 | gdb_test "thread" "Current thread is 3\.1 .*" "thread again" |
| 444 | } |