diff options
-rw-r--r-- | gdb/ChangeLog | 6 | ||||
-rw-r--r-- | gdb/breakpoint.c | 67 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 4 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 9 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/watch_thread_num.c | 63 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/watch_thread_num.exp | 64 |
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" +} + |