Changeset 790 in svn


Ignore:
Timestamp:
2011-04-25T16:36:10+02:00 (4 years ago)
Author:
Xuefer
Message:

Decompiler: decompile switch

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Decompiler.class.php

    r789 r790  
    564564                }
    565565                echo $indent, str($op['php'], $indent), ";\n";
     566                $EX['lastBlock'] = 'basic';
    566567            }
    567568        }
     
    667668    {
    668669        $this->dasmBasicBlock($EX, $first, $last);
    669         // $this->dumpRange($EX, $first, $last);
     670        // $this->dumpRange($EX, $first, $last, $indent);
    670671        $this->outputPhp($EX, $first, $last, $indent);
    671672    }
     
    699700    function decompileComplexBlock(&$EX, $first, $last, $indent) // {{{
    700701    {
     702        $T = &$EX['Ts'];
    701703        $opcodes = &$EX['opcodes'];
    702704
    703705        $firstOp = &$opcodes[$first];
    704706        $lastOp = &$opcodes[$last];
     707
     708        if ($firstOp['opcode'] == XC_SWITCH_FREE && isset($T[$firstOp['op1']['var']])) {
     709            // TODO: merge this code to CASE code. use SWITCH_FREE to detect begin of switch by using $Ts if possible
     710            $this->beginComplexBlock($EX);
     711            echo $indent, 'switch (' . str($this->getOpVal($firstOp['op1'], $EX)) . ') {', PHP_EOL;
     712            echo $indent, '}', PHP_EOL;
     713            $this->endComplexBlock($EX);
     714            return;
     715        }
     716
     717        if (
     718            ($firstOp['opcode'] == XC_CASE
     719            || $firstOp['opcode'] == XC_JMP && !empty($firstOp['jmpouts']) && $opcodes[$firstOp['jmpouts'][0]]['opcode'] == XC_CASE
     720            )
     721             && !empty($lastOp['jmpouts'])
     722        ) {
     723            $cases = array();
     724            $caseNext = null;
     725            $caseDefault = null;
     726            $caseOp = null;
     727            for ($i = $first; $i <= $last; ++$i) {
     728                $op = $opcodes[$i];
     729                if ($op['opcode'] == XC_CASE) {
     730                    if (!isset($caseOp)) {
     731                        $caseOp = $op;
     732                    }
     733                    $jmpz = $opcodes[$i + 1];
     734                    assert('$jmpz["opcode"] == XC_JMPZ');
     735                    $caseNext = $jmpz['jmpouts'][0];
     736                    $i = $cases[$i] = $caseNext - 1;
     737                }
     738                else if ($op['opcode'] == XC_JMP) {
     739                    // default
     740                    if ($op['jmpouts'][0] >= $i) {
     741                        $caseNext = $op['jmpouts'][0];
     742                        $caseDefault = $i;
     743                        $i = $cases[$i] = $caseNext - 1;
     744                    }
     745                }
     746            }
     747
     748            $this->beginComplexBlock($EX);
     749
     750            echo $indent, 'switch (', str($this->getOpVal($caseOp['op1'], $EX, true, true), $EX), ') {', PHP_EOL;
     751            $caseIsOut = false;
     752            foreach ($cases as $caseFirst => $caseLast) {
     753                if ($caseIsOut && !empty($EX['lastBlock']) && empty($lastCaseFall)) {
     754                    echo PHP_EOL;
     755                }
     756                unset($EX['lastBlock']);
     757
     758                $caseOp = $opcodes[$caseFirst];
     759
     760                echo $indent;
     761                if ($caseOp['opcode'] == XC_CASE) {
     762                    echo 'case ';
     763                    echo str($this->getOpVal($caseOp['op2'], $EX), $EX);
     764                    echo ':', PHP_EOL;
     765
     766                    $this->removeJmpInfo($EX, $caseFirst);
     767                    ++$caseFirst;
     768
     769                    assert('$opcodes[$caseFirst]["opcode"] == XC_JMPZ');
     770                    $this->removeJmpInfo($EX, $caseFirst);
     771                    ++$caseFirst;
     772                }
     773                else {
     774                    echo 'default';
     775                    echo ':', PHP_EOL;
     776
     777                    assert('$opcodes[$caseFirst]["opcode"] == XC_JMP');
     778                    $this->removeJmpInfo($EX, $caseFirst);
     779                    ++$caseFirst;
     780                }
     781
     782                assert('$opcodes[$caseLast]["opcode"] == XC_JMP');
     783                $this->removeJmpInfo($EX, $caseLast);
     784                --$caseLast;
     785                switch ($opcodes[$caseLast]['opcode']) {
     786                case XC_BRK:
     787                case XC_CONT:
     788                case XC_GOTO:
     789                    $lastCaseFall = false;
     790                    break;
     791
     792                default:
     793                    $lastCaseFall = true;
     794                }
     795
     796                $this->recognizeAndDecompileClosedBlocks($EX, $caseFirst, $caseLast, $indent . INDENT);
     797                $caseIsOut = true;
     798            }
     799            echo $indent, '}', PHP_EOL;
     800
     801            $this->endComplexBlock($EX);
     802            return;
     803        }
    705804
    706805        if ($lastOp['opcode'] == XC_JMPNZ && !empty($lastOp['jmpouts'])
     
    788887                $blockLast = -1;
    789888                $i = $blockFirst;
     889                // $this->dumpRange($EX, $i, $last, $indent);
    790890                do {
     891                    $op = $opcodes[$i];
    791892                    if (!empty($op['jmpins'])) {
    792893                        // care about jumping from blocks behind, not before
     
    810911                    $this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent);
    811912                    $i = $starti = $blockLast + 1;
    812                 }
    813                 continue;
     913                    continue;
     914                }
    814915            }
    815916            ++$i;
     
    876977                break;
    877978            */
     979
     980            case XC_SWITCH_FREE:
     981                $op['jmpouts'] = array($i + 1);
     982                $opcodes[$i + 1]['jmpins'][] = $i;
     983                break;
     984
     985            case XC_CASE:
     986                // just to link together
     987                $op['jmpouts'] = array($i + 2);
     988                $opcodes[$i + 2]['jmpins'][] = $i;
     989                break;
    878990            }
    879991            /*
     
    9141026        $EX['uses'] = array();
    9151027
     1028        $first = 0;
     1029        $last = count($opcodes) - 1;
     1030
     1031        /* dump whole array
     1032        $this->dasmBasicBlock($EX, $first, $last);
     1033        for ($i = $first; $i <= $last; ++$i) {
     1034            echo $i, "\t", $this->dumpop($opcodes[$i], $EX);
     1035        }
     1036        // */
    9161037        // decompile in a tree way
    917         $this->recognizeAndDecompileClosedBlocks($EX, 0, count($opcodes) - 1, $EX['indent']);
     1038        $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $EX['indent']);
    9181039        return $EX;
    9191040    }
     
    16731794                    // }}}
    16741795                case XC_SWITCH_FREE: // {{{
    1675                     // unset($T[$op1['var']]);
    16761796                    break;
    16771797                    // }}}
     
    17501870                    // }}}
    17511871                case XC_CASE:
    1752                     $switchValue = $this->getOpVal($op1, $EX);
     1872                    // $switchValue = $this->getOpVal($op1, $EX);
    17531873                    $caseValue = $this->getOpVal($op2, $EX);
    1754                     $resvar = str($switchValue) . ' == ' . str($caseValue);
     1874                    $resvar = $caseValue;
    17551875                    break;
    17561876                case XC_RECV_INIT:
     
    19492069    }
    19502070    // }}}
    1951     function dumpRange(&$EX, $first, $last) // {{{
     2071    function dumpRange(&$EX, $first, $last, $indent = '') // {{{
    19522072    {
    19532073        for ($i = $first; $i <= $last; ++$i) {
    1954             echo $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
    1955         }
    1956         echo "==", PHP_EOL;
     2074            echo $indent, $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
     2075        }
     2076        echo $indent, "==", PHP_EOL;
    19572077    }
    19582078    // }}}
  • trunk/decompilesample.php

    r789 r790  
    302302}
    303303
    304 switch ($switch) {
     304switch ($normalSwitch) {
    305305case 'case1':
    306306    echo 'case1';
     307
     308    switch ($nestedSwitch) {
     309    case 1:
     310    }
     311
    307312    break;
    308313
     
    312317
    313318default:
     319    switch ($nestedSwitch) {
     320    case 1:
     321    }
     322
    314323    echo 'default';
    315324    break;
     325}
     326
     327switch ($switchWithoutDefault) {
     328case 'case1':
     329    echo 'case1';
     330    break;
     331
     332case 'case2':
     333    echo 'case2';
     334    break;
     335}
     336
     337switch ($switchWithMiddleDefault) {
     338case 'case1':
     339    echo 'case1';
     340    break;
     341
     342default:
     343    echo 'default';
     344    break;
     345
     346case 'case2':
     347    echo 'case2';
     348    break;
     349}
     350
     351switch ($switchWithInitialDefault) {
     352default:
     353    echo 'default';
     354    break;
     355
     356case 'case1':
     357    echo 'case1';
     358    break;
     359
     360case 'case2':
     361    echo 'case2';
     362    break;
     363}
     364
     365switch (emptySwitch()) {
     366}
     367
     368switch (emptySwitch()) {
     369default:
    316370}
    317371
Note: See TracChangeset for help on using the changeset viewer.