代码之家  ›  专栏  ›  技术社区  ›  rocky

如何将op地址转换为正确的B::op类型?

  •  3
  • rocky  · 技术社区  · 6 年前

    在运行的Perl程序中,如果我有一个Op地址(通过 B::Concise Devel::Callsite 或者通过神秘的其他方式)有没有一种简单的方法将其转换成正确的B::OP类型,而不是遍历操作码树?

    为了让这一点更清楚,这里有一些代码:

    use Devel::Callsite;
    use B::Concise qw(set_style);
    use B;
    
    sub testing
    {
        sub foo { callsite() };
        my $op_addr =  foo;
        printf "Op address is 0x%x\n", $op_addr;
    
    
        # I can get OPs by walking and looking for $op_addr,
        # but I don't want to do that.
        my $walker = B::Concise::compile('-terse', '-src', \&testing);
        B::Concise::walk_output(\my $buf);
        $walker->();   # walks and renders into $buf;
        print $buf;
    }
    
    testing();
    

    $ perl /tmp/foo.pl
    Op address is 0x2026940
    B::Concise::compile(CODE(0x1f32b18))
    UNOP (0x1f40fd0) leavesub [1] 
        LISTOP (0x20aa870) lineseq 
    # 8:     my $op_addr =  foo;
             COP (0x1f7cd80) nextstate 
             BINOP (0x20aba80) sassign 
                UNOP (0x20ad200) entersub [2] 
                    UNOP (0x1f39b80) null [148] 
                        OP (0x1fd14f0) pushmark 
                        UNOP (0x1f397c0) null [17] 
                            SVOP (0x1f39890) gv  GV (0x1fa0968) *foo 
                OP (0x2026940) padsv [1]
                    ^^^^^^^^^^ 
    ....
    

    所以呢 0x2026940 B::OP 根据 this next() , sibling() name() 0x20aa870 那将是一个 LISTOP 另外还有一个 children() 方法。

    我加了B::简明只是为了说明发生了什么。实际上,我不想遍历操作树,因为我假设/希望地址实际上就是listop所在的位置。

    B::Op 我相信这是父类,但在那之后我想知道我们在讨论什么样的操作(UNOP,BINOP,LISTOP)。

    B: :操作 我们有一个 名称() 方法,所以我可以从中找出OP的子类。

    编辑: ikegami的解决方案现在是Devel::callsite1.0.1al版本的一部分,尽管它并不完全正确。

    1 回复  |  直到 6 年前
        1
  •  4
  •   ikegami Gilles Quénot    6 年前

    这复制了B的内部 make_op_object .

    use B qw( );
    
    use Inline C => <<'__EOS__';
    
        static const char * const opclassnames[] = {
            "B::NULL",
            "B::OP",
            "B::UNOP",
            "B::BINOP",
            "B::LOGOP",
            "B::LISTOP",
            "B::PMOP",
            "B::SVOP",
            "B::PADOP",
            "B::PVOP",
            "B::LOOP",
            "B::COP",
            "B::METHOP",
            "B::UNOP_AUX"
        };
    
        SV *make_op_object(IV o_addr) {
            const OP *o = INT2PTR(OP*, o_addr);
            SV *opsv = newSV(0);
            sv_setiv(newSVrv(opsv, opclassnames[op_class(o)]), o_addr);
            return opsv;
        }
    
    __EOS__
    

    示例用法:

    use Devel::Callsite qw( callsite );
    
    my $site = sub { return callsite() };
    my $addr = $site->();
    my $op = make_op_object($addr);
    say $op->name;
    
    推荐文章