On Wed, Dec 30, 2015 at 8:55 PM, Derick Rethans <der...@php.net> wrote:

> Hi!
>
> While investigating an issue with Xdebug and fast_call/fast_ret, I
> noticed that the opcodes "associated" with the "finally" statement, are
> rolled up in the previous line.
>
> The code:
>
>   1 <?php
>   2 function extractFile()
>   3 {
>   4     try {
>   5         echo "try\n";
>   6     } catch (Catch1 $e) {
>   7         echo "catch1\n";
>   8     } catch (Catch2 $e) {
>   9         echo "catch2\n";
>  10     } finally {
>  11         echo "finally\n";
>  12     }
>  13     echo "end\n";
>  14 }
>  15
>  16 extractFile();
>  17 ?>
>
>
> Produces:
>
> line     #* E I O op                           fetch          ext  return
> operands
>
> -------------------------------------------------------------------------------------
>    5     0  E >   ECHO
>  'try%0A'
>          1      > JMP
> ->7
>    6     2  E > > CATCH
> 'Catch1', !0, ->5
>    7     3    >   ECHO
>  'catch1%0A'
>          4      > JMP
> ->7
>    8     5  E > > CATCH
> 'Catch2', !0
>    9     6    >   ECHO
>  'catch2%0A'
>          7    > > FAST_CALL
> ->9
>          8*       JMP
> ->11
>   11     9    >   ECHO
>  'finally%0A'
>         10      > FAST_RET
>   13    11    >   ECHO
>  'end%0A'
>   14    12      > RETURN
>  null
>
>
> The FAST_CALL/JMP instructions should really be linked to line 10. Not
> doing so produces confusing results while doing code coverage, where it now
> shows that the "echo catch2\n" on line 9 is executed. This is of course not
> the case, but the linking of FAST_CALL and JMP to line 9 makes it look like
> this. Is it possible to change this so thta the FAST_CALL and JMP are
> linked
> to line 10 instead?
>

Yeah, you're right. Should be fixed with
https://github.com/php/php-src/commit/b3afeeabefc4777ec4797a7e2c3688e9e20be4cc
.


> And secondly, I am struggeling with where FAST_CALL and FAST_RET can jump
> to.
> Right now, I have:
>
>
> https://github.com/derickr/vld/commit/9cf01bba0a1aeef6a261c6c85b238552215a9f0b#diff-286f7620179e1ee0a20e81523d91ff24R1036
>
> +#if PHP_VERSION_ID >= 50500
> +       } else if (opcode.opcode == ZEND_FAST_CALL) {
> +#if PHP_VERSION_ID >= 70000
> +               *jmp1 = VLD_ZNODE_JMP_LINE(opcode.op1, position,
> base_address);
> +#else
> +               *jmp1 = ((long) VLD_ZNODE_ELEM(opcode.op1, jmp_addr) -
> (long) base_address) / sizeof(zend_op);
> +#endif
> +               if (opcode.extended_value) {
> +                       *jmp2 = VLD_ZNODE_ELEM(opcode.op2, opline_num);
> +               }
> +               return 1;
> +       } else if (opcode.opcode == ZEND_FAST_RET) {
> +               *jmp1 = position + 1;
> +               if (opcode.extended_value) {
> +                       *jmp2 = VLD_ZNODE_ELEM(opcode.op2, opline_num);
> +               }
> +               return 1;
> +#endif
>
> Which seems to work, although I am unsure about the "+ 1" for FAST_RET.
>

For PHP 7 only: FAST_CALL always jumps to op1. op2 is not a jmp addr, it's
a try_catch_array offset. For FAST_RET there are no jump addresses encoded
in the opline. It will either jump back to one past the invoking FAST_CALL
(of which there may be multiple), or (if finally is executed due to an
uncaught exception) it will jump back to the next applicable catch or
finally or leave the function.

Nikita


> I also never see anything for opcode.extended_value, and hence the *jmp is
> unset. This also returns dumping opcodes with this bit of code (code
> slightly
> lifted from dbg):
>
>
> https://github.com/derickr/vld/commit/9cf01bba0a1aeef6a261c6c85b238552215a9f0b#diff-286f7620179e1ee0a20e81523d91ff24R684
>
> +#if PHP_VERSION_ID >= 50600
> +       switch (op.opcode) {
> +               case ZEND_FAST_RET:
> +                       if (op.extended_value == ZEND_FAST_RET_TO_FINALLY)
> {
> +                               fetch_type = "to_finally";
> +                       } else if (op.extended_value ==
> ZEND_FAST_RET_TO_CATCH) {
> +                               fetch_type = "to_catch";
> +                       }
> +                       break;
> +               case ZEND_FAST_CALL:
> +                       if (op.extended_value ==
> ZEND_FAST_CALL_FROM_FINALLY)
> {
> +                               fetch_type = "from_finally";
> +                       }
> +                       break;
> +       }
> +#endif
> +
>
> Any hints?
>
> cheers,
> Derick
> --
> http://derickrethans.nl | http://xdebug.org
> Like Xdebug? Consider a donation: http://xdebug.org/donate.php
> twitter: @derickr and @xdebug
> Posted with an email client that doesn't mangle email: alpine
>

Reply via email to