* breakpoint.c: (watch_command_1): Parse additional optional
authorLuis Machado <luisgpm@br.ibm.com>
Mon, 17 Dec 2007 12:32:23 +0000 (12:32 +0000)
committerLuis Machado <luisgpm@br.ibm.com>
Mon, 17 Dec 2007 12:32:23 +0000 (12:32 +0000)
      "thread" parameter to the watchpoint command and set the
      "thread" member of the breakpoint struct.
      * doc/gdb.texinfo: Add new parameter's description.
      * testsuite/gdb.base/watch_thread_num.c: New testcase source file.
      * testsuite/gdb.base/watch_thread_num.exp: New testcase expect file.

gdb/ChangeLog
gdb/breakpoint.c
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/watch_thread_num.c [new file with mode: 0644]
gdb/testsuite/gdb.base/watch_thread_num.exp [new file with mode: 0644]

index 0cec62b32e0ddca30befc56dbb8b157e3e25c129..efda433051431fb0ac9390bc577d13e4876531f2 100644 (file)
@@ -1,3 +1,9 @@
+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
index 44c02f0593758f30f38943b480e616f4b910787b..877c571f0788bdaf924d9eebf9673db4fcb79f52 100644 (file)
@@ -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;
index c1150b8c1a51d851689f98b6d30394fafccc2d92..fb28f78787dcfb38ccc100bd4177f920db895374 100644 (file)
@@ -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
index 36f1dc44b5992c44780d6108380506ce458b90fa..65c97a2a0dee5de284d1d1c3ab5fb8620def652c 100644 (file)
@@ -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
index 9129aa9af93124a2a71bdd5ea296b36faa27e208..22eaae013ab422936c08df526556e719c2b00b82 100644 (file)
@@ -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 (file)
index 0000000..ab739cd
--- /dev/null
@@ -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 (file)
index 0000000..d5114ef
--- /dev/null
@@ -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"
+}
+