精确的 Perl 位置,例如 B::Deparse
Exact Perl location such as with B::Deparse
Perl 中一个长期存在的问题是如何identify a location with finer granularity than a line number。 (关注 link 以获得更多信息。)这个问题是关于如何获得它的。
最有前途的方法是使用正在考虑的 Perl 操作码地址并解析围绕它的语句。在 a 子例程级别,B::Deparse 将在给定代码引用的情况下重新创建 Perl。所以理想的是修改 B::Deparse 以允许您提供提供的操作以开始解析。如果做不到这一点,它可以改为解析封闭的子例程,显示遇到的每个语句的操作码地址。有关此示例,请参见下面的代码。
B::Concise can show a op-code disassembly for a subroutine. In its disassembly output, it gives addresses, and those addresses it gives match those returned, say, by Devel::Callsite。
问题是在如下所示检测 B::Deparse 之后,它给出的 OP 地址与 B::Concise 或 [=35= 给出的地址不匹配]Devel::Callsite。下面给出的输出显示了这一点。
我可以规范化地址,以便它们引用相对偏移量而不是绝对地址。然而,这是很多工作,很恶心,而且我什至不确定这是否会起作用,因为 Deparse 可能会通过 "pessimizing" 更改代码,或者,我猜,撤消优化。
为了具体起见,下面是一些显示不匹配的代码。请注意,反汇编中显示了 deparse 给出的地址中的 none。
use B::Deparse;
use B::Concise qw(set_style);
sub foo() {
my $x=1; $x+=1;
}
my $deparse = B::Deparse->new("-p", "-l", "-sC");
$body = $deparse->coderef2text(\&foo);
print($body, "\n");
my $walker = B::Concise::compile('-basic', 'foo', \&foo);
B::Concise::set_style_standard('debug');
B::Concise::walk_output(\my $buf);
$walker->(); # walks and renders into $buf;
print($buf);
package B::Deparse;
# Modified to show OP addresses
sub lineseq {
my($self, $root, $cx, @ops) = @_;
my($expr, @exprs);
my $out_cop = $self->{'curcop'};
my $out_seq = defined($out_cop) ? $out_cop->cop_seq : undef;
my $limit_seq;
if (defined $root) {
$limit_seq = $out_seq;
my $nseq;
$nseq = $self->find_scope_st($root->sibling) if ${$root->sibling};
$limit_seq = $nseq if !defined($limit_seq)
or defined($nseq) && $nseq < $limit_seq;
}
$limit_seq = $self->{'limit_seq'}
if defined($self->{'limit_seq'})
&& (!defined($limit_seq) || $self->{'limit_seq'} < $limit_seq);
local $self->{'limit_seq'} = $limit_seq;
my $fn = sub {
my ($text, $i) = @_;
my $op = $ops[$i];
push @exprs, sprintf("# op: 0x%x\n%s ", $op, $text);
};
$self->walk_lineseq($root, \@ops, $fn);
# $self->walk_lineseq($root, \@ops,
# sub { push @exprs, $_[0]} );
my $sep = $cx ? '; ' : ";\n";
my $body = join($sep, grep {length} @exprs);
my $subs = "";
if (defined $root && defined $limit_seq && !$self->{'in_format'}) {
$subs = join "\n", $self->seq_subs($limit_seq);
}
return join($sep, grep {length} $body, $subs);
}
我从 运行 得到的输出是:
() {
# op: 0x14a4b30
#line 4 "deparse-so.pl"
(my $x = 1) ;
# op: 0x14a4aa0
#line 4 "deparse-so.pl"
($x += 1) ;
}
main::foo:
UNOP (0xeb9978)
op_next 0
op_sibling 0
op_ppaddr PL_ppaddr[OP_LEAVESUB]
op_type 175
op_flags 4
op_private 65
op_first 0xeab7a0
LISTOP (0xeab7a0)
op_next 0xeb9978
op_sibling 0
op_ppaddr PL_ppaddr[OP_LINESEQ]
op_type 181
op_flags 12
op_private 0
op_first 0xeab7e8
op_last 0xeb9a20
COP (0xeab7e8)
op_next 0xeab890
op_sibling 0xeab848
op_ppaddr PL_ppaddr[OP_NEXTSTATE]
op_type 182
op_flags 1
op_private 0 0
BINOP (0xeab848)
op_next 0xeb99c0
op_sibling 0xeb99c0
op_ppaddr PL_ppaddr[OP_SASSIGN]
op_type 37
op_flags 69
op_private 2
op_first 0xeab890
op_last 0xeab8d0
SVOP (0xeab890)
op_next 0xeab8d0
op_sibling 0xeab8d0
op_ppaddr PL_ppaddr[OP_CONST]
op_type 5
op_flags 2
op_private 0
op_sv 0xea3c40
OP (0xeab8d0)
op_next 0xeab848
op_sibling 0
op_ppaddr PL_ppaddr[OP_PADSV]
op_type 9
op_flags 178
op_private 128
COP (0xeb99c0)
op_next 0xeab768
op_sibling 0xeb9a20
op_ppaddr PL_ppaddr[OP_NEXTSTATE]
op_type 182
op_flags 1
op_private 0 0
BINOP (0xeb9a20)
op_next 0xeb9978
op_sibling 0
op_ppaddr PL_ppaddr[OP_ADD]
op_type 63
op_flags 70
op_private 2
op_first 0xeab768
op_last 0xeb9a68
OP (0xeab768)
op_next 0xeb9a68
op_sibling 0xeb9a68
op_ppaddr PL_ppaddr[OP_PADSV]
op_type 9
op_flags 50
op_private 0
SVOP (0xeb9a68)
op_next 0xeb9a20
op_sibling 0
op_ppaddr PL_ppaddr[OP_CONST]
op_type 5
op_flags 2
op_private 0
op_sv 0xea3c10
B::Concise::compile(CODE(0xea3c70))
UNOP (0xeb9978)
op_next 0
op_sibling 0
op_ppaddr PL_ppaddr[OP_LEAVESUB]
op_type 175
op_flags 4
op_private 65
op_first 0xeab7a0
LISTOP (0xeab7a0)
op_next 0xeb9978
op_sibling 0
op_ppaddr PL_ppaddr[OP_LINESEQ]
op_type 181
op_flags 12
op_private 0
op_first 0xeab7e8
op_last 0xeb9a20
COP (0xeab7e8)
op_next 0xeab890
op_sibling 0xeab848
op_ppaddr PL_ppaddr[OP_NEXTSTATE]
op_type 182
op_flags 1
op_private 0 0
BINOP (0xeab848)
op_next 0xeb99c0
op_sibling 0xeb99c0
op_ppaddr PL_ppaddr[OP_SASSIGN]
op_type 37
op_flags 69
op_private 2
op_first 0xeab890
op_last 0xeab8d0
SVOP (0xeab890)
op_next 0xeab8d0
op_sibling 0xeab8d0
op_ppaddr PL_ppaddr[OP_CONST]
op_type 5
op_flags 2
op_private 0
op_sv 0xea3c40
OP (0xeab8d0)
op_next 0xeab848
op_sibling 0
op_ppaddr PL_ppaddr[OP_PADSV]
op_type 9
op_flags 178
op_private 128
COP (0xeb99c0)
op_next 0xeab768
op_sibling 0xeb9a20
op_ppaddr PL_ppaddr[OP_NEXTSTATE]
op_type 182
op_flags 1
op_private 0 0
BINOP (0xeb9a20)
op_next 0xeb9978
op_sibling 0
op_ppaddr PL_ppaddr[OP_ADD]
op_type 63
op_flags 70
op_private 2
op_first 0xeab768
op_last 0xeb9a68
OP (0xeab768)
op_next 0xeb9a68
op_sibling 0xeb9a68
op_ppaddr PL_ppaddr[OP_PADSV]
op_type 9
op_flags 50
op_private 0
SVOP (0xeb9a68)
op_next 0xeb9a20
op_sibling 0
op_ppaddr PL_ppaddr[OP_CONST]
op_type 5
op_flags 2
op_private 0
op_sv 0xea3c10
最后,作为鼓励人们在这里提供帮助的方式,如果这个问题得到解决,该解决方案可能会出现在 Perl 调试器中 Devel::Trepan 并允许您可靠地知道在调试器中停止时您的确切位置.
注意:已编辑以使问题更清楚。
svref_2object
returns 一个对象,允许您从传递给 svref_2object
的参数引用的结构中提取信息。
您正在打印该对象的地址(一个标量被祝福到 class B::CV
)。
use B qw( );
sub foo { }
my $cv = B::svref_2object(\&foo);
printf "%x\n", \&foo; # Numification of 1st ref to &foo.
printf "%x\n", \&foo; # Numification of 2nd ref to &foo.
printf "%x\n", $cv; # Numification of ref to B::CV object.
printf "%x\n", $cv->object_2svref(); # Numification of 3rd ref to &foo.
printf "%x\n", $$cv; # Address of struct referenced by svref_2object's arg (Undocumented)
引用 numify 到它们引用的地址,所以我们得到:
3c5eaf8
3c5eaf8
3c5e1b0
3c5eaf8
3c5eaf8
ikegami 隐藏在评论中的回答建议让我发现了我在第一个提出的解决方案中的概念缺陷:在 B::Deparse 中,一个词法数组变量存储 OP 和这些是指向实际代码 OP 结构的隐式指针。使用未记录的 $$
获取标量隐式指向的基础地址以提供正确的地址。所以在我的B::Deparse::lineseq猴子补丁代码中,改变:
push @exprs, sprintf("# op: 0x%x\n%s ", $op, $text);
至:
push @exprs, sprintf("# op: 0x%x\n%s ", $$op, $text);
^^
给我一个地址,我可以用它来匹配结果。
不过,要使它可用还有一些工作要做,所以如果有任何其他方法或建议,我很乐意听取他们的意见。
Devel::Trepan 0.70 版现在在其 deparse
命令中使用上述代码并适当修改,以便能够显示多个语句中的哪一个将是 运行.
Perl 中一个长期存在的问题是如何identify a location with finer granularity than a line number。 (关注 link 以获得更多信息。)这个问题是关于如何获得它的。
最有前途的方法是使用正在考虑的 Perl 操作码地址并解析围绕它的语句。在 a 子例程级别,B::Deparse 将在给定代码引用的情况下重新创建 Perl。所以理想的是修改 B::Deparse 以允许您提供提供的操作以开始解析。如果做不到这一点,它可以改为解析封闭的子例程,显示遇到的每个语句的操作码地址。有关此示例,请参见下面的代码。
B::Concise can show a op-code disassembly for a subroutine. In its disassembly output, it gives addresses, and those addresses it gives match those returned, say, by Devel::Callsite。
问题是在如下所示检测 B::Deparse 之后,它给出的 OP 地址与 B::Concise 或 [=35= 给出的地址不匹配]Devel::Callsite。下面给出的输出显示了这一点。
我可以规范化地址,以便它们引用相对偏移量而不是绝对地址。然而,这是很多工作,很恶心,而且我什至不确定这是否会起作用,因为 Deparse 可能会通过 "pessimizing" 更改代码,或者,我猜,撤消优化。
为了具体起见,下面是一些显示不匹配的代码。请注意,反汇编中显示了 deparse 给出的地址中的 none。
use B::Deparse;
use B::Concise qw(set_style);
sub foo() {
my $x=1; $x+=1;
}
my $deparse = B::Deparse->new("-p", "-l", "-sC");
$body = $deparse->coderef2text(\&foo);
print($body, "\n");
my $walker = B::Concise::compile('-basic', 'foo', \&foo);
B::Concise::set_style_standard('debug');
B::Concise::walk_output(\my $buf);
$walker->(); # walks and renders into $buf;
print($buf);
package B::Deparse;
# Modified to show OP addresses
sub lineseq {
my($self, $root, $cx, @ops) = @_;
my($expr, @exprs);
my $out_cop = $self->{'curcop'};
my $out_seq = defined($out_cop) ? $out_cop->cop_seq : undef;
my $limit_seq;
if (defined $root) {
$limit_seq = $out_seq;
my $nseq;
$nseq = $self->find_scope_st($root->sibling) if ${$root->sibling};
$limit_seq = $nseq if !defined($limit_seq)
or defined($nseq) && $nseq < $limit_seq;
}
$limit_seq = $self->{'limit_seq'}
if defined($self->{'limit_seq'})
&& (!defined($limit_seq) || $self->{'limit_seq'} < $limit_seq);
local $self->{'limit_seq'} = $limit_seq;
my $fn = sub {
my ($text, $i) = @_;
my $op = $ops[$i];
push @exprs, sprintf("# op: 0x%x\n%s ", $op, $text);
};
$self->walk_lineseq($root, \@ops, $fn);
# $self->walk_lineseq($root, \@ops,
# sub { push @exprs, $_[0]} );
my $sep = $cx ? '; ' : ";\n";
my $body = join($sep, grep {length} @exprs);
my $subs = "";
if (defined $root && defined $limit_seq && !$self->{'in_format'}) {
$subs = join "\n", $self->seq_subs($limit_seq);
}
return join($sep, grep {length} $body, $subs);
}
我从 运行 得到的输出是:
() {
# op: 0x14a4b30
#line 4 "deparse-so.pl"
(my $x = 1) ;
# op: 0x14a4aa0
#line 4 "deparse-so.pl"
($x += 1) ;
}
main::foo:
UNOP (0xeb9978)
op_next 0
op_sibling 0
op_ppaddr PL_ppaddr[OP_LEAVESUB]
op_type 175
op_flags 4
op_private 65
op_first 0xeab7a0
LISTOP (0xeab7a0)
op_next 0xeb9978
op_sibling 0
op_ppaddr PL_ppaddr[OP_LINESEQ]
op_type 181
op_flags 12
op_private 0
op_first 0xeab7e8
op_last 0xeb9a20
COP (0xeab7e8)
op_next 0xeab890
op_sibling 0xeab848
op_ppaddr PL_ppaddr[OP_NEXTSTATE]
op_type 182
op_flags 1
op_private 0 0
BINOP (0xeab848)
op_next 0xeb99c0
op_sibling 0xeb99c0
op_ppaddr PL_ppaddr[OP_SASSIGN]
op_type 37
op_flags 69
op_private 2
op_first 0xeab890
op_last 0xeab8d0
SVOP (0xeab890)
op_next 0xeab8d0
op_sibling 0xeab8d0
op_ppaddr PL_ppaddr[OP_CONST]
op_type 5
op_flags 2
op_private 0
op_sv 0xea3c40
OP (0xeab8d0)
op_next 0xeab848
op_sibling 0
op_ppaddr PL_ppaddr[OP_PADSV]
op_type 9
op_flags 178
op_private 128
COP (0xeb99c0)
op_next 0xeab768
op_sibling 0xeb9a20
op_ppaddr PL_ppaddr[OP_NEXTSTATE]
op_type 182
op_flags 1
op_private 0 0
BINOP (0xeb9a20)
op_next 0xeb9978
op_sibling 0
op_ppaddr PL_ppaddr[OP_ADD]
op_type 63
op_flags 70
op_private 2
op_first 0xeab768
op_last 0xeb9a68
OP (0xeab768)
op_next 0xeb9a68
op_sibling 0xeb9a68
op_ppaddr PL_ppaddr[OP_PADSV]
op_type 9
op_flags 50
op_private 0
SVOP (0xeb9a68)
op_next 0xeb9a20
op_sibling 0
op_ppaddr PL_ppaddr[OP_CONST]
op_type 5
op_flags 2
op_private 0
op_sv 0xea3c10
B::Concise::compile(CODE(0xea3c70))
UNOP (0xeb9978)
op_next 0
op_sibling 0
op_ppaddr PL_ppaddr[OP_LEAVESUB]
op_type 175
op_flags 4
op_private 65
op_first 0xeab7a0
LISTOP (0xeab7a0)
op_next 0xeb9978
op_sibling 0
op_ppaddr PL_ppaddr[OP_LINESEQ]
op_type 181
op_flags 12
op_private 0
op_first 0xeab7e8
op_last 0xeb9a20
COP (0xeab7e8)
op_next 0xeab890
op_sibling 0xeab848
op_ppaddr PL_ppaddr[OP_NEXTSTATE]
op_type 182
op_flags 1
op_private 0 0
BINOP (0xeab848)
op_next 0xeb99c0
op_sibling 0xeb99c0
op_ppaddr PL_ppaddr[OP_SASSIGN]
op_type 37
op_flags 69
op_private 2
op_first 0xeab890
op_last 0xeab8d0
SVOP (0xeab890)
op_next 0xeab8d0
op_sibling 0xeab8d0
op_ppaddr PL_ppaddr[OP_CONST]
op_type 5
op_flags 2
op_private 0
op_sv 0xea3c40
OP (0xeab8d0)
op_next 0xeab848
op_sibling 0
op_ppaddr PL_ppaddr[OP_PADSV]
op_type 9
op_flags 178
op_private 128
COP (0xeb99c0)
op_next 0xeab768
op_sibling 0xeb9a20
op_ppaddr PL_ppaddr[OP_NEXTSTATE]
op_type 182
op_flags 1
op_private 0 0
BINOP (0xeb9a20)
op_next 0xeb9978
op_sibling 0
op_ppaddr PL_ppaddr[OP_ADD]
op_type 63
op_flags 70
op_private 2
op_first 0xeab768
op_last 0xeb9a68
OP (0xeab768)
op_next 0xeb9a68
op_sibling 0xeb9a68
op_ppaddr PL_ppaddr[OP_PADSV]
op_type 9
op_flags 50
op_private 0
SVOP (0xeb9a68)
op_next 0xeb9a20
op_sibling 0
op_ppaddr PL_ppaddr[OP_CONST]
op_type 5
op_flags 2
op_private 0
op_sv 0xea3c10
最后,作为鼓励人们在这里提供帮助的方式,如果这个问题得到解决,该解决方案可能会出现在 Perl 调试器中 Devel::Trepan 并允许您可靠地知道在调试器中停止时您的确切位置.
注意:已编辑以使问题更清楚。
svref_2object
returns 一个对象,允许您从传递给 svref_2object
的参数引用的结构中提取信息。
您正在打印该对象的地址(一个标量被祝福到 class B::CV
)。
use B qw( );
sub foo { }
my $cv = B::svref_2object(\&foo);
printf "%x\n", \&foo; # Numification of 1st ref to &foo.
printf "%x\n", \&foo; # Numification of 2nd ref to &foo.
printf "%x\n", $cv; # Numification of ref to B::CV object.
printf "%x\n", $cv->object_2svref(); # Numification of 3rd ref to &foo.
printf "%x\n", $$cv; # Address of struct referenced by svref_2object's arg (Undocumented)
引用 numify 到它们引用的地址,所以我们得到:
3c5eaf8
3c5eaf8
3c5e1b0
3c5eaf8
3c5eaf8
ikegami 隐藏在评论中的回答建议让我发现了我在第一个提出的解决方案中的概念缺陷:在 B::Deparse 中,一个词法数组变量存储 OP 和这些是指向实际代码 OP 结构的隐式指针。使用未记录的 $$
获取标量隐式指向的基础地址以提供正确的地址。所以在我的B::Deparse::lineseq猴子补丁代码中,改变:
push @exprs, sprintf("# op: 0x%x\n%s ", $op, $text);
至:
push @exprs, sprintf("# op: 0x%x\n%s ", $$op, $text);
^^
给我一个地址,我可以用它来匹配结果。
不过,要使它可用还有一些工作要做,所以如果有任何其他方法或建议,我很乐意听取他们的意见。
Devel::Trepan 0.70 版现在在其 deparse
命令中使用上述代码并适当修改,以便能够显示多个语句中的哪一个将是 运行.