How can I monitor the Perl call stack? - perl

I'm using ActivePerl 5.8 on Windows XP.
use strict;
use warnings;
use Data::Dumper;
There are three subroutines used in my script.
To detect the call stack, I can only insert some print "some location"; and check the print result from console Window.
Is there any good method to monitor it? Thank you.

If it's your code, you might want to use:
Carp::cluck( "And here's the stack:" );
See Carp::cluck. It prints out a warning with a stack trace. It works like the "printf" style of debug output.

Use the debugger's T command.
Example:
$ perl -d -e'
sub foo {}
sub bar { foo; }
bar;
'
Loading DB routines from perl5db.pl version 1.32
Editor support available.
Enter h or `h h' for help, or `man perldebug' for more help.
main::(-e:4): bar;
DB<1> s
main::bar(-e:3): sub bar { foo; }
DB<1> s
main::foo(-e:2): sub foo {}
DB<1> T
. = main::foo() called from -e line 3
. = main::bar() called from -e line 4
DB<1> s
Debugged program terminated. Use q to quit or R to restart,
use o inhibit_exit to avoid stopping after program termination,
h q, h R or h o to get additional info.
DB<1> q

You weren't specific about why you'd like to monitor the call stack and trace your subs, so answers will have to be broad.
One method is caller:
caller
Returns the context of the current subroutine call. In scalar context, returns the caller's package name if there is a caller, that is, if we're in a subroutine or eval or require, and the undefined value otherwise. In list context, returns
# 0 1 2
($package, $filename, $line) = caller;
With EXPR, it returns some extra information that the debugger uses to print a stack trace. The value of EXPR indicates how many call frames to go back before the current one.
# 0 1 2 3 4
($package, $filename, $line, $subroutine, $hasargs,
# 5 6 7 8 9 10
$wantarray, $evaltext, $is_require, $hints, $bitmask, $hinthash)
= caller($i);
You might also use the Devel::Cover module:
Code coverage data are collected using a pluggable runops function which counts how many times each op is executed. These data are then mapped back to reality using the B compiler modules. There is also a statement profiling facility which needs a better backend to be really useful.
The more you tell us about what you want to do, the more helpful to you our answers will be!

You rarely need to directly manage the call stack in Perl. If you do caller is the tool you want. However, it is only rarely needed.
More often, I want to see a stack trace when I am debugging. Good news, its easy to get a stack trace, simply use Carp's confess and cluck functions instead of die and warn.
use strict;
use warnings;
use Carp;
bar(6.1);
bar(1);
sub foo {
confess "Oh noes" unless #_ == 6; # confess is fatal
}
sub bar {
my $count = shift;
cluck "bar is in trouble" unless int $count == $count; # cluck is not fatal
foo( ('a')x $count );
}
This gets you:
dao:~ toad$ perl test.pl
bar is in trouble at test.pl line 14
main::bar(6.1) called at test.pl line 5
Oh noes at test.pl line 9
main::foo('a') called at test.pl line 15
main::bar(1) called at test.pl line 6

Related

Perl eval scope

According to perldoc, String Eval should be performed in the current scope. But the following simple test seems to contradict this.
We need the following two simple files to set up the test. Please put them under the same folder.
test_eval_scope.pm
package test_eval_scope;
use strict;
use warnings;
my %h = (a=>'b');
sub f1 {
eval 'print %h, "\n"';
# print %h, "\n"; # this would work
# my $dummy = \%h; # adding this would also work
}
1
test_eval_scope.pl
#!/usr/bin/perl
use File::Basename;
use lib dirname (__FILE__);
use test_eval_scope;
test_eval_scope::f1();
When I run the program, I got the following error
$ test_eval_scope.pl
Variable "%h" is not available at (eval 1) line 1.
My question is why the variable %h is out of scope.
I have done some modification, and found the following:
If I run without eval(), as in the above comment, it will work.
meaning that %h should be in the scope.
If I just add a seemingly useless mentioning in the code, as in the above
comment, eval() will work too.
If I combine pl and pm file into one file, eval() will work too.
If I declare %h with 'our' instead of 'my', eval() will work too.
I encountered this question when I was writing a big program which parsed user-provided code during run time. I don't need solutions as I have plenty workarounds above. But I cannot explain why the above code doesn't work. This affects my perl pride.
My perl version is v5.26.1 on linux.
Thank you for your help!
Subs only capture variables they use. Since f1 doesn't use %h, it doesn't capture it, and %h becomes inaccessible to f1 after it goes out of scope when the module finishes executing.
Any reference to the var, including one that's optimized away, causes the sub to capture the variable. As such, the following does work:
sub f1 {
%h if 0;
eval 'print %h, "\n"';
}
Demo:
$ perl -M5.010 -we'
{
my $x = "x";
sub f { eval q{$x} }
sub g { $x if 0; eval q{$x} }
}
say "f: ", f();
say "g: ", g();
'
Variable "$x" is not available at (eval 1) line 1.
Use of uninitialized value in say at -e line 8.
f:
g: x

How to convince Devel::Trace to print the BEGIN-block statements?

