Browse Source

Decompiler, disassembler: fix catch for different PHP version; fetch hack is not necessary for PHP5.4+; update for ?: operator

git-svn-id: svn://svn.lighttpd.net/xcache/trunk@1306 c26eb9a1-5813-0410-bd6c-c2e55f420ca7
3.1
Xuefer 8 years ago
parent
commit
b6c66205a7
  1. 67
      lib/Decompiler.class.php
  2. 50
      mod_disassembler/sample.php
  3. 4
      xcache/xc_opcode_spec.c
  4. 8
      xcache/xc_opcode_spec_def.h

67
lib/Decompiler.class.php

@ -566,6 +566,7 @@ class Decompiler
XC_ASSIGN => "=",
XC_ASSIGN_REF => "= &",
XC_JMP_SET => "?:",
XC_JMP_SET_VAR => "?:",
XC_JMPZ_EX => "&&",
XC_JMPNZ_EX => "||",
);
@ -595,6 +596,7 @@ class Decompiler
// }}}
function stripNamespace($name) // {{{
{
$name = str($name);
$len = strlen($this->namespace) + 1;
if (substr($name, 0, $len) == $this->namespace . '\\') {
return substr($name, $len);
@ -663,6 +665,9 @@ class Decompiler
case XC_IS_VAR:
case XC_IS_TMP_VAR:
$T = &$EX['Ts'];
if (!isset($T[$op['var']])) {
printBacktrace();
}
$ret = $T[$op['var']];
if ($free && empty($this->keepTs)) {
unset($T[$op['var']]);
@ -833,12 +838,12 @@ class Decompiler
return false;
}
// }}}
// {{{ ?: excluding JMP_SET
// {{{ ?: excluding JMP_SET/JMP_SET_VAR
if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
&& $range[1] >= $range[0] + 3
&& $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN
&& ($opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN || $opcodes[$firstOp['jmpouts'][0] - 2]['opcode'] == XC_QM_ASSIGN_VAR)
&& $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP && $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $range[1] + 1
&& $lastOp['opcode'] == XC_QM_ASSIGN
&& ($lastOp['opcode'] == XC_QM_ASSIGN || $lastOp['opcode'] == XC_QM_ASSIGN_VAR)
) {
$trueRange = array($range[0] + 1, $firstOp['jmpouts'][0] - 2);
$falseRange = array($firstOp['jmpouts'][0], $range[1]);
@ -1013,9 +1018,9 @@ class Decompiler
$this->dasmBasicBlock($EX, array($catchFirst, $catchOpLine));
$catchOp = &$opcodes[$catchOpLine];
echo $indent, 'catch ('
, isset($catchOp['op1']['constant']) ? $catchOp['op1']['constant'] : str($this->getOpVal($catchOp['op1'], $EX))
, $this->stripNamespace(isset($catchOp['op1']['constant']) ? $catchOp['op1']['constant'] : str($this->getOpVal($catchOp['op1'], $EX)))
, ' '
, str($this->getOpVal($catchOp['op2'], $EX))
, isset($catchOp['op2']['constant']) ? '$' . $catchOp['op2']['constant'] : str($this->getOpVal($catchOp['op2'], $EX))
, ") {", PHP_EOL;
unset($catchOp);
@ -1314,6 +1319,7 @@ class Decompiler
case XC_JMPZ_EX:
case XC_JMPNZ_EX:
// case XC_JMP_SET:
// case XC_JMP_SET_VAR:
// case XC_FE_RESET:
case XC_FE_FETCH:
// case XC_JMP_NO_CTOR:
@ -1474,7 +1480,7 @@ class Decompiler
array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
$EX['object'] = (int) $res['var'];
$EX['called_scope'] = null;
$EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
$EX['fbc'] = 'new ' . $this->stripNamespace($this->getOpVal($op1, $EX));
break;
// }}}
case XC_THROW: // {{{
@ -1489,7 +1495,7 @@ class Decompiler
break;
// }}}
case XC_INSTANCEOF: // {{{
$resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
$resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . $this->stripNamespace($this->getOpVal($op2, $EX));
break;
// }}}
case XC_FETCH_CLASS: // {{{
@ -1536,27 +1542,37 @@ class Decompiler
case XC_FETCH_FUNC_ARG:
case XC_FETCH_UNSET:
case XC_FETCH_IS:
case XC_UNSET_VAR:
$rvalue = $this->getOpVal($op1, $EX);
$fetchtype = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type'];
if ($fetchtype == ZEND_FETCH_STATIC_MEMBER) {
$rvalue = $this->stripNamespace($op2['constant']) . '::$' . unquoteName($rvalue, $EX);
}
else if ($opc != XC_UNSET_VAR) {
$name = unquoteName($rvalue, $EX);
$fetchType = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type'];
$name = isset($op1['constant']) ? $op1['constant'] : unquoteName($this->getOpVal($op1, $EX), $EX);
if ($fetchType == ZEND_FETCH_STATIC_MEMBER) {
$class = isset($op2['constant']) ? $op2['constant'] : $this->getOpVal($op2, $EX);
$rvalue = $this->stripNamespace($class) . '::$' . $name;
}
else {
$rvalue = $this->getOpVal($op1, $EX);
$globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
$rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
$rvalue = new Decompiler_Fetch($rvalue, $fetchType, $globalname);
}
if ($opc == XC_UNSET_VAR) {
$op['php'] = "unset(" . str($rvalue, $EX) . ")";
$lastphpop = &$op;
}
else if ($res['op_type'] != XC_IS_UNUSED) {
if ($res['op_type'] != XC_IS_UNUSED) {
$resvar = $rvalue;
}
break;
// }}}
case XC_UNSET_VAR: // {{{
$fetchType = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type'];
if ($fetchType == ZEND_FETCH_STATIC_MEMBER) {
$class = isset($op2['constant']) ? $op2['constant'] /* PHP5.3- */ : $this->getOpVal($op2, $EX);
$rvalue = $this->stripNamespace($class) . '::$' . $op1['constant'];
}
else {
$rvalue = $this->getOpVal($op1, $EX);
}
$op['php'] = "unset(" . str($rvalue, $EX) . ")";
$lastphpop = &$op;
break;
// }}}
// {{{ case FETCH_DIM_*
case XC_FETCH_DIM_TMP_VAR:
case XC_FETCH_DIM_R:
@ -1737,7 +1753,8 @@ class Decompiler
}
$fetchtype = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type'];
if ($fetchtype == ZEND_FETCH_STATIC_MEMBER) {
$rvalue = $this->stripNamespace($op2['constant']) . '::' . unquoteName($rvalue, $EX);
$class = isset($op2['constant']) ? $op2['constant'] : $this->getOpVal($op2, $EX);
$rvalue = $this->stripNamespace($class) . '::' . unquoteName($rvalue, $EX);
}
}
else if ($opc == XC_ISSET_ISEMPTY) {
@ -2049,9 +2066,6 @@ class Decompiler
// }}}
case XC_JMP_NO_CTOR:
break;
case XC_JMP_SET: // ?:
$resvar = new Decompiler_Binop($this, $this->getOpVal($op1, $EX), XC_JMP_SET, null);
break;
case XC_JMPZ_EX: // and
case XC_JMPNZ_EX: // or
$resvar = $this->getOpVal($op1, $EX);
@ -2468,7 +2482,7 @@ class Decompiler
}
echo $isInterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
if ($class['parent']) {
echo ' extends ', $class['parent'];
echo ' extends ', $this->stripNamespace($class['parent']);
}
/* TODO */
if (!empty($class['interfaces'])) {
@ -2856,6 +2870,7 @@ foreach (array (
'XC_ISSET_ISEMPTY' => -1,
'XC_JMP_NO_CTOR' => -1,
'XC_JMP_SET' => -1,
'XC_JMP_SET_VAR' => -1,
'XC_QM_ASSIGN_VAR' => -1,
'XC_UNSET_DIM_OBJ' => -1,
) as $k => $v) {

50
mod_disassembler/sample.php

@ -36,24 +36,49 @@ abstract class ClassName
{
echo CONST_VALUE;
echo ClassName::CONST_VALUE;
unset(ClassName::$classProp1);
empty(ClassName::$classProp);
isset(ClassName::$classProp);
unset(ClassName::$classProp);
ClassName::$classProp = 1;
echo ClassName::$classProp;
empty($obj->objProp);
isset($obj->objProp);
unset($obj->objProp);
$obj->objProp = 1;
echo $obj->objProp;
empty($this->thisProp);
isset($this->thisProp);
unset($this->thisProp);
$this->thisProp = 1;
echo $this->thisProp;
unset($array['index']->valueProp);
unset($obj->array['index']);
unset($this->array['index']);
isset($GLOBALS['a']);
empty($GLOBALS['a']);
unset($GLOBALS['a']);
isset(ClassName::$a);
empty(ClassName::$a);
unset(ClassName::$a);
echo $GLOBALS['a'];
$obj->objProp = 1;
$this->thisProp = 1;
$array['index']->valueProp = 1;
empty($_GET['get']);
isset($_GET['get']);
unset($_GET['get']);
$_GET['get'] = 1;
echo $_GET['get'];
isset($GLOBALS['global']);
empty($GLOBALS['global']);
unset($GLOBALS['global']);
$GLOBALS['global'] = 1;
echo $GLOBALS['global'];
empty($array['index']);
isset($array['index']);
unset($array['index']);
$array['index'] = 1;
$array[1] = 1;
echo $array['index'];
empty($array['index']->indexProp);
isset($array['index']->indexProp);
unset($array['index']->indexProp);
$array['index']->indexProp = 1;
echo $array['index']->indexProp;
empty($GLOBALS['var']->indexProp);
isset($GLOBALS['var']->indexProp);
unset($GLOBALS['var']->indexProp);
$GLOBALS['var']->indexProp = 1;
echo $GLOBALS['var']->indexProp;
}
/** doc */
@ -437,6 +462,7 @@ $obj::__construct();
$a = $b ?: $d;
$a = ($b ?: $d) + $c;
$a = f1() ?: f2();
$a = C::f1() ?: C::f2();
$a = ($b ? $c : $d);
$a = ($b ? $c : $d) + $c;
$a = (f1() ? f3() : f2());

4
xcache/xc_opcode_spec.c

@ -5,6 +5,10 @@
/* {{{ opcode_spec */
#define OPSPEC(ext, op1, op2, res) { OPSPEC_##ext, OPSPEC_##op1, OPSPEC_##op2, OPSPEC_##res },
#define OPSPEC_VAR_2 OPSPEC_STD
#ifdef ZEND_ENGINE_2_4
#undef OPSPEC_FETCH
#define OPSPEC_FETCH OPSPEC_STD
#endif
#include "xc_opcode_spec_def.h"
zend_uchar xc_get_opcode_spec_count()

8
xcache/xc_opcode_spec_def.h

@ -79,11 +79,7 @@ static const xc_opcode_spec_t xc_opcode_spec[] = {
OPSPEC( UNUSED, STD, INCLUDE, VAR) /* 73 INCLUDE_OR_EVAL */
#ifdef ZEND_ENGINE_2_1
/* php 5.1 and up */
# ifdef ZEND_ENGINE_2_4
OPSPEC( UNUSED, STD, STD, UNUSED) /* 74 UNSET_VAR */
# else
OPSPEC( UNUSED, STD, FETCH, UNUSED) /* 74 UNSET_VAR */
# endif
OPSPEC( STD, STD, STD, UNUSED) /* 75 UNSET_DIM */
OPSPEC( STD, STD, STD, UNUSED) /* 76 UNSET_OBJ */
OPSPEC( BIT, STD, OPLINE, VAR) /* 77 FE_RESET */
@ -153,11 +149,7 @@ static const xc_opcode_spec_t xc_opcode_spec[] = {
#else
OPSPEC( UNUSED, UCLASS, STD, UNUSED) /* 113 INIT_STATIC_METHOD_CALL */
#endif
#ifdef ZEND_ENGINE_2_4
OPSPEC( ISSET, STD, STD, TMP) /* 114 ISSET_ISEMPTY_VAR */
#else
OPSPEC( ISSET, STD, FETCH, TMP) /* 114 ISSET_ISEMPTY_VAR */
#endif
OPSPEC( ISSET, STD, STD, TMP) /* 115 ISSET_ISEMPTY_DIM_OBJ */
OPSPEC( UNUSED, CLASS, STD, UNUSED) /* 116 IMPORT_FUNCTION */

Loading…
Cancel
Save