Changeset 795 in svn for trunk


Ignore:
Timestamp:
2011-04-26T05:28:21Z (4 years ago)
Author:
Xuefer
Message:

Decompiler: decompile try/catch

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Decompiler.class.php

    r791 r795  
    615615    function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
    616616    {
    617         for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
     617        $last = count($opcodes) - 1;
     618        for ($i = 0; $i <= $last; $i ++) {
    618619            if (function_exists('xcache_get_fixed_opcode')) {
    619620                $opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
     
    706707        $lastOp = &$opcodes[$last];
    707708
     709        // {{{ try/catch
     710        if (!empty($firstOp['jmpins']) && !empty($opcodes[$firstOp['jmpins'][0]]['isCatchBegin'])) {
     711            $catchBlocks = array();
     712            $catchFirst = $firstOp['jmpins'][0];
     713
     714            $tryFirst = $first;
     715            $tryLast = $catchFirst - 1;
     716
     717            // search for XC_CATCH
     718            $this->removeJmpInfo($EX, $catchFirst);
     719            for ($i = $catchFirst; $i <= $last; ) {
     720                if ($opcodes[$i]['opcode'] == XC_CATCH) {
     721                    $catchOpLine = $i;
     722                    $this->removeJmpInfo($EX, $catchOpLine);
     723
     724                    $catchNext = $opcodes[$catchOpLine]['extended_value'];
     725                    $catchBodyLast = $catchNext - 1;
     726                    if ($opcodes[$catchBodyLast]['opcode'] == XC_JMP) {
     727                        --$catchBodyLast;
     728                    }
     729
     730                    $catchBlocks[$catchFirst] = array($catchOpLine, $catchBodyLast);
     731
     732                    $i = $catchFirst = $catchNext;
     733                }
     734                else {
     735                    ++$i;
     736                }
     737            }
     738
     739            if ($opcodes[$tryLast]['opcode'] == XC_JMP) {
     740                --$tryLast;
     741            }
     742
     743            $this->beginComplexBlock($EX);
     744            echo $indent, 'try {', PHP_EOL;
     745            $this->recognizeAndDecompileClosedBlocks($EX, $tryFirst, $tryLast, $indent . INDENT);
     746            echo $indent, '}', PHP_EOL;
     747            foreach ($catchBlocks as $catchFirst => $catchInfo) {
     748                list($catchOpLine, $catchBodyLast) = $catchInfo;
     749                $catchBodyFirst = $catchOpLine + 1;
     750                $this->recognizeAndDecompileClosedBlocks($EX, $catchFirst, $catchOpLine, $indent);
     751                $catchOp = &$opcodes[$catchOpLine];
     752                echo $indent, 'catch (', str($this->getOpVal($catchOp['op1'], $EX)), ' ', str($this->getOpVal($catchOp['op2'], $EX)), ') {', PHP_EOL;
     753                unset($catchOp);
     754
     755                $EX['lastBlock'] = null;
     756                $this->recognizeAndDecompileClosedBlocks($EX, $catchBodyFirst, $catchBodyLast, $indent . INDENT);
     757                echo $indent, '}', PHP_EOL;
     758            }
     759            $this->endComplexBlock($EX);
     760            return;
     761        }
     762        // }}}
     763
    708764        if ($firstOp['opcode'] == XC_SWITCH_FREE && isset($T[$firstOp['op1']['var']])) {
    709765            // TODO: merge this code to CASE code. use SWITCH_FREE to detect begin of switch by using $Ts if possible
     
    722778        ) {
    723779            $cases = array();
    724             $caseNext = null;
    725780            $caseDefault = null;
    726781            $caseOp = null;
    727             for ($i = $first; $i <= $last; ++$i) {
     782            for ($i = $first; $i <= $last; ) {
    728783                $op = $opcodes[$i];
    729784                if ($op['opcode'] == XC_CASE) {
     
    734789                    assert('$jmpz["opcode"] == XC_JMPZ');
    735790                    $caseNext = $jmpz['jmpouts'][0];
    736                     $i = $cases[$i] = $caseNext - 1;
    737                 }
    738                 else if ($op['opcode'] == XC_JMP) {
     791                    $cases[$i] = $caseNext - 1;
     792                    $i = $caseNext;
     793                }
     794                else if ($op['opcode'] == XC_JMP && $op['jmpouts'][0] >= $i) {
    739795                    // default
    740                     if ($op['jmpouts'][0] >= $i) {
    741                         $caseNext = $op['jmpouts'][0];
    742                         $caseDefault = $i;
    743                         $i = $cases[$i] = $caseNext - 1;
    744                     }
     796                    $caseNext = $op['jmpouts'][0];
     797                    $caseDefault = $i;
     798                    $cases[$i] = $caseNext - 1;
     799                    $i = $caseNext;
     800                }
     801                else {
     802                    ++$i;
    745803                }
    746804            }
     
    881939
    882940        $starti = $first;
    883         for ($i = $starti; $i <= $last; ++$i) {
    884             $op = $opcodes[$i];
    885             if (!empty($op['jmpins']) || !empty($op['jmpouts'])) {
     941        for ($i = $starti; $i <= $last; ) {
     942            if (!empty($opcodes[$i]['jmpins']) || !empty($opcodes[$i]['jmpouts'])) {
    886943                $blockFirst = $i;
    887944                $blockLast = -1;
     
    902959                    ++$j;
    903960                } while ($j <= $blockLast);
    904                 assert('$blockLast <= $last');
     961                if (!assert('$blockLast <= $last')) {
     962                    var_dump($blockLast, $last);
     963                }
    905964
    906965                if ($blockLast >= $blockFirst) {
     
    910969                    $this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent);
    911970                    $starti = $blockLast + 1;
    912                     $i = $starti - 1;
    913                     continue;
    914                 }
     971                    $i = $starti;
     972                }
     973                else {
     974                    ++$i;
     975                }
     976            }
     977            else {
     978                ++$i;
    915979            }
    916980        }
     
    924988        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
    925989        $opcodes = &$op_array['opcodes'];
     990        $last = count($opcodes) - 1;
    926991        // {{{ build jmpins/jmpouts to op_array
    927         for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
     992        for ($i = 0; $i <= $last; $i ++) {
    928993            $op = &$opcodes[$i];
    929994            $op['line'] = $i;
     
    9871052                $opcodes[$i + 2]['jmpins'][] = $i;
    9881053                break;
     1054
     1055            case XC_CATCH:
     1056                $catchNext = $op['extended_value'];
     1057                $op['jmpouts'] = array($catchNext);
     1058                $opcodes[$catchNext]['jmpins'][] = $i;
     1059                break;
    9891060            }
    9901061            /*
     
    9951066        }
    9961067        unset($op);
     1068        if ($op_array['try_catch_array']) {
     1069            foreach ($op_array['try_catch_array'] as $try_catch_element) {
     1070                $catch_op = $try_catch_element['catch_op'];
     1071                $try_op = $try_catch_element['try_op'];
     1072                $opcodes[$try_op]['jmpins'][] = $catch_op;
     1073                $opcodes[$catch_op]['jmpouts'][] = $try_op;
     1074                $opcodes[$catch_op]['isCatchBegin'] = true;
     1075            }
     1076        }
    9971077        // }}}
    9981078        // build semi-basic blocks
    9991079        $nextbbs = array();
    10001080        $starti = 0;
    1001         for ($i = 1, $cnt = count($opcodes); $i < $cnt; $i ++) {
     1081        for ($i = 1; $i <= $last; $i ++) {
    10021082            if (isset($opcodes[$i]['jmpins'])
    10031083             || isset($opcodes[$i - 1]['jmpouts'])) {
     
    10061086            }
    10071087        }
    1008         $nextbbs[$starti] = $cnt;
     1088        $nextbbs[$starti] = $last + 1;
    10091089
    10101090        $EX = array();
     
    12391319                    // }}}
    12401320                case XC_CATCH: // {{{
    1241                     $resvar = 'catch (' . str($this->getOpVal($op1, $EX)) . ' ' . str($this->getOpVal($op2, $EX)) . ')';
    12421321                    break;
    12431322                    // }}}
     
    20222101    function dumpop($op, &$EX) // {{{
    20232102    {
     2103        assert('isset($op)');
    20242104        $op1 = $op['op1'];
    20252105        $op2 = $op['op2'];
     
    20532133                if ($k == 'result') {
    20542134                    var_dump($op);
     2135                    assert(0);
    20552136                    exit;
    2056                     assert(0);
    20572137                }
    20582138                else {
     
    20622142        }
    20632143        $d[';'] = $op['extended_value'];
     2144        if (!empty($op['jmpouts'])) {
     2145            $d['>>'] = implode(',', $op['jmpouts']);
     2146        }
     2147        if (!empty($op['jmpins'])) {
     2148            $d['<<'] = implode(',', $op['jmpins']);
     2149        }
    20642150
    20652151        foreach ($d as $k => $v) {
  • trunk/decompilesample.php

    r793 r795  
    257257$a = $b || $c;
    258258
    259 try {
    260     echo 'outer try 1';
     259do {
    261260    try {
    262         echo 'inner try';
    263     }
    264     catch (InnerException $e) {
     261        echo 'outer try 1';
     262
     263        try {
     264            echo 'inner try';
     265        }
     266        catch (InnerException $e) {
     267            echo $e;
     268        }
     269
     270        echo 'outer try 2';
     271    }
     272    catch (OuterException $e) {
    265273        echo $e;
    266274    }
    267     echo 'outer try 2';
    268 }
    269 catch (OuterException $e) {
    270     echo $e;
    271 }
     275} while (0);
    272276
    273277if (if_()) {
Note: See TracChangeset for help on using the changeset viewer.