* [RFA] Don't reset watchpoint block on solib load.
@ 2007-11-20 17:14 Vladimir Prus
2007-11-27 23:00 ` Jim Blandy
0 siblings, 1 reply; 25+ messages in thread
From: Vladimir Prus @ 2007-11-20 17:14 UTC (permalink / raw)
To: gdb-patches
There's code inside breakpoint_re_set_one to refresh watchpoints,
which seems suspicious to me.
First problem with that code is that it always resets watchpoint's
block to NULL. So, if we have a local watchpoint, and you do
dlopen (without exiting the scope where watchpoint is valid),
then the watchpoint's block will be reset to NULL, and
watchpoint's expression will be reparsed in global block --
which will surely break the watchpoint.
Second problem is that this code reevalautes the expression,
and given that insert_breakpoints does that too, we can just
reset breakpoints value to NULL, and have insert_breakpoints to the work.
Finally, this code reevaluates condition. While this is probably
correct way to handle case where meaning of condition changes due to
loading of shared library, there's no code to match for the
case when a shared library is unloaded. I think a more robust
approach if to reevaluate condition inside insert_bp_location.
This patch is prompted by the following problem:
void some_function() {
g = 10;
....
dlopen("whatever", ...);
....
g = 15;
}
If you set watchpoint on 'g', and continue over dlopen, the watchpoint is never hit.
The exact mode of failure differs. I actually have a testcase for this, and it
passes for me locally, and I would have liked to provide it, but there are two
issues for which I don't have yet a complete solution:
- if we have no debug information for ld.so, then when we stop in
ld.so, we cannot find the frame associated with watchpoint, and delete
watchpoint.
- if we have debug information for ld.so, then when we stop in
ld.so, gdb tries to reevaluate 'g'. Unfortunately, it does that in
wrong block, does not find 'g', and dies with internal error.
I have a hack for the second problem, that allows the test to work, but causes
regressions elsewhere. And I don't have yet an approach for the first problem,
so complete solution will take more time. For the time being, I think the
below patch makes sense independently as logic cleanup. OK?
- Volodya
* breakpoint.c (insert_bp_location): For watchpoints,
recompute condition.
(breakpoint_re_set_one): Instead of recomputing value
and condition for watchpoints, just reset value and
let insert_breakpoints/insert_bp_location recompute it.
---
gdb/breakpoint.c | 81 +++++++++++++++++++++++------------------------------
1 files changed, 35 insertions(+), 46 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 2f4bd8b..32f4dd1 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1111,6 +1111,18 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
}
}
}
+
+ if (bpt->owner->cond_string != NULL)
+ {
+ char *s = bpt->owner->cond_string;
+ if (bpt->cond)
+ {
+ xfree (bpt->cond);
+ bpt->cond = NULL;
+ }
+ bpt->cond = parse_exp_1 (&s, bpt->owner->exp_valid_block, 0);
+ }
+
/* Failure to insert a watchpoint on any memory value in the
value chain brings us here. */
if (!bpt->inserted)
@@ -7534,53 +7546,30 @@ breakpoint_re_set_one (void *bint)
case bp_hardware_watchpoint:
case bp_read_watchpoint:
case bp_access_watchpoint:
- innermost_block = NULL;
- /* The issue arises of what context to evaluate this in. The
- same one as when it was set, but what does that mean when
- symbols have been re-read? We could save the filename and
- functionname, but if the context is more local than that, the
- best we could do would be something like how many levels deep
- and which index at that particular level, but that's going to
- be less stable than filenames or function names. */
-
- /* So for now, just use a global context. */
+ /* Loading of new shared library can lead to symbols
+ used by watchpoint expression to become available.
+ Reparse expression. */
if (b->exp)
- {
- xfree (b->exp);
- /* Avoid re-freeing b->exp if an error during the call to
- parse_expression. */
- b->exp = NULL;
- }
- b->exp = parse_expression (b->exp_string);
- b->exp_valid_block = innermost_block;
- mark = value_mark ();
- if (b->val)
- {
- value_free (b->val);
- /* Avoid re-freeing b->val if an error during the call to
- 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);
-
- if (b->cond_string != NULL)
- {
- s = b->cond_string;
- if (b->loc->cond)
- {
- xfree (b->loc->cond);
- /* Avoid re-freeing b->exp if an error during the call
- to parse_exp_1. */
- b->loc->cond = NULL;
- }
- b->loc->cond = parse_exp_1 (&s, (struct block *) 0, 0);
- }
- if (breakpoint_enabled (b))
- mention (b);
- value_free_to_mark (mark);
+ {
+ xfree (b->exp);
+ b->exp = NULL;
+ }
+ s = b->exp_string;
+ b->exp = parse_exp_1 (&s, b->exp_valid_block, 0);
+
+ /* Since we reparsed expression, we need to update the
+ value. In fact, I'm not aware of any way how
+ reparsing an expression after loading of a shared library
+ can change a valid expression into another valid expression
+ but with different meaning, but better be safe. We set
+ value to NULL, and insert_breakpoints will update the value. */
+ if (b->val)
+ value_free (b->val);
+ b->val = NULL;
+
+ /* Loading of new shared library change the meaning of
+ watchpoint condition. However, insert_bp_location will
+ recompute watchpoint condition anyway, nothing to do here. */
break;
case bp_catch_catch:
case bp_catch_throw:
--
1.5.3.5
^ permalink raw reply [flat|nested] 25+ messages in thread* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-20 17:14 [RFA] Don't reset watchpoint block on solib load Vladimir Prus @ 2007-11-27 23:00 ` Jim Blandy 2007-11-28 15:59 ` Vladimir Prus 2007-11-29 6:55 ` Vladimir Prus 0 siblings, 2 replies; 25+ messages in thread From: Jim Blandy @ 2007-11-27 23:00 UTC (permalink / raw) To: Vladimir Prus; +Cc: gdb-patches Vladimir Prus <vladimir at codesourcery.com> writes: > There's code inside breakpoint_re_set_one to refresh watchpoints, > which seems suspicious to me. > > First problem with that code is that it always resets watchpoint's > block to NULL. So, if we have a local watchpoint, and you do > dlopen (without exiting the scope where watchpoint is valid), > then the watchpoint's block will be reset to NULL, and > watchpoint's expression will be reparsed in global block -- > which will surely break the watchpoint. Is that right? We set innermost_block to NULL, but then we call parse_expression, which should set innermost_block to the innermost block containing a symbol actually used by the expression. We also call breakpoint_re_set_one when we've unloaded a shared library. At that point, b->exp_valid_block could be a dangling pointer; we can't use it to re-parse the expression. I think the bug is that we re-parse the expression with parse_expression, which leaves the scope unspecified, defaulting to the currently selected frame. We should: 1) Verify that the frame given by b->watchpoint_frame is still valid, and delete the watchpoint if it isn't. 2) Call get_frame_block (b->watchpoint_frame) to see if we have a block for the frame's location, and deleting the watchpoint if we don't (saying we don't have the symbolic info available to update it), and 3) Call parse_exp_1 (..., watchpoint frame's block, ...) to reparse the watchpoint's expression in the proper block. > Second problem is that this code reevalautes the expression, > and given that insert_breakpoints does that too, we can just > reset breakpoints value to NULL, and have insert_breakpoints to the > work. I think it's an invariant that b->val may be NULL only when we have just started the inferior, and know that insert_breakpoints will be called. In other contexts, we don't always call insert_breakpoints before letting the program run. Wouldn't leaving the value NULL cause a problem in that case? > Finally, this code reevaluates condition. Re-parses, you mean? > While this is probably > correct way to handle case where meaning of condition changes due to > loading of shared library, there's no code to match for the > case when a shared library is unloaded. I think a more robust > approach if to reevaluate condition inside insert_bp_location. I agree. > This patch is prompted by the following problem: > > void some_function() { > > g = 10; > .... > dlopen("whatever", ...); > .... > g = 15; > } > > If you set watchpoint on 'g', and continue over dlopen, the watchpoint is never hit. > The exact mode of failure differs. I actually have a testcase for this, and it > passes for me locally, and I would have liked to provide it, but there are two > issues for which I don't have yet a complete solution: > > - if we have no debug information for ld.so, then when we stop in > ld.so, we cannot find the frame associated with watchpoint, and delete > watchpoint. Does this case arise in normal usage? I'm not saying it doesn't; I'm just not sure how to work around it either, so I'm wondering how serious a problem it is. > - if we have debug information for ld.so, then when we stop in > ld.so, gdb tries to reevaluate 'g'. Unfortunately, it does that in > wrong block, does not find 'g', and dies with internal error. My suggestion above should avoid this. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-27 23:00 ` Jim Blandy @ 2007-11-28 15:59 ` Vladimir Prus 2007-11-28 16:23 ` Vladimir Prus ` (3 more replies) 2007-11-29 6:55 ` Vladimir Prus 1 sibling, 4 replies; 25+ messages in thread From: Vladimir Prus @ 2007-11-28 15:59 UTC (permalink / raw) To: Jim Blandy; +Cc: gdb-patches On Wednesday 28 November 2007 02:00:15 Jim Blandy wrote: > > Vladimir Prus <vladimir at codesourcery.com> writes: > > There's code inside breakpoint_re_set_one to refresh watchpoints, > > which seems suspicious to me. > > > > First problem with that code is that it always resets watchpoint's > > block to NULL. So, if we have a local watchpoint, and you do > > dlopen (without exiting the scope where watchpoint is valid), > > then the watchpoint's block will be reset to NULL, and > > watchpoint's expression will be reparsed in global block -- > > which will surely break the watchpoint. > > Is that right? We set innermost_block to NULL, but then we call > parse_expression, which should set innermost_block to the innermost > block containing a symbol actually used by the expression. Except that parse_expression is called while we're inside shared lib machinery code -- so neither original block nor original frame is used, and parse_expression is likely to fail. > We also call breakpoint_re_set_one when we've unloaded a shared > library. At that point, b->exp_valid_block could be a dangling > pointer; we can't use it to re-parse the expression. > > I think the bug is that we re-parse the expression with > parse_expression, which leaves the scope unspecified, defaulting to > the currently selected frame. We should: > > 1) Verify that the frame given by b->watchpoint_frame is still valid, > and delete the watchpoint if it isn't. > > 2) Call get_frame_block (b->watchpoint_frame) to see if we have a > block for the frame's location, and deleting the watchpoint if we > don't (saying we don't have the symbolic info available to update > it), and > > 3) Call parse_exp_1 (..., watchpoint frame's block, ...) to reparse > the watchpoint's expression in the proper block. Let me try thinking out loud. 1. Suppose I have a watchpoint on a global variable. Such a watchpoint can reasonably survive program restart, and given that it can be set on a global variable (including static variables of C++ classes) defined in a shared library, it makes sense recompute such watchpoint when a shared library is loaded, or unloaded. I'm not 100% sure it works now, since we use evaluate_expression in few places, so if a watchpoint uses a variable defined in not-yet-loaded shared library, evaluate_expression will throw. I believe Dan's recent patch will fix this, however. 2. Suppose I have a watchpoint on a local variable. GDB does a fairly good job of removing the breakpoint when we leave the scope -- either using regular return, or longjmp or C++ exception -- and in any way the first watchpoint_check call will remove a watchpoint if we've left the scope. The only exception is disabled local watchpoint -- but it can't be re-enabled until we're inside watchpoint frame again. What this means is: 2.1 Assume we catch solib load/unload after exiting watchpoint scope. Then, we should not do anything -- if watchpoint should be deleted, it will be deleted by other code. And if it's disabled we can't reparse it, but should not delete it either (at least if we want to preserve the existing behaviour). 2.2 Assume we catch solib load/unload in a frame called from the frame where watchpoint is defined. Technically speaking, it's possible that either watchpoint expression, or watchpoint condition makes use of a global variable, and so can change. Not that watchpoint expression and condition are evaluated when watchpoint is created, and should be valid for watchpoint to exist. So, the only way for a watchpoint to change meaning if when a shared library is unloaded, and brings some symbols used by watchpoint with it. Then, the library can be re-loaded, and make the watchpoint valid again. It seems to me that while loading or unloading of a shared library from within frame where watchpoint is defined seems valid use-case, the case where a given library is both unloaded, and the reloaded, and it has a variable that watchpoint uses, is rather arcane. But we might as well still recompute watchpoint expression, since it's easy. The final conclusion is that we need to wrap the updating code in: if (b->exp_valid_block == NULL || find_frame_by_id (b->watchpoint_frame) != NULL) { } We don't need to delete watchpoint, here, if frame is no longer valid as other code will do that anyway. You've also suggested to use get_frame_block. Can you offer a case when the watchpoint frame is still valid, but the block is no longer valid? > > Second problem is that this code reevalautes the expression, > > and given that insert_breakpoints does that too, we can just > > reset breakpoints value to NULL, and have insert_breakpoints to the > > work. > > I think it's an invariant that b->val may be NULL only when we have > just started the inferior, and know that insert_breakpoints will be > called. In other contexts, we don't always call insert_breakpoints > before letting the program run. Wouldn't leaving the value NULL cause > a problem in that case? Presently, insert_breakpoints will be always called before resuming target -- look at 'proceed' and 'keep_going'. Note that this is independent of any bits of async support now present. Should we need to revise this, we'll revise this. > > Finally, this code reevaluates condition. > > Re-parses, you mean? Yes. > > While this is probably > > correct way to handle case where meaning of condition changes due to > > loading of shared library, there's no code to match for the > > case when a shared library is unloaded. I think a more robust > > approach if to reevaluate condition inside insert_bp_location. > > I agree. > > > This patch is prompted by the following problem: > > > > void some_function() { > > > > g = 10; > > .... > > dlopen("whatever", ...); > > .... > > g = 15; > > } > > > > If you set watchpoint on 'g', and continue over dlopen, the watchpoint is never hit. > > The exact mode of failure differs. I actually have a testcase for this, and it > > passes for me locally, and I would have liked to provide it, but there are two > > issues for which I don't have yet a complete solution: > > > > - if we have no debug information for ld.so, then when we stop in > > ld.so, we cannot find the frame associated with watchpoint, and delete > > watchpoint. > > Does this case arise in normal usage? I'm not saying it doesn't; I'm > just not sure how to work around it either, so I'm wondering how > serious a problem it is. This problem does not require any extraordinary setup. On my Kubuntu system, ld.so does not have debug symbols by default. So, to reproduce the problem you only need a local watchpoint in a function that calls, directly or indirectly, dlopen. This is not everybody have daily, of course, but still possible to have. > > - if we have debug information for ld.so, then when we stop in > > ld.so, gdb tries to reevaluate 'g'. Unfortunately, it does that in > > wrong block, does not find 'g', and dies with internal error. > > My suggestion above should avoid this. Oops! I failed to mention that 'g' is a global variable. So, your suggestion won't help -- as both block and frame id will be NULL for watchpoint on g. I don't fully understand the problem -- it appears that the innermost_block is set to NULL by c-exp.y to indicate that access to 'g' does not need any specific frame. However, 'g' is in static block for it's library, and is not visible everywhere. I've hacked this around like this: diff --git a/gdb/c-exp.y b/gdb/c-exp.y index 40dbc93..783ea77 100644 --- a/gdb/c-exp.y +++ b/gdb/c-exp.y @@ -697,7 +697,7 @@ variable: name_not_typename /* We want to use the selected frame, not another more inner frame which happens to be in the same block. */ - write_exp_elt_block (NULL); + write_exp_elt_block (block_found); write_exp_elt_sym (sym); write_exp_elt_opcode (OP_VAR_VALUE); } but this patch causes other problems. I attach the revised patch with that extra if, does it look OK? - Volodya * breakpoint.c (insert_bp_location): For watchpoints, recompute condition. (breakpoint_re_set_one): Instead of recomputing value and condition for watchpoints, just reset value and let insert_breakpoints/insert_bp_location recompute it. Don't do anything about disabled watchpoint. --- gdb/breakpoint.c | 107 +++++++++++++++++++++++++++++++++--------------------- 1 files changed, 65 insertions(+), 42 deletions(-) diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 2203f6e..6d06d33 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -1109,6 +1109,18 @@ Note: automatically using hardware breakpoints for read-only addresses.\n")); } } } + + if (bpt->owner->cond_string != NULL) + { + char *s = bpt->owner->cond_string; + if (bpt->cond) + { + xfree (bpt->cond); + bpt->cond = NULL; + } + bpt->cond = parse_exp_1 (&s, bpt->owner->exp_valid_block, 0); + } + /* Failure to insert a watchpoint on any memory value in the value chain brings us here. */ if (!bpt->inserted) @@ -7527,53 +7539,64 @@ breakpoint_re_set_one (void *bint) case bp_hardware_watchpoint: case bp_read_watchpoint: case bp_access_watchpoint: - innermost_block = NULL; - /* The issue arises of what context to evaluate this in. The - same one as when it was set, but what does that mean when - symbols have been re-read? We could save the filename and - functionname, but if the context is more local than that, the - best we could do would be something like how many levels deep - and which index at that particular level, but that's going to - be less stable than filenames or function names. */ - - /* So for now, just use a global context. */ - if (b->exp) - { - xfree (b->exp); - /* Avoid re-freeing b->exp if an error during the call to - parse_expression. */ - b->exp = NULL; - } - b->exp = parse_expression (b->exp_string); - b->exp_valid_block = innermost_block; - mark = value_mark (); - if (b->val) - { - value_free (b->val); - /* Avoid re-freeing b->val if an error during the call to - 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); + /* Watchpoint can be either on expression using entirely global variables, + or it can be on local variables. + + Watchpoints of the first kind are never auto-deleted, and even persist + across program restarts. Since they can use variables from shared + libraries, we need to reparse expression as libraries are loaded + and unloaded. + + Watchpoints on local variables can also change meaning as result + of solib event. For example, if a watchpoint uses both a local and + a global variables in expression, it's a local watchpoint, but + unloading of a shared library will make the expression invalid. + This is not a very common use case, but we still re-evaluate + expression, to avoid surprises to the user. + + Note that for local watchpoints, we re-evaluate it only if + watchpoints frame id is still valid. If it's not, it means + the watchpoint is out of scope and will be deleted soon. In fact, + I'm not sure we'll ever be called in this case. + + If a local watchpoint's frame id is still valid, then + b->exp_valid_block is likewise valid, and we can safely use it. + + Don't do anything about disabled watchpoints, since they will + be reevaluated again when enabled. */ - if (b->cond_string != NULL) + if (!breakpoint_enabled (b)) + break; + + if (b->exp_valid_block == NULL + || frame_find_by_id (b->watchpoint_frame) != NULL) { - s = b->cond_string; - if (b->loc->cond) + if (b->exp) { - xfree (b->loc->cond); - /* Avoid re-freeing b->exp if an error during the call - to parse_exp_1. */ - b->loc->cond = NULL; + xfree (b->exp); + b->exp = NULL; } - b->loc->cond = parse_exp_1 (&s, (struct block *) 0, 0); + s = b->exp_string; + b->exp = parse_exp_1 (&s, b->exp_valid_block, 0); + + /* Since we reparsed expression, we need to update the + value. I'm not aware of any way a single solib load or unload + can change a valid value into different valid value, but: + - even if the value is no longer valid, we have to record + this fact, so that when it becomes valid we reports this + as value change + - unloaded followed by load can change the value for sure. + + We set value to NULL, and insert_breakpoints will + update the value. */ + if (b->val) + value_free (b->val); + b->val = NULL; + + /* Loading of new shared library change the meaning of + watchpoint condition. However, insert_bp_location will + recompute watchpoint condition anyway, nothing to do here. */ } - if (breakpoint_enabled (b)) - mention (b); - value_free_to_mark (mark); break; case bp_catch_catch: case bp_catch_throw: -- 1.5.3.5 ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 15:59 ` Vladimir Prus @ 2007-11-28 16:23 ` Vladimir Prus 2007-11-28 19:46 ` Jim Blandy ` (2 subsequent siblings) 3 siblings, 0 replies; 25+ messages in thread From: Vladimir Prus @ 2007-11-28 16:23 UTC (permalink / raw) To: gdb-patches Vladimir Prus wrote: > I attach the revised patch with that extra if, does it look OK? In fact, you might want to hold off reviewing this patch until: 1. I post revised patch to make watchpoints use multiple locations, which will also introduce a single function to update watchpoint that will be used in breakpoint_re_set_one. 2. I figure out why current unmodified GDB does not actually handle watchpoints on variables in shared libraries that get loaded, and segfaults. - Volodya ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 15:59 ` Vladimir Prus 2007-11-28 16:23 ` Vladimir Prus @ 2007-11-28 19:46 ` Jim Blandy 2007-11-28 20:04 ` Vladimir Prus 2007-11-28 22:18 ` Jim Blandy 2008-01-16 1:29 ` [RFA] Don't reset watchpoint block on solib load Jim Blandy 3 siblings, 1 reply; 25+ messages in thread From: Jim Blandy @ 2007-11-28 19:46 UTC (permalink / raw) To: Vladimir Prus; +Cc: gdb-patches Vladimir Prus <vladimir at codesourcery.com> writes: > On Wednesday 28 November 2007 02:00:15 Jim Blandy wrote: >> >> Vladimir Prus <vladimir at codesourcery.com> writes: >> > There's code inside breakpoint_re_set_one to refresh watchpoints, >> > which seems suspicious to me. >> > >> > First problem with that code is that it always resets watchpoint's >> > block to NULL. So, if we have a local watchpoint, and you do >> > dlopen (without exiting the scope where watchpoint is valid), >> > then the watchpoint's block will be reset to NULL, and >> > watchpoint's expression will be reparsed in global block -- >> > which will surely break the watchpoint. >> >> Is that right? We set innermost_block to NULL, but then we call >> parse_expression, which should set innermost_block to the innermost >> block containing a symbol actually used by the expression. > > Except that parse_expression is called while we're inside shared lib > machinery code -- so neither original block nor original frame is > used, and parse_expression is likely to fail. > >> We also call breakpoint_re_set_one when we've unloaded a shared >> library. At that point, b->exp_valid_block could be a dangling >> pointer; we can't use it to re-parse the expression. >> >> I think the bug is that we re-parse the expression with >> parse_expression, which leaves the scope unspecified, defaulting to >> the currently selected frame. We should: >> >> 1) Verify that the frame given by b->watchpoint_frame is still valid, >> and delete the watchpoint if it isn't. >> >> 2) Call get_frame_block (b->watchpoint_frame) to see if we have a >> block for the frame's location, and deleting the watchpoint if we >> don't (saying we don't have the symbolic info available to update >> it), and >> >> 3) Call parse_exp_1 (..., watchpoint frame's block, ...) to reparse >> the watchpoint's expression in the proper block. > > Let me try thinking out loud. > > 1. Suppose I have a watchpoint on a global variable. Such a watchpoint > can reasonably survive program restart, and given that it can be set on > a global variable (including static variables of C++ classes) defined > in a shared library, it makes sense recompute such watchpoint > when a shared library is loaded, or unloaded. The steps I wrote don't address the case of watchpoints that aren't frame-relative. I wonder how we should be dealing with those. If we have a watchpoint on a static variable local to some file or block, then I don't honestly see how we can possibly re-set it correctly after a symbol reload with the data we have now. We can't tell whether b->exp_valid_block is a dangling pointer or not, and b->watchpoint_frame will be null on such watchpoints. At the moment, a watchpoint has two interesting fields: - b->exp_valid_block, which is set only when the watchpoint refers to frame-local variables. Frustratingly, it's NULL if the watchpoint refers to block-scoped static variables, even though we have no way of finding those variables again if we re-parse the expression. - b->watchpoint_frame, which establishes which instances of the local variables the watchpoint refers to. The interesting thing is that exp_valid_block is almost always used as a binary value. The only exception is when we use it as a sanity check on a frame we've found that matches b->watchpoint_frame. Should we instead be saving the PC in whose scope we parsed the expression? That's something we could legitimately look up in breakpoint_re_set_one after a symbol table change. The test in watchpoint_check could look up the PC's function and compare it to the frame's function. (There's also some terminology that's bugging me: the way the code calls watchpoints "in scope" or "out of scope" is misleading: it's not about scope, it's about what the ISO C standard calls "lifetime". For example, a static variable local to some block is "in scope" from the point of its declaration to the end of its block, but the variable's lifetime is the execution of the entire program (or until the shared library that contains the function is dlclosed). A watchpoint should be deleted when the lifetime of any of the objects it refers to ends, regardless of whether they are in scope or not.) (I need to eat lunch, but I'll get to the rest when I get back.) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 19:46 ` Jim Blandy @ 2007-11-28 20:04 ` Vladimir Prus 2007-11-28 22:37 ` Jim Blandy 2007-11-28 22:50 ` Jim Blandy 0 siblings, 2 replies; 25+ messages in thread From: Vladimir Prus @ 2007-11-28 20:04 UTC (permalink / raw) To: Jim Blandy; +Cc: gdb-patches On Wednesday 28 November 2007 22:45:58 you wrote: > > Vladimir Prus <vladimir at codesourcery.com> writes: > > On Wednesday 28 November 2007 02:00:15 Jim Blandy wrote: > >> > >> Vladimir Prus <vladimir at codesourcery.com> writes: > >> > There's code inside breakpoint_re_set_one to refresh watchpoints, > >> > which seems suspicious to me. > >> > > >> > First problem with that code is that it always resets watchpoint's > >> > block to NULL. So, if we have a local watchpoint, and you do > >> > dlopen (without exiting the scope where watchpoint is valid), > >> > then the watchpoint's block will be reset to NULL, and > >> > watchpoint's expression will be reparsed in global block -- > >> > which will surely break the watchpoint. > >> > >> Is that right? We set innermost_block to NULL, but then we call > >> parse_expression, which should set innermost_block to the innermost > >> block containing a symbol actually used by the expression. > > > > Except that parse_expression is called while we're inside shared lib > > machinery code -- so neither original block nor original frame is > > used, and parse_expression is likely to fail. > > > >> We also call breakpoint_re_set_one when we've unloaded a shared > >> library. At that point, b->exp_valid_block could be a dangling > >> pointer; we can't use it to re-parse the expression. > >> > >> I think the bug is that we re-parse the expression with > >> parse_expression, which leaves the scope unspecified, defaulting to > >> the currently selected frame. We should: > >> > >> 1) Verify that the frame given by b->watchpoint_frame is still valid, > >> and delete the watchpoint if it isn't. > >> > >> 2) Call get_frame_block (b->watchpoint_frame) to see if we have a > >> block for the frame's location, and deleting the watchpoint if we > >> don't (saying we don't have the symbolic info available to update > >> it), and > >> > >> 3) Call parse_exp_1 (..., watchpoint frame's block, ...) to reparse > >> the watchpoint's expression in the proper block. > > > > Let me try thinking out loud. > > > > 1. Suppose I have a watchpoint on a global variable. Such a watchpoint > > can reasonably survive program restart, and given that it can be set on > > a global variable (including static variables of C++ classes) defined > > in a shared library, it makes sense recompute such watchpoint > > when a shared library is loaded, or unloaded. > > The steps I wrote don't address the case of watchpoints that aren't > frame-relative. I wonder how we should be dealing with those. > > If we have a watchpoint on a static variable local to some file or > block, then I don't honestly see how we can possibly re-set it > correctly after a symbol reload with the data we have now. We can't > tell whether b->exp_valid_block is a dangling pointer or not, and > b->watchpoint_frame will be null on such watchpoints. I haven't run into any case when b->exp_valid_block is not-NULL, but b->watchpoint_frame is NULL. In fact, we don't need to care about blocks for global watchpoints -- just like ordinary breakpoint on 'foo' does not care which shared library 'foo' comes from, global watchpoint on 'important_data_structure' need not care about where that variable comes from. If we re-parse watchpoint expression on each solib load, things are fine. > At the moment, a watchpoint has two interesting fields: > > - b->exp_valid_block, which is set only when the watchpoint refers to > frame-local variables. Frustratingly, it's NULL if the watchpoint > refers to block-scoped static variables, even though we have no way > of finding those variables again if we re-parse the expression. Right, that's rather nasty. > - b->watchpoint_frame, which establishes which instances of the local > variables the watchpoint refers to. > > The interesting thing is that exp_valid_block is almost always used as > a binary value. The only exception is when we use it as a sanity > check on a frame we've found that matches b->watchpoint_frame. Yes, I noticed that too. > Should we instead be saving the PC in whose scope we parsed the > expression? That's something we could legitimately look up in > breakpoint_re_set_one after a symbol table change. The test in > watchpoint_check could look up the PC's function and compare it to the > frame's function. Well, it does not work with address randomization. And I think that for global watchpoints, just re-parsing the expression works good enough. > (There's also some terminology that's bugging me: the way the code > calls watchpoints "in scope" or "out of scope" is misleading: it's not > about scope, it's about what the ISO C standard calls "lifetime". For > example, a static variable local to some block is "in scope" from the > point of its declaration to the end of its block, but the variable's > lifetime is the execution of the entire program (or until the shared > library that contains the function is dlclosed). A watchpoint should > be deleted when the lifetime of any of the objects it refers to ends, > regardless of whether they are in scope or not.) Similar problem exists in MI varobjs -- where 'in scope' means something unclear. - Volodya ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 20:04 ` Vladimir Prus @ 2007-11-28 22:37 ` Jim Blandy 2007-11-29 6:09 ` Vladimir Prus 2007-11-28 22:50 ` Jim Blandy 1 sibling, 1 reply; 25+ messages in thread From: Jim Blandy @ 2007-11-28 22:37 UTC (permalink / raw) To: Vladimir Prus; +Cc: gdb-patches Vladimir Prus <vladimir at codesourcery.com> writes: >> The steps I wrote don't address the case of watchpoints that aren't >> frame-relative. I wonder how we should be dealing with those. >> >> If we have a watchpoint on a static variable local to some file or >> block, then I don't honestly see how we can possibly re-set it >> correctly after a symbol reload with the data we have now. We can't >> tell whether b->exp_valid_block is a dangling pointer or not, and >> b->watchpoint_frame will be null on such watchpoints. > > I haven't run into any case when b->exp_valid_block is not-NULL, > but b->watchpoint_frame is NULL. By 'dangling pointer', I mean that it's referring to a block that was freed when we freed the objfile it belongs to. My point was just that neither of those fields would be useful in addressing the problem I described. > In fact, we don't need to care about blocks for global watchpoints -- > just like ordinary breakpoint on 'foo' does not care which shared library > 'foo' comes from, global watchpoint on 'important_data_structure' need > not care about where that variable comes from. If we re-parse watchpoint > expression on each solib load, things are fine. Our messages crossed paths: I think we should worry about re-parsing global watchpoints in the proper scope. For example, we do take care to remember which function breakpoints refer to when there is more than one possible referent. In the transcript below, note that the breakpoint set on the static 'foo' in t2.c, as opposed to the global 'foo' in t1.c, remains there even when we re-read the main executable. Watchpoints should behave the same way. $ cat t1.c #include <stdio.h> void bar (void); void foo (void) { puts ("t1.c: foo"); } int main (int argc, char **argv) { foo (); bar (); return 0; } $ cat t2.c #include <stdio.h> static void foo (void) { puts ("t2.c: foo"); } void bar (void) { foo (); } $ gcc -g t1.c t2.c -o t $ ~/gdb/pub/bin/gdb t GNU gdb 6.7.50.20071127-cvs Copyright (C) 2007 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) break bar Breakpoint 1 at 0x80483de: file t2.c, line 13. (gdb) run Starting program: /home/jimb/play/t t1.c: foo Breakpoint 1, bar () at t2.c:13 13 foo (); (gdb) break foo Breakpoint 2 at 0x80483ca: file t2.c, line 6. (gdb) i br Num Type Disp Enb Address What 1 breakpoint keep y 0x080483de in bar at t2.c:13 breakpoint already hit 1 time 2 breakpoint keep y 0x080483ca in foo at t2.c:6 (gdb) c Continuing. Breakpoint 2, foo () at t2.c:6 6 puts ("t2.c: foo"); (gdb) shell touch t (gdb) run The program being debugged has been started already. Start it from the beginning? (y or n) y `/home/jimb/play/t' has changed; re-reading symbols. Starting program: /home/jimb/play/t t1.c: foo Breakpoint 1, bar () at t2.c:13 13 foo (); (gdb) info break Num Type Disp Enb Address What 1 breakpoint keep y 0x080483de in bar at t2.c:13 breakpoint already hit 1 time 2 breakpoint keep y 0x080483ca in foo at t2.c:6 (gdb) c Continuing. Breakpoint 2, foo () at t2.c:6 6 puts ("t2.c: foo"); (gdb) ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 22:37 ` Jim Blandy @ 2007-11-29 6:09 ` Vladimir Prus 0 siblings, 0 replies; 25+ messages in thread From: Vladimir Prus @ 2007-11-29 6:09 UTC (permalink / raw) To: Jim Blandy; +Cc: gdb-patches On Thursday 29 November 2007 01:36:35 Jim Blandy wrote: > > Vladimir Prus <vladimir at codesourcery.com> writes: > >> The steps I wrote don't address the case of watchpoints that aren't > >> frame-relative. I wonder how we should be dealing with those. > >> > >> If we have a watchpoint on a static variable local to some file or > >> block, then I don't honestly see how we can possibly re-set it > >> correctly after a symbol reload with the data we have now. We can't > >> tell whether b->exp_valid_block is a dangling pointer or not, and > >> b->watchpoint_frame will be null on such watchpoints. > > > > I haven't run into any case when b->exp_valid_block is not-NULL, > > but b->watchpoint_frame is NULL. > > By 'dangling pointer', I mean that it's referring to a block that was > freed when we freed the objfile it belongs to. My point was just that > neither of those fields would be useful in addressing the problem I > described. Yes, the 'dangling pointer' is a potential problem; I even have a half-finished patch for that. Except, that it's not easy to get such dangling pointer. For global watchpoint, exp_valid_block is NULL. For watchpoint on local var, to get dangling pointer you need to unloaded shlib from within shlib code, which is likely to crash before we get back. > > > In fact, we don't need to care about blocks for global watchpoints -- > > just like ordinary breakpoint on 'foo' does not care which shared library > > 'foo' comes from, global watchpoint on 'important_data_structure' need > > not care about where that variable comes from. If we re-parse watchpoint > > expression on each solib load, things are fine. > > Our messages crossed paths: I think we should worry about re-parsing > global watchpoints in the proper scope. > > For example, we do take care to remember which function breakpoints > refer to when there is more than one possible referent. In the > transcript below, note that the breakpoint set on the static 'foo' in > t2.c, as opposed to the global 'foo' in t1.c, remains there even when > we re-read the main executable. > > Watchpoints should behave the same way. Not that breakpoints in shared libraries do not behave this way, exactly because shared library can be loaded at random address. > This isn't what GDB does now, but I think this behavior is not hard to > obtain. When we set a watchpoint, instead of b->exp_valid_block, we > should record the PC in whose scope we parsed the expression. When we > check a watchpoint's condition, we should look up the PC's block: if > we can't find one, then we've unloaded symbolic information for that > watchpoint, and we should delete it. > > The tricky part is deciding what to do when the main executable file > is modified. It's hard to see what exactly the watchpoint should > stick to in this case, since the PC isn't a reliable identifier across > such changes. Perhaps it would be enough to also record the name of > the function and source file the PC falls in, re-parse if they have > remained stable, and delete the watchpoint if they have changed. The question is how useful this is. Program changes all the time, and PC can easily end up in a different function. And I think a change can also cause PC to end up in the same function and source file, but different block. And we don't have any way to persistently identify blocks. Anyway, the point of my two patches was to change watchpoints to use multiple locations internally, without breaking behaviour that GDB *now* tries to implement. Now, gdb tries to reparse global watchpoints, my patches keep that, except that now GDB does not crash doing so. You'd note my second patch has 'update_watchpoint' function, which is the single place to update watchpoint if something changes. Should we come up with a smarter approach of refreshing breakpoints, we can just rename the 'reparse' parameter to that function into 'symbols_changed', and let that function have any smart logic we'll come up. There will be no need to redo anything else of my patches. - Volodya ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 20:04 ` Vladimir Prus 2007-11-28 22:37 ` Jim Blandy @ 2007-11-28 22:50 ` Jim Blandy 1 sibling, 0 replies; 25+ messages in thread From: Jim Blandy @ 2007-11-28 22:50 UTC (permalink / raw) To: Vladimir Prus; +Cc: gdb-patches Vladimir Prus <vladimir at codesourcery.com> writes: >> Should we instead be saving the PC in whose scope we parsed the >> expression? That's something we could legitimately look up in >> breakpoint_re_set_one after a symbol table change. The test in >> watchpoint_check could look up the PC's function and compare it to the >> frame's function. > > Well, it does not work with address randomization. And I think that for > global watchpoints, just re-parsing the expression works good > enough. Address randomization is a good point. I think we should still be able to get the right behavior somehow, though. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 15:59 ` Vladimir Prus 2007-11-28 16:23 ` Vladimir Prus 2007-11-28 19:46 ` Jim Blandy @ 2007-11-28 22:18 ` Jim Blandy 2007-11-29 4:24 ` Eli Zaretskii 2008-01-16 1:29 ` [RFA] Don't reset watchpoint block on solib load Jim Blandy 3 siblings, 1 reply; 25+ messages in thread From: Jim Blandy @ 2007-11-28 22:18 UTC (permalink / raw) To: Vladimir Prus; +Cc: gdb-patches Actually, let me withdraw the three steps I suggested above. I understand that I'm straying from commenting on your patch --- apologies --- but that's because as I tried to think about it, I became confused about what behavior we actually want to get out of GDB. Here's the behavior I think we actually want: A watchpoint should 'stick' to the scope it was originally set in. For example, suppose I have a shared library libx.so with a source file x.c, and that x.c has a static variable S. And suppose there's also a global variable named S defined in the main program. While control is stopped somewhere in x.c, I set a watchpoint on S. Clearly, that watchpoint refers to x.c's static S, not the global S. Now, if I later unload libx.so, the watchpoint should delete itself with an appropriate message, just as a watchpoint on a stack variable does when its frame is popped --- when a shared library is unloaded, that ends the lifetimes of the variables it defines, just as exiting a block ends the lifetimes of the variables defined in the block. But specifically, the watchpoint should *not* transform into a watchpoint on the global S. That's an entirely different variable; it could even have a different type. This is what I mean by a watchpoint 'sticking' to the scope it was set in. So, opening and closing shared libraries should never cause us to re-parse a watchpoint's expression. Loading a shared library should never re-parse a watchpoint expression, because the watchpoint should stick to its original scope, which is still there. Unloading a shared library should never re-parse the watchpoint expression, but it should delete the watchpoint if it refers to variables from shared library, since they're gone now. This isn't what GDB does now, but I think this behavior is not hard to obtain. When we set a watchpoint, instead of b->exp_valid_block, we should record the PC in whose scope we parsed the expression. When we check a watchpoint's condition, we should look up the PC's block: if we can't find one, then we've unloaded symbolic information for that watchpoint, and we should delete it. The tricky part is deciding what to do when the main executable file is modified. It's hard to see what exactly the watchpoint should stick to in this case, since the PC isn't a reliable identifier across such changes. Perhaps it would be enough to also record the name of the function and source file the PC falls in, re-parse if they have remained stable, and delete the watchpoint if they have changed. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 22:18 ` Jim Blandy @ 2007-11-29 4:24 ` Eli Zaretskii 2007-11-29 7:04 ` Vladimir Prus 0 siblings, 1 reply; 25+ messages in thread From: Eli Zaretskii @ 2007-11-29 4:24 UTC (permalink / raw) To: Jim Blandy; +Cc: vladimir, gdb-patches > Cc: gdb-patches@sources.redhat.com > From: Jim Blandy <jimb@codesourcery.com> > Date: Wed, 28 Nov 2007 14:18:06 -0800 > > Now, if I later unload libx.so, the watchpoint should delete itself > with an appropriate message, just as a watchpoint on a stack variable > does when its frame is popped --- when a shared library is unloaded, > that ends the lifetimes of the variables it defines, just as exiting a > block ends the lifetimes of the variables defined in the block. Actually, a more useful behavior would be to disable the watchpoint in this case, and reenable it (and, possibly, re-parse the expression) if the library gets loaded again. Similarly when a watchpoint on a static variable, or an automatic variable in the `main' function, goes out of scope, because the program exits: it would be useful, at least as an option, to have the watchpoint re-enabled when the program is restarted. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-29 4:24 ` Eli Zaretskii @ 2007-11-29 7:04 ` Vladimir Prus 2007-11-29 18:54 ` Jim Blandy 0 siblings, 1 reply; 25+ messages in thread From: Vladimir Prus @ 2007-11-29 7:04 UTC (permalink / raw) To: Eli Zaretskii; +Cc: Jim Blandy, gdb-patches On Thursday 29 November 2007 07:24:36 Eli Zaretskii wrote: > > Cc: gdb-patches@sources.redhat.com > > From: Jim Blandy <jimb@codesourcery.com> > > Date: Wed, 28 Nov 2007 14:18:06 -0800 > > > > Now, if I later unload libx.so, the watchpoint should delete itself > > with an appropriate message, just as a watchpoint on a stack variable > > does when its frame is popped --- when a shared library is unloaded, > > that ends the lifetimes of the variables it defines, just as exiting a > > block ends the lifetimes of the variables defined in the block. > > Actually, a more useful behavior would be to disable the watchpoint in > this case, and reenable it (and, possibly, re-parse the expression) if > the library gets loaded again. This is probably good behaviour, indeed. Or maybe we should not disable watchpoint, but mark it as pending, in the same sense of "user wanted it to be enabled, but it won't trigger until a shared lib is loaded" that is used for ordinary watchpoints. But before we even get to that, we need to fix all the existing bugs with watchpoints/solib interaction. For example, currently a watchpoint on a global variable in shared library wedges gdb if that shared library is unloaded: Old value = 1 New value = 2 foo (i=2) at helper.cpp:7 7 } (gdb) n main () at main.cpp:14 14 dlclose(h); (gdb) n Address of symbol "g" is unknown. (gdb) n Single stepping until exit from function _dl_debug_state, which has no line number information. Address of symbol "g" is unknown. Here, all further 'next' commands will tell you the same. This is problem present before my patch, and I don't try to fix it. Then, there's problem whereby local watchpoint gets deleted if a completely unrelated shared library is loaded. Probably, there's much more. With that done, we can think about more useful general behaviour. - Volodya > > Similarly when a watchpoint on a static variable, or an automatic > variable in the `main' function, goes out of scope, because the > program exits: it would be useful, at least as an option, to have the > watchpoint re-enabled when the program is restarted. > ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-29 7:04 ` Vladimir Prus @ 2007-11-29 18:54 ` Jim Blandy 2007-11-29 19:03 ` Variable identification (Was: [RFA] Don't reset watchpoint block on solib load.) Vladimir Prus 0 siblings, 1 reply; 25+ messages in thread From: Jim Blandy @ 2007-11-29 18:54 UTC (permalink / raw) To: Vladimir Prus; +Cc: Eli Zaretskii, gdb-patches Vladimir Prus <vladimir at codesourcery.com> writes: > On Thursday 29 November 2007 07:24:36 Eli Zaretskii wrote: >> > Cc: gdb-patches@sources.redhat.com >> > From: Jim Blandy <jimb@codesourcery.com> >> > Date: Wed, 28 Nov 2007 14:18:06 -0800 >> > >> > Now, if I later unload libx.so, the watchpoint should delete itself >> > with an appropriate message, just as a watchpoint on a stack variable >> > does when its frame is popped --- when a shared library is unloaded, >> > that ends the lifetimes of the variables it defines, just as exiting a >> > block ends the lifetimes of the variables defined in the block. >> >> Actually, a more useful behavior would be to disable the watchpoint in >> this case, and reenable it (and, possibly, re-parse the expression) if >> the library gets loaded again. > > This is probably good behaviour, indeed. Or maybe we should not > disable watchpoint, but mark it as pending, in the same sense of > "user wanted it to be enabled, but it won't trigger until a shared > lib is loaded" that is used for ordinary watchpoints. I think so, too. I guess the key observation is that, while it's not meaningful to talk about a particular local variable "coming back alive", since each function call creates a distinct set of local variables, and you can have recursion, etc., it is meaningful to talk about a shared library being reloaded, and it's intuitive to identify the 'X' from the first loading with the 'X' in the second loading, even if they're at different addresses. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Variable identification (Was: [RFA] Don't reset watchpoint block on solib load.) 2007-11-29 18:54 ` Jim Blandy @ 2007-11-29 19:03 ` Vladimir Prus 2007-11-30 1:22 ` Michael Snyder 0 siblings, 1 reply; 25+ messages in thread From: Vladimir Prus @ 2007-11-29 19:03 UTC (permalink / raw) To: gdb-patches Jim Blandy wrote: >> This is probably good behaviour, indeed. Or maybe we should not >> disable watchpoint, but mark it as pending, in the same sense of >> "user wanted it to be enabled, but it won't trigger until a shared >> lib is loaded" that is used for ordinary watchpoints. > > I think so, too. I guess the key observation is that, while it's not > meaningful to talk about a particular local variable "coming back > alive", since each function call creates a distinct set of local > variables, and you can have recursion, etc., it is meaningful to talk > about a shared library being reloaded, and it's intuitive to identify > the 'X' from the first loading with the 'X' in the second loading, > even if they're at different addresses. Yes. I now recall this is more general problem with identification of variables in GDB. Say, you're in function, and you have local variable 'foo'. In GUI, you do something with 'foo' -- set display format to hex, expand it, and so on. It's highly desirable to keep this information for the next run of program, or even next run of the GUI -- even if variable is local, it's not likely that the display properties user wants depend on frame. Unfortunately, there's no way to do that. - Volodya ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Variable identification (Was: [RFA] Don't reset watchpoint block on solib load.) 2007-11-29 19:03 ` Variable identification (Was: [RFA] Don't reset watchpoint block on solib load.) Vladimir Prus @ 2007-11-30 1:22 ` Michael Snyder 2007-11-30 5:52 ` Vladimir Prus ` (2 more replies) 0 siblings, 3 replies; 25+ messages in thread From: Michael Snyder @ 2007-11-30 1:22 UTC (permalink / raw) To: Vladimir Prus; +Cc: gdb-patches On Thu, 2007-11-29 at 22:02 +0300, Vladimir Prus wrote: > Jim Blandy wrote: > > >> This is probably good behaviour, indeed. Or maybe we should not > >> disable watchpoint, but mark it as pending, in the same sense of > >> "user wanted it to be enabled, but it won't trigger until a shared > >> lib is loaded" that is used for ordinary watchpoints. > > > > I think so, too. I guess the key observation is that, while it's not > > meaningful to talk about a particular local variable "coming back > > alive", since each function call creates a distinct set of local > > variables, and you can have recursion, etc., it is meaningful to talk > > about a shared library being reloaded, and it's intuitive to identify > > the 'X' from the first loading with the 'X' in the second loading, > > even if they're at different addresses. > > Yes. I now recall this is more general problem with identification of > variables in GDB. Say, you're in function, and you have local variable > 'foo'. In GUI, you do something with 'foo' -- set display format to > hex, expand it, and so on. It's highly desirable to keep this > information for the next run of program, or even next run of the GUI -- > even if variable is local, it's not likely that the display properties > user wants depend on frame. > > Unfortunately, there's no way to do that. I haven't followed the discussion closely, but shouldn't it be up to the GUI to keep such persistant info? It's nothing to do with gdb, really. It's the GUI's state. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Variable identification (Was: [RFA] Don't reset watchpoint block on solib load.) 2007-11-30 1:22 ` Michael Snyder @ 2007-11-30 5:52 ` Vladimir Prus 2007-11-30 20:53 ` Eli Zaretskii 2007-12-01 1:39 ` Variable identification Jim Blandy 2 siblings, 0 replies; 25+ messages in thread From: Vladimir Prus @ 2007-11-30 5:52 UTC (permalink / raw) To: Michael Snyder; +Cc: gdb-patches On Friday 30 November 2007 04:09:46 Michael Snyder wrote: > On Thu, 2007-11-29 at 22:02 +0300, Vladimir Prus wrote: > > Jim Blandy wrote: > > >> This is probably good behaviour, indeed. Or maybe we should not > > >> disable watchpoint, but mark it as pending, in the same sense of > > >> "user wanted it to be enabled, but it won't trigger until a shared > > >> lib is loaded" that is used for ordinary watchpoints. > > > > > > I think so, too. I guess the key observation is that, while it's not > > > meaningful to talk about a particular local variable "coming back > > > alive", since each function call creates a distinct set of local > > > variables, and you can have recursion, etc., it is meaningful to talk > > > about a shared library being reloaded, and it's intuitive to identify > > > the 'X' from the first loading with the 'X' in the second loading, > > > even if they're at different addresses. > > > > Yes. I now recall this is more general problem with identification of > > variables in GDB. Say, you're in function, and you have local variable > > 'foo'. In GUI, you do something with 'foo' -- set display format to > > hex, expand it, and so on. It's highly desirable to keep this > > information for the next run of program, or even next run of the GUI -- > > even if variable is local, it's not likely that the display properties > > user wants depend on frame. > > > > Unfortunately, there's no way to do that. > > I haven't followed the discussion closely, but > shouldn't it be up to the GUI to keep such persistant > info? It's nothing to do with gdb, really. It's the > GUI's state. It's GUI state, true. But to keep it, GUI needs some identifier for variables, that is is persistent across program restarts, preferably even if program changes. Presently, there's no such identifier provided by GDB. - Volodya ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Variable identification (Was: [RFA] Don't reset watchpoint block on solib load.) 2007-11-30 1:22 ` Michael Snyder 2007-11-30 5:52 ` Vladimir Prus @ 2007-11-30 20:53 ` Eli Zaretskii 2007-12-01 1:39 ` Variable identification Jim Blandy 2 siblings, 0 replies; 25+ messages in thread From: Eli Zaretskii @ 2007-11-30 20:53 UTC (permalink / raw) To: Michael Snyder; +Cc: ghost, gdb-patches > From: Michael Snyder <msnyder@specifix.com> > Cc: gdb-patches@sources.redhat.com > Date: Thu, 29 Nov 2007 17:09:46 -0800 > > I haven't followed the discussion closely, but > shouldn't it be up to the GUI to keep such persistant > info? It's nothing to do with gdb, really. It's the > GUI's state. I'm not sure what you are talking about. This discussion mentioned two different aspects of watchpoints: I wanted the watchpoints on automatic variables defined in `main' to not be deleted when the program exits, and Vlad was talking about automatic variables in general (which hits the problem with recursive invocations of the same function). I submit that the former is how GDB should behave, and that the fact it doesn't today is a misfeature, unrelated to the GUI state. To a programmer, automatic variables in `main' are almost indistinguishable from static variables, so watchpoints on both kinds should behave the same. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Variable identification 2007-11-30 1:22 ` Michael Snyder 2007-11-30 5:52 ` Vladimir Prus 2007-11-30 20:53 ` Eli Zaretskii @ 2007-12-01 1:39 ` Jim Blandy 2007-12-01 1:47 ` Michael Snyder 2 siblings, 1 reply; 25+ messages in thread From: Jim Blandy @ 2007-12-01 1:39 UTC (permalink / raw) To: Michael Snyder; +Cc: Vladimir Prus, gdb-patches Michael Snyder <msnyder at specifix.com> writes: > On Thu, 2007-11-29 at 22:02 +0300, Vladimir Prus wrote: >> Jim Blandy wrote: >> >> >> This is probably good behaviour, indeed. Or maybe we should not >> >> disable watchpoint, but mark it as pending, in the same sense of >> >> "user wanted it to be enabled, but it won't trigger until a shared >> >> lib is loaded" that is used for ordinary watchpoints. >> > >> > I think so, too. I guess the key observation is that, while it's not >> > meaningful to talk about a particular local variable "coming back >> > alive", since each function call creates a distinct set of local >> > variables, and you can have recursion, etc., it is meaningful to talk >> > about a shared library being reloaded, and it's intuitive to identify >> > the 'X' from the first loading with the 'X' in the second loading, >> > even if they're at different addresses. >> >> Yes. I now recall this is more general problem with identification of >> variables in GDB. Say, you're in function, and you have local variable >> 'foo'. In GUI, you do something with 'foo' -- set display format to >> hex, expand it, and so on. It's highly desirable to keep this >> information for the next run of program, or even next run of the GUI -- >> even if variable is local, it's not likely that the display properties >> user wants depend on frame. >> >> Unfortunately, there's no way to do that. > > I haven't followed the discussion closely, but > shouldn't it be up to the GUI to keep such persistant > info? It's nothing to do with gdb, really. It's the > GUI's state. These questions all affect how watchpoints behave in the CLI as well. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: Variable identification 2007-12-01 1:39 ` Variable identification Jim Blandy @ 2007-12-01 1:47 ` Michael Snyder 0 siblings, 0 replies; 25+ messages in thread From: Michael Snyder @ 2007-12-01 1:47 UTC (permalink / raw) To: Jim Blandy; +Cc: Vladimir Prus, gdb-patches On Fri, 2007-11-30 at 17:38 -0800, Jim Blandy wrote: > Michael Snyder <msnyder at specifix.com> writes: > > On Thu, 2007-11-29 at 22:02 +0300, Vladimir Prus wrote: > >> Jim Blandy wrote: > >> > >> >> This is probably good behaviour, indeed. Or maybe we should not > >> >> disable watchpoint, but mark it as pending, in the same sense of > >> >> "user wanted it to be enabled, but it won't trigger until a shared > >> >> lib is loaded" that is used for ordinary watchpoints. > >> > > >> > I think so, too. I guess the key observation is that, while it's not > >> > meaningful to talk about a particular local variable "coming back > >> > alive", since each function call creates a distinct set of local > >> > variables, and you can have recursion, etc., it is meaningful to talk > >> > about a shared library being reloaded, and it's intuitive to identify > >> > the 'X' from the first loading with the 'X' in the second loading, > >> > even if they're at different addresses. > >> > >> Yes. I now recall this is more general problem with identification of > >> variables in GDB. Say, you're in function, and you have local variable > >> 'foo'. In GUI, you do something with 'foo' -- set display format to > >> hex, expand it, and so on. It's highly desirable to keep this > >> information for the next run of program, or even next run of the GUI -- > >> even if variable is local, it's not likely that the display properties > >> user wants depend on frame. > >> > >> Unfortunately, there's no way to do that. > > > > I haven't followed the discussion closely, but > > shouldn't it be up to the GUI to keep such persistant > > info? It's nothing to do with gdb, really. It's the > > GUI's state. > > These questions all affect how watchpoints behave in the CLI as well. Right, with the CLI being a special case of "the GUI" -- one in which we (gdb maintainers) have control of everything. GDB can keep track of the CLI "state", but other GUI should keep track of their own state. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-28 15:59 ` Vladimir Prus ` (2 preceding siblings ...) 2007-11-28 22:18 ` Jim Blandy @ 2008-01-16 1:29 ` Jim Blandy 2008-01-23 9:58 ` Vladimir Prus 3 siblings, 1 reply; 25+ messages in thread From: Jim Blandy @ 2008-01-16 1:29 UTC (permalink / raw) To: Vladimir Prus; +Cc: gdb-patches (Since it took me a bit to re-discover what this patch was about, I figure I should recap...) breakpoint_re_set_one gets called when the symbolic information available to GDB has changed: we've re-run or attached and the executable file has changed since we last read it, or the program has loaded or unloaded a shared library. The breakpoint_re_set_one function is responsible for updating all references to symbol table contents in breakpoints, watchpoints, etc. A watchpoint can refer to local variables that were in scope when it was set, so it may be associated with a particular frame. However, breakpoint_re_set_one re-parses watchpoint expressions using parse_expression, which parses in the scope of whatever frame happens to selected when it is called. This is very wrong: GDB can call breakpoint_re_set_one in many different circumstances, and the frame selected at that time has no necessary relationship to the frame in which the user set the watchpoint. In particular, GDB calls breakpoint_re_set_one when it stops for a shared library load or unload. At this point, the selected frame is the youngest frame, in the dynamic linker's debug breakpoint function. Since watchpoints' local variables are almost certainly not in scope in that function, GDB fails to re-parse watchpoint expressions that refer to local variables whenever we do a dlopen or dlclose. (And then fails to handle the error and dies.) For example: $ cat w1.c #include <dlfcn.h> int main (int argc, char **argv) { volatile int g = 1; g = 2; void *lib = dlopen ("libm.so", RTLD_NOW); g = 3; return g; } $ gcc -g w1.c -ldl -o w1 $ ~/gdb/pub/nat/gdb/gdb w1 GNU gdb 6.7.50.20080111-cvs Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) b 10 Breakpoint 1 at 0x8048403: file w1.c, line 10. (gdb) run Starting program: /home/jimb/play/w1 Breakpoint 1, main () at w1.c:10 10 void *lib = dlopen ("libm.so", RTLD_NOW); (gdb) watch g Hardware watchpoint 2: g (gdb) next Error in re-setting breakpoint 2: No symbol "g" in current context. Segmentation fault (core dumped) $ I believe Vlad's most recent patch is this one: http://sourceware.org/ml/gdb-patches/2007-11/msg00522.html The patch has two effects: First, in breakpoint_re_set_one (w), if W->exp_valid_block is NULL (meaning that the watchpoint refers to no local variables), or if it is set and GDB can find W->watchpoint_frame on the stack, then it tries to re-parse the expression in exp_valid_block. Second, it re-parses watchpoint condition expressions (the Y in 'watch X if Y') when it inserts breakpoints. I have two questions about this patch. - If we dlclose a shared library while there are still frames in that library's code on the stack, couldn't exp_valid_block be pointing to garbage (i.e. a 'struct block' in the shared library whose debug info has now been freed), even though frame_find_by_id can find the frame? Granted, the user's program is unhappy, because it's going to return to code that isn't there any more, but GDB shouldn't crash --- after all, debuggers are meant for use on unhappy programs. If we can find the frame, and we can find the frame's block, could we use that instead? In the perverse case I outlined, I assume we'd be able to find the frame, but not the block. Certainly, for watchpoints that cite no local variables, we should just always try to re-parse. The prior conversation identified some ugly issues there, too, but that's an existing bug; let's take it one step at a time. - Why shouldn't we re-parse the condition at the same time we re-parse the expression, in the same block? Why should we re-parse the condition when we insert breakpoints? Although I agreed to reparsing the condition when we insert breakpoints earlier in the thread, I can't see now why it's a good idea. It seems wasteful, since we remove and insert breakpoints frequently, and since we do remove and re-insert breakpoints on dlopen/dlclose, it doesn't seem to be a significantly more auspicious time to do the parse. ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2008-01-16 1:29 ` [RFA] Don't reset watchpoint block on solib load Jim Blandy @ 2008-01-23 9:58 ` Vladimir Prus 2008-01-29 15:23 ` Daniel Jacobowitz 0 siblings, 1 reply; 25+ messages in thread From: Vladimir Prus @ 2008-01-23 9:58 UTC (permalink / raw) To: Jim Blandy; +Cc: gdb-patches, Daniel Jacobowitz [-- Attachment #1: Type: text/plain, Size: 7869 bytes --] On Wednesday 16 January 2008 04:28:32 Jim Blandy wrote: > > (Since it took me a bit to re-discover what this patch was about, I > figure I should recap...) > > breakpoint_re_set_one gets called when the symbolic information > available to GDB has changed: we've re-run or attached and the > executable file has changed since we last read it, or the program has > loaded or unloaded a shared library. I think we've established that right now, breakpoint_re_set_one is not called when a library is unloaded. > The breakpoint_re_set_one > function is responsible for updating all references to symbol table > contents in breakpoints, watchpoints, etc. > > A watchpoint can refer to local variables that were in scope when it > was set, so it may be associated with a particular frame. However, > breakpoint_re_set_one re-parses watchpoint expressions using > parse_expression, which parses in the scope of whatever frame happens > to selected when it is called. This is very wrong: GDB can call > breakpoint_re_set_one in many different circumstances, and the frame > selected at that time has no necessary relationship to the frame in > which the user set the watchpoint. > > In particular, GDB calls breakpoint_re_set_one when it stops for a > shared library load or unload. At this point, the selected frame is > the youngest frame, in the dynamic linker's debug breakpoint function. > Since watchpoints' local variables are almost certainly not in scope > in that function, GDB fails to re-parse watchpoint expressions that > refer to local variables whenever we do a dlopen or dlclose. (And > then fails to handle the error and dies.) For example: > > $ cat w1.c > #include <dlfcn.h> > > int > main (int argc, char **argv) > { > volatile int g = 1; > > g = 2; > > void *lib = dlopen ("libm.so", RTLD_NOW); > > g = 3; > > return g; > } > $ gcc -g w1.c -ldl -o w1 > $ ~/gdb/pub/nat/gdb/gdb w1 > GNU gdb 6.7.50.20080111-cvs > Copyright (C) 2008 Free Software Foundation, Inc. > License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> > This is free software: you are free to change and redistribute it. > There is NO WARRANTY, to the extent permitted by law. Type "show copying" > and "show warranty" for details. > This GDB was configured as "i686-pc-linux-gnu"... > (gdb) b 10 > Breakpoint 1 at 0x8048403: file w1.c, line 10. > (gdb) run > Starting program: /home/jimb/play/w1 > > Breakpoint 1, main () at w1.c:10 > 10 void *lib = dlopen ("libm.so", RTLD_NOW); > (gdb) watch g > Hardware watchpoint 2: g > (gdb) next > Error in re-setting breakpoint 2: No symbol "g" in current context. > Segmentation fault (core dumped) > $ > > I believe Vlad's most recent patch is this one: > > http://sourceware.org/ml/gdb-patches/2007-11/msg00522.html > > The patch has two effects: > > First, in breakpoint_re_set_one (w), if W->exp_valid_block is NULL > (meaning that the watchpoint refers to no local variables), or if it > is set and GDB can find W->watchpoint_frame on the stack, then it > tries to re-parse the expression in exp_valid_block. > > Second, it re-parses watchpoint condition expressions (the Y in 'watch > X if Y') when it inserts breakpoints. > > I have two questions about this patch. > > - If we dlclose a shared library while there are still frames in that > library's code on the stack, couldn't exp_valid_block be pointing to > garbage (i.e. a 'struct block' in the shared library whose debug > info has now been freed), even though frame_find_by_id can find the > frame? It's possible. And it's pre-existing problem ;-) Basically, now both dlopen and dlclose mess up watchpoints, and the patch is a step that brings us closer to dlopen working. > Granted, the user's program is unhappy, because it's going to return > to code that isn't there any more, but GDB shouldn't crash --- after > all, debuggers are meant for use on unhappy programs. > > If we can find the frame, and we can find the frame's block, could > we use that instead? Did you mean "if we can find the same, and *can't* find the block"? Basically, if we have a watchpoint associated with frame id, and we can't find that frame id, there's nothing we can do -- because we can't access local variables relatively to frame base we don't know. However, it's possible that frame is found, but in fact, the block is gone -- in which case we should not try to use the gone block. As I mention, this is pre-existing problem. We need a mechanism to get notified when a block is gone. Note that it's strictly speaking different from shared library unloaded, since syntab is not necessary removed at this point. So, ideally, we'd need a new observer that's called when symtab is removed. We'll plug into that observer and disable all watchpoints which conditions use the gone blocks. In fact, I'm not sure that this problem is only relevant to watchpoints. Ordinary breakpoint might well have a condition that uses variables from shared libraries, and such condition will become invalid when shared library is removed. So, I think it's a global existing problem, and we should postpone it. > In the perverse case I outlined, I assume we'd > be able to find the frame, but not the block. > > Certainly, for watchpoints that cite no local variables, we should > just always try to re-parse. The prior conversation identified some > ugly issues there, too, but that's an existing bug; let's take it > one step at a time. > > - Why shouldn't we re-parse the condition at the same time we re-parse > the expression, in the same block? Why should we re-parse the > condition when we insert breakpoints? > > Although I agreed to reparsing the condition when we insert > breakpoints earlier in the thread, I can't see now why it's a good > idea. It seems wasteful, since we remove and insert breakpoints > frequently, and since we do remove and re-insert breakpoints on > dlopen/dlclose, it doesn't seem to be a significantly more > auspicious time to do the parse. Well, we reparse the entire watchpoint expression on each insert already, so reparsing a condition is not a big deal. However, you're right it's not needed, strictly speaking. Honestly, the point of moving it for this patch was to place all code for updating watchpoint in one place. The next patch, that switches watchpoint to using multiple locations, introduced update_watchpoint function which is a single place for all watchpoint updates. Looking at the patch, however, I see that I always reparse condition anyway. I've changed that patch to reparse condition only when update_watchpoint is called with reparse=1, which happens only from breakpoint_re_set_one, and I don't get any regression as result. So, I guess the solutions are either: 1. Omit the move of condition parsing from this patch, or 2. Keep condition parsing in this patch, and then commit the use-multiple-locations-for-watchpoint patch which will immediately make condition only reparsed when breakpoint_re_set_one is called. Given that use-multiple-locations-for-watchpoint patch is approved except for the bit that makes reparsing of condition optional, it seems that (2) is less work. Jim, does this look good for you? For convenience, I attach the current version of use-multiple-locations-for-watchpoint patch. The difference to the previous revision is as follows: @@ -966,7 +966,7 @@ update_watchpoint (struct breakpoint *b, int reparse) value_free (v); } - if (b->cond_string != NULL) + if (reparse && b->cond_string != NULL) { char *s = b->cond_string; if (b->loc->cond) Dan, is the patch still OK to commit? - Volodya [-- Attachment #2: 0003-Use-multiple-locations-for-hardware-watchpoints.patch --] [-- Type: text/x-diff, Size: 29515 bytes --] From 536a6f0019cc9915ed52c8169af88f4c5c12f057 Mon Sep 17 00:00:00 2001 From: Vladimir Prus <vladimir@codesourcery.com> Date: Tue, 20 Nov 2007 20:10:54 +0300 Subject: [RFA] Use multiple locations for hardware watchpoints. To: gdb-patches@sources.redhat.com X-KMail-Transport: CodeSourcery X-KMail-Identity: 901867920 This eliminates the need to traverse value chain, doing various checks, in three different places. * breakpoint.h (struct bp_location): New fields lengths and watchpoint_type. (struct breakpoint): Remove the val_chain field. * breakpoint.c (is_hardware_watchpoint): New. (free_valchain): Remove. (update_watchpoint): New. (insert_bp_location): For hardware watchpoint, just directly insert it. (insert_breakpoints): Call update_watchpoint_locations on all watchpoints. If we have failed to insert any location of a hardware watchpoint, remove all inserted locations. (remove_breakpoint): For hardware watchpoints, directly remove location. (watchpoints_triggered): Iterate over locations. (bpstat_stop_status): Use only first location of a resource watchpoint. (delete_breakpoint): Don't call free_valchain. (print_one_breakpoint): Don't print all locations for watchpoints. (breakpoint_re_set_one): Use update_watchpoint for watchpoints. testsuite/ * gdb.base/watchpoint-solib.exp: New. * gdb.base/watchpoint-solib.c: New. * gdb.base/watchpoint-solib-shr.c: New. --- gdb/breakpoint.c | 502 +++++++++++++------------ gdb/breakpoint.h | 9 +- gdb/testsuite/gdb.base/watchpoint-solib-shr.c | 25 ++ gdb/testsuite/gdb.base/watchpoint-solib.c | 68 ++++ gdb/testsuite/gdb.base/watchpoint-solib.exp | 89 +++++ 5 files changed, 441 insertions(+), 252 deletions(-) create mode 100644 gdb/testsuite/gdb.base/watchpoint-solib-shr.c create mode 100644 gdb/testsuite/gdb.base/watchpoint-solib.c create mode 100644 gdb/testsuite/gdb.base/watchpoint-solib.exp diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index ecc2478..0bed4ef 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -200,6 +200,15 @@ static void free_bp_location (struct bp_location *loc); static void mark_breakpoints_out (void); +static struct bp_location * +allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type); + +static void +unlink_locations_from_global_list (struct breakpoint *bpt); + +static int +is_hardware_watchpoint (struct breakpoint *bpt); + /* Prototypes for exported functions. */ /* If FALSE, gdb will not use hardware support for watchpoints, even @@ -808,24 +817,182 @@ insert_catchpoint (struct ui_out *uo, void *args) } } -/* Helper routine: free the value chain for a breakpoint (watchpoint). */ +static int +is_hardware_watchpoint (struct breakpoint *bpt) +{ + return (bpt->type == bp_hardware_watchpoint + || bpt->type == bp_read_watchpoint + || bpt->type == bp_access_watchpoint); +} +/* Assuming that B is a hardware breakpoint: + - 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. + + If the watchpoint is disabled, do nothing. If this is + local watchpoint that is out of scope, delete it. */ static void -free_valchain (struct bp_location *b) +update_watchpoint (struct breakpoint *b, int reparse) { - struct value *v; - struct value *n; + int within_current_scope; + struct value *mark = value_mark (); + struct frame_id saved_frame_id; + struct bp_location *loc; + bpstat bs; + + unlink_locations_from_global_list (b); + for (loc = b->loc; loc;) + { + struct bp_location *loc_next = loc->next; + remove_breakpoint (loc, mark_uninserted); + xfree (loc); + loc = loc_next; + } + b->loc = NULL; - /* Free the saved value chain. We will construct a new one - the next time the watchpoint is inserted. */ - for (v = b->owner->val_chain; v; v = n) + if (b->disposition == disp_del_at_next_stop) + return; + + /* Save the current frame's ID so we can restore it after + evaluating the watchpoint expression on its own frame. */ + /* FIXME drow/2003-09-09: It would be nice if evaluate_expression + took a frame parameter, so that we didn't have to change the + selected frame. */ + saved_frame_id = get_frame_id (get_selected_frame (NULL)); + + /* Determine if the watchpoint is within scope. */ + if (b->exp_valid_block == NULL) + within_current_scope = 1; + else { - n = value_next (v); - value_free (v); + struct frame_info *fi; + fi = frame_find_by_id (b->watchpoint_frame); + within_current_scope = (fi != NULL); + if (within_current_scope) + select_frame (fi); + } + + if (within_current_scope && reparse) + { + char *s; + if (b->exp) + { + xfree (b->exp); + b->exp = NULL; + } + s = b->exp_string; + b->exp = parse_exp_1 (&s, b->exp_valid_block, 0); + /* If the meaning of expression itself changed, the old value is + no longer relevant. We don't want to report a watchpoint hit + 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->owner->val_chain = NULL; + + + /* If we failed to parse the expression, for example because + it refers to a global variable in a not-yet-loaded shared library, + don't try to insert watchpoint. We don't automatically delete + such watchpoint, though, since failure to parse expression + is different from out-of-scope watchpoint. */ + if (within_current_scope && b->exp) + { + struct value *v, *next; + + /* 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); + + /* Look at each value on the value chain. */ + for (; v; v = next) + { + /* If it's a memory location, and GDB actually needed + its contents to evaluate the expression, then we + must watch it. */ + if (VALUE_LVAL (v) == lval_memory + && ! 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 + || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT + && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) + { + CORE_ADDR addr; + int len, type; + struct bp_location *loc, **tmp; + + addr = VALUE_ADDRESS (v) + value_offset (v); + len = TYPE_LENGTH (value_type (v)); + type = hw_write; + if (b->type == bp_read_watchpoint) + type = hw_read; + else if (b->type == bp_access_watchpoint) + type = hw_access; + + loc = allocate_bp_location (b, bp_hardware_watchpoint); + for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next)) + ; + *tmp = loc; + loc->address = addr; + loc->length = len; + loc->watchpoint_type = type; + } + } + + next = value_next (v); + if (v != b->val) + value_free (v); + } + + if (reparse && b->cond_string != NULL) + { + char *s = b->cond_string; + if (b->loc->cond) + { + xfree (b->loc->cond); + b->loc->cond = NULL; + } + b->loc->cond = parse_exp_1 (&s, b->exp_valid_block, 0); + } + } + else if (!within_current_scope) + { + printf_filtered (_("\ +Hardware watchpoint %d deleted because the program has left the block \n\ +in which its expression is valid.\n"), + b->number); + if (b->related_breakpoint) + b->related_breakpoint->disposition = disp_del_at_next_stop; + b->disposition = disp_del_at_next_stop; + } + + /* Restore the selected frame. */ + select_frame (frame_find_by_id (saved_frame_id)); } + /* Insert a low-level "breakpoint" of some type. BPT is the breakpoint. Any error messages are printed to TMP_ERROR_STREAM; and DISABLED_BREAKS, PROCESS_WARNING, and HW_BREAKPOINT_ERROR are used to report problems. @@ -1016,136 +1183,10 @@ Note: automatically using hardware breakpoints for read-only addresses.\n")); watchpoints. It's not clear that it's necessary... */ && bpt->owner->disposition != disp_del_at_next_stop) { - /* FIXME drow/2003-09-08: This code sets multiple hardware watchpoints - based on the expression. Ideally this should happen at a higher level, - and there should be one bp_location for each computed address we - must watch. As soon as a many-to-one mapping is available I'll - 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 - evaluating the watchpoint expression on its own frame. */ - /* FIXME drow/2003-09-09: It would be nice if evaluate_expression - took a frame parameter, so that we didn't have to change the - selected frame. */ - saved_frame_id = get_frame_id (get_selected_frame (NULL)); - - /* Determine if the watchpoint is within scope. */ - if (bpt->owner->exp_valid_block == NULL) - within_current_scope = 1; - else - { - struct frame_info *fi; - fi = frame_find_by_id (bpt->owner->watchpoint_frame); - within_current_scope = (fi != NULL); - if (within_current_scope) - select_frame (fi); - } - - if (within_current_scope) - { - free_valchain (bpt); - - /* Evaluate the expression and cut the chain of values - produced off from the value chain. - - 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); - - bpt->owner->val_chain = v; - bpt->inserted = 1; - - /* Look at each value on the value chain. */ - for (; v; v = value_next (v)) - { - /* If it's a memory location, and GDB actually needed - its contents to evaluate the expression, then we - must watch it. */ - if (VALUE_LVAL (v) == lval_memory - && ! 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 == bpt->owner->val_chain - || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT - && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) - { - CORE_ADDR addr; - int len, type; - - addr = VALUE_ADDRESS (v) + value_offset (v); - len = TYPE_LENGTH (value_type (v)); - type = hw_write; - if (bpt->owner->type == bp_read_watchpoint) - type = hw_read; - else if (bpt->owner->type == bp_access_watchpoint) - type = hw_access; - - val = target_insert_watchpoint (addr, len, type); - if (val == -1) - { - /* Don't exit the loop, try to insert - every value on the value chain. That's - because we will be removing all the - watches below, and removing a - watchpoint we didn't insert could have - adverse effects. */ - bpt->inserted = 0; - } - val = 0; - } - } - } - - if (bpt->owner->cond_string != NULL) - { - char *s = bpt->owner->cond_string; - if (bpt->cond) - { - xfree (bpt->cond); - bpt->cond = NULL; - } - bpt->cond = parse_exp_1 (&s, bpt->owner->exp_valid_block, 0); - } - - /* Failure to insert a watchpoint on any memory value in the - value chain brings us here. */ - if (!bpt->inserted) - { - remove_breakpoint (bpt, mark_uninserted); - *hw_breakpoint_error = 1; - fprintf_unfiltered (tmp_error_stream, - "Could not insert hardware watchpoint %d.\n", - bpt->owner->number); - val = -1; - } - } - else - { - printf_filtered (_("\ -Hardware watchpoint %d deleted because the program has left the block \n\ -in which its expression is valid.\n"), - bpt->owner->number); - if (bpt->owner->related_breakpoint) - bpt->owner->related_breakpoint->disposition = disp_del_at_next_stop; - bpt->owner->disposition = disp_del_at_next_stop; - } - - /* Restore the selected frame. */ - select_frame (frame_find_by_id (saved_frame_id)); - - return val; + val = target_insert_watchpoint (bpt->address, + bpt->length, + bpt->watchpoint_type); + bpt->inserted = (val != -1); } else if (bpt->owner->type == bp_catch_fork @@ -1178,6 +1219,7 @@ in which its expression is valid.\n"), void insert_breakpoints (void) { + struct breakpoint *bpt; struct bp_location *b, *temp; int error = 0; int val = 0; @@ -1192,6 +1234,10 @@ insert_breakpoints (void) there was an error. */ fprintf_unfiltered (tmp_error_stream, "Warning:\n"); + ALL_BREAKPOINTS (bpt) + if (is_hardware_watchpoint (bpt)) + update_watchpoint (bpt, 0 /* don't reparse */); + ALL_BP_LOCATIONS_SAFE (b, temp) { if (!breakpoint_enabled (b->owner)) @@ -1203,19 +1249,6 @@ insert_breakpoints (void) && !valid_thread_id (b->owner->thread)) continue; - /* FIXME drow/2003-10-07: This code should be pushed elsewhere when - hardware watchpoints are split into multiple loc breakpoints. */ - 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); - b->owner->val = val; - } - val = insert_bp_location (b, tmp_error_stream, &disabled_breaks, &process_warning, &hw_breakpoint_error); @@ -1223,6 +1256,39 @@ insert_breakpoints (void) error = val; } + /* If we failed to insert all locations of a watchpoint, + remove them, as half-inserted watchpoint is of limited use. */ + ALL_BREAKPOINTS (bpt) + { + int some_failed = 0; + struct bp_location *loc; + + if (!is_hardware_watchpoint (bpt)) + continue; + + if (bpt->enable_state != bp_enabled) + continue; + + for (loc = bpt->loc; loc; loc = loc->next) + if (!loc->inserted) + { + some_failed = 1; + break; + } + if (some_failed) + { + for (loc = bpt->loc; loc; loc = loc->next) + if (loc->inserted) + remove_breakpoint (loc, mark_uninserted); + + hw_breakpoint_error = 1; + fprintf_unfiltered (tmp_error_stream, + "Could not insert hardware watchpoint %d.\n", + bpt->number); + error = -1; + } + } + if (error) { /* If a hardware breakpoint or watchpoint was inserted, add a @@ -1508,46 +1574,15 @@ remove_breakpoint (struct bp_location *b, insertion_state_t is) return val; b->inserted = (is == mark_inserted); } - else if (b->loc_type == bp_loc_hardware_watchpoint - && breakpoint_enabled (b->owner) - && !b->duplicate) + else if (b->loc_type == bp_loc_hardware_watchpoint) { struct value *v; struct value *n; b->inserted = (is == mark_inserted); - /* Walk down the saved value chain. */ - for (v = b->owner->val_chain; v; v = value_next (v)) - { - /* For each memory reference remove the watchpoint - at that address. */ - if (VALUE_LVAL (v) == lval_memory - && ! value_lazy (v)) - { - struct type *vtype = check_typedef (value_type (v)); - - if (v == b->owner->val_chain - || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT - && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) - { - CORE_ADDR addr; - int len, type; + val = target_remove_watchpoint (b->address, b->length, + b->watchpoint_type); - addr = VALUE_ADDRESS (v) + value_offset (v); - len = TYPE_LENGTH (value_type (v)); - type = hw_write; - if (b->owner->type == bp_read_watchpoint) - type = hw_read; - else if (b->owner->type == bp_access_watchpoint) - type = hw_access; - - val = target_remove_watchpoint (addr, len, type); - if (val == -1) - b->inserted = 1; - val = 0; - } - } - } /* Failure to remove any of the hardware watchpoints comes here. */ if ((is == mark_uninserted) && (b->inserted)) warning (_("Could not remove hardware watchpoint %d."), @@ -2451,33 +2486,19 @@ watchpoints_triggered (struct target_waitstatus *ws) || b->type == bp_read_watchpoint || b->type == bp_access_watchpoint) { + struct bp_location *loc; struct value *v; b->watchpoint_triggered = watch_triggered_no; - for (v = b->val_chain; v; v = value_next (v)) - { - if (VALUE_LVAL (v) == lval_memory && ! value_lazy (v)) - { - struct type *vtype = check_typedef (value_type (v)); - - if (v == b->val_chain - || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT - && TYPE_CODE (vtype) != TYPE_CODE_ARRAY)) - { - CORE_ADDR vaddr; - - vaddr = VALUE_ADDRESS (v) + value_offset (v); - /* Exact match not required. Within range is - sufficient. */ - if (addr >= vaddr - && addr < vaddr + TYPE_LENGTH (value_type (v))) - { - b->watchpoint_triggered = watch_triggered_yes; - break; - } - } - } - } + for (loc = b->loc; loc; loc = loc->next) + /* Exact match not required. Within range is + sufficient. */ + if (addr >= loc->address + && addr < loc->address + loc->length) + { + b->watchpoint_triggered = watch_triggered_yes; + break; + } } return 1; @@ -2716,6 +2737,15 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid) && !inferior_has_execd (PIDGET (inferior_ptid), &b->exec_pathname)) continue; + /* For hardware watchpoints, we look only at the first location. + The watchpoint_check function will work on entire expression, + not the individual locations. For read watchopints, the + watchpoints_triggered function have checked all locations + alrea + */ + if (b->type == bp_hardware_watchpoint && bl != b->loc) + continue; + /* Come here if it's a watchpoint, or if the break address matches */ bs = bpstat_alloc (bl, bs); /* Alloc a bpstat to explain stop */ @@ -2909,6 +2939,10 @@ bpstat_stop_status (CORE_ADDR bp_addr, ptid_t ptid) || bs->breakpoint_at->owner->type == bp_read_watchpoint || bs->breakpoint_at->owner->type == bp_access_watchpoint)) { + /* remove/insert can invalidate bs->breakpoint_at, if this + location is no longer used by the watchpoint. Prevent + further code from trying to use it. */ + bs->breakpoint_at = NULL; remove_breakpoints (); insert_breakpoints (); break; @@ -3629,10 +3663,14 @@ print_one_breakpoint (struct breakpoint *b, disabled, we print it as if it had several locations, since otherwise it's hard to represent "breakpoint enabled, location disabled" - situation. */ + situation. + Note that while hardware watchpoints have + several locations internally, that's no a property + exposed to user. */ if (b->loc + && !is_hardware_watchpoint (b) && (b->loc->next || !b->loc->enabled) - && !ui_out_is_mi_like_p (uiout)) + && !ui_out_is_mi_like_p (uiout)) { struct bp_location *loc; int n = 1; @@ -6829,9 +6867,7 @@ delete_breakpoint (struct breakpoint *bpt) { if (loc->inserted) remove_breakpoint (loc, mark_inserted); - - free_valchain (loc); - + if (loc->cond) xfree (loc->cond); @@ -7265,39 +7301,7 @@ breakpoint_re_set_one (void *bint) Don't do anything about disabled watchpoints, since they will be reevaluated again when enabled. */ - - if (!breakpoint_enabled (b)) - break; - - if (b->exp_valid_block == NULL - || frame_find_by_id (b->watchpoint_frame) != NULL) - { - if (b->exp) - { - xfree (b->exp); - b->exp = NULL; - } - s = b->exp_string; - b->exp = parse_exp_1 (&s, b->exp_valid_block, 0); - - /* Since we reparsed expression, we need to update the - value. I'm not aware of any way a single solib load or unload - can change a valid value into different valid value, but: - - even if the value is no longer valid, we have to record - this fact, so that when it becomes valid we reports this - as value change - - unloaded followed by load can change the value for sure. - - We set value to NULL, and insert_breakpoints will - update the value. */ - if (b->val) - value_free (b->val); - b->val = NULL; - - /* Loading of new shared library change the meaning of - watchpoint condition. However, insert_bp_location will - recompute watchpoint condition anyway, nothing to do here. */ - } + update_watchpoint (b, 1 /* reparse */); break; /* We needn't really do anything to reset these, since the mask that requests them is unaffected by e.g., new libraries being diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 91667ab..7b72e19 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -273,6 +273,12 @@ struct bp_location bp_loc_other. */ CORE_ADDR address; + /* For hardware watchpoints, the size of data ad ADDRESS being watches. */ + int length; + + /* Type of hardware watchpoint. */ + enum target_hw_bp_type watchpoint_type; + /* For any breakpoint type with an address, this is the BFD section associated with the address. Used primarily for overlay debugging. */ asection *section; @@ -388,9 +394,6 @@ struct breakpoint /* Value of the watchpoint the last time we checked it. */ struct value *val; - /* Holds the value chain for a hardware watchpoint expression. */ - struct value *val_chain; - /* Holds the address of the related watchpoint_scope breakpoint when using watchpoints on local variables (might the concept of a related breakpoint be useful elsewhere, if not just call diff --git a/gdb/testsuite/gdb.base/watchpoint-solib-shr.c b/gdb/testsuite/gdb.base/watchpoint-solib-shr.c new file mode 100644 index 0000000..699f559 --- /dev/null +++ b/gdb/testsuite/gdb.base/watchpoint-solib-shr.c @@ -0,0 +1,25 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 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 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/>. */ + +#include <stdio.h> + +int g = 0; + +void foo (int i) +{ + g = i; +} diff --git a/gdb/testsuite/gdb.base/watchpoint-solib.c b/gdb/testsuite/gdb.base/watchpoint-solib.c new file mode 100644 index 0000000..b316024 --- /dev/null +++ b/gdb/testsuite/gdb.base/watchpoint-solib.c @@ -0,0 +1,68 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 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 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/>. */ + +#include <stdio.h> +#include <stdlib.h> + +#ifdef __WIN32__ +#include <windows.h> +#define dlopen(name, mode) LoadLibrary (TEXT (name)) +#ifdef _WIN32_WCE +# define dlsym(handle, func) GetProcAddress (handle, TEXT (func)) +#else +# define dlsym(handle, func) GetProcAddress (handle, func) +#endif +#define dlclose(handle) FreeLibrary (handle) +#define dlerror() "error %d occurred", GetLastError () +#else +#include <dlfcn.h> +#endif + + +void open_shlib () +{ + void *handle; + void (*foo) (int); + + handle = dlopen (SHLIB_NAME, RTLD_LAZY); + + if (!handle) + { + fprintf (stderr, dlerror ()); + exit (1); + } + + foo = (void (*)(int))dlsym (handle, "foo"); + + if (!foo) + { + fprintf (stderr, dlerror ()); + exit (1); + } + + foo (1); // call to foo + foo (2); + + dlclose (handle); +} + + +int main() +{ + open_shlib (); + return 0; +} diff --git a/gdb/testsuite/gdb.base/watchpoint-solib.exp b/gdb/testsuite/gdb.base/watchpoint-solib.exp new file mode 100644 index 0000000..fb5d886 --- /dev/null +++ b/gdb/testsuite/gdb.base/watchpoint-solib.exp @@ -0,0 +1,89 @@ +# 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/>. + +if $tracelevel then { + strace $tracelevel +} + +# +# test running programs +# +set prms_id 0 +set bug_id 0 + +if {[skip_shlib_tests]} { + return 0 +} + +# TODO: Use LoadLibrary on this target instead of dlopen. +if {[istarget arm*-*-symbianelf*]} { + return 0 +} + +set testfile "watchpoint-solib" +set libfile "watchpoint-solib-shr" +set libname "${libfile}.sl" +set libsrcfile ${libfile}.c +set srcfile $srcdir/$subdir/$testfile.c +set binfile $objdir/$subdir/$testfile +set shlibdir ${objdir}/${subdir} +set libsrc $srcdir/$subdir/$libfile.c +set lib_sl $objdir/$subdir/$libname + +if [get_compiler_info ${binfile}] { + return -1 +} + +set lib_opts debug +set exec_opts [list debug shlib_load additional_flags=-DSHLIB_NAME\=\"${libname}\"] + +if { [gdb_compile_shlib $libsrc $lib_sl $lib_opts] != "" + || [gdb_compile $srcfile $binfile executable $exec_opts] != ""} { + untested "Couldn't compile $libsrc or $srcfile." + return -1 +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} +gdb_load_shlibs $lib_sl + +if [target_info exists gdb_stub] { + gdb_step_for_stub; +} + +runto_main + + +gdb_test_multiple "break foo" "set pending breakpoint" { + -re ".*Make breakpoint pending.*y or \\\[n\\\]. $" { + gdb_test "y" "Breakpoint.*foo.*pending." "set pending breakpoint" + } +} + +gdb_test "continue" ".*Breakpoint 2.*foo.*" "continue to foo" +gdb_test "watch g" "Hardware watchpoint 3: g" "set watchpoint on g" +gdb_test "continue" ".*New value = 1.*" "continue to watchpoint hit" +rerun_to_main +gdb_test "continue" ".*Breakpoint 2.*foo.*" "continue to foo again" +gdb_test "continue" ".*New value = 1.*" "continue to watchpoint hit again" + + + + + -- 1.5.3.5 ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2008-01-23 9:58 ` Vladimir Prus @ 2008-01-29 15:23 ` Daniel Jacobowitz 0 siblings, 0 replies; 25+ messages in thread From: Daniel Jacobowitz @ 2008-01-29 15:23 UTC (permalink / raw) To: Vladimir Prus; +Cc: Jim Blandy, gdb-patches On Wed, Jan 23, 2008 at 12:57:27PM +0300, Vladimir Prus wrote: > So, I guess the solutions are either: > > 1. Omit the move of condition parsing from this patch, or > 2. Keep condition parsing in this patch, and then commit > the use-multiple-locations-for-watchpoint patch which will > immediately make condition only reparsed when breakpoint_re_set_one > is called. > > Given that use-multiple-locations-for-watchpoint patch is > approved except for the bit that makes reparsing of condition > optional, it seems that (2) is less work. All this sounds fine to me. I'm OK with this patch, which I believe is the one here: http://sourceware.org/ml/gdb-patches/2007-11/msg00522.html > For convenience, I attach the current version of > use-multiple-locations-for-watchpoint patch. The difference > to the previous revision is as follows: > > > @@ -966,7 +966,7 @@ update_watchpoint (struct breakpoint *b, int reparse) > value_free (v); > } > > - if (b->cond_string != NULL) > + if (reparse && b->cond_string != NULL) > { > char *s = b->cond_string; > if (b->loc->cond) > > > Dan, is the patch still OK to commit? Yes, it is. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-27 23:00 ` Jim Blandy 2007-11-28 15:59 ` Vladimir Prus @ 2007-11-29 6:55 ` Vladimir Prus 2007-11-29 18:40 ` Jim Blandy 1 sibling, 1 reply; 25+ messages in thread From: Vladimir Prus @ 2007-11-29 6:55 UTC (permalink / raw) To: Jim Blandy; +Cc: gdb-patches On Wednesday 28 November 2007 02:00:15 Jim Blandy wrote: > We also call breakpoint_re_set_one when we've unloaded a shared > library. Can you point me at a codepath that would cause breakpoint_re_set_one to be called when a shared library is *unloaded*? I've poked at this for a while, and can't see it. - Volodya ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-29 6:55 ` Vladimir Prus @ 2007-11-29 18:40 ` Jim Blandy 2007-11-29 18:45 ` Vladimir Prus 0 siblings, 1 reply; 25+ messages in thread From: Jim Blandy @ 2007-11-29 18:40 UTC (permalink / raw) To: Vladimir Prus; +Cc: gdb-patches Vladimir Prus <vladimir at codesourcery.com> writes: > On Wednesday 28 November 2007 02:00:15 Jim Blandy wrote: > >> We also call breakpoint_re_set_one when we've unloaded a shared >> library. > > Can you point me at a codepath that would cause breakpoint_re_set_one > to be called when a shared library is *unloaded*? I've poked at > this for a while, and can't see it. I beg your pardon. It does not. This is a pretty serious bug. A dlclose will call free_objfile: handle_inferior_event -> solib_add -> update_solib_list -> free_objfile but it takes no steps to clear references to the freed shared library's symbols. I had assumed that it must be calling clear_symtab_users. We need to call clear_symtab_users whenever any objfile is freed. Now, where to do this... ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [RFA] Don't reset watchpoint block on solib load. 2007-11-29 18:40 ` Jim Blandy @ 2007-11-29 18:45 ` Vladimir Prus 0 siblings, 0 replies; 25+ messages in thread From: Vladimir Prus @ 2007-11-29 18:45 UTC (permalink / raw) To: Jim Blandy; +Cc: gdb-patches On Thursday 29 November 2007 21:39:22 you wrote: > > Vladimir Prus <vladimir at codesourcery.com> writes: > > On Wednesday 28 November 2007 02:00:15 Jim Blandy wrote: > > > >> We also call breakpoint_re_set_one when we've unloaded a shared > >> library. > > > > Can you point me at a codepath that would cause breakpoint_re_set_one > > to be called when a shared library is *unloaded*? I've poked at > > this for a while, and can't see it. > > I beg your pardon. It does not. Excellent, at least I did not miss anything. > This is a pretty serious bug. A > dlclose will call free_objfile: > > handle_inferior_event > -> solib_add > -> update_solib_list > -> free_objfile > > but it takes no steps to clear references to the freed shared > library's symbols. I had assumed that it must be calling > clear_symtab_users. We need to call clear_symtab_users whenever any > objfile is freed. > > Now, where to do this... The precedent now is varobj_invalidate, called from clear_symbtab_users. The other precedent is preserve_values, called from free_objfile. I actually have a patch in works, that would make free_objfile call a function in breakpoints.c that will handle breakpoint referring to the unloaded solib. But I'd rather not mix this thing into an already big and scary patch ;-) - Volodya ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2008-01-29 15:17 UTC | newest] Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2007-11-20 17:14 [RFA] Don't reset watchpoint block on solib load Vladimir Prus 2007-11-27 23:00 ` Jim Blandy 2007-11-28 15:59 ` Vladimir Prus 2007-11-28 16:23 ` Vladimir Prus 2007-11-28 19:46 ` Jim Blandy 2007-11-28 20:04 ` Vladimir Prus 2007-11-28 22:37 ` Jim Blandy 2007-11-29 6:09 ` Vladimir Prus 2007-11-28 22:50 ` Jim Blandy 2007-11-28 22:18 ` Jim Blandy 2007-11-29 4:24 ` Eli Zaretskii 2007-11-29 7:04 ` Vladimir Prus 2007-11-29 18:54 ` Jim Blandy 2007-11-29 19:03 ` Variable identification (Was: [RFA] Don't reset watchpoint block on solib load.) Vladimir Prus 2007-11-30 1:22 ` Michael Snyder 2007-11-30 5:52 ` Vladimir Prus 2007-11-30 20:53 ` Eli Zaretskii 2007-12-01 1:39 ` Variable identification Jim Blandy 2007-12-01 1:47 ` Michael Snyder 2008-01-16 1:29 ` [RFA] Don't reset watchpoint block on solib load Jim Blandy 2008-01-23 9:58 ` Vladimir Prus 2008-01-29 15:23 ` Daniel Jacobowitz 2007-11-29 6:55 ` Vladimir Prus 2007-11-29 18:40 ` Jim Blandy 2007-11-29 18:45 ` Vladimir Prus
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox