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 "$_ => ${$vars->{$_}}
";
} elsif (not /^$vars$/) {
print "$_ => $vars->{$_}
";
}
}
++$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
.