# Copyright 2015-2016 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 . # Test thread ID parsing and display. load_lib gdb-python.exp standard_testfile # Multiple inferiors are needed, therefore both native and extended # gdbserver modes are supported. Only non-extended gdbserver is not # supported. if [target_info exists use_gdb_stub] { untested ${testfile}.exp return } if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {pthreads debug}] } { return -1 } clean_restart ${testfile} if { ![runto_main] } then { return -1 } # Issue "thread apply TID_LIST p 1234" and expect EXP_TID_LIST (a list # of thread ids) to be displayed. proc thread_apply {tid_list exp_tid_list {message ""}} { global decimal set any "\[^\r\n\]*" set expected [string_to_regexp $exp_tid_list] set r "" foreach tid $expected { append r "\[\r\n\]+" append r "Thread $tid $any:\r\n" append r "\\$$decimal = 1234" } set cmd "thread apply $tid_list" if {$message == ""} { set message $cmd } gdb_test "$cmd p 1234" $r $message } # Issue "info threads TID_LIST" and expect EXP_TID_LIST (a list of # thread ids) to be displayed. proc info_threads {tid_list exp_tid_list {message ""}} { set any "\[^\r\n\]*" set expected [string_to_regexp $exp_tid_list] set r [join $expected " ${any}\r\n${any} "] set r "${any} $r ${any}" set cmd "info threads $tid_list" if {$message == ""} { set message $cmd } gdb_test $cmd $r $message } # Issue "info threads TID_LIST" and expect INFO_THR output. Then # issue "thread apply TID_LIST" and expect THR_APPLY output. If # THR_APPLY is omitted, INFO_THR is expected instead. proc thr_apply_info_thr {tid_list info_thr {thr_apply ""}} { if {$thr_apply == ""} { set thr_apply $info_thr } info_threads $tid_list $info_thr thread_apply $tid_list $thr_apply } # Issue both "info threads TID_LIST" and "thread apply TID_LIST" and # expect both commands to error out with EXP_ERROR. proc thr_apply_info_thr_error {tid_list exp_error} { gdb_test "info threads $tid_list" \ $exp_error gdb_test "thread apply $tid_list p 1234" \ $exp_error \ "thread apply $tid_list" } # Issue both "info threads TID_LIST" and "thread apply TID_LIST" and # expect the command to error out with "Invalid thread ID: $EXPECTED". # EXPECTED is a literal string, not a regexp. proc thr_apply_info_thr_invalid {tid_list expected} { set expected [string_to_regexp $expected] gdb_test "info threads $tid_list" \ "Invalid thread ID: $expected" gdb_test "thread apply $tid_list p 1234" \ "Invalid thread ID: $expected p 1234" \ "thread apply $tid_list" } # "info threads" while there's only inferior 1 should show # single-number thread IDs. with_test_prefix "single inferior" { info_threads "" "1" gdb_test "thread" "Current thread is 1 .*" } # "info threads" while there are multiple inferiors should show # qualified thread IDs. with_test_prefix "two inferiors" { # Add another inferior. gdb_test "add-inferior" "Added inferior 2.*" "add empty inferior 2" # Now that we've added another inferior, thread IDs now show the # inferior number. info_threads "" "1.1" gdb_test "thread" "Current thread is 1\.1 .*" gdb_test "inferior 2" "Switching to inferior 2 .*" "switch to inferior 2" gdb_test "file ${binfile}" ".*" "load file in inferior 2" runto_main # Now that we've added another inferior, thread IDs now show the # inferior number. info_threads "" "1.1 2.1" \ "info threads show inferior numbers" gdb_test "thread" "Current thread is 2\.1 .*" \ "switch to thread using extended thread ID" gdb_breakpoint "thread_function1" gdb_continue_to_breakpoint "once" gdb_test "inferior 1" "Switching to inferior 1 .*" gdb_continue_to_breakpoint "twice" info_threads "" "1.1 1.2 2.1 2.2" \ "info threads again" # Confirm the convenience variable show the expected number. gdb_test "p \$_thread == 2" " = 1" # Without an explicit inferior component, GDB defaults to the # current inferior. Make sure we don't refer to a thread by # global ID by mistake. gdb_test "thread 4" "Unknown thread 1.4\\." # Test thread ID list parsing. Test qualified and unqualified # IDs; qualified and unqualified ranges; invalid IDs and invalid # ranges. # First spawn a couple more threads so ranges includes more than # two threads. with_test_prefix "more threads" { gdb_breakpoint "thread_function2" gdb_test "inferior 2" "Switching to inferior 2 .*" gdb_continue_to_breakpoint "once" gdb_test "inferior 1" "Switching to inferior 1 .*" gdb_continue_to_breakpoint "twice" } thr_apply_info_thr "1 2 3" \ "1.1 1.2 1.3" # Same, but with qualified thread IDs. thr_apply_info_thr "1.1 1.2 1.3 2.1 2.2" \ "1.1 1.2 1.3 2.1 2.2" # Test a thread number range. thr_apply_info_thr "1-3" \ "1.1 1.2 1.3" # Same, but using a qualified range. thr_apply_info_thr "1.1-3" \ "1.1 1.2 1.3" # A mix of qualified and unqualified thread IDs/ranges. thr_apply_info_thr "1.1 2-3" \ "1.1 1.2 1.3" thr_apply_info_thr "1 1.2-3" \ "1.1 1.2 1.3" # Likewise, but mix inferiors too. thr_apply_info_thr "2.1 2-3" \ "1.2 1.3 2.1" \ "2.1 1.2 1.3" # Multiple ranges with mixed explicit inferiors. thr_apply_info_thr "1.1-2 2.2-3" \ "1.1 1.2 2.2 2.3" # Now test a set of invalid thread IDs/ranges. thr_apply_info_thr_invalid "1." \ "1." thr_apply_info_thr_invalid "1-3 1." \ "1." thr_apply_info_thr_invalid "1.1.1" \ "1.1.1" thr_apply_info_thr_invalid "2 1.1.1" \ "1.1.1" thr_apply_info_thr_invalid "1.1.1 2" \ "1.1.1 2" thr_apply_info_thr_invalid "1-2.1" \ "1-2.1" thr_apply_info_thr_error "1-0" "inverted range" thr_apply_info_thr_error "1.1-0" "inverted range" thr_apply_info_thr_error "1-" "inverted range" thr_apply_info_thr_error "1.1-" "inverted range" thr_apply_info_thr_error "2-1" "inverted range" thr_apply_info_thr_error "1.2-1" "inverted range" thr_apply_info_thr_error "-1" "negative value" thr_apply_info_thr_error "1.-1" "negative value" # Check that we do parse the inferior number and don't confuse it. gdb_test "info threads 3.1" \ "No threads match '3.1'\." } if { ![skip_python_tests] } { with_test_prefix "python" { # Check that InferiorThread.num returns the expected number. gdb_py_test_silent_cmd "python t0 = gdb.selected_thread ()" \ "test gdb.selected_thread" 1 gdb_test "python print ('result = %s' % t0.num)" " = 3" \ "test InferiorThread.num" } } # Remove the second inferior and confirm that GDB goes back to showing # single-number thread IDs. with_test_prefix "back to one inferior" { gdb_test "kill inferior 2" "" "kill inferior 2" "Kill the program being debugged.*" "y" gdb_test "thread 1.1" "Switching to thread 1\.1 .*" gdb_test "remove-inferior 2" ".*" "remove inferior 2" # "info threads" while there's only inferior 1 should show # single-number thread IDs. info_threads "" "1 2 3" gdb_test "thread" "Current thread is 1 .*" } # Add another inferior and remove inferior 1. Since even though # there's a single inferior, its number is not 1, GDB should show # inferior-qualified thread IDs. with_test_prefix "single-inferior but not initial" { # Add another inferior. gdb_test "add-inferior" "Added inferior 3.*" "add empty inferior" # Now that we'd added another inferior, thread IDs should show the # inferior number. info_threads "" "1.1 1.2 1.3" \ "info threads with multiple inferiors" gdb_test "thread" "Current thread is 1\.1 .*" gdb_test "inferior 3" "Switching to inferior 3 .*" "switch to inferior 3" gdb_test "file ${binfile}" ".*" "load file in inferior 3" runto_main gdb_test "remove-inferior 1" ".*" "remove inferior 1" # Even though we have a single inferior, its number is > 1, so # thread IDs should include the inferior number. info_threads "" "3.1" \ "info threads with single inferior" gdb_test "thread" "Current thread is 3\.1 .*" "thread again" }