Index: gdb/testsuite/gdb.threads/thread-specific-bp.exp |
diff --git a/gdb/testsuite/gdb.threads/thread-specific-bp.exp b/gdb/testsuite/gdb.threads/thread-specific-bp.exp |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9f7d142693c0da991029c9e0adfa8bdd35e2f88b |
--- /dev/null |
+++ b/gdb/testsuite/gdb.threads/thread-specific-bp.exp |
@@ -0,0 +1,127 @@ |
+# Copyright (C) 2013 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 <http://www.gnu.org/licenses/>. |
+# |
+# Verify that a thread-specific breakpoint is deleted when the |
+# corresponding thread is gone. |
+ |
+standard_testfile |
+ |
+if {[gdb_compile_pthreads \ |
+ "${srcdir}/${subdir}/${srcfile}" \ |
+ "${binfile}" executable {debug} ] != "" } { |
+ return -1 |
+} |
+ |
+clean_restart ${binfile} |
+ |
+# Extract and return the thread ID of the thread stopped at function |
+# FUNC. |
+ |
+proc get_thread_id {func} { |
+ global gdb_prompt |
+ |
+ set thre -1 |
+ set test "get $func thread id" |
+ gdb_test_multiple "info threads" $test { |
+ -re "(\[0-9\]+)\[^\n\r\]*Thread\[^\n\r\]*$func.*$gdb_prompt $" { |
+ # Get the thread's id. |
+ set thre $expect_out(1,string) |
+ pass $test |
+ } |
+ } |
+ |
+ return $thre |
+} |
+ |
+proc check_thread_specific_breakpoint {mode} { |
+ with_test_prefix "$mode" { |
+ global gdb_prompt |
+ |
+ if ![runto_main] { |
+ untested "could not run to main" |
+ return -1 |
+ } |
+ |
+ set main_thre [get_thread_id "main"] |
+ if { $main_thre < 0 } { |
+ return -1 |
+ } |
+ |
+ gdb_breakpoint "start" |
+ gdb_continue_to_breakpoint "start" |
+ |
+ set start_thre [get_thread_id "start"] |
+ if { $start_thre < 0 } { |
+ return -1 |
+ } |
+ |
+ # Set a thread-specific breakpoint at "main". This can't ever |
+ # be hit, but that's OK. |
+ gdb_breakpoint "main thread $start_thre" |
+ gdb_test "info break" ".*breakpoint.*thread $start_thre" "breakpoint set" |
+ |
+ # Set breakpoint at a place only reacheable after the "start" |
+ # thread exits. |
+ gdb_breakpoint "end" |
+ |
+ # Switch back to the main thread, and resume all threads. The |
+ # "start" thread exits, and the main thread reaches "end". |
+ gdb_test "thread $main_thre" \ |
+ "Switching to thread $main_thre.*" \ |
+ "thread $main_thre selected" |
+ |
+ if { $mode == "non-stop" } { |
+ set cmd "continue -a" |
+ } else { |
+ set cmd "continue" |
+ } |
+ gdb_test "$cmd" \ |
+ "Breakpoint .* end .* at .*" \ |
+ "continue to end" |
+ |
+ # Force GDB to update the thread list. Otherwise, depending |
+ # on target, GDB may not realize that the start thread has |
+ # exited and thus not remove the thread specific breakpoint. |
+ set test "thread start is gone" |
+ gdb_test_multiple "info threads" $test { |
+ -re "\[0-9\]+.*start.*$gdb_prompt $" { |
+ fail $test |
+ } |
+ -re "$gdb_prompt $" { |
+ pass $test |
+ } |
+ } |
+ |
+ set test "thread-specific breakpoint was deleted" |
+ gdb_test_multiple "info breakpoint" $test { |
+ -re "thread $start_thre\n$gdb_prompt $" { |
+ fail $test |
+ } |
+ -re "$gdb_prompt $" { |
+ pass $test |
+ } |
+ } |
+ } |
+} |
+ |
+# Test all-stop mode. |
+check_thread_specific_breakpoint "all-stop" |
+ |
+clean_restart ${binfile} |
+ |
+# Test non-stop mode. |
+gdb_test_no_output "set target-async on" "set async mode" |
+gdb_test_no_output "set non-stop on" "set non-stop mode" |
+check_thread_specific_breakpoint "non-stop" |