Have a simple script p.pl:
use strict;
use warnings;
our $x;
BEGIN {
$x = 42;
}
print "$x\n";
When I run it as:
perl -d:Trace p.pl
prints:
>> p.pl:3: our $x;
>> p.pl:7: print "$x\n";
42
how to get printed the BEGIN block statements too, e.g. the $x = 42;?
Because my intention isn't clear, adding the clarification:
Looking for ANY way to print statements when the perl script runs (like Devel::Trace it does) but including the statements in the BEGIN block.
It's very possible. Set $DB::single in an early BEGIN block.
use strict;
use warnings;
our $x;
BEGIN { $DB::single = 1 }
BEGIN {
$x = 42;
}
print "$x\n";
$DB::single is a debugger variable used to determine whether the DB::DB function will be invoked at each line. In compilation phase it is usually false but you can set it in compilation phase in a BEGIN block.
This trick is also helpful to set a breakpoint inside a BEGIN block when you want to debug compile-time code in the standard debugger.
Disclaimer: This is just an attempt to explain the behaviour.
Devel::Trace hooks up to the Perl debugging API through the DB model. That is just code. It installs a sub DB::DB.
The big question is, when is that executed. According to perlmod, there are five block types that are executed at specific points during execution. One of them is BEGIN, which is the first.
Consider this program.
use strict;
use warnings;
our ($x, $y);
BEGIN { $x = '42' }
UNITCHECK { 'unitcheck' }
CHECK { 'check' }
INIT { 'init' }
END { 'end' }
print "$x\n";
This will output the following:
>> trace.pl:8: INIT { 'init' }
>> trace.pl:3: our ($x, $y);
>> trace.pl:11: print "$x\n";
42
>> trace.pl:9: END { 'end' }
So Devel::Trace sees the INIT block and the END block. But why the INIT block?
Above mentioned perlmod says:
INIT blocks are run just before the Perl runtime begins execution, in "first in, first out" (FIFO) order.
Apparently at that phase, the DB::DB has already been installed. I could not find any documentation that says when a sub definition is run exactly. However, it seems it's after BEGIN and before INIT. Hence, it does not see whatever goes on in the BEGIN.
Adding a BEGIN { $Devel::Trace::TRACE = 1 } to the beginning of the file also does not help.
I rummaged around in documentation for perldebug and the likes, but could not find an explanation of this behaviour. My guess is that the debugger interface doesn't know about BEGIN at all. They are executed very early after all (consider e.g. perl -c -E 'BEGIN{ say "foo" } say "bar"' will print foo.)

Why is my localized redefinition of a package sub not taking effect?

