-# Copyright 2015-2016 Free Software Foundation, Inc.
+# Copyright 2015-2020 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
# 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
+if [use_gdb_stub] {
+ untested "using gdb stub"
return
}
}
set cmd "thread apply $tid_list"
- if {$message == ""} {
- set message $cmd
+ if {$message != ""} {
+ gdb_test "$cmd p 1234" $r $message
+ return
}
- gdb_test "$cmd p 1234" $r $message
+
+ gdb_test "$cmd p 1234" $r
}
# Issue "info threads TID_LIST" and expect EXP_TID_LIST (a list of
set r [join $expected " ${any}\r\n${any} "]
set r "${any} $r ${any}"
set cmd "info threads $tid_list"
- if {$message == ""} {
- set message $cmd
+ if {$message != ""} {
+ gdb_test $cmd $r $message
+ return
}
- gdb_test $cmd $r $message
+ gdb_test $cmd $r
}
# Issue "info threads TID_LIST" and expect INFO_THR output. Then
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} {
+# Issue both "thread apply TID_LIST" and "info threads TID_LIST" and
+# expect commands to error out with EXP_ERROR_APPLY and EXP_ERROR_INFO.
+# If EXP_ERROR_INFO is missing, default to EXP_ERROR_APPLY.
+proc thr_apply_info_thr_error {tid_list exp_error_apply {exp_error_info ""}} {
+ if { "$exp_error_info" == "" } {
+ set exp_error_info "$exp_error_apply"
+ }
+
gdb_test "info threads $tid_list" \
- $exp_error
+ $exp_error_info
- gdb_test "thread apply $tid_list p 1234" \
- $exp_error \
- "thread apply $tid_list"
+ gdb_test "thread apply $tid_list" \
+ $exp_error_apply
}
# 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} {
+# EXPECTED is a literal string, not a regexp. If EXPECTED is omitted,
+# TID_LIST is expected instead.
+proc thr_apply_info_thr_invalid {tid_list {expected ""}} {
+ if {$expected == ""} {
+ set expected $tid_list
+ }
set expected [string_to_regexp $expected]
gdb_test "info threads $tid_list" \
"Invalid thread ID: $expected"
info_threads "" "1.1 1.2 2.1 2.2" \
"info threads again"
- # Confirm the convenience variable show the expected number.
+ # Same, but show the global ID.
+ gdb_test "info threads -gid" \
+ [multi_line \
+ " 1\.1 +1 +.*" \
+ "\\* 1\.2 +4 +.* thread_function1 .* at .*$srcfile:.*" \
+ " 2\.1 +2 +.*" \
+ " 2\.2 +3 +.* thread_function1 .* at .*$srcfile:.*"]
+
+ # Confirm the convenience variables show the expected numbers.
gdb_test "p \$_thread == 2" " = 1"
+ gdb_test "p \$_gthread == 4" " = 1"
# Without an explicit inferior component, GDB defaults to the
# current inferior. Make sure we don't refer to a thread by
gdb_continue_to_breakpoint "twice"
}
+ thr_apply_info_thr "1" \
+ "1.1"
+
+ thr_apply_info_thr "1.1" \
+ "1.1"
+
thr_apply_info_thr "1 2 3" \
"1.1 1.2 1.3"
thr_apply_info_thr "1.1-2 2.2-3" \
"1.1 1.2 2.2 2.3"
+ # All threads.
+ thread_apply "all" \
+ "2.3 2.2 2.1 1.3 1.2 1.1"
+ thread_apply "all -ascending" \
+ "1.1 1.2 1.3 2.1 2.2 2.3"
+
+ # Now test using GDB convenience variables.
+
+ gdb_test "p \$inf = 1" " = 1"
+ gdb_test "p \$thr_start = 2" " = 2"
+ gdb_test "p \$thr_end = 3" " = 3"
+
+ # Convenience variable for the inferior number, only.
+ thr_apply_info_thr "\$inf.2" \
+ "1.2"
+ thr_apply_info_thr "\$inf.2-3" \
+ "1.2 1.3"
+
+ # Convenience variables for thread numbers as well.
+ foreach prefix {"" "1." "\$inf."} {
+ thr_apply_info_thr "${prefix}\$thr_start" \
+ "1.2"
+ thr_apply_info_thr "${prefix}\$thr_start-\$thr_end" \
+ "1.2 1.3"
+ thr_apply_info_thr "${prefix}2-\$thr_end" \
+ "1.2 1.3"
+ thr_apply_info_thr "${prefix}\$thr_start-3" \
+ "1.2 1.3"
+
+ # Undefined convenience variable.
+ set prefix_re [string_to_regexp $prefix]
+ thr_apply_info_thr_error "${prefix}\$conv123" \
+ [multi_line \
+ "Convenience variable must have integer value\." \
+ "Invalid thread ID: ${prefix_re}\\\$conv123"]
+ }
+
+ # Convenience variables pointing at an inexisting thread and/or
+ # inferior.
+ gdb_test "p \$inf = 30" " = 30"
+ gdb_test "p \$thr = 20" " = 20"
+ # Try both the convenience variable and the literal number.
+ foreach thr {"\$thr" "20" "1.20" "\$inf.1" "30.1" } {
+ set expected [string_to_regexp $thr]
+ gdb_test "info threads $thr" "No threads match '${expected}'."
+ # "info threads" works like a filter. If there's any other
+ # valid thread in the list, there's no error.
+ info_threads "$thr 1.1" "1.1"
+ info_threads "1.1 $thr" "1.1"
+ }
+
+ gdb_test "thread apply \$thr p 1234" \
+ "warning: Unknown thread 1.20" \
+ "thread apply \$thr"
+
+ gdb_test "thread apply \$inf.1 p 1234" \
+ "warning: Unknown thread 30.1" \
+ "thread apply \$inf.1"
+
+ # Star ranges.
+
+ thr_apply_info_thr "1.*" \
+ "1.1 1.2 1.3"
+
+ thr_apply_info_thr "*" \
+ "1.1 1.2 1.3"
+
+ thr_apply_info_thr "1.* 2.1" \
+ "1.1 1.2 1.3 2.1"
+
+ thr_apply_info_thr "2.1 1.*" \
+ "1.1 1.2 1.3 2.1" \
+ "2.1 1.1 1.2 1.3"
+
+ thr_apply_info_thr "1.* 2.*" \
+ "1.1 1.2 1.3 2.1 2.2 2.3"
+
+ thr_apply_info_thr "2.* 1.*" \
+ "1.1 1.2 1.3 2.1 2.2 2.3" \
+ "2.1 2.2 2.3 1.1 1.2 1.3"
+
+ # There's no inferior 3, but "info threads" treats the thread list
+ # as a filter, so it's OK. "thread apply" complains about the
+ # unknown inferior through.
+ info_threads "1.1 3.*" \
+ "1.1"
+ gdb_test "thread apply 1.1 3.* p 1" \
+ "Thread 1.1.*warning: Unknown inferior 3"
+
# Now test a set of invalid thread IDs/ranges.
thr_apply_info_thr_invalid "1." \
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"
+ gdb_test "p \$zero = 0" " = 0"
+ gdb_test "p \$one = 1" " = 1"
+ gdb_test "p \$minus_one = -11" " = -11"
+ foreach prefix {"" "1." "$one."} {
+ set prefix_re [string_to_regexp $prefix]
+
+ thr_apply_info_thr_invalid "${prefix}foo"
+ thr_apply_info_thr_invalid "${prefix}1foo"
+ thr_apply_info_thr_invalid "${prefix}foo1"
+
+ thr_apply_info_thr_error "${prefix}1-0" "inverted range"
+ thr_apply_info_thr_error "${prefix}1-\$zero" "inverted range"
+ thr_apply_info_thr_error "${prefix}\$one-0" "inverted range"
+ thr_apply_info_thr_error "${prefix}\$one-\$zero" "inverted range"
+ thr_apply_info_thr_error "${prefix}1-" "inverted range"
+ thr_apply_info_thr_error "${prefix}2-1" "inverted range"
+ thr_apply_info_thr_error "${prefix}2-\$one" "inverted range"
+ if {$prefix == ""} {
+ thr_apply_info_thr_error "${prefix}-1" "Invalid thread ID: -1" \
+ "Unrecognized option at: -1"
+ thr_apply_info_thr_error "${prefix}-\$one" \
+ "Invalid thread ID: -\\\$one" "Unrecognized option at: -\\\$one"
+ } else {
+ thr_apply_info_thr_error "${prefix}-1" "negative value"
+ thr_apply_info_thr_error "${prefix}-\$one" "negative value"
+ }
+ thr_apply_info_thr_error "${prefix}\$minus_one" \
+ "negative value: ${prefix_re}\\\$minus_one"
+
+ thr_apply_info_thr_error "${prefix}1-*" "inverted range"
+ thr_apply_info_thr_invalid "${prefix}*1"
+ thr_apply_info_thr_invalid "${prefix}*foo"
+ thr_apply_info_thr_invalid "${prefix}foo*"
+ }
- thr_apply_info_thr_error "2-1" "inverted range"
- thr_apply_info_thr_error "1.2-1" "inverted range"
+ # Check that a valid thread ID list with a missing command errors
+ # out.
+ with_test_prefix "missing command" {
+ set output "Please specify a command following the thread ID list"
+ gdb_test "thread apply 1" $output
+ gdb_test "thread apply 1.1" $output
+ gdb_test "thread apply 1.1 1.2" $output
+ gdb_test "thread apply 1-2" $output
+ gdb_test "thread apply 1.1-2" $output
+ gdb_test "thread apply $thr" $output
+ gdb_test "thread apply 1.*" $output
+ }
- thr_apply_info_thr_error "-1" "negative value"
- thr_apply_info_thr_error "1.-1" "negative value"
+ # Check that thread ID list parsing stops at the non-number token
+ # "foo" in a corner case where the "foo" is followed by hyphens.
+ # In this corner case, GDB used to skip past "foo", and then parse
+ # "--1" as a tid range for the current inferior.
+ gdb_test "thread apply 1 foo --1" \
+ "Undefined command: \"foo\". Try \"help\"\\."
# Check that we do parse the inferior number and don't confuse it.
gdb_test "info threads 3.1" \
if { ![skip_python_tests] } {
with_test_prefix "python" {
- # Check that InferiorThread.num returns the expected number.
+ # Check that InferiorThread.num and InferiorThread.global_num
+ # return the expected numbers.
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"
+ gdb_test "python print ('result = %s' % t0.global_num)" " = 6" \
+ "test InferiorThread.global_num"
+
+ # Breakpoint.thread expects global IDs. Confirm that that
+ # works as expected.
+ delete_breakpoints
+ gdb_breakpoint "thread_function1"
+
+ gdb_py_test_silent_cmd "python bp = gdb.breakpoints()\[0\]" \
+ "get python breakpoint" 0
+ gdb_test "python bp.thread = 6" "thread = 6" \
+ "make breakpoint thread-specific with python"
+ # Check that the inferior-qualified ID is correct.
+ gdb_test "info breakpoint" \
+ "stop only in thread 1.3\r\n.*" \
+ "thread specific breakpoint right thread"
}
}