Changeset 790


Ignore:
Timestamp:
2011-04-25T16:36:10+02:00 (3 years ago)
Author:
moo
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.