Given the following Perl program:
package Foo;
use strict;
use warnings;
sub new {
my ($class) = #_;
return bless {}, $class;
}
sub c {
print "IN ORIG C\n";
}
sub DESTROY {
print "IN DESTROY\n";
c();
}
1;
package main;
use strict;
use warnings;
no warnings qw/redefine once/;
local *Foo::c = sub { print "IN MY C\n" };
my $f = Foo->new();
undef $f;
I expect output as:
IN DESTROY
IN MY C
But I actually get output as:
IN DESTROY
IN ORIG C
Q: Why is my localized redefinition of Foo::c not taking effect?
When perl code is compiled, globs for package variables/symbols are looked up (and created as necessary) and referenced directly from the compiled code.
So when you (temporarily) replace the symbol table entry for *Foo::c at runtime, all the already compiled code that used *Foo::c still uses the original glob. But do/require'd code or eval STRING or symbolic references won't.
(Very similar to Access package variable after its name is removed from symbol table in Perl?, see the examples there.)
This is a bug in perl which will be fixed in 5.22 (see Leon's comment below).
This happens because undef $f; doesn't actually free up and destroy $f, it just marks it as ready to
be freed by a nextstate op.
nextstate ops exist roughly between each statement, and they are there
to clean up the stack, among other things.
In your example, since undef $f is the last thing in the file, there
is no nextstate after it, so your local destructor goes out of scope
before $f's destructor is called (or, the global destruction that
happens just isn't aware of your local change.)
When you add a print statement after undef $f, the nextstate op
before the print calls your local destructor.
You can see the additional nextstate in your example at
https://gist.github.com/calid/aeb939147fdd171cffe3#file-04-diff-concise-out.
You can also see this behaviour by checking caller() in your DESTROY method:
sub DESTROY {
my ($pkg, $file, $line) = caller;
print "Destroyed at $pkg, $file, $line\n";
c();
}
mhorsfall#tworivers:~$ perl foo.pl
Destroyed at main, foo.pl, 0
IN DESTROY
IN ORIG C
mhorsfall#tworivers:~$ echo 'print "hi\n"' >> foo.pl
mhorsfall#tworivers:~$ perl foo.pl
Destroyed at main, foo.pl, 30
IN DESTROY
IN MY C
hi
(Line 30 being the print "hi\n")
Hope that sheds some light on this.
Cheers.
The problem here doesn't have to do with compile time vs runtime but rather with scoping.
The use of local limits the scope of your modified Foo::c to the remainder of the current scope (which in your example is the remainder of your script). But DESTROY doesn't run in that scope, even when you explicitly undef $f (See http://perldoc.perl.org/perlobj.html#Destructors for more discussion of the behavior of DESTROY). It runs at an undetermined time later, specifically AFTER $f has "gone out of scope". Therefore, any localized changes you have made in the scope of $f will not apply whenever DESTROY finally runs.
You can see this yourself by simply removing the local in your example:
With local
IN DESTROY
IN ORIG C
Without local
IN DESTROY
IN MY C
Or by adding a few additional subroutines and calling them in package::main scope:
package Foo;
...
sub d {
c();
}
sub DESTROY {
print "IN DESTROY\n";
c();
}
1;
package main;
...
sub e {
Foo::c();
}
local *Foo::c = sub { print "IN MY C\n" };
my $f = Foo->new();
Foo::c();
Foo::d();
e();
undef $f;
Which prints
IN MY C
IN MY C
IN MY C
IN DESTROY
IN ORIG C
So only in DESTROY is the original c used, further demonstrating that this is a scoping issue.
Also see https://stackoverflow.com/a/19100461/232706 for a great explanation of Perl scoping rules.

How do I rerun a subroutine without restarting the script in Perl's debugger?

Suppose I have a situation where I'm trying to experiment with some Perl code.
perl -d foo.pl
Foo.pl chugs it's merry way around (it's a big script), and I decide I want to rerun a particular subroutine and single step through it, but without restarting the process. How would I do that?
The debugger command b method sets a breakpoint at the beginning of your subroutine.
DB<1> b foo
DB<2> &foo(12)
main::foo(foo.pl:2): my ($x) = #_;
DB<<3>> s
main::foo(foo.pl:3): $x += 3;
DB<<3>> s
main::foo(foo.pl:4): print "x = $x\n";
DB<<3>> _
Sometimes you may have to qualify the subroutine names with a package name.
DB<1> use MyModule
DB<2> b MyModule::MySubroutine
just do: func_name(args)
e.g.
sub foo {
my $arg = shift;
print "hello $arg\n";
}
In perl -d:
DB<1> foo('tom')
hello tom
Responding to the edit regarding wanting to re-step through a subroutine.
This is not entirely the most elegant way of doing this, but I don't have another method off the top of my head and am interested in other people's answers to this question :
my $stop_foo = 0;
while(not $stop_foo) {
foo();
}
sub foo {
my $a = 1 + 1;
}
The debugger will continually execute foo, but you can stop the next loop by executing '$stop_foo++' in the debugger.
Again, I don't really feel like that's the best way but it does get the job done with only minor additions to the debugged code.

How can I redefine 'open' properly in Perl?

Some time ago, I ask a question: How do I redefine built in Perl functions?
And the answers have served me well. I have a package that overrides Perl's 'open' function enabling me to log file access.
Now I've come to a case that breaks the functionality of the original code.
use strict;
use warnings;
use Data::Dumper;
sub myopen (*;#) {
my $p;
my $retval = CORE::open($p, $_[1]);
{
no strict;
*{"main::$_[0]"} = $p;
}
return $retval;
}
BEGIN {
*CORE::GLOBAL::open = *myopen;
};
my #a = (1, 2, 3);
open(CHECK, ">dump") or print "UNABLE TO OPEN DUMPER FILE: $!\n";
print CHECK "test\n";
print CHECK Data::Dumper->Dump(\#a);
close CHECK
Now I get this message:
Can't locate object method "CHECK" via package "Data::Dumper"
How do I fix it?
Try using a name other than "CHECK".
"CHECK" is a special function which is called during compile time, and you really shouldn't use it.
$ open CHECK , '<', 'foo.txt';
Took 0.00224494934082031 seconds.
Runtime error: Undefined subroutine &Devel::REPL::Plugin::Packages::DefaultScratchpad::CHECK called at (eval 329) line 5.
$ open CHECKS , '<', 'foo.txt';
Took 0.00155806541442871 seconds.
$
More on 'CHECK'
Why that specific error?
perl -MO=Deparse -e 'print CHECK Data::Dumper 1';
print 'Data::Dumper'->CHECK(1);
Also, you're using global file handles, which are problematic.
use this notation:
open my $fh, '<' , $foo ;
print <$fh>;
close $fh;
These are extra beneficial is they self-close when they go out of scope.
Compare:
> perl -MData::Dumper -e'local*_=*STDOUT;print _ Data::Dumper->Dump([2]);'
Can't locate object method "_" via package "Data::Dumper" at -e line 1.
to
> perl -MData::Dumper -e'local*_=*STDOUT;print _ ( Data::Dumper->Dump([2]) );'
$VAR1 = 2;
I used a different name from "STDOUT" because it seems to only gets the indirect object wrong when it's not a built-in handle.
This will work and without producing the error...
print {*CHECK} Data::Dumper->Dump(\#a);
This stops it being confused has an "Indirect Object Syntax"
However I do recommend steering clear of using CHECK and other special named code blocks in Perl and using lexical variables for filehandles is the preferred method. PBP