Re: Debugger Questions - Variable Scope (source++)
by tye (Sage) on May 16, 2014 at 05:42 UTC
|
You have the source code. Why don't you take a look at it? Your requested feature is dang simple to add. For example (skipping the re-indenting of some lines in order to make the 'diff' smaller):
--- perl-5.10.1/lib/perl5db.pl
+++ ~/lib/perl5db.pl
@@ -1957,9 +1957,14 @@
for ( my $n = 0 ; $n <= $#to_watch ; $n++ ) {
$evalarg = $to_watch[$n];
+ my $val;
+ if( ref $evalarg ) {
+ $val = $$evalarg;
+ } else {
local $onetimeDump; # Tell DB::eval() to not output re
+sults
# Fix context DB::eval() wants to return an array, but
# we need a scalar here.
- my ($val) = join( "', '", &eval );
+ ($val) = join( "', '", &eval );
+ }
$val = ( ( defined $val ) ? "'$val'" : 'undef' );
@@ -5289,5 +5294,12 @@
# ... save it.
- push @to_watch, $expr;
+ my $val;
+ if( $expr =~ /^\$\w+$/ ) {
+ $evalarg = "\\$expr";
+ ( $val ) = &eval;
+ push @to_watch, $val;
+ $val = $$val;
+ } else {
+ push @to_watch, $expr;
# Parameterize DB::eval and call it to get the expression's v
+alue
@@ -5295,5 +5307,6 @@
# return a list value.
$evalarg = $expr;
- my ($val) = join( ' ', &eval );
+ ($val) = join( ' ', &eval );
+ }
$val = ( defined $val ) ? "'$val'" : 'undef';
If you ask for the list of watch expressions, the simple ones will be displayed in a rather useless manner. And you should probably weaken the reference taken as otherwise adding a watch point could prevent a destructor from firing.
On the plus side, I suspect that the new simple watch points will have less of a performance impact than the previous implementation imposed.
| [reply] [Watch: Dir/Any] [d/l] |
|
Almost 3 years later, I actually tried this. It does not appear to work: execution does not stop when the variable changes value, and the L command does not show the watchpoint. My Perl version is 5.8.8; that might be important.
You're right, the solution is pretty simple. Create a ref to the variable of interest and make the watchpoint the dereferenced value. This has the very slight disadvantage of having to wait until the variable of interest has been created, but avoiding the maddening interruptions is wonderful!
Program slightly modified for demonstration purposes:
use strict;
my $t = 14;
print "$t\n";
$t = 15;
print "$t\n";
blah();
print "$t\n";
sub blah {
my $t = 42;
print "$t\n";
}
Debug session - Was:
DB<1> w $t
DB<2> c
Watchpoint 0: $t changed:
old value: ''
new value: '14'
main::(dbt.pl:4): print "$t\n";
DB<2> c
14
Watchpoint 0: $t changed:
old value: '14'
new value: '15'
main::(dbt.pl:6): print "$t\n";
DB<2> c
15
Watchpoint 0: $t changed: <<<<< the bane of my existence
old value: '15'
new value: '42'
main::blah(dbt.pl:12): print "$t\n";
DB<2> c
42
Watchpoint 0: $t changed: <<<<< just more bane
old value: '42'
new value: '15'
main::(dbt.pl:8): print "$t\n";
DB<2> c
15
Watchpoint 0: $t changed:
old value: '15'
new value: ''
Debugged program terminated.
Now:
DB<1> w $t
DB<2> c
Watchpoint 0: $t changed:
old value: ''
new value: '14'
main::(dbt.pl:4): print "$t\n";
DB<2> W $t
DB<3> $z=\$t
DB<4> w $$z
DB<5> c
14
Watchpoint 0: $$z changed:
old value: '14'
new value: '15'
main::(dbt.pl:6): print "$t\n";
DB<5> c
15
42
15
Watchpoint 0: $$z changed:
old value: '15'
new value: ''
Debugged program terminated.
But God demonstrates His own love toward us, in that while we were yet sinners, Christ died for us. Romans 5:8 (NASB)
| [reply] [Watch: Dir/Any] [d/l] [select] |
|
It does not appear to work: execution does not stop when the variable changes value
I must misunderstand some of what you wrote. The only times I see it not stopping (in your example output) is exactly those places where I thought you had requested that it not stop.
and the L command does not show the watchpoint
Yeah, you might have to debug the code. I don't think I had that problem when I ran it years ago, so I'm not planning on trying to reproduce your problem in order to debug for you at this point (especially since it seems that I am misunderstanding something).
| [reply] [Watch: Dir/Any] |
|
Could you please elaborate a bit?
I'm mobile ATM and starring at the code without possibility to test...
But what I'm figuring out is that you add support for watching a ref to a var.
Now I'm not sure how this solves the problem since variables in a special scope are not guaranteed to have the same ref after a reenter (like different calls to a function).
Or am I missing something?
Cheers Rolf
( addicted to the Perl Programming Language)
| [reply] [Watch: Dir/Any] |
|
I don't see why one should assume that "watch for the value of a particular variable to change" should include "and it might change because a whole different variable comes into existence because you called the function again".
Feel free to implement your own semantics for "watch". This took me a whole few minutes, including testing it. But when I implement semantics for "watch a variable", I actually want to watch a variable, not "watch whichever instance of a whole class of related variables is currently in scope, if any".
Another benefit with my approach is that I get notified of changes that happen to the value of the watched variable even when it isn't currently in scope under the same name. That's actually the type of thing that makes "what the heck is changing $x?!" tricky to find which might actually motivate me to want a debugger's "watch" feature. *shrug*
| [reply] [Watch: Dir/Any] |
|
|
|
Re: Debugger Questions - Variable Scope
by LanX (Saint) on May 15, 2014 at 23:29 UTC
|
IIRC are watch expressions just evaled text, and there is no way to tell plain Perl which pad a lexical var belongs to.
So no official way AFAIK ...
... BUT since watch expressions are just evaled text (sic ;-) you can use hacks to restrict them to a range of lines or to be dependent on caller.
I'm too lazy now to fiddle around by myself, but this thread should show you some approaches:
Make debugger break on source lines matching a pattern
HTH! =)
Cheers Rolf
( addicted to the Perl Programming Language)
| [reply] [Watch: Dir/Any] |
|
| [reply] [Watch: Dir/Any] |
|
> The YAPC talk referenced seems especially interesting for this problem and others.
hmm not really, I didn't try to mess with "watch".
I'm personally using and testing my patched version for years now, and there are edge cases where it fails.
The debugger really needs refactoring and modularization.
For instance the command-loop spreads over hundreds and hundreds of lines with if-blocks on regex-conditions and interwoven POD as documentation, where order matters. Thats extremely hard to patch.
Plus there doesn't seem to be any test suite. :(
Cheers Rolf
( addicted to the Perl Programming Language)
| [reply] [Watch: Dir/Any] |
Re: Debugger Questions - Variable Scope
by Laurent_R (Canon) on May 16, 2014 at 06:16 UTC
|
This behavior of the debugger is exactly what I would expect and hope to get, and I would curse any other behavior. If I watch some $t variable, I really want to know what will happen if I use this variable anywhere in my code. Semantically, it is true that you really have two different $t variables, one scoped to the program, and another one scoped to the subroutine. But from the standpoint of what the code does and sees, or of what I see when I read the code, you have only one variable name. So if my code uses this variable name, I really wish the debugger to tell me that this variable name now refers to a different content. The debugger is doing it right on this issue.
| [reply] [Watch: Dir/Any] |
|
I see your point here and I agree - that should remain the default behavior. I would like the option of telling the debugger to ignore certain instances of change, such as the variable becoming undefined when executing code in another package. I'm voluntarily blinding myself by doing this to cut down on the noise.
| [reply] [Watch: Dir/Any] |
Re: Debugger Questions - Variable Scope
by LanX (Saint) on May 16, 2014 at 18:23 UTC
|
using tye's reference approach without patching the sources:
You could use actions to set and unset a global variable holding a ref to the variable to be watched:
something like the following watches between the lines 10 and 13 only!
DB<2> a 10 $WATCH=\$t
DB<3> a 13 $WATCH=\undef
DB<4> w ${$WATCH}
IMHO you could even define your own alias in .perldb to automate this.
something like rw 10-13 $t for "regional watch".
Tye's remarks about weakening to avoid leaks are still valid...
Cheers Rolf
( addicted to the Perl Programming Language)
| [reply] [Watch: Dir/Any] [d/l] [select] |