This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 4/4] Add new test for thread-specific breakpoints with conditions


While developing the gdbserver-based thread-specific breakpoints, I had
a few bugs in my implementation, which lead me to write these tests.  I
think it would be useful to have them in the testsuite, since it was
easy to get something wrong with the generation of the condition.

gdb/testsuite/ChangeLog:

	* gdb.threads/thread-specific-plus-condition.exp: New file.
	* gdb.threads/thread-specific-plus-condition.c: New file.
---
 .../gdb.threads/thread-specific-plus-condition.c   |  66 +++++
 .../gdb.threads/thread-specific-plus-condition.exp | 324 +++++++++++++++++++++
 2 files changed, 390 insertions(+)
 create mode 100644 gdb/testsuite/gdb.threads/thread-specific-plus-condition.c
 create mode 100644 gdb/testsuite/gdb.threads/thread-specific-plus-condition.exp

diff --git a/gdb/testsuite/gdb.threads/thread-specific-plus-condition.c b/gdb/testsuite/gdb.threads/thread-specific-plus-condition.c
new file mode 100644
index 0000000000..f20eca6de2
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/thread-specific-plus-condition.c
@@ -0,0 +1,66 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2017 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/>.  */
+
+#include <pthread.h>
+#include <assert.h>
+
+static pthread_barrier_t barrier;
+static int x = 0;
+
+static void *
+thread_2_func (void *varg)
+{
+  int i;
+
+  /* Tell the main thread the thread has started.  */
+  pthread_barrier_wait (&barrier);
+
+  /* Wait until main tells us we can start looping.  */
+  pthread_barrier_wait (&barrier);
+
+  for (i = 0; i < 100; i++)
+    x++; /* thread_2_func loop tag */
+
+  return NULL;
+}
+
+int
+main (void)
+{
+  pthread_t thread2;
+  int res;
+
+  pthread_barrier_init (&barrier, NULL, 2);
+
+  res = pthread_create (&thread2, NULL, thread_2_func, NULL);
+  assert (res == 0);
+
+  /* Wait until the thread has started.  */
+  pthread_barrier_wait (&barrier);
+
+  /* thread started tag */
+
+  /* Tell the thread it can start looping.  */
+  pthread_barrier_wait (&barrier);
+
+  res = pthread_join (thread2, NULL);
+  assert (res == 0);
+
+  /* main done tag */
+
+  return 0;
+}
diff --git a/gdb/testsuite/gdb.threads/thread-specific-plus-condition.exp b/gdb/testsuite/gdb.threads/thread-specific-plus-condition.exp
new file mode 100644
index 0000000000..33e3fcd798
--- /dev/null
+++ b/gdb/testsuite/gdb.threads/thread-specific-plus-condition.exp
@@ -0,0 +1,324 @@
+# Copyright 2004-2017 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/>.
+
+# This file was written by Daniel Jacobowitz <drow@mvista.com>.
+
+standard_testfile
+
+# Start the test program with the given number of threads.  Pause it at the
+# point where we know all the threads are started.
+#
+# Return 1 on success, 0 on error.
+
+proc setup { conditional_breakpoints_packet ax_thread_id } {
+    global srcdir subdir srcfile binfile
+
+    if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "debug"] != "" } {
+	fail "failed to compile"
+	return 0
+    }
+
+    clean_restart ${binfile}
+
+    runto_main
+
+    gdb_test_no_output "set remote conditional-breakpoints-packet $conditional_breakpoints_packet"
+    gdb_test_no_output "set remote ax-thread-id-packet $ax_thread_id"
+
+    gdb_breakpoint [gdb_get_line_number "thread started tag"]
+    gdb_continue_to_breakpoint "thread started"
+
+    # Look up breakpoint lines used many times in the tests.
+    global thread_2_bp_line main_bp_line
+
+    set thread_2_bp_line [gdb_get_line_number "thread_2_func loop tag"]
+    set main_bp_line [gdb_get_line_number "main done tag"]
+
+    return 1
+}
+
+# To keep the proc names short, the following notation is used.
+#
+# test_X: test a single breakpoint
+# test_X_Y: test two breakpoints at the same location
+#
+# X and Y can contain:
+#
+# U: unconditional breakpoint
+# C: conditional breakpoint that will evaluate to true
+# c: conditional breakpoint that will evaluate to false
+# T: thread-specific breakpoint for the right thread
+# t: thread-specific breakpoint for the wrong thread
+
+# Thread-specific breakpoint, wrong thread.
+
+proc test_t { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	return
+    }
+
+    # Breakpoint under test.
+    gdb_breakpoint "$thread_2_bp_line thread 1"
+
+    # Catch-all breakpoint.
+    set expected_breakpoint_hit [gdb_breakpoint $main_bp_line]
+
+    gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+}
+
+# Thread-specific breakpoint, right thread.
+
+proc test_T { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	return
+    }
+
+    # Breakpoint under test.
+    set expected_breakpoint_hit [gdb_breakpoint "$thread_2_bp_line thread 2"]
+
+    # Catch-all breakpoint.
+    gdb_breakpoint $main_bp_line
+
+    gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+}
+
+# Thread-specific breakpoint, wrong thread, true condition.
+
+proc test_tC { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	return
+    }
+
+    # Breakpoint under test.
+    gdb_breakpoint "$thread_2_bp_line thread 1 if i == 10"
+
+    # Catch-all breakpoint.
+    set expected_breakpoint_hit [gdb_breakpoint $main_bp_line]
+
+    gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+}
+
+# Breakpoint with condition false, right thread.
+
+proc test_Tc { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	return
+    }
+
+    # Breakpoint under test.
+    gdb_breakpoint "$thread_2_bp_line thread 2 if i == 99999"
+
+    # Catch-all breakpoint.
+    set expected_breakpoint_hit [gdb_breakpoint $main_bp_line]
+
+    gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+}
+
+# Breakpoint with condition true, right thread.
+
+proc test_TC { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	return
+    }
+
+    # Breakpoint under test.
+    set expected_breakpoint_hit [gdb_breakpoint "$thread_2_bp_line thread 2 if i == 10"]
+
+    # Catch-all breakpoint.
+    gdb_breakpoint $main_bp_line
+
+    gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+}
+
+# Breakpoint 1: wrong thread
+# Breakpoint 2: unconditional
+
+proc test_t_U { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    foreach_with_prefix run { 0 1 } {
+	if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	    continue
+	}
+
+	# Breakpoints under test.
+	if { $run == 0 } {
+	    gdb_breakpoint "$thread_2_bp_line thread 1"
+	    set expected_breakpoint_hit [gdb_breakpoint $thread_2_bp_line]
+	} else {
+	    set expected_breakpoint_hit [gdb_breakpoint $thread_2_bp_line]
+	    gdb_breakpoint "$thread_2_bp_line thread 1"
+	}
+
+	# Catch-all breakpoint.
+	gdb_breakpoint $main_bp_line
+
+	gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+    }
+}
+
+# Breakpoint 1: wrong thread
+# Breakpoint 2: right thread
+
+proc test_t_T { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    foreach_with_prefix run { 0 1 } {
+	if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	    continue
+	}
+
+	# Breakpoints under test.
+	if { $run == 0 } {
+	    set expected_breakpoint_hit [gdb_breakpoint "$thread_2_bp_line thread 2"]
+	    gdb_breakpoint "$thread_2_bp_line thread 1"
+	} else {
+	    gdb_breakpoint "$thread_2_bp_line thread 1"
+	    set expected_breakpoint_hit [gdb_breakpoint "$thread_2_bp_line thread 2"]
+	}
+
+	# Catch-all breakpoint.
+	gdb_breakpoint $main_bp_line
+
+	gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+    }
+}
+
+# Breakpoint 1: right thread
+# Breakpoint 2: right thread
+
+proc test_T_T { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	return
+    }
+
+    # Event though both breakpoints are hit, GDB's current implementation only
+    # reports the first one.
+    set expected_breakpoint_hit [gdb_breakpoint "$thread_2_bp_line thread 2"]
+    gdb_breakpoint "$thread_2_bp_line thread 2"
+
+    # Catch-all breakpoint.
+    gdb_breakpoint $main_bp_line
+
+    gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+}
+
+# Breakpoint 1: wrong thread
+# Breakpoint 2: wrong thread
+
+proc test_t_t { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	return
+    }
+
+    gdb_breakpoint "$thread_2_bp_line thread 1"
+    gdb_breakpoint "$thread_2_bp_line thread 1"
+
+    # Catch-all breakpoint.
+    set expected_breakpoint_hit [gdb_breakpoint $main_bp_line]
+
+    gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+}
+
+# Breakpoint 1: wrong thread
+# Breakpoint 2: false condition
+
+proc test_t_c { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    foreach_with_prefix run { 0 1 } {
+	if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	    continue
+	}
+
+	# Breakpoints under test.
+	if { $run == 0 } {
+	    gdb_breakpoint "$thread_2_bp_line thread 1"
+	    gdb_breakpoint "$thread_2_bp_line if i == 9999"
+	} else {
+	    gdb_breakpoint "$thread_2_bp_line if i == 9999"
+	    gdb_breakpoint "$thread_2_bp_line thread 1"
+	}
+
+	# Catch-all breakpoint.
+	set expected_breakpoint_hit [gdb_breakpoint "$main_bp_line"]
+
+	gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+    }
+}
+
+# Breakpoint 1: right thread, false condition
+# Breakpoint 2: wrong thread, true condition
+
+proc test_Tc_tC { conditional_breakpoints_packet ax_thread_id_packet } {
+    global thread_2_bp_line main_bp_line
+
+    foreach_with_prefix run { 0 1 } {
+	if { ![setup $conditional_breakpoints_packet $ax_thread_id_packet] } {
+	    continue
+	}
+
+	# Breakpoints under test.
+	if { $run == 0 } {
+	    gdb_breakpoint "$thread_2_bp_line thread 1 if i == 10"
+	    gdb_breakpoint "$thread_2_bp_line thread 2 if i == 9999"
+	} else {
+	    gdb_breakpoint "$thread_2_bp_line thread 2 if i == 9999"
+	    gdb_breakpoint "$thread_2_bp_line thread 1 if i == 10"
+	}
+
+	# Catch-all breakpoint.
+	set expected_breakpoint_hit [gdb_breakpoint "$main_bp_line"]
+
+	gdb_continue_to_breakpoint "continue to breakpoint" .* $expected_breakpoint_hit
+    }
+}
+
+set procs {
+    test_t
+    test_T
+    test_tC
+    test_Tc
+    test_TC
+    test_t_U
+    test_t_T
+    test_T_T
+    test_t_t
+    test_t_c
+    test_Tc_tC
+}
+
+foreach_with_prefix conditional_breakpoints_packet { auto off } {
+    foreach_with_prefix ax_thread_id_packet { auto off } {
+	foreach_with_prefix procname $procs {
+	    # Call the test procedure.
+	    $procname $conditional_breakpoints_packet $ax_thread_id_packet
+	}
+    }
+}
-- 
2.11.0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]