* [rfc] Allow watchpoints on inaccessible memory
@ 2007-08-21 14:25 Daniel Jacobowitz
2007-08-21 16:33 ` Jim Blandy
` (3 more replies)
0 siblings, 4 replies; 15+ messages in thread
From: Daniel Jacobowitz @ 2007-08-21 14:25 UTC (permalink / raw)
To: gdb-patches
Here's something I've been meaning to try for ages. Suppose you have
a global variable pointing to some dynamically allocated storage, and
you want to find writes into that storage. When the pointer isn't
initialized you can't even set the watchpoint:
#include <stdlib.h>
char *ptr;
int
main ()
{
ptr = malloc (65536);
ptr[32768] = 1;
}
(gdb) watch ptr[32768]
Cannot access memory at address 0x8000
When it is initialized you can, but if you re-run then GDB falls over:
(gdb) r
Starting program: /space/fsf/watch
Error in re-setting breakpoint 2:
Cannot access memory at address 0x8000
Cannot access memory at address 0x8000
This limitation is unnecessary. Hardware watchpoint registers work
by trapping actual write operations; they don't (usually anyway)
require access to the actual contents. If we treat "inaccessible" as
a sentinel value not equal to any other value, we can set the
watchpoint at any time.
(gdb) r
Starting program: /space/fsf/watch
Hardware watchpoint 1: ptr[32768]
Hardware watchpoint 1: ptr[32768]
Hardware watchpoint 1: ptr[32768]
Old value = <unknown>
New value = 0 '\0'
main () at watch.c:10
10 ptr[32768] = 1;
(gdb) c
Continuing.
Hardware watchpoint 1: ptr[32768]
Old value = 0 '\0'
New value = 1 '\001'
main () at watch.c:11
11 }
(gdb)
Continuing.
Program exited with code 020.
The first <unknown> -> 0 transition is the initialization of "ptr".
Suddenly we're not dereferencing NULL any more, we're looking at some
newly allocated storage. A hardware watchpoint on the pointer detects
this automatically. The 0 -> 1 transition then is obvious.
This is much nicer :-) Any opinions on this change? Also, does it
deserve a NEWS entry and should it go in 6.7?
--
Daniel Jacobowitz
CodeSourcery
2007-08-21 Daniel Jacobowitz <dan@codesourcery.com>
* Makefile.in (breakpoint.o): Update.
* breakpoint.c (insert_bp_location): Handle exceptions while
evaluating and fetching the watchpoint expression. Always watch
the outermost value even if it is lazy.
(insert_breakpoints, remove_breakpoint, bpstat_stop_status)
(watch_command_1, can_use_hardware_watchpoint, breakpoint_re_set_one)
(do_enable_breakpoint): Likewise.
(watchpoint_check): Likewise. Report changes when a value becomes
readable or unreadable.
(watchpoint_value_print): New.
(print_it_typical): Use it. Do not free or clear old_val. Print
watchpoints even if old_val == NULL.
2007-08-21 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.base/watchpoint.c (global_ptr, func4): New.
(main): Call func4.
* gdb.base/watchpoint.exp: Call test_inaccessible_watchpoint.
(test_inaccessible_watchpoint): New.
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.928
diff -u -p -r1.928 Makefile.in
--- Makefile.in 10 Aug 2007 17:52:09 -0000 1.928
+++ Makefile.in 21 Aug 2007 12:45:03 -0000
@@ -1853,7 +1853,7 @@ breakpoint.o: breakpoint.c $(defs_h) $(s
$(objfiles_h) $(source_h) $(linespec_h) $(completer_h) $(gdb_h) \
$(ui_out_h) $(cli_script_h) $(gdb_assert_h) $(block_h) $(solib_h) \
$(solist_h) $(observer_h) $(exceptions_h) $(gdb_events_h) \
- $(mi_common_h) $(memattr_h) $(ada_lang_h) $(top_h)
+ $(mi_common_h) $(memattr_h) $(ada_lang_h) $(top_h) $(wrapper_h)
bsd-kvm.o: bsd-kvm.c $(defs_h) $(cli_cmds_h) $(command_h) $(frame_h) \
$(regcache_h) $(target_h) $(value_h) $(gdbcore_h) $(gdb_assert_h) \
$(readline_h) $(bsd_kvm_h)
Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.261
diff -u -p -r1.261 breakpoint.c
--- breakpoint.c 17 Aug 2007 17:06:02 -0000 1.261
+++ breakpoint.c 21 Aug 2007 13:18:28 -0000
@@ -56,6 +56,7 @@
#include "memattr.h"
#include "ada-lang.h"
#include "top.h"
+#include "wrapper.h"
#include "gdb-events.h"
#include "mi/mi-common.h"
@@ -1025,8 +1026,6 @@ Note: automatically using hardware break
convert this. */
int within_current_scope;
- struct value *mark = value_mark ();
- struct value *v;
struct frame_id saved_frame_id;
/* Save the current frame's ID so we can restore it after
@@ -1050,6 +1049,9 @@ Note: automatically using hardware break
if (within_current_scope)
{
+ struct value *mark = value_mark ();
+ struct value *v = NULL;
+
free_valchain (bpt);
/* Evaluate the expression and cut the chain of values
@@ -1058,9 +1060,12 @@ Note: automatically using hardware break
Make sure the value returned isn't lazy; we use
laziness to determine what memory GDB actually needed
in order to compute the value of the expression. */
- v = evaluate_expression (bpt->owner->exp);
- value_contents (v);
- value_release_to_mark (mark);
+ gdb_evaluate_expression (bpt->owner->exp, &v);
+ if (v != NULL)
+ {
+ gdb_value_fetch_lazy (v);
+ value_release_to_mark (mark);
+ }
bpt->owner->val_chain = v;
bpt->inserted = 1;
@@ -1072,7 +1077,7 @@ Note: automatically using hardware break
its contents to evaluate the expression, then we
must watch it. */
if (VALUE_LVAL (v) == lval_memory
- && ! value_lazy (v))
+ && (v == bpt->owner->val_chain || ! value_lazy (v)))
{
struct type *vtype = check_typedef (value_type (v));
@@ -1255,11 +1260,13 @@ insert_breakpoints (void)
if ((b->loc_type == bp_loc_hardware_watchpoint
|| b->owner->type == bp_watchpoint) && !b->owner->val)
{
- struct value *val;
- val = evaluate_expression (b->owner->exp);
- release_value (val);
- if (value_lazy (val))
- value_fetch_lazy (val);
+ struct value *val = NULL;
+ gdb_evaluate_expression (b->owner->exp, &val);
+ if (val != NULL)
+ {
+ gdb_value_fetch_lazy (val);
+ release_value (val);
+ }
b->owner->val = val;
}
@@ -1577,7 +1584,7 @@ remove_breakpoint (struct bp_location *b
/* For each memory reference remove the watchpoint
at that address. */
if (VALUE_LVAL (v) == lval_memory
- && ! value_lazy (v))
+ && (v == b->owner->val_chain || ! value_lazy (v)))
{
struct type *vtype = check_typedef (value_type (v));
@@ -2129,6 +2136,17 @@ top:
do_cleanups (old_chain);
}
+/* Print out the (old or new) value associated with a watchpoint. */
+
+static void
+watchpoint_value_print (struct value *val, struct ui_file *stream)
+{
+ if (val == NULL || value_lazy (val))
+ fprintf_unfiltered (stream, _("<unknown>"));
+ else
+ value_print (val, stream, 0, Val_pretty_default);
+}
+
/* This is the normal print function for a bpstat. In the future,
much of this logic could (should?) be moved to bpstat_stop_status,
by having it set different print_it values.
@@ -2305,26 +2323,21 @@ print_it_typical (bpstat bs)
case bp_watchpoint:
case bp_hardware_watchpoint:
- if (bs->old_val != NULL)
- {
- annotate_watchpoint (bs->breakpoint_at->number);
- if (ui_out_is_mi_like_p (uiout))
- ui_out_field_string
- (uiout, "reason",
- async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
- mention (bs->breakpoint_at);
- ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
- ui_out_text (uiout, "\nOld value = ");
- value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
- ui_out_field_stream (uiout, "old", stb);
- ui_out_text (uiout, "\nNew value = ");
- value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
- ui_out_field_stream (uiout, "new", stb);
- do_cleanups (ui_out_chain);
- ui_out_text (uiout, "\n");
- value_free (bs->old_val);
- bs->old_val = NULL;
- }
+ annotate_watchpoint (bs->breakpoint_at->number);
+ if (ui_out_is_mi_like_p (uiout))
+ ui_out_field_string
+ (uiout, "reason",
+ async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+ mention (bs->breakpoint_at);
+ ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+ ui_out_text (uiout, "\nOld value = ");
+ watchpoint_value_print (bs->old_val, stb->stream);
+ ui_out_field_stream (uiout, "old", stb);
+ ui_out_text (uiout, "\nNew value = ");
+ watchpoint_value_print (bs->breakpoint_at->val, stb->stream);
+ ui_out_field_stream (uiout, "new", stb);
+ do_cleanups (ui_out_chain);
+ ui_out_text (uiout, "\n");
/* More than one watchpoint may have been triggered. */
return PRINT_UNKNOWN;
break;
@@ -2337,7 +2350,7 @@ print_it_typical (bpstat bs)
mention (bs->breakpoint_at);
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
- value_print (bs->breakpoint_at->val, stb->stream, 0, Val_pretty_default);
+ watchpoint_value_print (bs->breakpoint_at->val, stb->stream);
ui_out_field_stream (uiout, "value", stb);
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
@@ -2345,7 +2358,7 @@ print_it_typical (bpstat bs)
break;
case bp_access_watchpoint:
- if (bs->old_val != NULL)
+ if (bs->old_val != NULL)
{
annotate_watchpoint (bs->breakpoint_at->number);
if (ui_out_is_mi_like_p (uiout))
@@ -2357,8 +2370,6 @@ print_it_typical (bpstat bs)
ui_out_text (uiout, "\nOld value = ");
value_print (bs->old_val, stb->stream, 0, Val_pretty_default);
ui_out_field_stream (uiout, "old", stb);
- value_free (bs->old_val);
- bs->old_val = NULL;
ui_out_text (uiout, "\nNew value = ");
}
else
@@ -2371,7 +2382,7 @@ print_it_typical (bpstat bs)
ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value");
ui_out_text (uiout, "\nValue = ");
}
- value_print (bs->breakpoint_at->val, stb->stream, 0,Val_pretty_default);
+ watchpoint_value_print (bs->breakpoint_at->val, stb->stream);
ui_out_field_stream (uiout, "new", stb);
do_cleanups (ui_out_chain);
ui_out_text (uiout, "\n");
@@ -2590,11 +2601,23 @@ watchpoint_check (void *p)
we might be in the middle of evaluating a function call. */
struct value *mark = value_mark ();
- struct value *new_val = evaluate_expression (bs->breakpoint_at->exp);
- if (!value_equal (b->val, new_val))
+ struct value *new_val = NULL;
+ int old_valid, new_valid;
+
+ gdb_evaluate_expression (bs->breakpoint_at->exp, &new_val);
+ if (new_val != NULL)
+ gdb_value_fetch_lazy (new_val);
+
+ old_valid = (b->val != NULL && ! value_lazy (b->val));
+ new_valid = (new_val != NULL && ! value_lazy (new_val));
+ if (old_valid != new_valid
+ || (old_valid && !value_equal (b->val, new_val)))
{
- release_value (new_val);
- value_free_to_mark (mark);
+ if (new_val != NULL)
+ {
+ release_value (new_val);
+ value_free_to_mark (mark);
+ }
bs->old_val = b->val;
b->val = new_val;
/* We will stop here */
@@ -2824,7 +2847,7 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
for (v = b->val_chain; v; v = value_next (v))
{
if (VALUE_LVAL (v) == lval_memory
- && ! value_lazy (v))
+ && (v == b->val_chain || ! value_lazy (v)))
{
struct type *vtype = check_typedef (value_type (v));
@@ -5723,10 +5746,13 @@ watch_command_1 (char *arg, int accessfl
exp_end = arg;
exp_valid_block = innermost_block;
mark = value_mark ();
- val = evaluate_expression (exp);
- release_value (val);
- if (value_lazy (val))
- value_fetch_lazy (val);
+ val = NULL;
+ gdb_evaluate_expression (exp, &val);
+ if (val != NULL)
+ {
+ gdb_value_fetch_lazy (val);
+ release_value (val);
+ }
tok = arg;
while (*tok == ' ' || *tok == '\t')
@@ -5894,7 +5920,7 @@ can_use_hardware_watchpoint (struct valu
{
if (VALUE_LVAL (v) == lval_memory)
{
- if (value_lazy (v))
+ if (v != head && value_lazy (v))
/* A lazy memory lvalue is one that GDB never needed to fetch;
we either just used its address (e.g., `a' in `a.b') or
we never needed it at all (e.g., `a' in `a,b'). */
@@ -7319,10 +7345,13 @@ breakpoint_re_set_one (void *bint)
evaluate_expression. */
b->val = NULL;
}
- b->val = evaluate_expression (b->exp);
- release_value (b->val);
- if (value_lazy (b->val) && breakpoint_enabled (b))
- value_fetch_lazy (b->val);
+ gdb_evaluate_expression (b->exp, &b->val);
+ if (b->val)
+ {
+ release_value (b->val);
+ if (value_lazy (b->val) && breakpoint_enabled (b))
+ gdb_value_fetch_lazy (b->val);
+ }
if (b->cond_string != NULL)
{
@@ -7675,10 +7704,13 @@ is valid is not currently in scope.\n"),
value_free (bpt->val);
mark = value_mark ();
- bpt->val = evaluate_expression (bpt->exp);
- release_value (bpt->val);
- if (value_lazy (bpt->val))
- value_fetch_lazy (bpt->val);
+ bpt->val = NULL;
+ gdb_evaluate_expression (bpt->exp, &bpt->val);
+ if (bpt->val)
+ {
+ release_value (bpt->val);
+ gdb_value_fetch_lazy (bpt->val);
+ }
if (bpt->type == bp_hardware_watchpoint ||
bpt->type == bp_read_watchpoint ||
Index: testsuite/gdb.base/watchpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/watchpoint.c,v
retrieving revision 1.2
diff -u -p -r1.2 watchpoint.c
--- testsuite/gdb.base/watchpoint.c 17 Mar 2003 19:51:58 -0000 1.2
+++ testsuite/gdb.base/watchpoint.c 21 Aug 2007 14:23:20 -0000
@@ -39,6 +39,8 @@ struct foo struct1, struct2, *ptr1, *ptr
int doread = 0;
+char *global_ptr;
+
void marker1 ()
{
}
@@ -110,6 +112,14 @@ func1 ()
return 73;
}
+void
+func4 ()
+{
+ buf[0] = 3;
+ global_ptr = buf;
+ buf[0] = 7;
+}
+
int main ()
{
#ifdef usestubs
@@ -185,5 +195,7 @@ int main ()
func3 ();
+ func4 ();
+
return 0;
}
Index: testsuite/gdb.base/watchpoint.exp
===================================================================
RCS file: /cvs/src/src/gdb/testsuite/gdb.base/watchpoint.exp,v
retrieving revision 1.14
diff -u -p -r1.14 watchpoint.exp
--- testsuite/gdb.base/watchpoint.exp 2 Mar 2007 22:11:15 -0000 1.14
+++ testsuite/gdb.base/watchpoint.exp 21 Aug 2007 14:23:20 -0000
@@ -646,6 +646,30 @@ proc test_watchpoint_and_breakpoint {} {
}
}
+proc test_inaccessible_watchpoint {} {
+ global gdb_prompt
+
+ # This is a test for watchpoints on currently inaccessible (but later
+ # valid) memory.
+
+ if [runto func4] then {
+ gdb_test "watch *global_ptr" ".*atchpoint \[0-9\]+: \\*global_ptr"
+ gdb_test "next" ".*global_ptr = buf.*"
+ gdb_test_multiple "next" "next over ptr init" {
+ -re ".*atchpoint \[0-9\]+: \\*global_ptr\r\n\r\nOld value = .*\r\nNew value = 3 .*\r\n.*$gdb_prompt $" {
+ # We can not test for <unknown> here because NULL may be readable.
+ # This test does rely on *NULL != 3.
+ pass "next over ptr init"
+ }
+ }
+ gdb_test_multiple "next" "next over buffer set" {
+ -re ".*atchpoint \[0-9\]+: \\*global_ptr\r\n\r\nOld value = 3 .*\r\nNew value = 7 .*\r\n.*$gdb_prompt $" {
+ pass "next over buffer set"
+ }
+ }
+ }
+}
+
# Start with a fresh gdb.
gdb_exit
@@ -798,6 +822,8 @@ if [initialize] then {
}
}
+ test_inaccessible_watchpoint
+
# See above.
if [istarget "mips-idt-*"] then {
gdb_exit
^ permalink raw reply [flat|nested] 15+ messages in thread* Re: [rfc] Allow watchpoints on inaccessible memory 2007-08-21 14:25 [rfc] Allow watchpoints on inaccessible memory Daniel Jacobowitz @ 2007-08-21 16:33 ` Jim Blandy 2007-08-21 18:06 ` Daniel Jacobowitz 2007-08-21 19:04 ` Eli Zaretskii ` (2 subsequent siblings) 3 siblings, 1 reply; 15+ messages in thread From: Jim Blandy @ 2007-08-21 16:33 UTC (permalink / raw) To: gdb-patches Daniel Jacobowitz <drow@false.org> writes: > This is much nicer :-) Any opinions on this change? Also, does it > deserve a NEWS entry and should it go in 6.7? This is definitely very cool. Certainly watchpoints shouldn't refuse to be set because their expression (currently) yields an error. One thing I don't understand: why are the "always watch the outermost value even if it is lazy" changes needed? The code that evaluates the watchpoint condition should always simply unlazy the expression's final value to begin with, so it'll never be lazy by the time the other code sees it. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2007-08-21 16:33 ` Jim Blandy @ 2007-08-21 18:06 ` Daniel Jacobowitz 2007-08-21 22:49 ` Jim Blandy 0 siblings, 1 reply; 15+ messages in thread From: Daniel Jacobowitz @ 2007-08-21 18:06 UTC (permalink / raw) To: Jim Blandy; +Cc: gdb-patches On Tue, Aug 21, 2007 at 09:33:28AM -0700, Jim Blandy wrote: > One thing I don't understand: why are the "always watch the outermost > value even if it is lazy" changes needed? The code that evaluates the > watchpoint condition should always simply unlazy the expression's > final value to begin with, so it'll never be lazy by the time the > other code sees it. But that might fail. That's why I switched from value_fetch_lazy to gdb_value_fetch_lazy, which catches exceptiosn. Consider "watch *0"; evaluating the expression works fine, but fetching the result of evaluate_expression will call memory_error. We still want to set the watchpoint. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2007-08-21 18:06 ` Daniel Jacobowitz @ 2007-08-21 22:49 ` Jim Blandy 2007-08-21 23:17 ` Daniel Jacobowitz 0 siblings, 1 reply; 15+ messages in thread From: Jim Blandy @ 2007-08-21 22:49 UTC (permalink / raw) To: gdb-patches Daniel Jacobowitz <drow@false.org> writes: > On Tue, Aug 21, 2007 at 09:33:28AM -0700, Jim Blandy wrote: >> One thing I don't understand: why are the "always watch the outermost >> value even if it is lazy" changes needed? The code that evaluates the >> watchpoint condition should always simply unlazy the expression's >> final value to begin with, so it'll never be lazy by the time the >> other code sees it. > > But that might fail. That's why I switched from value_fetch_lazy to > gdb_value_fetch_lazy, which catches exceptiosn. Consider "watch *0"; > evaluating the expression works fine, but fetching the result of > evaluate_expression will call memory_error. We still want to set > the watchpoint. Okay, I see. So there are actually two independent changes here: - Even when we can't unlazy the final value of an expression, we may be able to set a hardware watchpoint on it, because hardware watchpoints don't require the address being watched to actually be accessible. - When evaluating an expression to yield even a lazy a result fails, we can treat the fact of failure as a distinct value, and watch for that to change. This change could be generalized, although I'm not sure it's worth it. In evaluating an expression like p->q->r->s, if p->q is an invalid address, we could set a hardware watchpoint on p->q. In other words, watching the values produced by a failing expression up to the point of failure would allow us to use hardware watchpoints whenever possible. As it stands, your patch will record NULL as that watchpoint's value, and single-step to watch for changes. A lot of this rationale was not obvious to me by a long shot; I spent about an hour working it all out. I think the patch needs more comments. If you'd like me to write them, just say the word; I like writing docs. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2007-08-21 22:49 ` Jim Blandy @ 2007-08-21 23:17 ` Daniel Jacobowitz 0 siblings, 0 replies; 15+ messages in thread From: Daniel Jacobowitz @ 2007-08-21 23:17 UTC (permalink / raw) To: gdb-patches On Tue, Aug 21, 2007 at 03:49:06PM -0700, Jim Blandy wrote: > This change could be generalized, although I'm not sure it's worth it. > In evaluating an expression like p->q->r->s, if p->q is an invalid > address, we could set a hardware watchpoint on p->q. In other words, > watching the values produced by a failing expression up to the point > of failure would allow us to use hardware watchpoints whenever > possible. As it stands, your patch will record NULL as that > watchpoint's value, and single-step to watch for changes. No, that's not true. It will find the memory references that were un-lazied and wait for their values to change. In your example that will be p and p->q but the value will be NULL because evaluation didn't finish. > A lot of this rationale was not obvious to me by a long shot; I spent > about an hour working it all out. I think the patch needs more > comments. If you'd like me to write them, just say the word; I like > writing docs. I don't understand what subtleties you've found, to be honest. The approach is a simple extension of what was already there; I think you're inventing some of the complexity :-) You're welcome to add comments if you prefer though. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2007-08-21 14:25 [rfc] Allow watchpoints on inaccessible memory Daniel Jacobowitz 2007-08-21 16:33 ` Jim Blandy @ 2007-08-21 19:04 ` Eli Zaretskii 2007-11-20 7:56 ` Vladimir Prus 2008-02-28 16:27 ` Daniel Jacobowitz 3 siblings, 0 replies; 15+ messages in thread From: Eli Zaretskii @ 2007-08-21 19:04 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches > Date: Tue, 21 Aug 2007 10:25:00 -0400 > From: Daniel Jacobowitz <drow@false.org> > > This is much nicer :-) Any opinions on this change? I like it. > Also, does it deserve a NEWS entry Yes, I'd think so. > and should it go in 6.7? Don't see why not. Thanks. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2007-08-21 14:25 [rfc] Allow watchpoints on inaccessible memory Daniel Jacobowitz 2007-08-21 16:33 ` Jim Blandy 2007-08-21 19:04 ` Eli Zaretskii @ 2007-11-20 7:56 ` Vladimir Prus 2008-02-28 16:27 ` Daniel Jacobowitz 3 siblings, 0 replies; 15+ messages in thread From: Vladimir Prus @ 2007-11-20 7:56 UTC (permalink / raw) To: gdb-patches Daniel Jacobowitz <drow <at> false.org> writes: > > Here's something I've been meaning to try for ages. Suppose you have > a global variable pointing to some dynamically allocated storage, and > you want to find writes into that storage. When the pointer isn't > initialized you can't even set the watchpoint: ...... > - v = evaluate_expression (bpt->owner->exp); > - value_contents (v); > - value_release_to_mark (mark); > + gdb_evaluate_expression (bpt->owner->exp, &v); > + if (v != NULL) > + { > + gdb_value_fetch_lazy (v); > + value_release_to_mark (mark); > + } In fact, this patch is likely to fix a nasty issue with watchpoints in shared libraries. Say you have a watchpoint set on global variable 'g' in a shared library, and the shared library is unloaded. Next time you try to "next", or "continue", insert_bp_location will try to evaluate watchpoint expression again, and throw -- which will terminate next or continue operation, leaving program at the same place -- which is extremely confusing. - Volodya ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2007-08-21 14:25 [rfc] Allow watchpoints on inaccessible memory Daniel Jacobowitz ` (2 preceding siblings ...) 2007-11-20 7:56 ` Vladimir Prus @ 2008-02-28 16:27 ` Daniel Jacobowitz 2008-02-29 10:11 ` Eli Zaretskii 2008-02-29 17:54 ` Jim Blandy 3 siblings, 2 replies; 15+ messages in thread From: Daniel Jacobowitz @ 2008-02-28 16:27 UTC (permalink / raw) To: gdb-patches; +Cc: Eli Zaretskii, Jim Blandy On Tue, Aug 21, 2007 at 10:25:00AM -0400, Daniel Jacobowitz wrote: > Here's something I've been meaning to try for ages. Suppose you have > a global variable pointing to some dynamically allocated storage, and > you want to find writes into that storage. When the pointer isn't > initialized you can't even set the watchpoint: I have updated this patch, simplified, centralized, commented more thoroughly, and added a NEWS entry. Jim, is this version clearer? Eli, is the NEWS entry OK? -- Daniel Jacobowitz CodeSourcery 2008-02-28 Daniel Jacobowitz <dan@codesourcery.com> * breakpoint.c (fetch_watchpoint_value): New function. (update_watchpoint): Set and clear val_valid. Use fetch_watchpoint_value. Handle unreadable values on the value chain. Correct check for user-requested array watchpoints. (breakpoint_init_inferior): Clear val_valid. (watchpoint_value_print): New function. (print_it_typical): Use it. Do not free or clear old_val. Print watchpoints even if old_val == NULL. (watchpoint_check): Use fetch_watchpoint_value. Check for values becoming readable or unreadable. (watch_command_1): Use fetch_watchpoint_value. Set val_valid. (do_enable_watchpoint): Likewise. * breakpoint.h (struct breakpoint): Update comment for val. Add val_valid. * NEWS: Mention watchpoints on inaccessible memory. 2008-02-28 Daniel Jacobowitz <dan@codesourcery.com> * gdb.base/watchpoint.c (global_ptr, func4): New. (main): Call func4. * gdb.base/watchpoint.exp: Call test_inaccessible_watchpoint. (test_inaccessible_watchpoint): New. Index: breakpoint.c =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.c,v retrieving revision 1.304 diff -u -p -r1.304 breakpoint.c --- breakpoint.c 27 Feb 2008 20:27:49 -0000 1.304 +++ breakpoint.c 28 Feb 2008 15:56:06 -0000 @@ -55,6 +55,7 @@ #include "memattr.h" #include "ada-lang.h" #include "top.h" +#include "wrapper.h" #include "gdb-events.h" #include "mi/mi-common.h" @@ -826,7 +827,65 @@ is_hardware_watchpoint (struct breakpoin || bpt->type == bp_access_watchpoint); } -/* Assuming that B is a hardware breakpoint: +/* Find the current value of a watchpoint on EXP. Return the value in + *VALP and *RESULTP and the chain of intermediate and final values + in *VAL_CHAIN. RESULTP and VAL_CHAIN may be NULL if the caller does + not need them. + + If an error occurs while evaluating the expression, *RESULTP will + be set to NULL. *RESULTP may be a lazy value, if the result could + not be read from memory. It is used to determine whether a value + is user-specified (we should watch the whole value) or intermediate + (we should watch only the bit used to locate the final value). + + If the final value, or any intermediate value, could not be read + from memory, *VALP will be set to NULL. *VAL_CHAIN will still be + set to any referenced values. *VALP will never be a lazy value. + This is the value which we store in struct breakpoint. + + If VAL_CHAIN is non-NULL, *VAL_CHAIN will be released from the + value chain. The caller must free the values individually. If + VAL_CHAIN is NULL, all generated values will be left on the value + chain. */ + +static void +fetch_watchpoint_value (struct expression *exp, struct value **valp, + struct value **resultp, struct value **val_chain) +{ + struct value *mark, *new_mark, *result; + + *valp = NULL; + if (resultp) + *resultp = NULL; + if (val_chain) + *val_chain = NULL; + + /* Evaluate the expression. */ + mark = value_mark (); + result = NULL; + gdb_evaluate_expression (exp, &result); + new_mark = value_mark (); + if (mark == new_mark) + return; + if (resultp) + *resultp = result; + + /* Make sure it's not lazy, so that after the target stops again we + have a non-lazy previous value to compare with. */ + if (result != NULL + && (!value_lazy (result) || gdb_value_fetch_lazy (result))) + *valp = result; + + if (val_chain) + { + /* Return the chain of intermediate values. We use this to + decide which addresses to watch. */ + *val_chain = new_mark; + value_release_to_mark (mark); + } +} + +/* Assuming that B is a hardware watchpoint: - Reparse watchpoint expression, is REPARSE is non-zero - Evaluate expression and store the result in B->val - Update the list of values that must be watched in B->loc. @@ -837,7 +896,6 @@ static void update_watchpoint (struct breakpoint *b, int reparse) { int within_current_scope; - struct value *mark = value_mark (); struct frame_id saved_frame_id; struct bp_location *loc; bpstat bs; @@ -889,9 +947,9 @@ update_watchpoint (struct breakpoint *b, to the user when the old value and the new value may actually be completely different objects. */ value_free (b->val); - b->val = NULL; + b->val = NULL; + b->val_valid = 0; } - /* If we failed to parse the expression, for example because it refers to a global variable in a not-yet-loaded shared library, @@ -900,43 +958,37 @@ update_watchpoint (struct breakpoint *b, is different from out-of-scope watchpoint. */ if (within_current_scope && b->exp) { - struct value *v, *next; + struct value *val_chain, *v, *result, *next; + + fetch_watchpoint_value (b->exp, &v, &result, &val_chain); - /* Evaluate the expression and make sure it's not lazy, so that - after target stops again, we have a non-lazy previous value - to compare with. Also, making the value non-lazy will fetch - intermediate values as needed, which we use to decide which - addresses to watch. - - The value returned by evaluate_expression is stored in b->val. - In addition, we look at all values which were created - during evaluation, and set watchoints at addresses as needed. - Those values are explicitly deleted here. */ - v = evaluate_expression (b->exp); /* Avoid setting b->val if it's already set. The meaning of b->val is 'the last value' user saw, and we should update it only if we reported that last value to user. As it happens, the code that reports it updates b->val directly. */ - if (b->val == NULL) - b->val = v; - value_contents (v); - value_release_to_mark (mark); + if (!b->val_valid) + { + b->val = v; + b->val_valid = 1; + } /* Look at each value on the value chain. */ - for (; v; v = next) + for (v = val_chain; v; v = next) { /* If it's a memory location, and GDB actually needed its contents to evaluate the expression, then we - must watch it. */ + must watch it. If the first value returned is + still lazy, that means an error occurred reading it; + watch it anyway in case it becomes readable. */ if (VALUE_LVAL (v) == lval_memory - && ! value_lazy (v)) + && (v == val_chain || ! value_lazy (v))) { struct type *vtype = check_typedef (value_type (v)); /* We only watch structs and arrays if user asked for it explicitly, never if they just happen to appear in the middle of some value chain. */ - if (v == b->val + if (v == result || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) { @@ -1681,6 +1733,7 @@ breakpoint_init_inferior (enum inf_conte if (b->val) value_free (b->val); b->val = NULL; + b->val_valid = 0; } break; default: @@ -2103,6 +2156,17 @@ top: do_cleanups (old_chain); } +/* Print out the (old or new) value associated with a watchpoint. */ + +static void +watchpoint_value_print (struct value *val, struct ui_file *stream) +{ + if (val == NULL) + fprintf_unfiltered (stream, _("<unreadable>")); + else + value_print (val, stream, 0, Val_pretty_default); +} + /* This is the normal print function for a bpstat. In the future, much of this logic could (should?) be moved to bpstat_stop_status, by having it set different print_it values. @@ -2221,26 +2285,21 @@ print_it_typical (bpstat bs) case bp_watchpoint: case bp_hardware_watchpoint: - if (bs->old_val != NULL) - { - annotate_watchpoint (b->number); - if (ui_out_is_mi_like_p (uiout)) - ui_out_field_string - (uiout, "reason", - async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER)); - mention (b); - ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value"); - ui_out_text (uiout, "\nOld value = "); - value_print (bs->old_val, stb->stream, 0, Val_pretty_default); - ui_out_field_stream (uiout, "old", stb); - ui_out_text (uiout, "\nNew value = "); - value_print (b->val, stb->stream, 0, Val_pretty_default); - ui_out_field_stream (uiout, "new", stb); - do_cleanups (ui_out_chain); - ui_out_text (uiout, "\n"); - value_free (bs->old_val); - bs->old_val = NULL; - } + annotate_watchpoint (b->number); + if (ui_out_is_mi_like_p (uiout)) + ui_out_field_string + (uiout, "reason", + async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER)); + mention (b); + ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value"); + ui_out_text (uiout, "\nOld value = "); + watchpoint_value_print (bs->old_val, stb->stream); + ui_out_field_stream (uiout, "old", stb); + ui_out_text (uiout, "\nNew value = "); + watchpoint_value_print (b->val, stb->stream); + ui_out_field_stream (uiout, "new", stb); + do_cleanups (ui_out_chain); + ui_out_text (uiout, "\n"); /* More than one watchpoint may have been triggered. */ return PRINT_UNKNOWN; break; @@ -2253,7 +2312,7 @@ print_it_typical (bpstat bs) mention (b); ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value"); ui_out_text (uiout, "\nValue = "); - value_print (b->val, stb->stream, 0, Val_pretty_default); + watchpoint_value_print (b->val, stb->stream); ui_out_field_stream (uiout, "value", stb); do_cleanups (ui_out_chain); ui_out_text (uiout, "\n"); @@ -2261,7 +2320,7 @@ print_it_typical (bpstat bs) break; case bp_access_watchpoint: - if (bs->old_val != NULL) + if (bs->old_val != NULL) { annotate_watchpoint (b->number); if (ui_out_is_mi_like_p (uiout)) @@ -2271,10 +2330,8 @@ print_it_typical (bpstat bs) mention (b); ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value"); ui_out_text (uiout, "\nOld value = "); - value_print (bs->old_val, stb->stream, 0, Val_pretty_default); + watchpoint_value_print (bs->old_val, stb->stream); ui_out_field_stream (uiout, "old", stb); - value_free (bs->old_val); - bs->old_val = NULL; ui_out_text (uiout, "\nNew value = "); } else @@ -2287,7 +2344,7 @@ print_it_typical (bpstat bs) ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "value"); ui_out_text (uiout, "\nValue = "); } - value_print (b->val, stb->stream, 0,Val_pretty_default); + watchpoint_value_print (b->val, stb->stream); ui_out_field_stream (uiout, "new", stb); do_cleanups (ui_out_chain); ui_out_text (uiout, "\n"); @@ -2574,13 +2631,20 @@ watchpoint_check (void *p) we might be in the middle of evaluating a function call. */ struct value *mark = value_mark (); - struct value *new_val = evaluate_expression (b->exp); - if (!value_equal (b->val, new_val)) + struct value *new_val; + + fetch_watchpoint_value (b->exp, &new_val, NULL, NULL); + if ((b->val != NULL) != (new_val != NULL) + || (b->val != NULL && !value_equal (b->val, new_val))) { - release_value (new_val); - value_free_to_mark (mark); + if (new_val != NULL) + { + release_value (new_val); + value_free_to_mark (mark); + } bs->old_val = b->val; b->val = new_val; + b->val_valid = 1; /* We will stop here */ return WP_VALUE_CHANGED; } @@ -5746,10 +5810,9 @@ watch_command_1 (char *arg, int accessfl exp_end = arg; exp_valid_block = innermost_block; mark = value_mark (); - val = evaluate_expression (exp); - release_value (val); - if (value_lazy (val)) - value_fetch_lazy (val); + fetch_watchpoint_value (exp, &val, NULL, NULL); + if (val != NULL) + release_value (val); tok = arg; while (*tok == ' ' || *tok == '\t') @@ -5838,6 +5901,7 @@ watch_command_1 (char *arg, int accessfl b->exp_valid_block = exp_valid_block; b->exp_string = savestring (exp_start, exp_end - exp_start); b->val = val; + b->val_valid = 1; b->loc->cond = cond; if (cond_start) b->cond_string = savestring (cond_start, cond_end - cond_start); @@ -7721,11 +7785,11 @@ is valid is not currently in scope.\n"), if (bpt->val) value_free (bpt->val); mark = value_mark (); - bpt->val = evaluate_expression (bpt->exp); - release_value (bpt->val); - if (value_lazy (bpt->val)) - value_fetch_lazy (bpt->val); - + fetch_watchpoint_value (bpt->exp, &bpt->val, NULL, NULL); + if (bpt->val) + release_value (bpt->val); + bpt->val_valid = 1; + if (bpt->type == bp_hardware_watchpoint || bpt->type == bp_read_watchpoint || bpt->type == bp_access_watchpoint) Index: breakpoint.h =================================================================== RCS file: /cvs/src/src/gdb/breakpoint.h,v retrieving revision 1.65 diff -u -p -r1.65 breakpoint.h --- breakpoint.h 1 Feb 2008 16:24:46 -0000 1.65 +++ breakpoint.h 28 Feb 2008 15:56:07 -0000 @@ -391,8 +391,13 @@ struct breakpoint /* The largest block within which it is valid, or NULL if it is valid anywhere (e.g. consists just of global symbols). */ struct block *exp_valid_block; - /* Value of the watchpoint the last time we checked it. */ + /* Value of the watchpoint the last time we checked it, or NULL + when we do not know the value yet or the value was not + readable. VAL is never lazy. */ struct value *val; + /* Nonzero if VAL is valid. If VAL_VALID is set but VAL is NULL, + then an error occurred reading the value. */ + int val_valid; /* Holds the address of the related watchpoint_scope breakpoint when using watchpoints on local variables (might the concept Index: testsuite/gdb.base/watchpoint.c =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/watchpoint.c,v retrieving revision 1.2 diff -u -p -r1.2 watchpoint.c --- testsuite/gdb.base/watchpoint.c 17 Mar 2003 19:51:58 -0000 1.2 +++ testsuite/gdb.base/watchpoint.c 28 Feb 2008 15:56:35 -0000 @@ -39,6 +39,8 @@ struct foo struct1, struct2, *ptr1, *ptr int doread = 0; +char *global_ptr; + void marker1 () { } @@ -110,6 +112,14 @@ func1 () return 73; } +void +func4 () +{ + buf[0] = 3; + global_ptr = buf; + buf[0] = 7; +} + int main () { #ifdef usestubs @@ -185,5 +195,7 @@ int main () func3 (); + func4 (); + return 0; } Index: testsuite/gdb.base/watchpoint.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/watchpoint.exp,v retrieving revision 1.16 diff -u -p -r1.16 watchpoint.exp --- testsuite/gdb.base/watchpoint.exp 1 Jan 2008 22:53:19 -0000 1.16 +++ testsuite/gdb.base/watchpoint.exp 28 Feb 2008 15:56:35 -0000 @@ -645,6 +645,30 @@ proc test_watchpoint_and_breakpoint {} { } } +proc test_inaccessible_watchpoint {} { + global gdb_prompt + + # This is a test for watchpoints on currently inaccessible (but later + # valid) memory. + + if [runto func4] then { + gdb_test "watch *global_ptr" ".*atchpoint \[0-9\]+: \\*global_ptr" + gdb_test "next" ".*global_ptr = buf.*" + gdb_test_multiple "next" "next over ptr init" { + -re ".*atchpoint \[0-9\]+: \\*global_ptr\r\n\r\nOld value = .*\r\nNew value = 3 .*\r\n.*$gdb_prompt $" { + # We can not test for <unknown> here because NULL may be readable. + # This test does rely on *NULL != 3. + pass "next over ptr init" + } + } + gdb_test_multiple "next" "next over buffer set" { + -re ".*atchpoint \[0-9\]+: \\*global_ptr\r\n\r\nOld value = 3 .*\r\nNew value = 7 .*\r\n.*$gdb_prompt $" { + pass "next over buffer set" + } + } + } +} + # Start with a fresh gdb. gdb_exit @@ -797,6 +821,8 @@ if [initialize] then { } } + test_inaccessible_watchpoint + # See above. if [istarget "mips-idt-*"] then { gdb_exit Index: NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.260 diff -u -p -r1.260 NEWS --- NEWS 27 Feb 2008 20:50:49 -0000 1.260 +++ NEWS 28 Feb 2008 16:15:16 -0000 @@ -9,6 +9,9 @@ set debug timetstamp show debug timestamp Display timestamps with GDB debugging output. +* Watchpoints can now be set on unreadable memory locations, e.g. addresses +which will be allocated using malloc later in program execution. + *** Changes in GDB 6.8 * New native configurations ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2008-02-28 16:27 ` Daniel Jacobowitz @ 2008-02-29 10:11 ` Eli Zaretskii 2008-03-02 4:24 ` Daniel Jacobowitz 2008-02-29 17:54 ` Jim Blandy 1 sibling, 1 reply; 15+ messages in thread From: Eli Zaretskii @ 2008-02-29 10:11 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches, jimb > Date: Thu, 28 Feb 2008 11:17:49 -0500 > From: Daniel Jacobowitz <drow@false.org> > Cc: Eli Zaretskii <eliz@gnu.org>, Jim Blandy <jimb@red-bean.com> > > Eli, is the NEWS entry OK? Yes, but I think we should mention this feature in the manual as well. Btw, are there any command, either CLI or MI, that print the current value of the watched expression? If there are, we need to fix them somehow in the case struct value is NULL. Also, maybe we should display <PENDING> in "info break" in this case, like we do with breakpoints. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2008-02-29 10:11 ` Eli Zaretskii @ 2008-03-02 4:24 ` Daniel Jacobowitz 2008-03-02 21:09 ` Eli Zaretskii 0 siblings, 1 reply; 15+ messages in thread From: Daniel Jacobowitz @ 2008-03-02 4:24 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches, jimb On Fri, Feb 29, 2008 at 12:10:00PM +0200, Eli Zaretskii wrote: > > Date: Thu, 28 Feb 2008 11:17:49 -0500 > > From: Daniel Jacobowitz <drow@false.org> > > Cc: Eli Zaretskii <eliz@gnu.org>, Jim Blandy <jimb@red-bean.com> > > > > Eli, is the NEWS entry OK? > > Yes, but I think we should mention this feature in the manual as well. What do you think of the attached? > Btw, are there any command, either CLI or MI, that print the current > value of the watched expression? If there are, we need to fix them > somehow in the case struct value is NULL. No, there are no commands that do this; I checked all the uses of struct breakpoint's val field. > Also, maybe we should display <PENDING> in "info break" in this case, > like we do with breakpoints. That goes in the address field, which we don't use for other watchpoints. And we don't print the current value in info break, so I think this is a full-fledged watchpoint; everything is displayed as if we could read the value. -- Daniel Jacobowitz CodeSourcery 2008-03-01 Daniel Jacobowitz <dan@codesourcery.com> * doc/gdb.texinfo (Set Watchpoints): Mention watchpoints on unreadable memory. Delete obsolete SPARClite reference. Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.471 diff -u -p -r1.471 gdb.texinfo --- doc/gdb.texinfo 28 Feb 2008 16:26:18 -0000 1.471 +++ doc/gdb.texinfo 2 Mar 2008 04:23:36 -0000 @@ -3211,6 +3211,16 @@ expression can use any operators valid i language (@pxref{Languages}). @end itemize +You can set a watchpoint on an expression even if the expression can +not be evaluated yet. For instance, you can set a watchpoint on +@samp{*global_ptr} before @samp{global_ptr} is initialized. +@value{GDBN} will stop when your program sets @samp{global_ptr} and +the expression produces a valid value. If the expression becomes +valid in some other way than changing a variable (e.g.@: if the memory +pointed to by @samp{*global_ptr} becomes readable as the result of a +@code{malloc} call), @value{GDBN} may not stop until the next time +the expression changes. + @cindex software watchpoints @cindex hardware watchpoints Depending on your system, watchpoints may be implemented in software or @@ -3338,17 +3348,6 @@ exhaust the resources available for hard That's because @value{GDBN} needs to watch every variable in the expression with separately allocated resources. -The SPARClite DSU will generate traps when a program accesses some data -or instruction address that is assigned to the debug registers. For the -data addresses, DSU facilitates the @code{watch} command. However the -hardware breakpoint registers can only take two data watchpoints, and -both watchpoints must be the same kind. For example, you can set two -watchpoints with @code{watch} commands, two with @code{rwatch} commands, -@strong{or} two with @code{awatch} commands, but you cannot set one -watchpoint with one command and the other with a different command. -@value{GDBN} will reject the command if you try to mix watchpoints. -Delete or disable unused watchpoint commands before setting new ones. - If you call a function interactively using @code{print} or @code{call}, any watchpoints you have set will be inactive until @value{GDBN} reaches another kind of breakpoint or the call completes. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2008-03-02 4:24 ` Daniel Jacobowitz @ 2008-03-02 21:09 ` Eli Zaretskii 2008-03-02 23:23 ` Daniel Jacobowitz 0 siblings, 1 reply; 15+ messages in thread From: Eli Zaretskii @ 2008-03-02 21:09 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches, jimb > Date: Sat, 1 Mar 2008 23:24:32 -0500 > From: Daniel Jacobowitz <drow@false.org> > Cc: gdb-patches@sourceware.org, jimb@red-bean.com > > On Fri, Feb 29, 2008 at 12:10:00PM +0200, Eli Zaretskii wrote: > > > Date: Thu, 28 Feb 2008 11:17:49 -0500 > > > From: Daniel Jacobowitz <drow@false.org> > > > Cc: Eli Zaretskii <eliz@gnu.org>, Jim Blandy <jimb@red-bean.com> > > > > > > Eli, is the NEWS entry OK? > > > > Yes, but I think we should mention this feature in the manual as well. > > What do you think of the attached? Fine with me, thanks. > everything is displayed as if we could read the value. And therein lies the problem, no? ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2008-03-02 21:09 ` Eli Zaretskii @ 2008-03-02 23:23 ` Daniel Jacobowitz 2008-03-03 4:27 ` Eli Zaretskii 0 siblings, 1 reply; 15+ messages in thread From: Daniel Jacobowitz @ 2008-03-02 23:23 UTC (permalink / raw) To: gdb-patches On Sun, Mar 02, 2008 at 11:09:10PM +0200, Eli Zaretskii wrote: > And therein lies the problem, no? Do you think it is a problem? I think they're pretty much normal watchpoints. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2008-03-02 23:23 ` Daniel Jacobowitz @ 2008-03-03 4:27 ` Eli Zaretskii 2008-03-03 14:07 ` Daniel Jacobowitz 0 siblings, 1 reply; 15+ messages in thread From: Eli Zaretskii @ 2008-03-03 4:27 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: gdb-patches > Date: Sun, 2 Mar 2008 18:23:02 -0500 > From: Daniel Jacobowitz <drow@false.org> > > On Sun, Mar 02, 2008 at 11:09:10PM +0200, Eli Zaretskii wrote: > > And therein lies the problem, no? > > Do you think it is a problem? I think they're pretty much normal watchpoints. I disagree, but maybe I'm the only one, and the issue is minor anyway. ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2008-03-03 4:27 ` Eli Zaretskii @ 2008-03-03 14:07 ` Daniel Jacobowitz 0 siblings, 0 replies; 15+ messages in thread From: Daniel Jacobowitz @ 2008-03-03 14:07 UTC (permalink / raw) To: gdb-patches On Mon, Mar 03, 2008 at 06:26:38AM +0200, Eli Zaretskii wrote: > > Date: Sun, 2 Mar 2008 18:23:02 -0500 > > From: Daniel Jacobowitz <drow@false.org> > > > > On Sun, Mar 02, 2008 at 11:09:10PM +0200, Eli Zaretskii wrote: > > > And therein lies the problem, no? > > > > Do you think it is a problem? I think they're pretty much normal watchpoints. > > I disagree, but maybe I'm the only one, and the issue is minor anyway. OK. For now, I've checked in the patch; if you'd like, you're welcome follow up with any changes. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: [rfc] Allow watchpoints on inaccessible memory 2008-02-28 16:27 ` Daniel Jacobowitz 2008-02-29 10:11 ` Eli Zaretskii @ 2008-02-29 17:54 ` Jim Blandy 1 sibling, 0 replies; 15+ messages in thread From: Jim Blandy @ 2008-02-29 17:54 UTC (permalink / raw) To: gdb-patches, Eli Zaretskii, Jim Blandy On Thu, Feb 28, 2008 at 8:17 AM, Daniel Jacobowitz <drow@false.org> wrote: > On Tue, Aug 21, 2007 at 10:25:00AM -0400, Daniel Jacobowitz wrote: > > Here's something I've been meaning to try for ages. Suppose you have > > a global variable pointing to some dynamically allocated storage, and > > you want to find writes into that storage. When the pointer isn't > > initialized you can't even set the watchpoint: > > I have updated this patch, simplified, centralized, commented more > thoroughly, and added a NEWS entry. Jim, is this version clearer? Yes, much more so. Thanks. ^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2008-03-03 14:07 UTC | newest] Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-08-21 14:25 [rfc] Allow watchpoints on inaccessible memory Daniel Jacobowitz 2007-08-21 16:33 ` Jim Blandy 2007-08-21 18:06 ` Daniel Jacobowitz 2007-08-21 22:49 ` Jim Blandy 2007-08-21 23:17 ` Daniel Jacobowitz 2007-08-21 19:04 ` Eli Zaretskii 2007-11-20 7:56 ` Vladimir Prus 2008-02-28 16:27 ` Daniel Jacobowitz 2008-02-29 10:11 ` Eli Zaretskii 2008-03-02 4:24 ` Daniel Jacobowitz 2008-03-02 21:09 ` Eli Zaretskii 2008-03-02 23:23 ` Daniel Jacobowitz 2008-03-03 4:27 ` Eli Zaretskii 2008-03-03 14:07 ` Daniel Jacobowitz 2008-02-29 17:54 ` Jim Blandy
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox