I\'m aware of this idiom:
eval {
...
};
$DB::single = 1 if $@;
...but, as far as I can tell, if the debugger stops after the eva
Note This was written for the original question, before it was changed. It retrieves all lexical variables for each frame in the call stack at the point where die
is thrown, without the debugger.
For debugging, Carp::Always is helpful.
Also, for errors you seem to be after, you can override die
to get Carp
's backtrace
eval {
local $SIG{__DIE__} = \&Carp::confess;
# ... code ...
};
if ($@) { print $@ }
This has limitations and complexities to be aware of, see eval and %SIG in perlvar, and die, but given the lack of detail on what triggers the error it should be worth trying.
Since __DIE__
hook runs when die
is triggered, in it we can examine the call stack 'live'.
The code below uses caller to walk the stack and for basic info, and PadWalker to get lexical variables for each frame. I put some variables in subs so to more easily follow the output.
use warnings;
use strict;
use PadWalker qw(peek_my);
my $ondie = sub {
my $sf = 0;
while ( my @call = caller($sf) ) { # go through stack frames
say "At $sf frame, |@call[0..3]|";
my $vars = peek_my($sf); # lexicals for this frame
for (keys %$vars) {
if (ref($vars->{$_}) eq 'SCALAR') {
print "\t$_ => ${$vars->{$_}}\n";
} elsif (not /^\$vars$/) {
print "\t$_ => $vars->{$_}\n";
}
}
++$sf;
}
};
eval {
local $SIG{__DIE__} = $ondie;
top_level(25);
};
if ($@) { print "eval: $@" }
sub top_level {
my ($top_x, $sub_name) = (12.1, (caller(0))[3]);
next_level($_[0]);
};
sub next_level {
my ($next_x, $sub_name) = (7, (caller(0))[3]);
$_[0] / 0;
};
The output
At 0 frame, |main debug_stack.pl 51 main::__ANON__| $sf => 0 @call => ARRAY(0x15464c8) At 1 frame, |main debug_stack.pl 59 main::next_level| $next_x => 7 $ondie => REF(0x1587938) $sub_name => main::next_level At 2 frame, |main debug_stack.pl 38 main::top_level| $top_x => 12.1 $ondie => REF(0x1587938) $sub_name => main::top_level At 3 frame, |main debug_stack.pl 36 (eval)| $ondie => REF(0x1587938) eval: Illegal division by zero at debug_stack.pl line 51.
The PadWalker's peek_my
returns a hashref, where each value is a reference. I dereference only scalars, for demonstration, and also exclude $vars
, where PadWalker
's findings are stored, from prints. To leave out the handler itself start with my $sf = 1
.
if there was a way to stop exactly at the point of failure
$SIG{__DIE__}
is called where the exception is thrown, so you could add
local $SIG{__DIE__} = sub { $DB::single = 1; die(@_); };
$ cat a.pl
sub g {
die "!";
}
sub f {
g();
}
local $SIG{__DIE__} = sub { $DB::single = 1; die(@_); };
f();
$ perl -d a.pl
Loading DB routines from perl5db.pl version 1.49_04
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(a.pl:9): local $SIG{__DIE__} = sub { $DB::single = 1; die(@_); };
DB<1> r
main::CODE(0x1067280)(a.pl:9): local $SIG{__DIE__} = sub { $DB::single = 1; die(@_); };
DB<1> T
@ = DB::DB called from file 'a.pl' line 9
$ = main::__ANON__[a.pl:9]('! at a.pl line 2.^J') called from file 'a.pl' line 2
. = main::g() called from file 'a.pl' line 6
. = main::f() called from file 'a.pl' line 10
You can view a stack backtrace when the program is paused at any breakpoint using the T
command
Alternatively, you may set the dieLevel
option with o dieLevel=1
to cause an automatic backtrace on any exception