aboutsummaryrefslogtreecommitdiff
path: root/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'gdb')
-rw-r--r--gdb/ChangeLog6
-rw-r--r--gdb/breakpoint.c67
-rw-r--r--gdb/doc/ChangeLog4
-rw-r--r--gdb/doc/gdb.texinfo9
-rw-r--r--gdb/testsuite/ChangeLog5
-rw-r--r--gdb/testsuite/gdb.base/watch_thread_num.c63
-rw-r--r--gdb/testsuite/gdb.base/watch_thread_num.exp64
7 files changed, 215 insertions, 3 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0cec62b..efda433 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,11 @@
2007-12-17 Luis Machado <luisgpm@br.ibm.com>
+ * breakpoint.c: (watch_command_1): Parse additional optional
+ "thread" parameter to the watchpoint command and set the
+ "thread" member of the breakpoint struct.
+
+2007-12-17 Luis Machado <luisgpm@br.ibm.com>
+
* breakpoint.c (bpstat_stop_status): Check an additional
condition before evaluating an expression value.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 44c02f0..877c571 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -5606,7 +5606,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
struct frame_info *prev_frame = NULL;
char *exp_start = NULL;
char *exp_end = NULL;
- char *tok, *end_tok;
+ char *tok, *id_tok_start, *end_tok;
int toklen;
char *cond_start = NULL;
char *cond_end = NULL;
@@ -5614,10 +5614,72 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
int i, other_type_used, target_resources_ok = 0;
enum bptype bp_type;
int mem_cnt = 0;
+ int thread = -1;
init_sal (&sal); /* initialize to zeroes */
- /* Parse arguments. */
+ /* Make sure that we actually have parameters to parse. */
+ if (arg != NULL && arg[0] != '\0')
+ {
+ toklen = strlen (arg); /* Size of argument list. */
+
+ /* Points tok to the end of the argument list. */
+ tok = arg + toklen - 1;
+
+ /* Go backwards in the parameters list. Skip the last parameter.
+ If we're expecting a 'thread <thread_num>' parameter, this should
+ be the thread identifier. */
+ while (tok > arg && (*tok == ' ' || *tok == '\t'))
+ tok--;
+ while (tok > arg && (*tok != ' ' && *tok != '\t'))
+ tok--;
+
+ /* Points end_tok to the beginning of the last token. */
+ id_tok_start = tok + 1;
+
+ /* Go backwards in the parameters list. Skip one more parameter.
+ If we're expecting a 'thread <thread_num>' parameter, we should
+ reach a "thread" token. */
+ while (tok > arg && (*tok == ' ' || *tok == '\t'))
+ tok--;
+
+ end_tok = tok;
+
+ while (tok > arg && (*tok != ' ' && *tok != '\t'))
+ tok--;
+
+ /* Move the pointer forward to skip the whitespace and
+ calculate the length of the token. */
+ tok++;
+ toklen = end_tok - tok;
+
+ if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+ {
+ /* At this point we've found a "thread" token, which means
+ the user is trying to set a watchpoint that triggers
+ only in a specific thread. */
+ char *endp;
+
+ /* Extract the thread ID from the next token. */
+ thread = strtol (id_tok_start, &endp, 0);
+
+ /* Check if the user provided a valid numeric value for the
+ thread ID. */
+ if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+ error (_("Invalid thread ID specification %s."), id_tok_start);
+
+ /* Check if the thread actually exists. */
+ if (!valid_thread_id (thread))
+ error (_("Unknown thread %d."), thread);
+
+ /* Truncate the string and get rid of the thread <thread_num>
+ parameter before the parameter list is parsed by the
+ evaluate_expression() function. */
+ *tok = '\0';
+ }
+ }
+
+ /* Parse the rest of the arguments. */
innermost_block = NULL;
exp_start = arg;
exp = parse_exp_1 (&arg, 0, 0);
@@ -5710,6 +5772,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty)
b = set_raw_breakpoint (sal, bp_type);
set_breakpoint_count (breakpoint_count + 1);
b->number = breakpoint_count;
+ b->thread = thread;
b->disposition = disp_donttouch;
b->exp = exp;
b->exp_valid_block = exp_valid_block;
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index c1150b8..fb28f78 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -1,3 +1,7 @@
+2007-12-17 Luis Machado <luisgpm@br.ibm.com>
+
+ * doc/gdb.texinfo: Add new parameter's description.
+
2007-12-16 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.texinfo (Overview): Clarify run-length encoding
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 36f1dc4..65c97a2 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3216,7 +3216,7 @@ times slower than normal execution. (But this may still be worth it, to
catch errors where you have no clue what part of your program is the
culprit.)
-On some systems, such as HP-UX, @sc{gnu}/Linux and most other
+On some systems, such as HP-UX, PowerPC, @sc{gnu}/Linux and most other
x86-based targets, @value{GDBN} includes support for hardware
watchpoints, which do not slow down the running of your program.
@@ -3357,6 +3357,13 @@ way of doing that would be to set a code breakpoint at the entry to the
In multi-threaded programs, watchpoints will detect changes to the
watched expression from every thread.
+@kindex watch thread thread_num
+@item watch @var{expr} thread @var{threadnum}
+Set a watchpoint that will break when @var{expr} is either read from
+or written into by the thread identified by @var{threadnum}. If @var{expr}
+is modified by any other threads not matching @var{threadnum}, @value{GDBN}
+will not break. Note that this will only work with Hardware Watchpoints.
+
@quotation
@emph{Warning:} In multi-threaded programs, software watchpoints
have only limited usefulness. If @value{GDBN} creates a software
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index 9129aa9..22eaae0 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2007-12-17 Luis Machado <luisgpm@br.ibm.com>
+
+ * testsuite/gdb.base/watch_thread_num.c: New testcase source file.
+ * testsuite/gdb.base/watch_thread_num.exp: New testcase expect file.
+
2007-12-17 Joel Brobecker <brobecker@adacore.com>
* gdb.ada/frame_args/foo.adb: New file.
diff --git a/gdb/testsuite/gdb.base/watch_thread_num.c b/gdb/testsuite/gdb.base/watch_thread_num.c
new file mode 100644
index 0000000..ab739cd
--- /dev/null
+++ b/gdb/testsuite/gdb.base/watch_thread_num.c
@@ -0,0 +1,63 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2002, 2003, 2004, 2007 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 2 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, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ This file is copied from schedlock.c. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+void *thread_function (void *arg); /* Pointer to function executed by each thread */
+
+#define NUM 5
+
+static unsigned int shared_var = 1;
+
+int main () {
+ int res;
+ pthread_t threads[NUM];
+ void *thread_result;
+ long i;
+
+ for (i = 0; i < NUM; i++)
+ {
+ res = pthread_create (&threads[i],
+ NULL,
+ thread_function,
+ (void *) i);
+ }
+
+ thread_result = thread_function ((void *) i);
+
+ exit (EXIT_SUCCESS);
+}
+
+void *thread_function (void *arg) {
+ int my_number = (long) arg;
+ /* Don't run forever. Run just short of it :) */
+ while (shared_var > 0)
+ {
+ shared_var++;
+ usleep (1); /* Loop increment. */
+ }
+
+ pthread_exit (NULL);
+}
+
diff --git a/gdb/testsuite/gdb.base/watch_thread_num.exp b/gdb/testsuite/gdb.base/watch_thread_num.exp
new file mode 100644
index 0000000..d5114ef
--- /dev/null
+++ b/gdb/testsuite/gdb.base/watch_thread_num.exp
@@ -0,0 +1,64 @@
+# This testcase is part of GDB, the GNU debugger.
+
+# Copyright 2007
+# 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/>. */
+
+# watch-thread_num.exp Test thread <thread_num> parameter for
+# watch commands.
+#
+
+if $tracelevel then {
+ strace $tracelevel
+}
+
+set testfile watch_thread_num
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+# What compiler are we using?
+#
+if [get_compiler_info ${binfile}] {
+ return -1
+}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug libs=-lpthread}] != "" } {
+ untested watch_thread_num.exp
+ return -1
+}
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if { ![runto main] } then {
+ fail "run to main"
+ return
+}
+
+gdb_test "watch shared_var thread 0" "Unknown thread 0\." "Watchpoint on invalid thread"
+gdb_test "watch shared_var thread" "A syntax error in expression, near `thread'\." "Invalid watch syntax"
+
+gdb_test "Next 5" ""
+
+gdb_test "watch shared_var thread 2" "Hardware watchpoint 2: shared_var" "Watchpoint on shared variable"
+gdb_test "info breakpoint 2" "stop only in thread 2"
+
+for {set i 0} {$i < 10} {incr i 1} {
+gdb_test "continue" "Hardware watchpoint 2: shared_var.*" "Watchpoint triggered"
+gdb_test "thread" "\\\[Current thread is 2 \\\(Thread $hex \\\(LWP $decimal\\\)\\\)\\\]" "Check thread that triggered"
+}
+