Browse Source

Decompiler: decompile switch

git-svn-id: svn://svn.lighttpd.net/xcache/trunk@790 c26eb9a1-5813-0410-bd6c-c2e55f420ca7
3.0
Xuefer 11 years ago
parent
commit
bcf7d47fea
  1. 138
      Decompiler.class.php
  2. 56
      decompilesample.php

138
Decompiler.class.php

@ -563,6 +563,7 @@ class Decompiler
echo PHP_EOL;
}
echo $indent, str($op['php'], $indent), ";\n";
$EX['lastBlock'] = 'basic';
}
}
if ($curticks) {
@ -666,7 +667,7 @@ class Decompiler
function decompileBasicBlock(&$EX, $first, $last, $indent) // {{{
{
$this->dasmBasicBlock($EX, $first, $last);
// $this->dumpRange($EX, $first, $last);
// $this->dumpRange($EX, $first, $last, $indent);
$this->outputPhp($EX, $first, $last, $indent);
}
// }}}
@ -698,11 +699,109 @@ class Decompiler
// }}}
function decompileComplexBlock(&$EX, $first, $last, $indent) // {{{
{
$T = &$EX['Ts'];
$opcodes = &$EX['opcodes'];
$firstOp = &$opcodes[$first];
$lastOp = &$opcodes[$last];
if ($firstOp['opcode'] == XC_SWITCH_FREE && isset($T[$firstOp['op1']['var']])) {
// TODO: merge this code to CASE code. use SWITCH_FREE to detect begin of switch by using $Ts if possible
$this->beginComplexBlock($EX);
echo $indent, 'switch (' . str($this->getOpVal($firstOp['op1'], $EX)) . ') {', PHP_EOL;
echo $indent, '}', PHP_EOL;
$this->endComplexBlock($EX);
return;
}
if (
($firstOp['opcode'] == XC_CASE
|| $firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0]]['opcode'] == XC_CASE
)
&& !empty($lastOp['jmpouts'])
) {
$cases = array();
$caseNext = null;
$caseDefault = null;
$caseOp = null;
for ($i = $first; $i <= $last; ++$i) {
$op = $opcodes[$i];
if ($op['opcode'] == XC_CASE) {
if (!isset($caseOp)) {
$caseOp = $op;
}
$jmpz = $opcodes[$i + 1];
assert('$jmpz["opcode"] == XC_JMPZ');
$caseNext = $jmpz['jmpouts'][0];
$i = $cases[$i] = $caseNext - 1;
}
else if ($op['opcode'] == XC_JMP) {
// default
if ($op['jmpouts'][0] >= $i) {
$caseNext = $op['jmpouts'][0];
$caseDefault = $i;
$i = $cases[$i] = $caseNext - 1;
}
}
}
$this->beginComplexBlock($EX);
echo $indent, 'switch (', str($this->getOpVal($caseOp['op1'], $EX, true, true), $EX), ') {', PHP_EOL;
$caseIsOut = false;
foreach ($cases as $caseFirst => $caseLast) {
if ($caseIsOut && !empty($EX['lastBlock']) && empty($lastCaseFall)) {
echo PHP_EOL;
}
unset($EX['lastBlock']);
$caseOp = $opcodes[$caseFirst];
echo $indent;
if ($caseOp['opcode'] == XC_CASE) {
echo 'case ';
echo str($this->getOpVal($caseOp['op2'], $EX), $EX);
echo ':', PHP_EOL;
$this->removeJmpInfo($EX, $caseFirst);
++$caseFirst;
assert('$opcodes[$caseFirst]["opcode"] == XC_JMPZ');
$this->removeJmpInfo($EX, $caseFirst);
++$caseFirst;
}
else {
echo 'default';
echo ':', PHP_EOL;
assert('$opcodes[$caseFirst]["opcode"] == XC_JMP');
$this->removeJmpInfo($EX, $caseFirst);
++$caseFirst;
}
assert('$opcodes[$caseLast]["opcode"] == XC_JMP');
$this->removeJmpInfo($EX, $caseLast);
--$caseLast;
switch ($opcodes[$caseLast]['opcode']) {
case XC_BRK:
case XC_CONT:
case XC_GOTO:
$lastCaseFall = false;
break;
default:
$lastCaseFall = true;
}
$this->recognizeAndDecompileClosedBlocks($EX, $caseFirst, $caseLast, $indent . INDENT);
$caseIsOut = true;
}
echo $indent, '}', PHP_EOL;
$this->endComplexBlock($EX);
return;
}
if ($lastOp['opcode'] == XC_JMPNZ && !empty($lastOp['jmpouts'])
&& $lastOp['jmpouts'][0] == $first) {
$this->removeJmpInfo($EX, $last);
@ -787,7 +886,9 @@ class Decompiler
$blockFirst = $i;
$blockLast = -1;
$i = $blockFirst;
// $this->dumpRange($EX, $i, $last, $indent);
do {
$op = $opcodes[$i];
if (!empty($op['jmpins'])) {
// care about jumping from blocks behind, not before
foreach ($op['jmpins'] as $oplineNumber) {
@ -809,8 +910,8 @@ class Decompiler
}
$this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent);
$i = $starti = $blockLast + 1;
continue;
}
continue;
}
++$i;
}
@ -875,6 +976,17 @@ class Decompiler
$op['jmpouts'] = array();
break;
*/
case XC_SWITCH_FREE:
$op['jmpouts'] = array($i + 1);
$opcodes[$i + 1]['jmpins'][] = $i;
break;
case XC_CASE:
// just to link together
$op['jmpouts'] = array($i + 2);
$opcodes[$i + 2]['jmpins'][] = $i;
break;
}
/*
if (!empty($op['jmpouts']) || !empty($op['jmpins'])) {
@ -913,8 +1025,17 @@ class Decompiler
$EX['recvs'] = array();
$EX['uses'] = array();
$first = 0;
$last = count($opcodes) - 1;
/* dump whole array
$this->dasmBasicBlock($EX, $first, $last);
for ($i = $first; $i <= $last; ++$i) {
echo $i, "\t", $this->dumpop($opcodes[$i], $EX);
}
// */
// decompile in a tree way
$this->recognizeAndDecompileClosedBlocks($EX, 0, count($opcodes) - 1, $EX['indent']);
$this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $EX['indent']);
return $EX;
}
// }}}
@ -1672,7 +1793,6 @@ class Decompiler
break;
// }}}
case XC_SWITCH_FREE: // {{{
// unset($T[$op1['var']]);
break;
// }}}
case XC_FREE: // {{{
@ -1749,9 +1869,9 @@ class Decompiler
break;
// }}}
case XC_CASE:
$switchValue = $this->getOpVal($op1, $EX);
// $switchValue = $this->getOpVal($op1, $EX);
$caseValue = $this->getOpVal($op2, $EX);
$resvar = str($switchValue) . ' == ' . str($caseValue);
$resvar = $caseValue;
break;
case XC_RECV_INIT:
case XC_RECV:
@ -1948,12 +2068,12 @@ class Decompiler
echo PHP_EOL;
}
// }}}
function dumpRange(&$EX, $first, $last) // {{{
function dumpRange(&$EX, $first, $last, $indent = '') // {{{
{
for ($i = $first; $i <= $last; ++$i) {
echo $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
echo $indent, $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
}
echo "==", PHP_EOL;
echo $indent, "==", PHP_EOL;
}
// }}}
function dargs(&$EX, $indent) // {{{

56
decompilesample.php

@ -301,18 +301,72 @@ foreach ($array as $key => $value) {
}
}
switch ($switch) {
switch ($normalSwitch) {
case 'case1':
echo 'case1';
switch ($nestedSwitch) {
case 1:
}
break;
case 'case2':
echo 'case2';
break;
default:
switch ($nestedSwitch) {
case 1:
}
echo 'default';
break;
}
switch ($switchWithoutDefault) {
case 'case1':
echo 'case1';
break;
case 'case2':
echo 'case2';
break;
}
switch ($switchWithMiddleDefault) {
case 'case1':
echo 'case1';
break;
default:
echo 'default';
break;
case 'case2':
echo 'case2';
break;
}
switch ($switchWithInitialDefault) {
default:
echo 'default';
break;
case 'case1':
echo 'case1';
break;
case 'case2':
echo 'case2';
break;
}
switch (emptySwitch()) {
}
switch (emptySwitch()) {
default:
}
declare (ticks=1) {

Loading…
Cancel
Save