diff options
author | Sergio Durigan Junior <sergiodj@redhat.com> | 2010-06-16 18:30:34 +0000 |
---|---|---|
committer | Sergio Durigan Junior <sergiodj@redhat.com> | 2010-06-16 18:30:34 +0000 |
commit | 65d79d4b97a28b720c44e26571170a3af5d300f6 (patch) | |
tree | b77afb71ac6b18133c28dfe87c7820bf7ddb3420 /gdb/breakpoint.c | |
parent | 3e23530232f272b7a55c6492948bdd76f65e7334 (diff) | |
download | gdb-65d79d4b97a28b720c44e26571170a3af5d300f6.zip gdb-65d79d4b97a28b720c44e26571170a3af5d300f6.tar.gz gdb-65d79d4b97a28b720c44e26571170a3af5d300f6.tar.bz2 |
gdb/ChangeLog:
2010-06-16 Sergio Durigan Junior <sergiodj@redhat.com>
Jan Kratochvil <jan.kratochvil@redhat.com>
* breakpoint.c: Include parser-defs.h.
(watchpoint_exp_is_const): New function.
(watch_command_1): Call watchpoint_exp_is_const to check
if the expression is constant.
gdb/doc/ChangeLog:
2010-06-16 Jan Kratochvil <jan.kratochvil@redhat.com>
* gdb.texinfo: Include information about the correct use
of addresses in the `watch' command.
gdb/testsuite/ChangeLog:
2010-06-16 Jan Kratochvil <jan.kratochvil@redhat.com>
Sergio Durigan Junior <sergiodj@redhat.com>
* gdb.base/watch-notconst.c: New file.
* gdb.base/watch-notconst.S: New file.
* gdb.base/watch-notconst2.c: New file.
* gdb.base/watch-notconst2.S: New file.
* gdb.base/watch-notconst.exp: New file.
* gdb.base/watchpoint.c (global_ptr_ptr): New variable.
(func4): Add operations on `global_ptr_ptr'.
* gdb.base/watchpoint.exp (test_constant_watchpoint): New
routine to test watchpoints created with a constant expression.
(test_inaccessible_watchpoint): Include tests for watchpoints
created with a constant expression.
Diffstat (limited to 'gdb/breakpoint.c')
-rw-r--r-- | gdb/breakpoint.c | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index f851cbe..a0fb887 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -61,6 +61,7 @@ #include "valprint.h" #include "jit.h" #include "xml-syscall.h" +#include "parser-defs.h" /* readline include files */ #include "readline/readline.h" @@ -7767,6 +7768,111 @@ stopat_command (char *arg, int from_tty) break_command_1 (arg, 0, from_tty); } +/* Return non-zero if EXP is verified as constant. Returned zero means EXP is + variable. Also the constant detection may fail for some constant + expressions and in such case still falsely return zero. */ +static int +watchpoint_exp_is_const (const struct expression *exp) +{ + int i = exp->nelts; + + while (i > 0) + { + int oplenp, argsp; + + /* We are only interested in the descriptor of each element. */ + operator_length (exp, i, &oplenp, &argsp); + i -= oplenp; + + switch (exp->elts[i].opcode) + { + case BINOP_ADD: + case BINOP_SUB: + case BINOP_MUL: + case BINOP_DIV: + case BINOP_REM: + case BINOP_MOD: + case BINOP_LSH: + case BINOP_RSH: + case BINOP_LOGICAL_AND: + case BINOP_LOGICAL_OR: + case BINOP_BITWISE_AND: + case BINOP_BITWISE_IOR: + case BINOP_BITWISE_XOR: + case BINOP_EQUAL: + case BINOP_NOTEQUAL: + case BINOP_LESS: + case BINOP_GTR: + case BINOP_LEQ: + case BINOP_GEQ: + case BINOP_REPEAT: + case BINOP_COMMA: + case BINOP_EXP: + case BINOP_MIN: + case BINOP_MAX: + case BINOP_INTDIV: + case BINOP_CONCAT: + case BINOP_IN: + case BINOP_RANGE: + case TERNOP_COND: + case TERNOP_SLICE: + case TERNOP_SLICE_COUNT: + + case OP_LONG: + case OP_DOUBLE: + case OP_DECFLOAT: + case OP_LAST: + case OP_COMPLEX: + case OP_STRING: + case OP_BITSTRING: + case OP_ARRAY: + case OP_TYPE: + case OP_NAME: + case OP_OBJC_NSSTRING: + + case UNOP_NEG: + case UNOP_LOGICAL_NOT: + case UNOP_COMPLEMENT: + case UNOP_ADDR: + case UNOP_HIGH: + /* Unary, binary and ternary operators: We have to check their + operands. If they are constant, then so is the result of + that operation. For instance, if A and B are determined to be + constants, then so is "A + B". + + UNOP_IND is one exception to the rule above, because the value + of *ADDR is not necessarily a constant, even when ADDR is. */ + break; + + case OP_VAR_VALUE: + /* Check whether the associated symbol is a constant. + We use SYMBOL_CLASS rather than TYPE_CONST because it's + possible that a buggy compiler could mark a variable as constant + even when it is not, and TYPE_CONST would return true in this + case, while SYMBOL_CLASS wouldn't. + We also have to check for function symbols because they are + always constant. */ + { + struct symbol *s = exp->elts[i + 2].symbol; + + if (SYMBOL_CLASS (s) != LOC_BLOCK + && SYMBOL_CLASS (s) != LOC_CONST + && SYMBOL_CLASS (s) != LOC_CONST_BYTES) + return 0; + break; + } + + /* The default action is to return 0 because we are using + the optimistic approach here: If we don't know something, + then it is not a constant. */ + default: + return 0; + } + } + + return 1; +} + /* accessflag: hw_write: watch write, hw_read: watch read, hw_access: watch access (read or write) */ @@ -7861,6 +7967,17 @@ watch_command_1 (char *arg, int accessflag, int from_tty) while (exp_end > exp_start && (exp_end[-1] == ' ' || exp_end[-1] == '\t')) --exp_end; + /* Checking if the expression is not constant. */ + if (watchpoint_exp_is_const (exp)) + { + int len; + + len = exp_end - exp_start; + while (len > 0 && isspace (exp_start[len - 1])) + len--; + error (_("Cannot watch constant value `%.*s'."), len, exp_start); + } + exp_valid_block = innermost_block; mark = value_mark (); fetch_watchpoint_value (exp, &val, NULL, NULL); |