我知道这个成语:
/((?:[a-z]+\.)+[a-z]+)/gi
...但是,据我所知,如果调试器在eval {
...
};
$DB::single = 1 if $@;
之后停止,那么检查堆栈中的帧已经太晚了,因为它们恰好发生错误。
有没有办法在错误发生时准确地停止调试器,并检查调用堆栈中的帧?
答案 0 :(得分:6)
注意这是在原始问题发生变化之前编写的。它在没有调试器的情况下,在抛出die
的位置检索调用堆栈中每个帧的所有词法变量。
对于调试,Carp::Always很有帮助。
此外,对于您似乎遇到的错误,您可以覆盖die
以获取Carp
的回溯
eval {
local $SIG{__DIE__} = \&Carp::confess;
# ... code ...
};
if ($@) { print $@ }
这需要注意的局限性和复杂性,请参阅eval和%SIG in perlvar以及die,但由于缺乏触发错误的详细信息,因此值得尝试。
由于__DIE__
挂钩在die
被触发时运行,因此我们可以检查调用堆栈'live'。
下面的代码使用caller来遍历堆栈和基本信息,并使用PadWalker来获取每个帧的词法变量。 subs中的变量可以更容易地跟随输出。
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;
};
输出
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.
PadWalker的peek_my
返回一个hashref,其中每个值都是一个引用。我仅取消引用标量,以进行演示,并从打印件中排除$vars
,其中存储了PadWalker
的结果。要省略处理程序本身,请从my $sf = 1
开始。
答案 1 :(得分:4)
在抛出异常的地方调用如果有办法在故障点完全停止
$SIG{__DIE__}
,因此您可以添加
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
答案 2 :(得分:2)
使用T
命令在任何断点暂停程序时,可以查看堆栈回溯
或者,您可以将dieLevel
选项设置为o dieLevel=1
,以便对任何异常进行自动回溯