我知道这个成语:
eval {
...
};
$DB::single = 1 if $@;
Run Code Online (Sandbox Code Playgroud)
...但是,据我所知,如果调试器在eval检测到堆栈中的帧已经太晚之后就停止了,因为它们恰好是错误发生的瞬间.
有没有办法在错误发生时准确地停止调试器,并检查调用堆栈中的帧?
注意 这是在原始问题发生变化之前编写的.它在die没有调试器的情况下,在抛出的位置检索调用堆栈中每个帧的所有词法变量.
对于调试,Carp :: Always很有帮助.
此外,对于您似乎遇到的错误,您可以覆盖die以获取Carp回溯
eval {
local $SIG{__DIE__} = \&Carp::confess;
# ... code ...
};
if ($@) { print $@ }
Run Code Online (Sandbox Code Playgroud)
这有一些局限性和复杂性需要注意,请参阅perlvar中的eval和%SIG,并且死亡,但由于缺乏触发错误的详细信息,它应该值得尝试.
由于__DIE__钩子在die触发时运行,因此我们可以检查调用堆栈"实时".
下面的代码使用调用者来遍历堆栈和基本信息,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;
};
Run Code Online (Sandbox Code Playgroud)
输出
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.
是否有一种方法可以完全在故障点停止
$SIG{__DIE__} 在引发异常的地方调用,因此您可以添加
local $SIG{__DIE__} = sub { $DB::single = 1; die(@_); };
Run Code Online (Sandbox Code Playgroud)
$ cat a.pl
sub g {
die "!";
}
sub f {
g();
}
local $SIG{__DIE__} = sub { $DB::single = 1; die(@_); };
f();
Run Code Online (Sandbox Code Playgroud)
$ 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
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
124 次 |
| 最近记录: |