Browse Source

Decompiler: remove unused code

master
Xuefer 6 years ago
parent
commit
c5ca1ac9a4
  1. 159
      lib/Decompiler.class.php

159
lib/Decompiler.class.php

@ -857,25 +857,25 @@ class Decompiler
{
$opcodes = &$EX['opcodes'];
$firstOp = &$opcodes[$range[0]];
return $firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_JMP
&& !empty($opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'])
&& $opcodes[$firstOp['jmpouts'][0] - 1]['jmpouts'][0] == $range[1] + 1;
return $firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmptos']) && $opcodes[$firstOp['jmptos'][0] - 1]['opcode'] == XC_JMP
&& !empty($opcodes[$firstOp['jmptos'][0] - 1]['jmptos'])
&& $opcodes[$firstOp['jmptos'][0] - 1]['jmptos'][0] == $range[1] + 1;
}
// }}}
function removeJmpInfo(&$EX, $line) // {{{
{
$opcodes = &$EX['opcodes'];
if (!isset($opcodes[$line]['jmpouts'])) {
if (!isset($opcodes[$line]['jmptos'])) {
printBacktrace();
}
foreach ($opcodes[$line]['jmpouts'] as $jmpTo) {
$jmpins = &$opcodes[$jmpTo]['jmpins'];
$jmpins = array_flip($jmpins);
unset($jmpins[$line]);
$jmpins = array_keys($jmpins);
foreach ($opcodes[$line]['jmptos'] as $jmpTo) {
$jmpfroms = &$opcodes[$jmpTo]['jmpfroms'];
$jmpfroms = array_flip($jmpfroms);
unset($jmpfroms[$line]);
$jmpfroms = array_keys($jmpfroms);
}
// $opcodes[$line]['opcode'] = XC_NOP;
unset($opcodes[$line]['jmpouts']);
unset($opcodes[$line]['jmptos']);
}
// }}}
function beginScope(&$EX, $doIndent = true) // {{{
@ -915,8 +915,8 @@ class Decompiler
$lastOp = &$opcodes[$range[1]];
// {{{ && || and or
if (($firstOp['opcode'] == XC_JMPZ_EX || $firstOp['opcode'] == XC_JMPNZ_EX) && !empty($firstOp['jmpouts'])
&& $firstOp['jmpouts'][0] == $range[1] + 1
if (($firstOp['opcode'] == XC_JMPZ_EX || $firstOp['opcode'] == XC_JMPNZ_EX) && !empty($firstOp['jmptos'])
&& $firstOp['jmptos'][0] == $range[1] + 1
&& $lastOp['opcode'] == XC_BOOL
&& $firstOp['opcode']['result']['var'] == $lastOp['opcode']['result']['var']
) {
@ -933,14 +933,14 @@ class Decompiler
}
// }}}
// {{{ ?: excluding JMP_SET/JMP_SET_VAR
if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmptos'])
&& $range[1] >= $range[0] + 3
&& ($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
&& ($opcodes[$firstOp['jmptos'][0] - 2]['opcode'] == XC_QM_ASSIGN || $opcodes[$firstOp['jmptos'][0] - 2]['opcode'] == XC_QM_ASSIGN_VAR)
&& $opcodes[$firstOp['jmptos'][0] - 1]['opcode'] == XC_JMP && $opcodes[$firstOp['jmptos'][0] - 1]['jmptos'][0] == $range[1] + 1
&& ($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]);
$trueRange = array($range[0] + 1, $firstOp['jmptos'][0] - 2);
$falseRange = array($firstOp['jmptos'][0], $range[1]);
$this->removeJmpInfo($EX, $range[0]);
$condition = $this->getOpVal($firstOp['op1'], $EX);
@ -953,7 +953,7 @@ class Decompiler
}
// }}}
// {{{ goto (TODO: recognize BRK which is translated to JMP by optimizer)
if ($firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $firstOp['jmpouts'][0] == $range[1] + 1) {
if ($firstOp['opcode'] == XC_JMP && !empty($firstOp['jmptos']) && $firstOp['jmptos'][0] == $range[1] + 1) {
$this->removeJmpInfo($EX, $range[0]);
assert(XC_GOTO != -1);
$firstOp['opcode'] = XC_GOTO;
@ -966,11 +966,11 @@ class Decompiler
}
// }}}
// {{{ for
if (!empty($firstOp['jmpins']) && $opcodes[$firstOp['jmpins'][0]]['opcode'] == XC_JMP
&& $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmpouts']) && $lastOp['jmpouts'][0] <= $firstOp['jmpins'][0]
&& !empty($opcodes[$range[1] + 1]['jmpins']) && $opcodes[$opcodes[$range[1] + 1]['jmpins'][0]]['opcode'] == XC_JMPZNZ
if (!empty($firstOp['jmpfroms']) && $opcodes[$firstOp['jmpfroms'][0]]['opcode'] == XC_JMP
&& $lastOp['opcode'] == XC_JMP && !empty($lastOp['jmptos']) && $lastOp['jmptos'][0] <= $firstOp['jmpfroms'][0]
&& !empty($opcodes[$range[1] + 1]['jmpfroms']) && $opcodes[$opcodes[$range[1] + 1]['jmpfroms'][0]]['opcode'] == XC_JMPZNZ
) {
$nextRange = array($lastOp['jmpouts'][0], $firstOp['jmpins'][0]);
$nextRange = array($lastOp['jmptos'][0], $firstOp['jmpfroms'][0]);
$conditionRange = array($range[0], $nextRange[0] - 1);
$this->removeJmpInfo($EX, $conditionRange[1]);
$bodyRange = array($nextRange[1], $range[1]);
@ -1016,7 +1016,7 @@ class Decompiler
$this->beginComplexBlock($EX);
$isElseIf = false;
do {
$ifRange = array($range[0], $opcodes[$range[0]]['jmpouts'][0] - 1);
$ifRange = array($range[0], $opcodes[$range[0]]['jmptos'][0] - 1);
$this->removeJmpInfo($EX, $ifRange[0]);
$this->removeJmpInfo($EX, $ifRange[1]);
$condition = $this->getOpVal($opcodes[$ifRange[0]]['op1'], $EX);
@ -1033,7 +1033,7 @@ class Decompiler
$range[0] = $ifRange[1] + 1;
for ($i = $ifRange[1] + 1; $i <= $range[1]; ++$i) {
// find first jmpout
if (!empty($opcodes[$i]['jmpouts'])) {
if (!empty($opcodes[$i]['jmptos'])) {
if ($this->isIfCondition($EX, array($i, $range[1]))) {
$this->dasmBasicBlock($EX, array($range[0], $i));
$range[0] = $i;
@ -1054,9 +1054,9 @@ class Decompiler
$this->endComplexBlock($EX);
return;
}
if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmpouts'])
&& $firstOp['jmpouts'][0] - 1 == $range[1]
&& ($opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_RETURN || $opcodes[$firstOp['jmpouts'][0] - 1]['opcode'] == XC_GENERATOR_RETURN)) {
if ($firstOp['opcode'] == XC_JMPZ && !empty($firstOp['jmptos'])
&& $firstOp['jmptos'][0] - 1 == $range[1]
&& ($opcodes[$firstOp['jmptos'][0] - 1]['opcode'] == XC_RETURN || $opcodes[$firstOp['jmptos'][0] - 1]['opcode'] == XC_GENERATOR_RETURN)) {
$this->beginComplexBlock($EX);
$this->removeJmpInfo($EX, $range[0]);
$condition = $this->getOpVal($opcodes[$range[0]]['op1'], $EX);
@ -1071,9 +1071,9 @@ class Decompiler
}
// }}}
// {{{ try/catch
if (!empty($firstOp['jmpins']) && !empty($opcodes[$firstOp['jmpins'][0]]['isCatchBegin'])) {
if (!empty($firstOp['jmpfroms']) && !empty($opcodes[$firstOp['jmpfroms'][0]]['isCatchBegin'])) {
$catchBlocks = array();
$catchFirst = $firstOp['jmpins'][0];
$catchFirst = $firstOp['jmpfroms'][0];
$tryRange = array($range[0], $catchFirst - 1);
@ -1135,11 +1135,8 @@ class Decompiler
}
// }}}
// {{{ switch/case
if (
($firstOp['opcode'] == XC_CASE
|| $firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0]]['opcode'] == XC_CASE
)
&& !empty($lastOp['jmpouts'])
if ($firstOp['opcode'] == XC_CASE && !empty($lastOp['jmptos'])
|| $firstOp['opcode'] == XC_JMP && !empty($firstOp['jmptos']) && $opcodes[$firstOp['jmptos'][0]]['opcode'] == XC_CASE && !empty($lastOp['jmptos'])
) {
$cases = array();
$caseDefault = null;
@ -1152,13 +1149,13 @@ class Decompiler
}
$jmpz = $opcodes[$i + 1];
assert('$jmpz["opcode"] == XC_JMPZ');
$caseNext = $jmpz['jmpouts'][0];
$caseNext = $jmpz['jmptos'][0];
$cases[$i] = $caseNext - 1;
$i = $caseNext;
}
else if ($op['opcode'] == XC_JMP && $op['jmpouts'][0] >= $i) {
else if ($op['opcode'] == XC_JMP && $op['jmptos'][0] >= $i) {
// default
$caseNext = $op['jmpouts'][0];
$caseNext = $op['jmptos'][0];
$caseDefault = $i;
$cases[$i] = $caseNext - 1;
$i = $caseNext;
@ -1227,8 +1224,8 @@ class Decompiler
}
// }}}
// {{{ do/while
if ($lastOp['opcode'] == XC_JMPNZ && !empty($lastOp['jmpouts'])
&& $lastOp['jmpouts'][0] == $range[0]) {
if ($lastOp['opcode'] == XC_JMPNZ && !empty($lastOp['jmptos'])
&& $lastOp['jmptos'][0] == $range[0]) {
$this->removeJmpInfo($EX, $range[1]);
$this->beginComplexBlock($EX);
@ -1247,7 +1244,7 @@ class Decompiler
$firstJmp = -1;
$firstJmpOp = null;
for ($i = $range[0]; $i <= $range[1]; ++$i) {
if (!empty($opcodes[$i]['jmpouts'])) {
if (!empty($opcodes[$i]['jmptos'])) {
$firstJmp = $i;
$firstJmpOp = &$opcodes[$firstJmp];
break;
@ -1258,7 +1255,7 @@ class Decompiler
$lastJmp = -1;
$lastJmpOp = null;
for ($i = $range[1]; $i > $firstJmp; --$i) {
if (!empty($opcodes[$i]['jmpouts'])) {
if (!empty($opcodes[$i]['jmptos'])) {
$lastJmp = $i;
$lastJmpOp = &$opcodes[$lastJmp];
break;
@ -1269,9 +1266,9 @@ class Decompiler
// {{{ while
if (isset($firstJmpOp)
&& $firstJmpOp['opcode'] == XC_JMPZ
&& $firstJmpOp['jmpouts'][0] > $range[1]
&& $firstJmpOp['jmptos'][0] > $range[1]
&& $lastOp['opcode'] == XC_JMP
&& !empty($lastOp['jmpouts']) && $lastOp['jmpouts'][0] == $range[0]) {
&& !empty($lastOp['jmptos']) && $lastOp['jmptos'][0] == $range[0]) {
$this->removeJmpInfo($EX, $firstJmp);
$this->removeJmpInfo($EX, $range[1]);
$this->beginComplexBlock($EX);
@ -1293,10 +1290,10 @@ class Decompiler
// {{{ foreach
if (isset($firstJmpOp)
&& $firstJmpOp['opcode'] == XC_FE_FETCH
&& !empty($firstJmpOp['jmpouts']) && $firstJmpOp['jmpouts'][0] > $lastJmp
&& !empty($firstJmpOp['jmptos']) && $firstJmpOp['jmptos'][0] > $lastJmp
&& isset($lastJmpOp)
&& $lastJmpOp['opcode'] == XC_JMP
&& !empty($lastJmpOp['jmpouts']) && $lastJmpOp['jmpouts'][0] == $firstJmp) {
&& !empty($lastJmpOp['jmptos']) && $lastJmpOp['jmptos'][0] == $firstJmp) {
$this->removeJmpInfo($EX, $firstJmp);
$this->removeJmpInfo($EX, $lastJmp);
$this->beginComplexBlock($EX);
@ -1330,22 +1327,22 @@ class Decompiler
$starti = $range[0];
for ($i = $starti; $i <= $range[1]; ) {
if (!empty($opcodes[$i]['jmpins']) || !empty($opcodes[$i]['jmpouts'])) {
if (!empty($opcodes[$i]['jmpfroms']) || !empty($opcodes[$i]['jmptos'])) {
$blockFirst = $i;
$blockLast = -1;
$j = $blockFirst;
do {
$op = $opcodes[$j];
if (!empty($op['jmpins'])) {
if (!empty($op['jmpfroms'])) {
// care about jumping from blocks behind, not before
foreach ($op['jmpins'] as $oplineNumber) {
foreach ($op['jmpfroms'] as $oplineNumber) {
if ($oplineNumber <= $range[1] && $blockLast < $oplineNumber) {
$blockLast = $oplineNumber;
}
}
}
if (!empty($op['jmpouts'])) {
$blockLast = max($blockLast, max($op['jmpouts']) - 1);
if (!empty($op['jmptos'])) {
$blockLast = max($blockLast, max($op['jmptos']) - 1);
}
++$j;
} while ($j <= $blockLast);
@ -1380,7 +1377,7 @@ class Decompiler
}
}
// }}}
function buildJmpInfo(&$op_array) // {{{ build jmpins/jmpouts to op_array
function buildJmpInfo(&$op_array) // {{{ build jmpfroms/jmptos to op_array
{
$opcodes = &$op_array['opcodes'];
$last = count($opcodes) - 1;
@ -1390,7 +1387,7 @@ class Decompiler
switch ($op['opcode']) {
case XC_CONT:
case XC_BRK:
$op['jmpouts'] = array();
$op['jmptos'] = array();
break;
case XC_GOTO:
@ -1409,8 +1406,8 @@ class Decompiler
fprintf(STDERR, "%d: internal error\n", __LINE__);
break;
}
$op['jmpouts'] = array($target);
$opcodes[$target]['jmpins'][] = $i;
$op['jmptos'] = array($target);
$opcodes[$target]['jmpfroms'][] = $i;
break;
case XC_JMPZNZ:
@ -1424,9 +1421,9 @@ class Decompiler
fprintf(STDERR, "%d: internal error\n", __LINE__);
break;
}
$op['jmpouts'] = array($jmpz, $jmpnz);
$opcodes[$jmpz]['jmpins'][] = $i;
$opcodes[$jmpnz]['jmpins'][] = $i;
$op['jmptos'] = array($jmpz, $jmpnz);
$opcodes[$jmpz]['jmpfroms'][] = $i;
$opcodes[$jmpnz]['jmpfroms'][] = $i;
break;
case XC_JMPZ:
@ -1443,31 +1440,31 @@ class Decompiler
fprintf(STDERR, "%d: internal error\n", __LINE__);
break;
}
$op['jmpouts'] = array($target);
$opcodes[$target]['jmpins'][] = $i;
$op['jmptos'] = array($target);
$opcodes[$target]['jmpfroms'][] = $i;
break;
/*
case XC_RETURN:
$op['jmpouts'] = array();
$op['jmptos'] = array();
break;
*/
case XC_CASE:
// just to link together
$op['jmpouts'] = array($i + 2);
$opcodes[$i + 2]['jmpins'][] = $i;
$op['jmptos'] = array($i + 2);
$opcodes[$i + 2]['jmpfroms'][] = $i;
break;
case XC_CATCH:
$catchNext = $op['extended_value'];
$catchBegin = $opcodes[$i - 1]['opcode'] == XC_FETCH_CLASS ? $i - 1 : $i;
$opcodes[$catchBegin]['jmpouts'] = array($catchNext);
$opcodes[$catchNext]['jmpins'][] = $catchBegin;
$opcodes[$catchBegin]['jmptos'] = array($catchNext);
$opcodes[$catchNext]['jmpfroms'][] = $catchBegin;
break;
}
/*
if (!empty($op['jmpouts']) || !empty($op['jmpins'])) {
if (!empty($op['jmptos']) || !empty($op['jmpfroms'])) {
echo $i, "\t", xcache_get_opcode($op['opcode']), PHP_EOL;
}
// */
@ -1482,8 +1479,8 @@ class Decompiler
$catch_op = $try_catch_element['catch_op'];
$try_op = $try_catch_element['try_op'];
do {
$opcodes[$try_op]['jmpins'][] = $catch_op;
$opcodes[$catch_op]['jmpouts'][] = $try_op;
$opcodes[$try_op]['jmpfroms'][] = $catch_op;
$opcodes[$catch_op]['jmptos'][] = $try_op;
if ($opcodes[$catch_op]['opcode'] == XC_CATCH) {
$catch_op = $opcodes[$catch_op]['extended_value'];
}
@ -1504,26 +1501,12 @@ class Decompiler
$this->buildJmpInfo($op_array);
$opcodes = &$op_array['opcodes'];
$last = count($opcodes) - 1;
// build semi-basic blocks
$nextbbs = array();
$starti = 0;
for ($i = 1; $i <= $last; $i++) {
if (isset($opcodes[$i]['jmpins'])
|| isset($opcodes[$i - 1]['jmpouts'])) {
$nextbbs[$starti] = $i;
$starti = $i;
}
}
$nextbbs[$starti] = $last + 1;
$EX = array();
$EX['Ts'] = array();
$EX['indent'] = $indent;
$EX['nextbbs'] = $nextbbs;
$EX['op_array'] = &$op_array;
$EX['opcodes'] = &$opcodes;
$EX['range'] = array(0, count($opcodes) - 1);
// func call
$EX['object'] = null;
$EX['called_scope'] = null;
@ -1560,7 +1543,8 @@ class Decompiler
}
// */
// decompile in a tree way
$this->recognizeAndDecompileClosedBlocks($EX, $EX['range'], $EX['indent']);
$range = array(0, count($opcodes) - 1);
$this->recognizeAndDecompileClosedBlocks($EX, $range);
return $EX;
}
// }}}
@ -2044,8 +2028,9 @@ class Decompiler
// possible missing tailing \0 (outside of the string)
$key = substr($key . ".", 0, strlen($key));
if (!isset($this->dc['class_table'][$key])) {
echo "class not found: ", $key, "\nexisting classes are:\n";
echo $EX['indent'], "/* class not found: ", $key, ", existing classes are:\n";
var_dump(array_keys($this->dc['class_table']));
echo "*/\n";
break;
}
$class = &$this->dc['class_table'][$key];
@ -2493,11 +2478,11 @@ class Decompiler
}
}
$d[';'] = $op['extended_value'];
if (!empty($op['jmpouts'])) {
$d['>>'] = implode(',', $op['jmpouts']);
if (!empty($op['jmptos'])) {
$d['>>'] = implode(',', $op['jmptos']);
}
if (!empty($op['jmpins'])) {
$d['<<'] = implode(',', $op['jmpins']);
if (!empty($op['jmpfroms'])) {
$d['<<'] = implode(',', $op['jmpfroms']);
}
foreach ($d as $k => $v) {

Loading…
Cancel
Save