From 37e4754d76e3bf273485512fd6c81201e2d571f9 Mon Sep 17 00:00:00 2001 From: Luis Machado Date: Mon, 17 Dec 2007 12:32:23 +0000 Subject: [PATCH] * breakpoint.c: (watch_command_1): Parse additional optional "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 | 6 ++ gdb/breakpoint.c | 67 ++++++++++++++++++++- gdb/doc/ChangeLog | 4 ++ gdb/doc/gdb.texinfo | 9 ++- gdb/testsuite/ChangeLog | 5 ++ gdb/testsuite/gdb.base/watch_thread_num.c | 63 +++++++++++++++++++ gdb/testsuite/gdb.base/watch_thread_num.exp | 64 ++++++++++++++++++++ 7 files changed, 215 insertions(+), 3 deletions(-) create mode 100644 gdb/testsuite/gdb.base/watch_thread_num.c create mode 100644 gdb/testsuite/gdb.base/watch_thread_num.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0cec62b32e0..efda4330514 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,9 @@ +2007-12-17 Luis Machado + + * 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 * breakpoint.c (bpstat_stop_status): Check an additional diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 44c02f05937..877c571f078 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 ' 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 ' 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 + 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 c1150b8c1a5..fb28f78787d 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,7 @@ +2007-12-17 Luis Machado + + * doc/gdb.texinfo: Add new parameter's description. + 2007-12-16 Daniel Jacobowitz * gdb.texinfo (Overview): Clarify run-length encoding diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 36f1dc44b59..65c97a2a0de 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 9129aa9af93..22eaae013ab 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2007-12-17 Luis Machado + + * 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 * 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 00000000000..ab739cd13e0 --- /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 +#include +#include +#include + +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 00000000000..d5114ef9f22 --- /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 . */ + +# watch-thread_num.exp Test thread 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" +} + -- 2.30.2