[PATCH 5/5] ITSET test case.
Yao Qi
yao@codesourcery.com
Tue Apr 2 14:46:00 GMT 2013
gdb/testsuite:
2013-04-02 Yao Qi <yao@codesourcery.com>
* gdb.base/itset.exp, gdb.base/itset.c: New.
* gdb.multi/itset.exp, gdb.multi/itset.c: New.
---
gdb/testsuite/gdb.base/itset.c | 95 ++++++++++++
gdb/testsuite/gdb.base/itset.exp | 295 +++++++++++++++++++++++++++++++++++++
gdb/testsuite/gdb.multi/itset.c | 70 +++++++++
gdb/testsuite/gdb.multi/itset.exp | 151 +++++++++++++++++++
4 files changed, 611 insertions(+), 0 deletions(-)
create mode 100644 gdb/testsuite/gdb.base/itset.c
create mode 100644 gdb/testsuite/gdb.base/itset.exp
create mode 100644 gdb/testsuite/gdb.multi/itset.c
create mode 100644 gdb/testsuite/gdb.multi/itset.exp
diff --git a/gdb/testsuite/gdb.base/itset.c b/gdb/testsuite/gdb.base/itset.c
new file mode 100644
index 0000000..bf80b51
--- /dev/null
+++ b/gdb/testsuite/gdb.base/itset.c
@@ -0,0 +1,95 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 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/>. */
+
+#include <pthread.h>
+#include <unistd.h>
+
+static void
+marker1 (void)
+{}
+
+static void
+marker2 (void)
+{}
+
+static void
+end (void)
+{}
+
+#define NR_THREADS 2
+static pthread_mutex_t lock1;
+static pthread_mutex_t lock2;
+static pthread_cond_t cond1;
+static pthread_cond_t cond2;
+
+static void *
+thread_function (void *arg)
+{
+ int *flag = (int *) arg;
+ static int counter = 0;
+
+ /* Wait until all child threads are running. */
+ pthread_mutex_lock (&lock1);
+ ++counter;
+ if (counter < NR_THREADS)
+ pthread_cond_wait (&cond1, &lock1);
+ else
+ pthread_cond_broadcast (&cond1);
+ pthread_mutex_unlock (&lock1);
+
+ if (*flag == 0)
+ marker2 ();
+
+ /* Make sure no thread exists when GDB is examining the threads. */
+ pthread_mutex_lock (&lock2);
+ ++counter;
+ if (counter < 2 * NR_THREADS)
+ pthread_cond_wait (&cond2, &lock2);
+ else
+ pthread_cond_signal (&cond2);
+ pthread_mutex_unlock (&lock2);
+
+}
+
+int
+main (int argc, char *argv[], char *envp[])
+{
+ pthread_t threads[NR_THREADS];
+ int flags[NR_THREADS];
+ int i, j;
+
+ pthread_mutex_init (&lock1, NULL);
+ pthread_mutex_init (&lock2, NULL);
+ pthread_cond_init (&cond1, NULL);
+ pthread_cond_init (&cond2, NULL);
+
+ for (i = 0; i < NR_THREADS; i++)
+ {
+ flags[i] = i;
+ pthread_create (&threads[i], NULL, thread_function,
+ (void *) (&flags[i]));
+ }
+
+ marker1 ();
+
+ for (j = 0; j < NR_THREADS; j++)
+ pthread_join (threads[j], NULL);
+
+ end ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.base/itset.exp b/gdb/testsuite/gdb.base/itset.exp
new file mode 100644
index 0000000..a76dda6
--- /dev/null
+++ b/gdb/testsuite/gdb.base/itset.exp
@@ -0,0 +1,295 @@
+# Copyright 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/>.
+
+standard_testfile .c
+set executable $testfile
+
+if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" \
+ "${binfile}" executable [list nowarnings debug]] != "" } {
+ untested itset.exp
+ return -1
+}
+
+# Test the behaviour of ITSET without any running process.
+
+proc test_itset_without_running_process { } {
+ with_test_prefix "wo run" {
+ global srcdir
+ global subdir
+ global binfile
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ # Test `maint info itsets'
+ gdb_test_sequence "maint info itsets" "maint info itsets 1" {
+ "\[\r\n\]Num\[ \]+Name\[ \]+What"
+ "\[\r\n\]\-1\[ \]+all\[ \]+all"
+ }
+
+ # Test `info itsets'
+ with_test_prefix "info itsets" {
+ gdb_test "info itsets" "No named itsets\." \
+ "no itsets no arg"
+ gdb_test "info itsets 1" "No named itset found with number 1\." \
+ "no itsets with number"
+ }
+
+ # Test defset and undefset
+ gdb_test_no_output "defset itset-t1 t1"
+ gdb_test_no_output "defset itset-t2 t2"
+
+ with_test_prefix "viewset" {
+ if [ gdb_test_sequence "viewset" "no arg" {
+ "\[\n\r\]all contains:"
+ "\[\n\r\] inferiors: 1"
+ "\[\n\r\]itset-t1 contains:"
+ "\[\n\r\]itset-t2 contains:"
+ } ] {
+ fail "no arg"
+ }
+
+ gdb_test_sequence "viewset i1" "arg i1" {
+ "\[\n\r\]i1 contains:"
+ "\[\n\r\] inferiors: 1"
+ }
+ }
+
+ gdb_test "whichsets itset-t1" ".*"
+
+ with_test_prefix "info itsets" {
+ gdb_test_sequence "info itsets" "itset-t1" {
+ "\[\n\r\]1\[ \]+itset-t1\[ \]+t1"
+ "\[\n\r\]2\[ \]+itset-t2\[ \]+t2"
+ }
+ }
+
+ with_test_prefix "maint info itsets" {
+ if [ gdb_test_sequence "maint info itsets" "2" {
+ "\[\n\r\]\Num\[ \]+Name\[ \]+What"
+ "\[\n\r\]1\[ \]+itset-t1\[ \]+t1"
+ "\[\n\r\]2\[ \]+itset-t2\[ \]+t2"
+ } ] {
+ fail "2"
+ }
+ }
+
+ # Test undefset
+ gdb_test_no_output "undefset itset-t1"
+ gdb_test_no_output "undefset -all"
+
+ # Test whichsets. Is it correct to output nothing in this case?
+ gdb_test_no_output "whichsets i1"
+
+ with_test_prefix "scope" {
+ gdb_test "scope" "Focus is `all\' \\(current inferior is 1\\)" \
+ "no arg"
+ gdb_test "scope i10" "warning: focus set is empty\[\r\n\]+Current inferior is 1\." \
+ "empty focus"
+ gdb_test "scope i1" "Current inferior is 1\." "i1"
+ }
+ }
+}
+
+# Test various error messages from ITSET related commands.
+
+proc test_itset_check_error { } {
+ with_test_prefix "error message" {
+ global srcdir
+ global subdir
+ global binfile
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ with_test_prefix "defset" {
+ gdb_test "defset" "Argument required \\(no args\\)\." \
+ "without args"
+
+ gdb_test_no_output "defset itset-i1 i1"
+ gdb_test "defset itset-i1 i2" "itset itset-i1 already exists" \
+ "already exists"
+
+ gdb_test_no_output "undefset -all"
+ }
+
+ with_test_prefix "undefset" {
+ gdb_test "undefset" "Argument required \\(no args\\)\." \
+ "without args"
+ gdb_test "undefset itset-c1" "itset itset-c1 does not exist" \
+ "does not exist"
+
+ gdb_test_no_output "defset itset-i1 i1"
+ gdb_test_no_output "undefset -all"
+ }
+
+ gdb_test "info itsets foo" "No named itset found with number foo\."
+ }
+}
+
+proc test_itset_check_syntax { } {
+ with_test_prefix "syntax" {
+ global srcdir
+ global subdir
+ global binfile
+
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_load ${binfile}
+
+ gdb_test "defset itset-t1 t2-a" "Expected digit in I/T set, at `a'"
+
+ gdb_test "defset itset1 all,other" "Unknown named I/T set: `other\'"
+ }
+}
+
+test_itset_without_running_process
+
+test_itset_check_error
+
+test_itset_check_syntax
+
+# Test the behaviour of ITSET in single-thread.
+
+proc test_itset_with_running_single_thread { } {
+ with_test_prefix "w run st" {
+ global executable
+ global binfile
+
+ # Start with a fresh gdb.
+ clean_restart ${executable}
+ if ![runto_main] {
+ fail "Can't run to main"
+ return -1
+ }
+
+ gdb_test_no_output "defset itset-t1 t1"
+ gdb_test_no_output "defset itset-t2 t2"
+ gdb_test_no_output "defset itset-t1-t2 t1-2"
+
+ gdb_test "whichsets t1" \
+ "i1\.t1 \\(Thread .*\\) is in: all, itset-t1, itset-t1-t2"
+ # whichsets for current itset.
+ gdb_test "whichsets" \
+ "i1\.t1 \\(Thread .*\\) is in: all, itset-t1, itset-t1-t2"
+
+ # Test viewset
+ set test "viewset t1"
+ if [ gdb_test_sequence "viewset t1" $test {
+ "\[\n\r\]t1 contains:"
+ "\[\n\r\] inferiors: 1"
+ "\[\n\r\] threads: 1"
+ } ] {
+ fail $test
+ }
+
+ with_test_prefix "scope" {
+ gdb_test "scope i1" "Current inferior is 1\." "i1"
+ gdb_test "scope t1-2" "Current inferior is 1\." "t1-2"
+ }
+
+ }
+}
+
+test_itset_with_running_single_thread
+
+proc test_target_set { } {
+ with_test_prefix "target set" {
+ global executable
+ global binfile
+ global gdb_prompt
+
+ # Start with a fresh gdb.
+ clean_restart ${executable}
+ if ![runto_main] {
+ fail "Can't run to main"
+ return -1
+ }
+
+ gdb_test "break end" "Breakpoint 2 at .*"
+ gdb_test "scope t1-2 break marker2" "Breakpoint 3 at .*"
+ gdb_test "scope t1 break marker2" "Breakpoint 4 at .*"
+ gdb_test "scope t2 break marker2" "Breakpoint 5 at .*"
+
+ set nonstop 0
+ gdb_test_multiple "show non-stop" "show non-stop" {
+ -re "Controlling the inferior in non-stop mode is off\..*$gdb_prompt $" {
+ set nonstop 0
+ }
+ -re "Controlling the inferior in non-stop mode is on\..*$gdb_prompt $" {
+ set nonstop 1
+ }
+ }
+
+ # Thread 2 hits the breakpoint on marker2.
+ gdb_test "continue" ".*Breakpoint 3, marker2.*" \
+ "continue to marker2"
+ if { $nonstop } {
+ # In non-stop mode, switch to the thread hits breakpoint.
+ gdb_test "thread 2"
+ }
+ gdb_test "continue" ".*Breakpoint 2, end.*" \
+ "continue to end"
+
+ # Check the hit count of breakpoints. Hit count of breakpoint
+ # 4 should zero.
+ gdb_test_sequence "info breakpoints" "info break" {
+ "\[\r\n\]Num Type Disp Enb Address +What"
+ "\[\r\n\]1 breakpoint"
+ "\[\r\n\]\tbreakpoint already hit 1 time"
+ "\[\r\n\]2 breakpoint"
+ "\[\r\n\]\tbreakpoint already hit 1 time"
+ "\[\r\n\]3 breakpoint"
+ "\[\r\n\]\tbreakpoint already hit 1 time"
+ "\[\r\n\]4 breakpoint"
+ "\[\r\n\]5 breakpoint"
+ "\[\r\n\]\tbreakpoint already hit 1 time"
+ }
+
+ # Start with a fresh gdb.
+ clean_restart ${executable}
+ if ![runto_main] {
+ fail "Can't run to main"
+ return -1
+ }
+ gdb_test "scope t2 break marker2" "Breakpoint 2 at .*"
+ # Thread 2 hits the breakpoint on marker2.
+ gdb_test "continue" ".*Breakpoint 2, marker2.*" \
+ "continue to marker2"
+
+ # Update GDB's knowledge on existing threads.
+ gdb_test "info threads"
+ global hex
+
+ # Thread 2 is stopped due to hitting a breakpoint, it should
+ # appear in the output unconditionally. Thread 1 and thread
+ # 3 don't hit breakpoint, so they are stopped in all-stop
+ # mode, or running in non-stop mode. In other words, the
+ # backtrace output has thread 1 and thread 3 in all-stop mode.
+ if { $nonstop } {
+ gdb_test "scope all bt" \
+ "Thread 2 .*#0 marker2 \\(\\).*#1 ${hex} in thread_function .*"
+ } else {
+ gdb_test "scope all bt" \
+ "Thread 3 .* ${hex} in thread_function .*Thread 2 .*#0 marker2 \\(\\).*#1 ${hex} in thread_function .*Thread 1 .* ${hex} in pthread_join.* ${hex} in main .*"
+ }
+ }
+}
+
+test_target_set
diff --git a/gdb/testsuite/gdb.multi/itset.c b/gdb/testsuite/gdb.multi/itset.c
new file mode 100644
index 0000000..4af8ebc
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/itset.c
@@ -0,0 +1,70 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 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/>. */
+
+#include <pthread.h>
+#include <unistd.h>
+
+static void
+end (void)
+{}
+
+#define NR_THREADS 2
+
+static pthread_mutex_t lock;
+static pthread_cond_t cond;
+static int counter = 0;
+
+static void *
+thread_function (void *arg)
+{
+ /* Wait until all threads are running. */
+ pthread_mutex_lock (&lock);
+ ++counter;
+
+ if (counter < NR_THREADS)
+ pthread_cond_wait (&cond, &lock);
+ else
+ pthread_cond_broadcast (&cond);
+
+ pthread_mutex_unlock (&lock);
+
+ /* Don't exit when GDB is examining threads. */
+ sleep (10);
+}
+
+int
+main (int argc, char *argv[], char *envp[])
+{
+ pthread_t threads[NR_THREADS];
+ int i;
+
+ pthread_mutex_init (&lock, NULL);
+ pthread_cond_init (&cond, NULL);
+
+ for (i = 0; i < NR_THREADS; i++)
+ pthread_create (&threads[i], NULL, thread_function, NULL);
+
+ /* Wait until all threads are running. */
+ pthread_mutex_lock (&lock);
+ if (counter < NR_THREADS)
+ pthread_cond_wait (&cond, &lock);
+ pthread_mutex_unlock (&lock);
+
+ end ();
+
+ return 0;
+}
diff --git a/gdb/testsuite/gdb.multi/itset.exp b/gdb/testsuite/gdb.multi/itset.exp
new file mode 100644
index 0000000..b92c852
--- /dev/null
+++ b/gdb/testsuite/gdb.multi/itset.exp
@@ -0,0 +1,151 @@
+# Copyright 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/>.
+
+# The plain remote target can't do multiple inferiors.
+if [target_info exists use_gdb_stub] {
+ return
+}
+standard_testfile .c
+set executable ${testfile}
+
+if { [gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" \
+ executable [list nowarnings debug]] != "" } {
+ untested itset.exp
+ return -1
+}
+
+# Test the behaviour of itset in multi-inferior and mulit-thread.
+
+proc test_itset { } {
+ with_test_prefix "/w run" {
+ global executable
+ global binfile
+ global srcfile
+ global gdb_prompt
+
+ # Start with a fresh gdb.
+ clean_restart ${executable}
+ if ![runto_main] {
+ fail "Can't run to main 1"
+ return -1
+ }
+
+ gdb_test "add-inferior -exec ${binfile}" \
+ "Added inferior 2.*" \
+ "add inferior 2 with -exec ${binfile}"
+
+ gdb_test "inferior 2"
+ if ![runto_main] {
+ fail "Can't run to main 2"
+ return -1
+ }
+
+ # So far, there are two inferiors i1 and i2. Each of them has
+ # only one thread.
+ gdb_test_no_output "defset s1 i1.t1,i2.t2-10"
+ gdb_test "whichsets t1" "i1\.t1 \\(Thread .*\\) is in: all, s1" \
+ "1 thread: s1 contains i1.t1"
+ gdb_test "whichsets t2" "i2\.t2 \\(Thread .*\\) is in: all, s1" \
+ "1 thread: s1 contains i2.t2"
+
+ # This breakpoint is set to both inferior 1 and inferior 2.
+ gdb_test "break end" \
+ "Breakpoint \[0-9\] at .* end.*"
+
+ gdb_test "inferior 1"
+ gdb_test "continue" ".*Breakpoint \[0-9\], end.*" \
+ "continue to end"
+
+ # Now, there are three threads in inferior 1, t1, t3, t4, and
+ # still only one thread t2 in inferior 2.
+ # Update GDB's knowledge on existing threads.
+ gdb_test "info threads" ".*"
+ gdb_test "whichsets t2" "i2\.t2 \\(Thread .*\\) is in: all, s1" \
+ "1 thread: s1 contains i1.t2"
+ gdb_test "whichsets t3" "i1\.t3 \\(Thread .*\\) is in: all" \
+ "1 thread: s1 contains i1.t3"
+ gdb_test "whichsets t4" "i1\.t4 \\(Thread .*\\) is in: all" \
+ "1 thread: s1 contains i1.t4"
+
+
+ }
+}
+
+# Test the target set of commands.
+
+proc test_target_set { } {
+ with_test_prefix "target set" {
+ global executable
+ global binfile
+ global srcfile
+ global gdb_prompt
+
+ # Start with a fresh gdb.
+ clean_restart ${executable}
+ if ![runto_main] {
+ fail "Can't run to main 1"
+ return -1
+ }
+
+ gdb_test "add-inferior -exec ${binfile}" \
+ "Added inferior 2.*" \
+ "add inferior 2 with -exec ${binfile}"
+
+ gdb_test "inferior 2"
+ if ![runto_main] {
+ fail "Can't run to main 2"
+ return -1
+ }
+
+ # This breakpoint is set to both inferior 1 and inferior 2.
+ gdb_test "break end" \
+ "Breakpoint \[0-9\] at .* end.*"
+
+ gdb_test "inferior 1"
+ gdb_test "continue" ".*Breakpoint \[0-9\], end.*" \
+ "continue to end"
+
+ set nonstop 0
+ gdb_test_multiple "show non-stop" "show non-stop" {
+ -re "Controlling the inferior in non-stop mode is off\..*$gdb_prompt $" {
+ set nonstop 0
+ }
+ -re "Controlling the inferior in non-stop mode is on\..*$gdb_prompt $" {
+ set nonstop 1
+ }
+ }
+
+ # Fore GDB to refresh its thread list.
+ gdb_test "info threads"
+
+ # Thread 1, 3, and 4.
+ global hex
+
+ # Thread 1 in inferior 1 hits the breakpoint, and is stopped.
+ # Thread 2 in inferior 2 is stopped.
+ # Thread 3 and 4 don't hit breakpoint, so they are stopped in
+ # all-stop, or running in non-stop mode.
+ if { $nonstop } {
+ gdb_test "scope all bt" \
+ "Thread 2 .*#0 main \\(.*Thread 1 .*#0 end \\(\\) .* ${hex} in main \\(.*"
+ } else {
+ gdb_test "scope all bt" \
+ "Thread 4 .* ${hex} in thread_function .*Thread 3 .* ${hex} in thread_function .*Thread 2 .*#0 main \\(.*Thread 1 .*#0 end \\(\\) .* ${hex} in main \\(.*"
+ }
+ }
+}
+
+test_itset
+
+test_target_set
--
1.7.7.6
More information about the Gdb-patches
mailing list