This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 4/4] Add new test for thread-specific breakpoints with conditions
- From: Simon Marchi <simon dot marchi at ericsson dot com>
- To: <gdb-patches at sourceware dot org>
- Cc: Simon Marchi <simon dot marchi at ericsson dot com>
- Date: Tue, 18 Apr 2017 18:13:21 -0400
- Subject: [PATCH 4/4] Add new test for thread-specific breakpoints with conditions
- Authentication-results: sourceware.org; auth=none
- Authentication-results: sourceware.org; dkim=none (message not signed) header.d=none;sourceware.org; dmarc=none action=none header.from=ericsson.com;
- References: <20170418221321.20993-1-simon.marchi@ericsson.com>
- Spamdiagnosticmetadata: NSPM
- Spamdiagnosticoutput: 1:99
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