Changeset 787 in svn for trunk/Decompiler.class.php


Ignore:
Timestamp:
2011-04-25T11:46:09+02:00 (4 years ago)
Author:
Xuefer
Message:

decompile code branch

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/Decompiler.class.php

    r781 r787  
    522522    }
    523523    // }}}
    524     function outputPhp(&$opcodes, $opline, $last, $indent) // {{{
     524    function outputPhp(&$EX, $opline, $last, $indent) // {{{
    525525    {
    526526        $origindent = $indent;
    527527        $curticks = 0;
    528528        for ($i = $opline; $i <= $last; $i ++) {
    529             $op = $opcodes[$i];
     529            $op = $EX['opcodes'][$i];
     530            if (isset($op['gofrom'])) {
     531                echo 'label' . $i, ":\n";
     532            }
    530533            if (isset($op['php'])) {
    531534                $toticks = isset($op['ticks']) ? (int) str($op['ticks']) : 0;
     
    648651    }
    649652    // }}}
     653    function decompileBasicBlock(&$EX, $first, $last, $indent) // {{{
     654    {
     655        $this->dasmBasicBlock($EX, $first, $last);
     656        // $this->dumpRange($EX, $first, $last);
     657        $this->outputPhp($EX, $first, $last, $indent);
     658    }
     659    // }}}
     660    function removeJmpInfo(&$EX, $line) // {{{
     661    {
     662        $opcodes = &$EX['opcodes'];
     663        foreach ($opcodes[$line]['jmpouts'] as $jmpTo) {
     664            $jmpins = &$opcodes[$jmpTo]['jmpins'];
     665            $jmpins = array_flip($jmpins);
     666            unset($jmpins[$line]);
     667            $jmpins = array_keys($jmpins);
     668        }
     669        $opcodes[$line]['opcode'] = XC_NOP;
     670        unset($opcodes[$line]['jmpouts']);
     671    }
     672    // }}}
     673    function decompileComplexBlock(&$EX, $first, $last, $indent) // {{{
     674    {
     675        $opcodes = &$EX['opcodes'];
     676
     677        $firstOp = &$opcodes[$first];
     678        $lastOp = &$opcodes[$last];
     679
     680        if ($lastOp['opcode'] == XC_JMPNZ
     681         && $lastOp['jmpouts'][0] == $first) {
     682            $this->removeJmpInfo($EX, $last);
     683            echo $indent, 'do {', PHP_EOL;
     684            $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $indent . INDENT);
     685            echo $indent, '} while (', str($this->getOpVal($lastOp['op1'], $EX)), ');', PHP_EOL;
     686            return;
     687        }
     688
     689        $firstJmp = null;
     690        $firstJmpOp = null;
     691        for ($i = $first; $i <= $last; ++$i) {
     692            if (!empty($opcodes[$i]['jmpouts'])) {
     693                $firstJmp = $i;
     694                $firstJmpOp = &$opcodes[$firstJmp];
     695                break;
     696            }
     697        }
     698
     699        if (isset($firstJmpOp)
     700         && $firstJmpOp['opcode'] == XC_JMPZ
     701         && $lastOp['opcode'] == XC_JMP
     702         && $lastOp['jmpouts'][0] == $first) {
     703            $this->removeJmpInfo($EX, $firstJmp);
     704            $this->removeJmpInfo($EX, $last);
     705
     706            ob_start();
     707            $this->recognizeAndDecompileClosedBlocks($EX, $first, $last, $indent . INDENT);
     708            $code = ob_get_clean();
     709            echo $indent, 'while (', str($this->getOpVal($firstJmpOp['op1'], $EX)), ') {', PHP_EOL;
     710            echo $code;
     711            echo $indent, '}', PHP_EOL;
     712            return;
     713        }
     714
     715        $this->decompileBasicBlock($EX, $first, $last, $indent);
     716    }
     717    // }}}
     718    function recognizeAndDecompileClosedBlocks(&$EX, $first, $last, $indent) // {{{ decompile in a tree way
     719    {
     720        $opcodes = &$EX['opcodes'];
     721        $firstComplex = false;
     722
     723        $i = $starti = $first;
     724        while ($i <= $last) {
     725            $op = $opcodes[$i];
     726            if (!empty($op['jmpins']) || !empty($op['jmpouts'])) {
     727                $blockFirst = $i;
     728                $blockLast = -1;
     729                $i = $blockFirst;
     730                do {
     731                    if (!empty($op['jmpins'])) {
     732                        // care about jumping from blocks behind, not before
     733                        foreach ($op['jmpins'] as $oplineNumber) {
     734                            if ($oplineNumber <= $last && $blockLast < $oplineNumber) {
     735                                $blockLast = $oplineNumber;
     736                            }
     737                        }
     738                    }
     739                    if (!empty($op['jmpouts'])) {
     740                        $blockLast = max($blockLast, max($op['jmpouts']) - 1);
     741                    }
     742                    ++$i;
     743                } while ($i <= $blockLast);
     744                assert('$blockLast <= $last');
     745
     746                if ($blockLast >= $blockFirst) {
     747                    if ($blockFirst > $starti) {
     748                        $this->decompileBasicBlock($EX, $starti, $blockFirst - 1, $indent);
     749                    }
     750                    $this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent);
     751                    $i = $starti = $blockLast + 1;
     752                }
     753                continue;
     754            }
     755            ++$i;
     756        }
     757        if ($starti <= $last) {
     758            $this->decompileBasicBlock($EX, $starti, $last, $indent);
     759        }
     760    }
     761    // }}}
    650762    function &dop_array($op_array, $indent = '') // {{{
    651763    {
    652764        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
    653765        $opcodes = &$op_array['opcodes'];
    654         $EX['indent'] = '';
    655         // {{{ build jmp array
     766        // {{{ build jmpins/jmpouts to op_array
    656767        for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
    657768            $op = &$opcodes[$i];
    658             /*
    659             if ($op['opcode'] == XC_JMPZ) {
    660                 $this->dumpop($op, $EX);
    661                 var_dump($op);
    662             }
    663             continue;
    664             */
    665769            $op['line'] = $i;
    666770            switch ($op['opcode']) {
     
    671775
    672776            case XC_GOTO:
     777                $target = $op['op1']['var'];
     778                $op['goto'] = $target;
     779                $opcodes[$target]['gofrom'][] = $i;
     780                break;
     781
    673782            case XC_JMP:
    674783                $target = $op['op1']['var'];
     
    708817            */
    709818            }
     819            /*
     820            if (!empty($op['jmpouts']) || !empty($op['jmpins'])) {
     821                echo $i, "\t", xcache_get_opcode($op['opcode']), PHP_EOL;
     822            }
     823            // */
    710824        }
    711825        unset($op);
     
    740854        $EX['uses'] = array();
    741855
    742         for ($next = 0, $last = $EX['last'];
    743                 $loop = $this->outputCode($EX, $next, $last, $indent, true);
    744                 list($next, $last) = $loop) {
    745             // empty
    746         }
     856        // decompile in a tree way
     857        $this->recognizeAndDecompileClosedBlocks($EX, 0, count($opcodes) - 1, $EX['indent']);
    747858        return $EX;
    748859    }
     
    765876        }
    766877        $this->dasmBasicBlock($EX, $opline, $end);
    767         $this->outputPhp($EX['opcodes'], $opline, $end, $indent);
     878        $this->outputPhp($EX, $opline, $end, $indent);
    768879        // jmpout op
    769880        $op = &$EX['opcodes'][$end];
     
    833944                break;
    834945
    835             case XC_GOTO:
    836                 echo $indent, 'goto', ' line', $op['jmpouts'][0], ';', "\n";
    837                 break;
    838 
    839946            default:
    840947                echo $indent;
     
    8941001        $lastphpop = null;
    8951002
    896         for ($i = $opline, $ic = $last + 1; $i < $ic; $i ++) {
     1003        for ($i = $opline; $i <= $last; $i ++) {
    8971004            // {{{ prepair
    8981005            $op = &$opcodes[$i];
     
    13821489
    13831490                    for (;;) {
    1384                         if ($i + 1 < $ic
     1491                        if ($i + 1 <= $last
    13851492                         && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
    13861493                         && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
    13871494                            // continue
    13881495                        }
    1389                         else if ($i + 2 < $ic
     1496                        else if ($i + 2 <= $last
    13901497                         && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
    13911498                         && $opcodes[$i + 2]['op1']['var'] == $res['var']
     
    15921699                    break;
    15931700                case XC_GOTO:
     1701                    $resvar = 'goto label' . $op['op1']['var'];
     1702                    $istmpres = false;
     1703                    break;
     1704
    15941705                case XC_JMP: // {{{
    15951706                    $op['cond'] = null;
     
    17951906        }
    17961907        echo PHP_EOL;
     1908    }
     1909    // }}}
     1910    function dumpRange(&$EX, $first, $last) // {{{
     1911    {
     1912        for ($i = $first; $i <= $last; ++$i) {
     1913            echo $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);
     1914        }
     1915        echo "==", PHP_EOL;
    17971916    }
    17981917    // }}}
Note: See TracChangeset for help on using the changeset viewer.