Browse Source

Disassembler: can now recover compile time constant

git-svn-id: svn://svn.lighttpd.net/xcache/trunk@1302 c26eb9a1-5813-0410-bd6c-c2e55f420ca7
3.1
Xuefer 8 years ago
parent
commit
beb0ee22d1
  1. 74
      lib/Decompiler.class.php
  2. 11
      mod_disassembler/sample.php

74
lib/Decompiler.class.php

@ -25,6 +25,12 @@ function str($code, $indent = '') // {{{
return (string) $code;
}
// }}}
function unsetArray(&$array, $name) // {{{
{
unset($array[$name]);
}
// }}}
function foldToCode($src, $indent = '') // {{{ wrap or rewrap anything to Decompiler_Code
{
if (is_array($indent)) {
@ -47,7 +53,7 @@ function foldToCode($src, $indent = '') // {{{ wrap or rewrap anything to Decomp
return $src;
}
// }}}
function value($value) // {{{
function value($value, &$EX) // {{{
{
$spec = xcache_get_special_value($value);
if (isset($spec)) {
@ -62,10 +68,15 @@ function value($value) // {{{
// use as is
}
else if (is_array($value)) {
$value = new Decompiler_ConstArray($value);
$value = new Decompiler_ConstArray($value, $EX);
}
else {
$value = new Decompiler_Value($value);
if (isset($EX['value2constant'][$value])) {
$value = new Decompiler_Code($EX['value2constant'][$value]);
}
else {
$value = new Decompiler_Value($value);
}
}
return $value;
}
@ -440,11 +451,11 @@ class Decompiler_Array extends Decompiler_Value // {{{
// }}}
class Decompiler_ConstArray extends Decompiler_Array // {{{
{
function Decompiler_ConstArray($array)
function Decompiler_ConstArray($array, &$EX)
{
$elements = array();
foreach ($array as $key => $value) {
$elements[] = array(value($key), value($value));
$elements[] = array(value($key, $EX), value($value, $EX));
}
$this->value = $elements;
}
@ -465,6 +476,9 @@ class Decompiler
{
public $namespace;
public $namespaceDecided;
public $activeClass;
public $activeMethod;
public $activeFunction;
function Decompiler()
{
@ -612,7 +626,7 @@ class Decompiler
{
switch ($op['op_type']) {
case XC_IS_CONST:
return value($op['constant']);
return value($op['constant'], $EX);
case XC_IS_VAR:
case XC_IS_TMP_VAR:
@ -1344,6 +1358,16 @@ class Decompiler
$EX['recvs'] = array();
$EX['uses'] = array();
$EX['lastBlock'] = null;
$EX['value2constant'] = array();
if (isset($this->activeClass)) {
$EX['value2constant'][$this->activeClass] = '__CLASS__';
}
if (isset($this->activeMethod)) {
$EX['value2constant'][$this->activeMethod] = '__METHOD__';
}
if (isset($this->activeFunction)) {
$EX['value2constant'][$this->activeFunction] = '__FUNCTION__';
}
/* dump whole array
$this->keepTs = true;
@ -1362,8 +1386,9 @@ class Decompiler
$T = &$EX['Ts'];
$opcodes = &$EX['opcodes'];
$lastphpop = null;
$currentSourceLine = null;
for ($i = $range[0]; $i <= $range[1]; $i ++) {
for ($i = $range[0]; $i <= $range[1]; $i ++, unsetArray($EX['value2constant'], $currentSourceLine)) {
// {{{ prepair
$op = &$opcodes[$i];
$opc = $op['opcode'];
@ -1376,6 +1401,8 @@ class Decompiler
$op2 = $op['op2'];
$res = $op['result'];
$ext = $op['extended_value'];
$currentSourceLine = $op['line'];
$EX['value2constant'][$currentSourceLine] = '__LINE__';
$opname = xcache_get_opcode($opc);
@ -1440,10 +1467,7 @@ class Decompiler
$istmpres = true;
}
else {
$class = $this->getOpVal($op2, $EX);
if (isset($op2['constant'])) {
$class = $this->stripNamespace(unquoteName($class));
}
$class = isset($op2['constant']) ? $op2['constant'] : $this->getOpVal($op2, $EX);
}
$resvar = $class;
break;
@ -1475,8 +1499,7 @@ class Decompiler
$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) {
$class = $this->getOpVal($op2, $EX);
$rvalue = unquoteName(str($class)) . '::$' . unquoteName($rvalue, $EX);
$rvalue = $this->stripNamespace($op2['constant']) . '::$' . unquoteName($rvalue, $EX);
}
else if ($opc != XC_UNSET_VAR) {
$name = unquoteName($rvalue, $EX);
@ -1625,7 +1648,7 @@ class Decompiler
if (isset($statics[$name])) {
$var = $statics[$name];
$resvar .= ' = ';
$resvar .= str(value($var), $EX);
$resvar .= str(value($var, $EX), $EX);
}
unset($statics);
break 2;
@ -1673,8 +1696,7 @@ class Decompiler
}
$fetchtype = defined('ZEND_FETCH_TYPE_MASK') ? ($ext & ZEND_FETCH_TYPE_MASK) : $op2['EA.type'];
if ($fetchtype == ZEND_FETCH_STATIC_MEMBER) {
$class = $this->getOpVal($op2, $EX);
$rvalue = unquoteName(str($class)) . '::' . unquoteName($rvalue, $EX);
$rvalue = $this->stripNamespace($op2['constant']) . '::' . unquoteName($rvalue, $EX);
}
}
else if ($opc == XC_ISSET_ISEMPTY) {
@ -1739,7 +1761,7 @@ class Decompiler
$EX['called_scope'] = null;
}
$EX['fbc'] = $this->getOpVal($op2, $EX);
$EX['fbc'] = isset($op2['constant']) ? $op2['constant'] : $this->getOpVal($op2, $EX);
if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
$EX['fbc'] = '__construct';
}
@ -1845,7 +1867,9 @@ class Decompiler
unset($fetchop, $addop);
$i += 2;
}
$this->activeClass = $class['name'];
$this->dclass($class, $EX['indent']);
$this->activeClass = null;
echo "\n";
unset($class);
break;
@ -1861,7 +1885,7 @@ class Decompiler
$op2val = $this->getOpVal($op2, $EX);
switch ($opc) {
case XC_ADD_CHAR:
$op2val = value(chr(str($op2val)));
$op2val = value(chr(str($op2val)), $EX);
break;
case XC_ADD_STRING:
break;
@ -2023,7 +2047,7 @@ class Decompiler
$offset = isset($op1['var']) ? $op1['var'] : $op1['constant'];
$lvalue = $this->getOpVal($op['result'], $EX);
if ($opc == XC_RECV_INIT) {
$default = value($op['op2']['constant']);
$default = value($op['op2']['constant'], $EX);
}
else {
$default = null;
@ -2430,7 +2454,7 @@ class Decompiler
foreach ($class[$type] as $name => $v) {
echo $newindent;
echo $prefix, $name, ' = ';
echo str(value($v), $newindent);
echo str(value($v, $EX), $newindent);
echo ";\n";
}
}
@ -2501,7 +2525,7 @@ class Decompiler
}
if (isset($value)) {
echo ' = ';
echo str(value($value), $newindent);
echo str(value($value, $EX), $newindent);
}
echo ";\n";
}
@ -2548,7 +2572,11 @@ class Decompiler
break;
}
}
$this->activeMethod = $this->activeClass . '::' . $opa['function_name'];
$this->activeFunction = $opa['function_name'];
$this->dfunction($func, $newindent, $decorations, $isInterface || $isAbstractMethod);
$this->activeFunction = null;
$this->activeMethod = null;
if ($opa['function_name'] == 'Decompiler') {
//exit;
}
@ -2590,14 +2618,18 @@ class Decompiler
echo "<?". "php\n\n";
foreach ($this->dc['class_table'] as $key => $class) {
if ($key{0} != "\0") {
$this->activeClass = $class['name'];
$this->dclass($class);
$this->activeClass = null;
echo "\n";
}
}
foreach ($this->dc['function_table'] as $key => $func) {
if ($key{0} != "\0") {
$this->activeFunction = $key;
$this->dfunction($func);
$this->activeFunction = null;
echo "\n";
}
}

11
mod_disassembler/sample.php

@ -36,7 +36,7 @@ abstract class ClassName
{
echo CONST_VALUE;
echo ClassName::CONST_VALUE;
unset(t::$classProp1);
unset(ClassName::$classProp1);
unset($obj->objProp);
unset($this->thisProp);
unset($array['index']->valueProp);
@ -45,6 +45,9 @@ abstract class ClassName
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;
@ -57,7 +60,7 @@ abstract class ClassName
abstract public function abastractMethod();
/** doc */
public function method(array $a = NULL, $b = NULL)
public function method($a = NULL, $b = NULL)
{
}
@ -109,6 +112,7 @@ final class Child extends ClassName implements IInterface
ClassName::__construct();
echo __CLASS__;
echo __METHOD__;
echo __FUNCTION__;
throw new Exception();
$this->methodCall();
}
@ -121,10 +125,12 @@ final class Child extends ClassName implements IInterface
static public function __callStatic($name, $args)
{
parent::__callStatic($name, $args);
}
public function __toString()
{
parent::__toString();
}
public function __set($name, $value)
@ -168,6 +174,7 @@ if ($late) {
function lateBindingFunction($arg)
{
echo 'lateFunction';
return new lateBindingFunction();
}
}

Loading…
Cancel
Save