source: trunk/Decompiler.class.php @ 760

Last change on this file since 760 was 760, checked in by moo, 3 years ago

Decompiler: jmp_set/jmpz adjust

  • Property svn:eol-style set to native
File size: 55.0 KB
RevLine 
[1]1<?php
2
3define('INDENT', "\t");
4ini_set('error_reporting', E_ALL);
5
6function color($str, $color = 33)
7{
8    return "\x1B[{$color}m$str\x1B[0m";
9}
10
[737]11function str($code, $indent = '') // {{{
12{
[744]13    if (is_array($code)) {
14        $array = array();
15        foreach ($code as $key => $value) {
16            $array[$key] = str($value, $indent);
17        }
18        return $array;
19    }
[737]20    if (is_object($code)) {
[744]21        $code = foldToCode($code, $indent);
22        return $code->toCode($indent);
[737]23    }
24
25    return (string) $code;
26}
27// }}}
[744]28function foldToCode($src, $indent = '') // {{{ wrap or rewrap anything to Decompiler_Code
[1]29{
30    if (is_array($indent)) {
31        $indent = $indent['indent'];
32    }
33
[741]34    if (!is_object($src)) {
35        return new Decompiler_Code($src);
[1]36    }
37
[741]38    if (!method_exists($src, 'toCode')) {
39        var_dump($src);
40        exit('no toCode');
41    }
42    if (get_class($src) != 'Decompiler_Code') {
43        // rewrap it
44        $src = new Decompiler_Code($src->toCode($indent));
45    }
46
47    return $src;
[1]48}
49// }}}
50function value($value) // {{{
51{
52    $spec = xcache_get_special_value($value);
53    if (isset($spec)) {
54        $value = $spec;
55        if (!is_array($value)) {
56            // constant
57            return $value;
58        }
59    }
60
[737]61    if (is_a($value, 'Decompiler_Object')) {
[723]62        // use as is
63    }
64    else if (is_array($value)) {
[737]65        $value = new Decompiler_ConstArray($value);
[1]66    }
67    else {
[713]68        $value = new Decompiler_Value($value);
[1]69    }
70    return $value;
71}
72// }}}
[753]73function unquoteName_($str, $asProperty, $indent = '') // {{{
[749]74{
75    $str = str($str, $indent);
[753]76    if (preg_match("!^'[\\w_][\\w\\d_\\\\]*'\$!", $str)) {
77        return str_replace('\\\\', '\\', substr($str, 1, -1));
[749]78    }
[753]79    else if ($asProperty) {
[749]80        return "{" . $str . "}";
81    }
[753]82    else {
83        return $str;
84    }
[749]85}
86// }}}
[753]87function unquoteProperty($str, $indent = '') // {{{
88{
89    return unquoteName_($str, true, $indent);
90}
91// }}}
[749]92function unquoteName($str, $indent = '') // {{{
93{
[753]94    return unquoteName_($str, false, $indent);
[749]95}
96// }}}
[1]97class Decompiler_Object // {{{
98{
99}
100// }}}
101class Decompiler_Value extends Decompiler_Object // {{{
102{
103    var $value;
104
105    function Decompiler_Value($value = null)
106    {
107        $this->value = $value;
108    }
109
[732]110    function toCode($indent)
[1]111    {
[750]112        $code = var_export($this->value, true);
113        if (gettype($this->value) == 'string') {
114            switch ($this->value) {
115            case "\r":
116                return '"\\r"';
117            case "\n":
118                return '"\\n"';
119            case "\r\n":
120                return '"\\r\\n"';
121            }
122            $code = str_replace("\r\n", '\' . "\\r\\n" . \'', $code);
123            $code = str_replace("\r", '\' . "\\r" . \'', $code);
124            $code = str_replace("\n", '\' . "\\n" . \'', $code);
125        }
126        return $code;
[1]127    }
128}
129// }}}
130class Decompiler_Code extends Decompiler_Object // {{{
131{
132    var $src;
133
134    function Decompiler_Code($src)
135    {
[743]136        assert('isset($src)');
[1]137        $this->src = $src;
138    }
139
[732]140    function toCode($indent)
[1]141    {
[741]142        return $this->src;
[737]143    }
[1]144}
145// }}}
146class Decompiler_Binop extends Decompiler_Code // {{{
147{
148    var $opc;
149    var $op1;
150    var $op2;
151    var $parent;
[732]152    var $indent;
[1]153
154    function Decompiler_Binop($parent, $op1, $opc, $op2)
155    {
156        $this->parent = &$parent;
157        $this->opc = $opc;
158        $this->op1 = $op1;
159        $this->op2 = $op2;
160    }
161
[732]162    function toCode($indent)
[1]163    {
[757]164        $opstr = $this->parent->binops[$this->opc];
165
[744]166        $op1 = foldToCode($this->op1, $indent);
[1]167        if (is_a($this->op1, 'Decompiler_Binop') && $this->op1->opc != $this->opc) {
[757]168            $op1 = "(" . str($op1, $indent) . ")";
[1]169        }
[757]170        $op2 = foldToCode($this->op2, $indent);
171        if (is_a($this->op2, 'Decompiler_Binop') && $this->op2->opc != $this->opc && substr($opstr, -1) != '=') {
172            $op2 = "(" . str($op2, $indent) . ")";
[1]173        }
[757]174
175        if (str($op1) == '0' && ($this->opc == XC_ADD || $this->opc == XC_SUB)) {
176            return $opstr . str($op2, $indent);
177        }
178
179        return str($op1) . ' ' . $opstr . ' ' . str($op2);
[1]180    }
181}
182// }}}
183class Decompiler_Fetch extends Decompiler_Code // {{{
184{
185    var $src;
186    var $fetchType;
187
188    function Decompiler_Fetch($src, $type, $globalsrc)
189    {
190        $this->src = $src;
191        $this->fetchType = $type;
192        $this->globalsrc = $globalsrc;
193    }
194
[732]195    function toCode($indent)
[1]196    {
197        switch ($this->fetchType) {
198        case ZEND_FETCH_LOCAL:
199            return '$' . substr($this->src, 1, -1);
200        case ZEND_FETCH_STATIC:
[749]201            if (ZEND_ENGINE_2_3) {
202                // closure local variable?
203                return str($this->src);
204            }
[1]205            die('static fetch cant to string');
206        case ZEND_FETCH_GLOBAL:
207        case ZEND_FETCH_GLOBAL_LOCK:
208            return $this->globalsrc;
209        default:
210            var_dump($this->fetchType);
211            assert(0);
212        }
213    }
214}
215// }}}
216class Decompiler_Box // {{{
217{
218    var $obj;
219
220    function Decompiler_Box(&$obj)
221    {
222        $this->obj = &$obj;
223    }
224
[732]225    function toCode($indent)
[1]226    {
[732]227        return $this->obj->toCode($indent);
[1]228    }
229}
230// }}}
231class Decompiler_Dim extends Decompiler_Value // {{{
232{
233    var $offsets = array();
234    var $isLast = false;
[749]235    var $isObject = false;
[1]236    var $assign = null;
237
[732]238    function toCode($indent)
[1]239    {
240        if (is_a($this->value, 'Decompiler_ListBox')) {
[749]241            $exp = str($this->value->obj->src, $indent);
[1]242        }
243        else {
[749]244            $exp = str($this->value, $indent);
[1]245        }
[749]246        $last = count($this->offsets) - 1;
247        foreach ($this->offsets as $i => $dim) {
248            if ($this->isObject && $i == $last) {
249                $exp .= '->' . unquoteProperty($dim, $indent);
250            }
251            else {
252                $exp .= '[' . str($dim, $indent) . ']';
253            }
[1]254        }
255        return $exp;
256    }
257}
258// }}}
259class Decompiler_DimBox extends Decompiler_Box // {{{
260{
261}
262// }}}
263class Decompiler_List extends Decompiler_Code // {{{
264{
265    var $src;
266    var $dims = array();
267    var $everLocked = false;
268
[732]269    function toCode($indent)
[1]270    {
271        if (count($this->dims) == 1 && !$this->everLocked) {
272            $dim = $this->dims[0];
273            unset($dim->value);
274            $dim->value = $this->src;
275            if (!isset($dim->assign)) {
[754]276                return str($dim, $indent);
[1]277            }
[754]278            return str($this->dims[0]->assign, $indent) . ' = ' . str($dim, $indent);
[1]279        }
280        /* flatten dims */
281        $assigns = array();
282        foreach ($this->dims as $dim) {
283            $assign = &$assigns;
284            foreach ($dim->offsets as $offset) {
285                $assign = &$assign[$offset];
286            }
[744]287            $assign = foldToCode($dim->assign, $indent);
[1]288        }
[754]289        return str($this->toList($assigns)) . ' = ' . str($this->src, $indent);
[1]290    }
291
292    function toList($assigns)
293    {
294        $keys = array_keys($assigns);
295        if (count($keys) < 2) {
296            $keys[] = 0;
297        }
298        $max = call_user_func_array('max', $keys);
299        $list = 'list(';
300        for ($i = 0; $i <= $max; $i ++) {
301            if ($i) {
302                $list .= ', ';
303            }
304            if (!isset($assigns[$i])) {
305                continue;
306            }
307            if (is_array($assigns[$i])) {
308                $list .= $this->toList($assigns[$i]);
309            }
310            else {
311                $list .= $assigns[$i];
312            }
313        }
314        return $list . ')';
315    }
316}
317// }}}
318class Decompiler_ListBox extends Decompiler_Box // {{{
319{
320}
321// }}}
322class Decompiler_Array extends Decompiler_Value // {{{
323{
[737]324    // emenets
325    function Decompiler_Array()
[1]326    {
[737]327        $this->value = array();
[1]328    }
329
[732]330    function toCode($indent)
[1]331    {
[737]332        $subindent = $indent . INDENT;
333
334        $elementsCode = array();
335        $index = 0;
336        foreach ($this->value as $element) {
337            list($key, $value) = $element;
338            if (!isset($key)) {
339                $key = $index++;
340            }
341            $elementsCode[] = array(str($key, $subindent), str($value, $subindent), $key, $value);
342        }
343
[1]344        $exp = "array(";
[732]345        $indent = $indent . INDENT;
[735]346        $assocWidth = 0;
[1]347        $multiline = 0;
348        $i = 0;
[737]349        foreach ($elementsCode as $element) {
350            list($keyCode, $valueCode) = $element;
351            if ((string) $i !== $keyCode) {
[735]352                $assocWidth = 1;
[737]353                break;
[735]354            }
355            ++$i;
356        }
[737]357        foreach ($elementsCode as $element) {
358            list($keyCode, $valueCode, $key, $value) = $element;
[735]359            if ($assocWidth) {
[737]360                $len = strlen($keyCode);
[735]361                if ($assocWidth < $len) {
362                    $assocWidth = $len;
[1]363                }
364            }
[737]365            if (is_array($value) || is_a($value, 'Decompiler_Array')) {
[1]366                $multiline ++;
367            }
368        }
369
370        $i = 0;
[737]371        foreach ($elementsCode as $element) {
372            list($keyCode, $value) = $element;
[1]373            if ($multiline) {
374                if ($i) {
375                    $exp .= ",";
376                }
377                $exp .= "\n";
378                $exp .= $indent;
379            }
380            else {
381                if ($i) {
382                    $exp .= ", ";
383                }
384            }
385
[735]386            if ($assocWidth) {
387                if ($multiline) {
[737]388                    $exp .= sprintf("%-{$assocWidth}s => ", $keyCode);
[735]389                }
390                else {
[737]391                    $exp .= $keyCode . ' => ';
[735]392                }
[1]393            }
394
[737]395            $exp .= $value;
[1]396
397            $i ++;
398        }
399        if ($multiline) {
[732]400            $exp .= "\n$indent)";
[1]401        }
402        else {
403            $exp .= ")";
404        }
405        return $exp;
406    }
407}
408// }}}
[737]409class Decompiler_ConstArray extends Decompiler_Array // {{{
410{
411    function Decompiler_ConstArray($array)
412    {
413        $elements = array();
414        foreach ($array as $key => $value) {
415            $elements[] = array(value($key), value($value));
416        }
417        $this->value = $elements;
418    }
419}
420// }}}
[1]421class Decompiler_ForeachBox extends Decompiler_Box // {{{
422{
423    var $iskey;
424
[732]425    function toCode($indent)
[1]426    {
427        return 'foreach (' . '';
428    }
429}
430// }}}
431
432class Decompiler
433{
[753]434    var $namespace;
435    var $namespaceDecided;
[1]436
437    function Decompiler()
438    {
439        // {{{ opinfo
440        $this->unaryops = array(
441                XC_BW_NOT   => '~',
442                XC_BOOL_NOT => '!',
443                );
444        $this->binops = array(
445                XC_ADD                 => "+",
446                XC_ASSIGN_ADD          => "+=",
447                XC_SUB                 => "-",
448                XC_ASSIGN_SUB          => "-=",
449                XC_MUL                 => "*",
450                XC_ASSIGN_MUL          => "*=",
451                XC_DIV                 => "/",
452                XC_ASSIGN_DIV          => "/=",
453                XC_MOD                 => "%",
454                XC_ASSIGN_MOD          => "%=",
455                XC_SL                  => "<<",
456                XC_ASSIGN_SL           => "<<=",
457                XC_SR                  => ">>",
458                XC_ASSIGN_SR           => ">>=",
459                XC_CONCAT              => ".",
460                XC_ASSIGN_CONCAT       => ".=",
461                XC_IS_IDENTICAL        => "===",
462                XC_IS_NOT_IDENTICAL    => "!==",
463                XC_IS_EQUAL            => "==",
464                XC_IS_NOT_EQUAL        => "!=",
465                XC_IS_SMALLER          => "<",
466                XC_IS_SMALLER_OR_EQUAL => "<=",
467                XC_BW_OR               => "|",
468                XC_ASSIGN_BW_OR        => "|=",
469                XC_BW_AND              => "&",
470                XC_ASSIGN_BW_AND       => "&=",
471                XC_BW_XOR              => "^",
472                XC_ASSIGN_BW_XOR       => "^=",
473                XC_BOOL_XOR            => "xor",
474                );
475        // }}}
476        $this->includeTypes = array( // {{{
477                ZEND_EVAL         => 'eval',
478                ZEND_INCLUDE      => 'include',
479                ZEND_INCLUDE_ONCE => 'include_once',
480                ZEND_REQUIRE      => 'require',
481                ZEND_REQUIRE_ONCE => 'require_once',
482                );
483                // }}}
484    }
[753]485    function detectNamespace($name) // {{{
486    {
487        if ($this->namespaceDecided) {
488            return;
489        }
490
491        if (strpos($name, '\\') !== false) {
492            $this->namespace = strtok($name, '\\');
493            echo 'namespace ', $this->namespace, ";\n\n";
494        }
495
496        $this->namespaceDecided = true;
497    }
498    // }}}
499    function stripNamespace($name) // {{{
500    {
501        $len = strlen($this->namespace) + 1;
502        if (substr($name, 0, $len) == $this->namespace . '\\') {
503            return substr($name, $len);
504        }
505        else {
506            return $name;
507        }
508    }
509    // }}}
[1]510    function outputPhp(&$opcodes, $opline, $last, $indent) // {{{
511    {
512        $origindent = $indent;
513        $curticks = 0;
514        for ($i = $opline; $i <= $last; $i ++) {
515            $op = $opcodes[$i];
516            if (isset($op['php'])) {
[746]517                $toticks = isset($op['ticks']) ? (int) str($op['ticks']) : 0;
[1]518                if ($curticks != $toticks) {
[746]519                    $oldticks = $curticks;
520                    $curticks = $toticks;
521                    if (!$curticks) {
[749]522                        echo $origindent, "}\n\n";
[1]523                        $indent = $origindent;
524                    }
525                    else {
[746]526                        if ($oldticks) {
[749]527                            echo $origindent, "}\n\n";
[1]528                        }
[746]529                        else if (!$oldticks) {
[1]530                            $indent .= INDENT;
531                        }
[746]532                        echo $origindent, "declare (ticks=$curticks) {\n";
[1]533                    }
534                }
[744]535                echo $indent, str($op['php'], $indent), ";\n";
[1]536            }
537        }
538        if ($curticks) {
539            echo $origindent, "}\n";
540        }
541    }
542    // }}}
543    function getOpVal($op, &$EX, $tostr = true, $free = false) // {{{
544    {
545        switch ($op['op_type']) {
546        case XC_IS_CONST:
[744]547            return foldToCode(value($op['constant']), $EX);
[1]548
549        case XC_IS_VAR:
550        case XC_IS_TMP_VAR:
551            $T = &$EX['Ts'];
[716]552            $ret = $T[$op['var']];
[1]553            if ($tostr) {
[744]554                $ret = foldToCode($ret, $EX);
[1]555            }
556            if ($free) {
[716]557                unset($T[$op['var']]);
[1]558            }
559            return $ret;
560
561        case XC_IS_CV:
[716]562            $var = $op['var'];
[1]563            $var = $EX['op_array']['vars'][$var];
564            return '$' . $var['name'];
565
566        case XC_IS_UNUSED:
567            return null;
568        }
569    }
570    // }}}
[716]571    function removeKeyPrefix($array, $prefix) // {{{
572    {
573        $prefixLen = strlen($prefix);
574        $ret = array();
575        foreach ($array as $key => $value) {
576            if (substr($key, 0, $prefixLen) == $prefix) {
577                $key = substr($key, $prefixLen);
578            }
579            $ret[$key] = $value;
580        }
581        return $ret;
582    }
583    // }}}
[735]584    function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
[1]585    {
[716]586        for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
587            if (function_exists('xcache_get_fixed_opcode')) {
588                $opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
589            }
590            if (isset($opcodes[$i]['op1'])) {
591                $opcodes[$i]['op1'] = $this->removeKeyPrefix($opcodes[$i]['op1'], 'u.');
592                $opcodes[$i]['op2'] = $this->removeKeyPrefix($opcodes[$i]['op2'], 'u.');
593                $opcodes[$i]['result'] = $this->removeKeyPrefix($opcodes[$i]['result'], 'u.');
594            }
595            else {
596                $op = array(
597                    'op1' => array(),
598                    'op2' => array(),
599                    'op3' => array(),
600                );
601                foreach ($opcodes[$i] as $name => $value) {
602                    if (preg_match('!^(op1|op2|result)\\.(.*)!', $name, $m)) {
603                        list(, $which, $field) = $m;
604                        $op[$which][$field] = $value;
605                    }
606                    else if (preg_match('!^(op1|op2|result)_type$!', $name, $m)) {
607                        list(, $which) = $m;
608                        $op[$which]['op_type'] = $value;
609                    }
610                    else {
611                        $op[$name] = $value;
612                    }
613                }
614                $opcodes[$i] = $op;
615            }
616        }
[735]617
618        if ($removeTailing) {
619            $last = count($opcodes) - 1;
620            if ($opcodes[$last]['opcode'] == XC_HANDLE_EXCEPTION) {
621                unset($opcodes[$last]);
622                --$last;
623            }
624            if ($opcodes[$last]['opcode'] == XC_RETURN) {
625                $op1 = $opcodes[$last]['op1'];
626                if ($op1['op_type'] == XC_IS_CONST && array_key_exists('constant', $op1) && $op1['constant'] === $defaultReturnValue) {
627                    unset($opcodes[$last]);
628                    --$last;
629                }
630            }
631        }
[731]632        return $opcodes;
633    }
634    // }}}
635    function &dop_array($op_array, $indent = '') // {{{
636    {
[735]637        $op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
[731]638        $opcodes = &$op_array['opcodes'];
639        $EX['indent'] = '';
[1]640        // {{{ build jmp array
641        for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
642            $op = &$opcodes[$i];
643            /*
644            if ($op['opcode'] == XC_JMPZ) {
645                $this->dumpop($op, $EX);
646                var_dump($op);
647            }
648            continue;
649            */
650            $op['line'] = $i;
651            switch ($op['opcode']) {
[758]652            case XC_CONT:
653            case XC_BRK:
654                $op['jmpouts'] = array();
655                break;
656
[749]657            case XC_GOTO:
[1]658            case XC_JMP:
[716]659                $target = $op['op1']['var'];
[1]660                $op['jmpouts'] = array($target);
661                $opcodes[$target]['jmpins'][] = $i;
662                break;
663
664            case XC_JMPZNZ:
[716]665                $jmpz = $op['op2']['opline_num'];
[1]666                $jmpnz = $op['extended_value'];
667                $op['jmpouts'] = array($jmpz, $jmpnz);
668                $opcodes[$jmpz]['jmpins'][] = $i;
669                $opcodes[$jmpnz]['jmpins'][] = $i;
670                break;
671
672            case XC_JMPZ:
673            case XC_JMPNZ:
674            case XC_JMPZ_EX:
675            case XC_JMPNZ_EX:
[749]676            case XC_JMP_SET:
[1]677            // case XC_FE_RESET:
678            case XC_FE_FETCH:
679            // case XC_JMP_NO_CTOR:
[716]680                $target = $op['op2']['opline_num'];
[1]681                //if (!isset($target)) {
682                //  $this->dumpop($op, $EX);
683                //  var_dump($op); exit;
684                //}
685                $op['jmpouts'] = array($target);
686                $opcodes[$target]['jmpins'][] = $i;
687                break;
688
689            /*
690            case XC_RETURN:
691                $op['jmpouts'] = array();
692                break;
693            */
694            }
695        }
696        unset($op);
697        // }}}
698        // build semi-basic blocks
699        $nextbbs = array();
700        $starti = 0;
701        for ($i = 1, $cnt = count($opcodes); $i < $cnt; $i ++) {
702            if (isset($opcodes[$i]['jmpins'])
703             || isset($opcodes[$i - 1]['jmpouts'])) {
704                $nextbbs[$starti] = $i;
705                $starti = $i;
706            }
707        }
708        $nextbbs[$starti] = $cnt;
709
710        $EX = array();
711        $EX['Ts'] = array();
712        $EX['indent'] = $indent;
713        $EX['nextbbs'] = $nextbbs;
714        $EX['op_array'] = &$op_array;
715        $EX['opcodes'] = &$opcodes;
716        // func call
717        $EX['object'] = null;
[720]718        $EX['called_scope'] = null;
[1]719        $EX['fbc'] = null;
720        $EX['argstack'] = array();
721        $EX['arg_types_stack'] = array();
722        $EX['last'] = count($opcodes) - 1;
723        $EX['silence'] = 0;
724
725        for ($next = 0, $last = $EX['last'];
726                $loop = $this->outputCode($EX, $next, $last, $indent, true);
727                list($next, $last) = $loop) {
728            // empty
729        }
730        return $EX;
731    }
732    // }}}
733    function outputCode(&$EX, $opline, $last, $indent, $loop = false) // {{{
734    {
735        $op = &$EX['opcodes'][$opline];
736        $next = $EX['nextbbs'][$opline];
737
738        $end = $next - 1;
739        if ($end > $last) {
740            $end = $last;
741        }
742
743        if (isset($op['jmpins'])) {
744            echo "\nline", $op['line'], ":\n";
745        }
746        else {
747            // echo ";;;\n";
748        }
749        $this->dasmBasicBlock($EX, $opline, $end);
750        $this->outputPhp($EX['opcodes'], $opline, $end, $indent);
751        // jmpout op
752        $op = &$EX['opcodes'][$end];
753        $op1 = $op['op1'];
754        $op2 = $op['op2'];
755        $ext = $op['extended_value'];
756        $line = $op['line'];
757
758        if (isset($EX['opcodes'][$next])) {
759            if (isset($last) && $next > $last) {
760                $next = null;
761            }
762        }
763        else {
764            $next = null;
765        }
766        if ($op['opcode'] == XC_FE_FETCH) {
767            $opline = $next;
[716]768            $next = $op['op2']['opline_num'];
[1]769            $end = $next - 1;
770
771            ob_start();
772            $this->outputCode($EX, $opline, $end /* - 1 skip last jmp */, $indent . INDENT);
773            $body = ob_get_clean();
774
[744]775            $as = foldToCode($op['fe_as'], $EX);
[1]776            if (isset($op['fe_key'])) {
[744]777                $as = str($op['fe_key'], $EX) . ' => ' . str($as);
[1]778            }
[744]779            echo "{$indent}foreach (" . str($op['fe_src'], $EX) . " as $as) {\n";
[1]780            echo $body;
781            echo "{$indent}}";
782            // $this->outputCode($EX, $next, $last, $indent);
783            // return;
784        }
785        /*
786        if ($op['opcode'] == XC_JMPZ) {
[716]787            $target = $op2['opline_num'];
[1]788            if ($line + 1) {
789                $nextblock = $EX['nextbbs'][$next];
790                $jmpop = end($nextblock);
791                if ($jmpop['opcode'] == XC_JMP) {
[716]792                    $ifendline = $op2['opline_num'];
[1]793                    if ($ifendline >= $line) {
794                        $cond = $op['cond'];
795                        echo "{$indent}if ($cond) {\n";
796                        $this->outputCode($EX, $next, $last, INDENT . $indent);
797                        echo "$indent}\n";
798                        $this->outputCode($EX, $target, $last, $indent);
799                        return;
800                    }
801                }
802            }
803        }
804        */
805        if (!isset($next)) {
806            return;
807        }
[758]808        if (isset($op['jmpouts']) && isset($op['isjmp'])) {
[1]809            if (isset($op['cond'])) {
[746]810                echo "{$indent}check (" . str($op["cond"]) . ") {\n";
[1]811                echo INDENT;
812            }
[758]813            switch ($op['opcode']) {
814            case XC_CONT:
815            case XC_BRK:
816                break;
817
818            case XC_GOTO:
819                echo $indent, 'goto', ' line', $op['jmpouts'][0], ';', "\n";
820                break;
821
822            default:
823                echo $indent;
824                echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];
825                if (isset($op['jmpouts'][1])) {
826                    echo ', line', $op['jmpouts'][1];
827                }
828                echo ";";
829                // echo ' // <- line', $op['line'];
830                echo "\n";
[1]831            }
832            if (isset($op['cond'])) echo "$indent}\n";
833        }
834
835        // proces JMPZ_EX/JMPNZ_EX for AND,OR
836        $op = &$EX['opcodes'][$next];
837        /*
838        if (isset($op['jmpins'])) {
839            foreach (array_reverse($op['jmpins']) as $fromline) {
840                $fromop = $EX['opcodes'][$fromline];
841                switch ($fromop['opcode']) {
842                case XC_JMPZ_EX: $opstr = 'and'; break;
843                case XC_JMPNZ_EX: $opstr = 'or'; break;
844                case XC_JMPZNZ: var_dump($fromop); exit;
845                default: continue 2;
846                }
847
[716]848                $var = $fromop['result']['var'];
[1]849                var_dump($EX['Ts'][$var]);
850                $EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';
851            }
852            #$this->outputCode($EX, $next, $last, $indent);
853            #return;
854        }
855        */
856        if (isset($op['cond_false'])) {
857            // $this->dumpop($op, $EX);
858            // any true comes here, so it's a "or"
[744]859            $cond = implode(' and ', str($op['cond_false']));
[1]860            // var_dump($op['cond'] = $cond);
861            /*
862            $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
863            unset($op['cond_true']);
864            */
865        }
866
867        if ($loop) {
868            return array($next, $last);
869        }
870        $this->outputCode($EX, $next, $last, $indent);
871    }
872    // }}}
873    function dasmBasicBlock(&$EX, $opline, $last) // {{{
874    {
875        $T = &$EX['Ts'];
876        $opcodes = &$EX['opcodes'];
877        $lastphpop = null;
878
879        for ($i = $opline, $ic = $last + 1; $i < $ic; $i ++) {
880            // {{{ prepair
881            $op = &$opcodes[$i];
882            $opc = $op['opcode'];
883            if ($opc == XC_NOP) {
884                continue;
885            }
886
887            $op1 = $op['op1'];
888            $op2 = $op['op2'];
889            $res = $op['result'];
890            $ext = $op['extended_value'];
891
892            $opname = xcache_get_opcode($opc);
893
894            if ($opname == 'UNDEF' || !isset($opname)) {
895                echo 'UNDEF OP:';
896                $this->dumpop($op, $EX);
897                continue;
898            }
[760]899            // echo $i; $this->dumpop($op, $EX); //var_dump($op);
[1]900
901            $resvar = null;
[731]902            if ((ZEND_ENGINE_2_4 ? ($res['op_type'] & EXT_TYPE_UNUSED) : ($res['EA.type'] & EXT_TYPE_UNUSED)) || $res['op_type'] == XC_IS_UNUSED) {
[1]903                $istmpres = false;
904            }
905            else {
906                $istmpres = true;
907            }
908            // }}}
909            // echo $opname, "\n";
910
911            $call = array(&$this, $opname);
912            if (is_callable($call)) {
913                $this->{$opname}($op, $EX);
914            }
915            else if (isset($this->binops[$opc])) { // {{{
916                $op1val = $this->getOpVal($op1, $EX, false);
917                $op2val = $this->getOpVal($op2, $EX, false);
918                $rvalue = new Decompiler_Binop($this, $op1val, $opc, $op2val);
919                $resvar = $rvalue;
920                // }}}
921            }
922            else if (isset($this->unaryops[$opc])) { // {{{
923                $op1val = $this->getOpVal($op1, $EX);
924                $myop = $this->unaryops[$opc];
[757]925                $rvalue = $myop . str($op1val);
[1]926                $resvar = $rvalue;
927                // }}}
928            }
929            else {
930                switch ($opc) {
931                case XC_NEW: // {{{
[720]932                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[716]933                    $EX['object'] = (int) $res['var'];
[720]934                    $EX['called_scope'] = null;
[749]935                    $EX['fbc'] = 'new ' . unquoteName($this->getOpVal($op1, $EX), $EX);
[731]936                    if (!ZEND_ENGINE_2) {
[1]937                        $resvar = '$new object$';
938                    }
939                    break;
940                    // }}}
[749]941                case XC_THROW: // {{{
942                    $resvar = 'throw ' . str($this->getOpVal($op1, $EX));
943                    break;
944                    // }}}
945                case XC_CLONE: // {{{
946                    $resvar = 'clone ' . str($this->getOpVal($op1, $EX));
947                    break;
948                    // }}}
949                case XC_CATCH: // {{{
950                    $resvar = 'catch (' . str($this->getOpVal($op1, $EX)) . ' ' . str($this->getOpVal($op2, $EX)) . ')';
951                    break;
952                    // }}}
953                case XC_INSTANCEOF: // {{{
954                    $resvar = str($this->getOpVal($op1, $EX)) . ' instanceof ' . str($this->getOpVal($op2, $EX));
955                    break;
956                    // }}}
[1]957                case XC_FETCH_CLASS: // {{{
958                    if ($op2['op_type'] == XC_IS_UNUSED) {
[731]959                        switch (($ext & (defined('ZEND_FETCH_CLASS_MASK') ? ZEND_FETCH_CLASS_MASK : 0xFF))) {
[1]960                        case ZEND_FETCH_CLASS_SELF:
961                            $class = 'self';
962                            break;
963                        case ZEND_FETCH_CLASS_PARENT:
964                            $class = 'parent';
[722]965                            break;
966                        case ZEND_FETCH_CLASS_STATIC:
967                            $class = 'static';
968                            break;
[1]969                        }
[722]970                        $istmpres = true;
[1]971                    }
972                    else {
[749]973                        $class = $this->getOpVal($op2, $EX);
974                        if (isset($op2['constant'])) {
[753]975                            $class = $this->stripNamespace(unquoteName($class));
[1]976                        }
977                    }
978                    $resvar = $class;
979                    break;
980                    // }}}
981                case XC_FETCH_CONSTANT: // {{{
[749]982                    if ($op1['op_type'] == XC_IS_UNUSED) {
[753]983                        $resvar = $this->stripNamespace($op2['constant']);
[749]984                        break;
985                    }
986
[1]987                    if ($op1['op_type'] == XC_IS_CONST) {
[753]988                        $resvar = $this->stripNamespace($op1['constant']);
[1]989                    }
990                    else {
[749]991                        $resvar = $this->getOpVal($op1, $EX);
[1]992                    }
[749]993
994                    $resvar = str($resvar) . '::' . unquoteName($this->getOpVal($op2, $EX));
[1]995                    break;
996                    // }}}
997                    // {{{ case XC_FETCH_*
998                case XC_FETCH_R:
999                case XC_FETCH_W:
1000                case XC_FETCH_RW:
1001                case XC_FETCH_FUNC_ARG:
1002                case XC_FETCH_UNSET:
1003                case XC_FETCH_IS:
1004                case XC_UNSET_VAR:
1005                    $rvalue = $this->getOpVal($op1, $EX);
[731]1006                    if (defined('ZEND_FETCH_TYPE_MASK')) {
1007                        $fetchtype = ($ext & ZEND_FETCH_TYPE_MASK);
1008                    }
1009                    else {
1010                        $fetchtype = $op2[!ZEND_ENGINE_2 ? 'fetch_type' : 'EA.type'];
1011                    }
[1]1012                    switch ($fetchtype) {
1013                    case ZEND_FETCH_STATIC_MEMBER:
1014                        $class = $this->getOpVal($op2, $EX);
[749]1015                        $rvalue = str($class) . '::$' . unquoteName($rvalue, $EX);
[1]1016                        break;
1017                    default:
[749]1018                        $name = unquoteName($rvalue, $EX);
1019                        $globalname = xcache_is_autoglobal($name) ? "\$$name" : "\$GLOBALS[" . str($rvalue) . "]";
[1]1020                        $rvalue = new Decompiler_Fetch($rvalue, $fetchtype, $globalname);
1021                        break;
1022                    }
1023                    if ($opc == XC_UNSET_VAR) {
[744]1024                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
[1]1025                        $lastphpop = &$op;
1026                    }
1027                    else if ($res['op_type'] != XC_IS_UNUSED) {
1028                        $resvar = $rvalue;
1029                    }
1030                    break;
1031                    // }}}
1032                    // {{{ case XC_FETCH_DIM_*
1033                case XC_FETCH_DIM_TMP_VAR:
1034                case XC_FETCH_DIM_R:
1035                case XC_FETCH_DIM_W:
1036                case XC_FETCH_DIM_RW:
1037                case XC_FETCH_DIM_FUNC_ARG:
1038                case XC_FETCH_DIM_UNSET:
1039                case XC_FETCH_DIM_IS:
1040                case XC_ASSIGN_DIM:
[749]1041                case XC_UNSET_DIM_OBJ: // PHP 4 only
[1]1042                case XC_UNSET_DIM:
[749]1043                case XC_UNSET_OBJ:
[1]1044                    $src = $this->getOpVal($op1, $EX, false);
1045                    if (is_a($src, "Decompiler_ForeachBox")) {
1046                        $src->iskey = $this->getOpVal($op2, $EX);
1047                        $resvar = $src;
1048                        break;
1049                    }
[749]1050
1051                    if (is_a($src, "Decompiler_DimBox")) {
[1]1052                        $dimbox = $src;
1053                    }
1054                    else {
1055                        if (!is_a($src, "Decompiler_ListBox")) {
[749]1056                            $op1val = $this->getOpVal($op1, $EX, false);
1057                            $list = new Decompiler_List(isset($op1val) ? $op1val : '$this');
[1]1058
1059                            $src = new Decompiler_ListBox($list);
[716]1060                            if (!isset($op1['var'])) {
[1]1061                                $this->dumpop($op, $EX);
1062                                var_dump($op);
[716]1063                                die('missing var');
[1]1064                            }
[716]1065                            $T[$op1['var']] = $src;
[1]1066                            unset($list);
1067                        }
1068                        $dim = new Decompiler_Dim($src);
1069                        $src->obj->dims[] = &$dim;
1070
1071                        $dimbox = new Decompiler_DimBox($dim);
1072                    }
1073                    $dim = &$dimbox->obj;
1074                    $dim->offsets[] = $this->getOpVal($op2, $EX);
1075                    if ($ext == ZEND_FETCH_ADD_LOCK) {
1076                        $src->obj->everLocked = true;
1077                    }
1078                    else if ($ext == ZEND_FETCH_STANDARD) {
1079                        $dim->isLast = true;
1080                    }
[749]1081                    if ($opc == XC_UNSET_OBJ) {
1082                        $dim->isObject = true;
1083                    }
[1]1084                    unset($dim);
1085                    $rvalue = $dimbox;
[749]1086                    unset($dimbox);
[1]1087
1088                    if ($opc == XC_ASSIGN_DIM) {
1089                        $lvalue = $rvalue;
1090                        ++ $i;
1091                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
[749]1092                        $resvar = str($lvalue, $EX) . ' = ' . str($rvalue);
[1]1093                    }
[749]1094                    else if ($opc == XC_UNSET_DIM || $opc == XC_UNSET_OBJ) {
[744]1095                        $op['php'] = "unset(" . str($rvalue, $EX) . ")";
[1]1096                        $lastphpop = &$op;
1097                    }
1098                    else if ($res['op_type'] != XC_IS_UNUSED) {
1099                        $resvar = $rvalue;
1100                    }
1101                    break;
1102                    // }}}
1103                case XC_ASSIGN: // {{{
1104                    $lvalue = $this->getOpVal($op1, $EX);
1105                    $rvalue = $this->getOpVal($op2, $EX, false);
1106                    if (is_a($rvalue, 'Decompiler_ForeachBox')) {
1107                        $type = $rvalue->iskey ? 'fe_key' : 'fe_as';
1108                        $rvalue->obj[$type] = $lvalue;
[716]1109                        unset($T[$op2['var']]);
[1]1110                        break;
1111                    }
1112                    if (is_a($rvalue, "Decompiler_DimBox")) {
1113                        $dim = &$rvalue->obj;
1114                        $dim->assign = $lvalue;
1115                        if ($dim->isLast) {
[744]1116                            $resvar = foldToCode($dim->value, $EX);
[1]1117                        }
1118                        unset($dim);
1119                        break;
1120                    }
[744]1121                    $resvar = "$lvalue = " . str($rvalue, $EX);
[1]1122                    break;
1123                    // }}}
1124                case XC_ASSIGN_REF: // {{{
1125                    $lvalue = $this->getOpVal($op1, $EX);
1126                    $rvalue = $this->getOpVal($op2, $EX, false);
1127                    if (is_a($rvalue, 'Decompiler_Fetch')) {
[749]1128                        $src = str($rvalue->src, $EX);
[754]1129                        if ('$' . unquoteName($src) == $lvalue) {
[1]1130                            switch ($rvalue->fetchType) {
1131                            case ZEND_FETCH_GLOBAL:
[731]1132                            case ZEND_FETCH_GLOBAL_LOCK:
[1]1133                                $resvar = 'global ' . $lvalue;
1134                                break 2;
1135                            case ZEND_FETCH_STATIC:
1136                                $statics = &$EX['op_array']['static_variables'];
1137                                $resvar = 'static ' . $lvalue;
[754]1138                                $name = unquoteName($src);
[1]1139                                if (isset($statics[$name])) {
1140                                    $var = $statics[$name];
1141                                    $resvar .= ' = ';
[744]1142                                    $resvar .= str(value($var), $EX);
[1]1143                                }
1144                                unset($statics);
1145                                break 2;
[731]1146                            default:
[1]1147                            }
1148                        }
1149                    }
[731]1150                    // TODO: PHP_6 global
[754]1151                    $rvalue = str($rvalue, $EX);
[1]1152                    $resvar = "$lvalue = &$rvalue";
1153                    break;
1154                    // }}}
1155                // {{{ case XC_FETCH_OBJ_*
1156                case XC_FETCH_OBJ_R:
1157                case XC_FETCH_OBJ_W:
1158                case XC_FETCH_OBJ_RW:
1159                case XC_FETCH_OBJ_FUNC_ARG:
1160                case XC_FETCH_OBJ_UNSET:
1161                case XC_FETCH_OBJ_IS:
1162                case XC_ASSIGN_OBJ:
1163                    $obj = $this->getOpVal($op1, $EX);
1164                    if (!isset($obj)) {
1165                        $obj = '$this';
1166                    }
[749]1167                    $rvalue = str($obj) . "->" . unquoteProperty($this->getOpVal($op2, $EX), $EX);
[1]1168                    if ($res['op_type'] != XC_IS_UNUSED) {
1169                        $resvar = $rvalue;
1170                    }
1171                    if ($opc == XC_ASSIGN_OBJ) {
1172                        ++ $i;
1173                        $lvalue = $rvalue;
1174                        $rvalue = $this->getOpVal($opcodes[$i]['op1'], $EX);
[749]1175                        $resvar = "$lvalue = " . str($rvalue);
[1]1176                    }
1177                    break;
1178                    // }}}
1179                case XC_ISSET_ISEMPTY_DIM_OBJ:
1180                case XC_ISSET_ISEMPTY_PROP_OBJ:
1181                case XC_ISSET_ISEMPTY:
1182                case XC_ISSET_ISEMPTY_VAR: // {{{
1183                    if ($opc == XC_ISSET_ISEMPTY_VAR) {
1184                        $rvalue = $this->getOpVal($op1, $EX);;
1185                        if (preg_match($this->rQuotedName, $rvalue)) {
1186                            $rvalue = '$' . substr($rvalue, 1, -1);
1187                        }
1188                        else {
[733]1189                            $rvalue = '${' . $rvalue . '}';
[1]1190                        }
[716]1191                        if ($op2['EA.type'] == ZEND_FETCH_STATIC_MEMBER) {
[1]1192                            $class = $this->getOpVal($op2, $EX);
1193                            $rvalue = $class . '::' . $rvalue;
1194                        }
1195                    }
1196                    else if ($opc == XC_ISSET_ISEMPTY) {
1197                        $rvalue = $this->getOpVal($op1, $EX);
1198                    }
1199                    else {
1200                        $container = $this->getOpVal($op1, $EX);
1201                        $dim = $this->getOpVal($op2, $EX);
[717]1202                        if ($opc == XC_ISSET_ISEMPTY_PROP_OBJ) {
1203                            if (preg_match($this->rQuotedName, $dim)) {
1204                                $rvalue = $container . "->" . substr($dim, 1, -1);
1205                            }
1206                            else {
1207                                $rvalue = $container . "->{" . $dim . "}";
1208                            }
1209                        }
1210                        else {
1211                            $rvalue = $container . "[$dim]";
1212                        }
[1]1213                    }
1214
[731]1215                    switch ((!ZEND_ENGINE_2 ? $op['op2']['var'] /* constant */ : $ext) & (ZEND_ISSET|ZEND_ISEMPTY)) {
[1]1216                    case ZEND_ISSET:
1217                        $rvalue = "isset($rvalue)";
1218                        break;
1219                    case ZEND_ISEMPTY:
1220                        $rvalue = "empty($rvalue)";
1221                        break;
1222                    }
1223                    $resvar = $rvalue;
1224                    break;
1225                    // }}}
1226                case XC_SEND_VAR_NO_REF:
1227                case XC_SEND_VAL:
1228                case XC_SEND_REF:
1229                case XC_SEND_VAR: // {{{
1230                    $ref = ($opc == XC_SEND_REF ? '&' : '');
[744]1231                    $EX['argstack'][] = $ref . str($this->getOpVal($op1, $EX));
[1]1232                    break;
1233                    // }}}
[720]1234                case XC_INIT_STATIC_METHOD_CALL:
[749]1235                case XC_INIT_METHOD_CALL: // {{{
[720]1236                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[722]1237                    if ($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL || $op1['op_type'] != XC_IS_UNUSED) {
[1]1238                        $obj = $this->getOpVal($op1, $EX);
1239                        if (!isset($obj)) {
1240                            $obj = '$this';
1241                        }
[722]1242                        if ($opc == XC_INIT_STATIC_METHOD_CALL || /* PHP4 */ isset($op1['constant'])) {
[720]1243                            $EX['object'] = null;
[753]1244                            $EX['called_scope'] = $this->stripNamespace(unquoteName($obj, $EX));
[720]1245                        }
1246                        else {
1247                            $EX['object'] = $obj;
1248                            $EX['called_scope'] = null;
1249                        }
[1]1250                        if ($res['op_type'] != XC_IS_UNUSED) {
1251                            $resvar = '$obj call$';
1252                        }
1253                    }
1254                    else {
1255                        $EX['object'] = null;
[720]1256                        $EX['called_scope'] = null;
[1]1257                    }
1258
[749]1259                    $EX['fbc'] = $this->getOpVal($op2, $EX, false);
1260                    if (($opc == XC_INIT_STATIC_METHOD_CALL || $opc == XC_INIT_METHOD_CALL) && !isset($EX['fbc'])) {
1261                        $EX['fbc'] = '__construct';
[1]1262                    }
[749]1263                    break;
1264                    // }}}
[753]1265                case XC_INIT_NS_FCALL_BY_NAME:
[749]1266                case XC_INIT_FCALL_BY_NAME: // {{{
[755]1267                    array_push($EX['arg_types_stack'], array($EX['fbc'], $EX['object'], $EX['called_scope']));
[749]1268                    if (!ZEND_ENGINE_2 && ($ext & ZEND_CTOR_CALL)) {
1269                        break;
[1]1270                    }
[749]1271                    $EX['object'] = null;
1272                    $EX['called_scope'] = null;
1273                    $EX['fbc'] = $this->getOpVal($op2, $EX);
[1]1274                    break;
1275                    // }}}
[749]1276                case XC_INIT_FCALL_BY_FUNC: // {{{ deprecated even in PHP 4?
1277                    $EX['object'] = null;
1278                    $EX['called_scope'] = null;
1279                    $which = $op1['var'];
1280                    $EX['fbc'] = $EX['op_array']['funcs'][$which]['name'];
1281                    break;
1282                    // }}}
[1]1283                case XC_DO_FCALL_BY_FUNC:
[716]1284                    $which = $op1['var'];
[1]1285                    $fname = $EX['op_array']['funcs'][$which]['name'];
1286                    $args = $this->popargs($EX, $ext);
1287                    $resvar = $fname . "($args)";
1288                    break;
1289                case XC_DO_FCALL:
[749]1290                    $fname = unquoteName($this->getOpVal($op1, $EX, false), $EX);
[1]1291                    $args = $this->popargs($EX, $ext);
1292                    $resvar = $fname . "($args)";
1293                    break;
1294                case XC_DO_FCALL_BY_NAME: // {{{
1295                    $object = null;
1296
[749]1297                    $fname = unquoteName($EX['fbc'], $EX);
[1]1298                    if (!is_int($EX['object'])) {
1299                        $object = $EX['object'];
1300                    }
1301
1302                    $args = $this->popargs($EX, $ext);
1303
[753]1304                    $prefix = (isset($object) ? $object . '->' : '' )
1305                        . (isset($EX['called_scope']) ? $EX['called_scope'] . '::' : '' );
1306                    $resvar = $prefix
1307                        . (!$prefix ? $this->stripNamespace($fname) : $fname)
1308                        . "($args)";
[1]1309                    unset($args);
1310
1311                    if (is_int($EX['object'])) {
1312                        $T[$EX['object']] = $resvar;
1313                        $resvar = null;
1314                    }
[720]1315                    list($EX['fbc'], $EX['object'], $EX['called_scope']) = array_pop($EX['arg_types_stack']);
[1]1316                    break;
1317                    // }}}
1318                case XC_VERIFY_ABSTRACT_CLASS: // {{{
[716]1319                    //unset($T[$op1['var']]);
[1]1320                    break;
1321                    // }}}
1322                case XC_DECLARE_CLASS: 
[714]1323                case XC_DECLARE_INHERITED_CLASS:
1324                case XC_DECLARE_INHERITED_CLASS_DELAYED: // {{{
[716]1325                    $key = $op1['constant'];
[714]1326                    if (!isset($this->dc['class_table'][$key])) {
1327                        echo 'class not found: ', $key, 'existing classes are:', "\n";
1328                        var_dump(array_keys($this->dc['class_table']));
[1]1329                        exit;
1330                    }
[714]1331                    $class = &$this->dc['class_table'][$key];
[751]1332                    if (!isset($class['name'])) {
1333                        $class['name'] = unquoteName($this->getOpVal($op2, $EX), $EX);
1334                    }
[714]1335                    if ($opc == XC_DECLARE_INHERITED_CLASS || $opc == XC_DECLARE_INHERITED_CLASS_DELAYED) {
[1]1336                        $ext /= XC_SIZEOF_TEMP_VARIABLE;
1337                        $class['parent'] = $T[$ext];
1338                        unset($T[$ext]);
1339                    }
1340                    else {
1341                        $class['parent'] = null;
1342                    }
1343
[749]1344                    for (;;) {
1345                        if ($i + 1 < $ic
1346                         && $opcodes[$i + 1]['opcode'] == XC_ADD_INTERFACE
1347                         && $opcodes[$i + 1]['op1']['var'] == $res['var']) {
1348                            // continue
1349                        }
1350                        else if ($i + 2 < $ic
1351                         && $opcodes[$i + 2]['opcode'] == XC_ADD_INTERFACE
1352                         && $opcodes[$i + 2]['op1']['var'] == $res['var']
1353                         && $opcodes[$i + 1]['opcode'] == XC_FETCH_CLASS) {
1354                            // continue
1355                        }
1356                        else {
1357                            break;
1358                        }
1359
[1]1360                        $fetchop = &$opcodes[$i + 1];
[753]1361                        $interface = $this->stripNamespace(unquoteName($this->getOpVal($fetchop['op2'], $EX), $EX));
[1]1362                        $addop = &$opcodes[$i + 2];
[753]1363                        $class['interfaces'][$addop['extended_value']] = $interface;
[1]1364                        unset($fetchop, $addop);
1365                        $i += 2;
1366                    }
1367                    $this->dclass($class);
[749]1368                    echo "\n";
[1]1369                    unset($class);
1370                    break;
1371                    // }}}
1372                case XC_INIT_STRING: // {{{
1373                    $resvar = "''";
1374                    break;
1375                    // }}}
1376                case XC_ADD_CHAR:
1377                case XC_ADD_STRING:
1378                case XC_ADD_VAR: // {{{
1379                    $op1val = $this->getOpVal($op1, $EX);
1380                    $op2val = $this->getOpVal($op2, $EX);
1381                    switch ($opc) {
1382                    case XC_ADD_CHAR:
[749]1383                        $op2val = value(chr(str($op2val)));
[1]1384                        break;
1385                    case XC_ADD_STRING:
1386                        break;
1387                    case XC_ADD_VAR:
1388                        break;
1389                    }
[749]1390                    if (str($op1val) == "''") {
[1]1391                        $rvalue = $op2val;
1392                    }
[749]1393                    else if (str($op2val) == "''") {
[1]1394                        $rvalue = $op1val;
1395                    }
1396                    else {
[744]1397                        $rvalue = str($op1val) . ' . ' . str($op2val);
[1]1398                    }
1399                    $resvar = $rvalue;
1400                    // }}}
1401                    break;
1402                case XC_PRINT: // {{{
1403                    $op1val = $this->getOpVal($op1, $EX);
1404                    $resvar = "print($op1val)";
1405                    break;
1406                    // }}}
1407                case XC_ECHO: // {{{
1408                    $op1val = $this->getOpVal($op1, $EX);
[744]1409                    $resvar = "echo " . str($op1val);
[1]1410                    break;
1411                    // }}}
1412                case XC_EXIT: // {{{
1413                    $op1val = $this->getOpVal($op1, $EX);
1414                    $resvar = "exit($op1val)";
1415                    break;
1416                    // }}}
1417                case XC_INIT_ARRAY:
1418                case XC_ADD_ARRAY_ELEMENT: // {{{
1419                    $rvalue = $this->getOpVal($op1, $EX, false, true);
1420
1421                    if ($opc == XC_ADD_ARRAY_ELEMENT) {
[737]1422                        $assoc = $this->getOpVal($op2, $EX);
1423                        if (isset($assoc)) {
1424                            $T[$res['var']]->value[] = array($assoc, $rvalue);
[1]1425                        }
1426                        else {
[737]1427                            $T[$res['var']]->value[] = array(null, $rvalue);
[1]1428                        }
1429                    }
1430                    else {
1431                        if ($opc == XC_INIT_ARRAY) {
1432                            $resvar = new Decompiler_Array();
1433                            if (!isset($rvalue)) {
1434                                continue;
1435                            }
1436                        }
1437
[737]1438                        $assoc = $this->getOpVal($op2, $EX);
1439                        if (isset($assoc)) {
1440                            $resvar->value[] = array($assoc, $rvalue);
[1]1441                        }
1442                        else {
[737]1443                            $resvar->value[] = array(null, $rvalue);
[1]1444                        }
1445                    }
1446                    break;
1447                    // }}}
1448                case XC_QM_ASSIGN: // {{{
1449                    $resvar = $this->getOpVal($op1, $EX);
1450                    break;
1451                    // }}}
1452                case XC_BOOL: // {{{
1453                    $resvar = /*'(bool) ' .*/ $this->getOpVal($op1, $EX);
1454                    break;
1455                    // }}}
1456                case XC_RETURN: // {{{
[744]1457                    $resvar = "return " . str($this->getOpVal($op1, $EX));
[1]1458                    break;
1459                    // }}}
1460                case XC_INCLUDE_OR_EVAL: // {{{
[716]1461                    $type = $op2['var']; // hack
[1]1462                    $keyword = $this->includeTypes[$type];
[749]1463                    $resvar = "$keyword " . str($this->getOpVal($op1, $EX));
[1]1464                    break;
1465                    // }}}
1466                case XC_FE_RESET: // {{{
1467                    $resvar = $this->getOpVal($op1, $EX);
1468                    break;
1469                    // }}}
1470                case XC_FE_FETCH: // {{{
1471                    $op['fe_src'] = $this->getOpVal($op1, $EX);
1472                    $fe = new Decompiler_ForeachBox($op);
1473                    $fe->iskey = false;
[716]1474                    $T[$res['var']] = $fe;
[1]1475
1476                    ++ $i;
1477                    if (($ext & ZEND_FE_FETCH_WITH_KEY)) {
1478                        $fe = new Decompiler_ForeachBox($op);
1479                        $fe->iskey = true;
1480
1481                        $res = $opcodes[$i]['result'];
[716]1482                        $T[$res['var']] = $fe;
[1]1483                    }
1484                    break;
1485                    // }}}
1486                case XC_SWITCH_FREE: // {{{
[716]1487                    // unset($T[$op1['var']]);
[1]1488                    break;
1489                    // }}}
1490                case XC_FREE: // {{{
[716]1491                    $free = $T[$op1['var']];
[1]1492                    if (!is_a($free, 'Decompiler_Array') && !is_a($free, 'Decompiler_Box')) {
1493                        $op['php'] = is_object($free) ? $free : $this->unquote($free, '(', ')');
1494                        $lastphpop = &$op;
1495                    }
[716]1496                    unset($T[$op1['var']], $free);
[1]1497                    break;
1498                    // }}}
1499                case XC_JMP_NO_CTOR:
1500                    break;
[749]1501                case XC_JMP_SET: // ?:
[760]1502                    $resvar = $this->getOpVal($op1, $EX);
1503                    $op['cond'] = $resvar; 
1504                    $op['isjmp'] = true;
1505                    break;
[1]1506                case XC_JMPNZ: // while
1507                case XC_JMPZNZ: // for
1508                case XC_JMPZ_EX: // and
1509                case XC_JMPNZ_EX: // or
1510                case XC_JMPZ: // {{{
1511                    if ($opc == XC_JMP_NO_CTOR && $EX['object']) {
1512                        $rvalue = $EX['object'];
1513                    }
1514                    else {
1515                        $rvalue = $this->getOpVal($op1, $EX);
1516                    }
1517
1518                    if (isset($op['cond_true'])) {
1519                        // any true comes here, so it's a "or"
1520                        $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;
1521                        unset($op['cond_true']);
1522                    }
1523                    if (isset($op['cond_false'])) {
[723]1524                        echo "TODO(cond_false):\n";
[1]1525                        var_dump($op);// exit;
1526                    }
[760]1527                    if ($opc == XC_JMPZ_EX || $opc == XC_JMPNZ_EX) {
[716]1528                        $targetop = &$EX['opcodes'][$op2['opline_num']];
[1]1529                        if ($opc == XC_JMPNZ_EX) {
[744]1530                            $targetop['cond_true'][] = foldToCode($rvalue, $EX);
[1]1531                        }
1532                        else {
[744]1533                            $targetop['cond_false'][] = foldToCode($rvalue, $EX);
[1]1534                        }
1535                        unset($targetop);
1536                    }
1537                    else {
1538                        $op['cond'] = $rvalue; 
1539                        $op['isjmp'] = true;
1540                    }
1541                    break;
1542                    // }}}
[758]1543                case XC_CONT:
1544                case XC_BRK:
1545                    $op['cond'] = null;
1546                    $op['isjmp'] = true;
1547                    $resvar = $opc == XC_CONT ? 'continue' : 'break';
1548                    $count = str($this->getOpVal($op2, $EX));
1549                    if ($count != '1') {
1550                        $resvar .= ' ' . $count;
1551                    }
1552                    break;
[749]1553                case XC_GOTO:
[1]1554                case XC_JMP: // {{{
1555                    $op['cond'] = null;
1556                    $op['isjmp'] = true;
1557                    break;
1558                    // }}}
1559                case XC_CASE:
[743]1560                    $switchValue = $this->getOpVal($op1, $EX);
1561                    $caseValue = $this->getOpVal($op2, $EX);
[744]1562                    $resvar = str($switchValue) . ' == ' . str($caseValue);
[743]1563                    break;
[1]1564                case XC_RECV_INIT:
1565                case XC_RECV:
1566                    $offset = $this->getOpVal($op1, $EX);
1567                    $lvalue = $this->getOpVal($op['result'], $EX);
1568                    if ($opc == XC_RECV_INIT) {
[716]1569                        $default = value($op['op2']['constant']);
[1]1570                    }
1571                    else {
1572                        $default = null;
1573                    }
[737]1574                    $EX['recvs'][str($offset)] = array($lvalue, $default);
[1]1575                    break;
1576                case XC_POST_DEC:
1577                case XC_POST_INC:
1578                case XC_POST_DEC_OBJ:
1579                case XC_POST_INC_OBJ:
1580                case XC_PRE_DEC:
1581                case XC_PRE_INC:
1582                case XC_PRE_DEC_OBJ:
1583                case XC_PRE_INC_OBJ: // {{{
1584                    $flags = array_flip(explode('_', $opname));
1585                    if (isset($flags['OBJ'])) {
[749]1586                        $resvar = $this->getOpVal($op1, $EX) . '->' . unquoteProperty($this->getOpVal($op2, $EX), $EX);
[1]1587                    }
1588                    else {
1589                        $resvar = $this->getOpVal($op1, $EX);
1590                    }
1591                    $opstr = isset($flags['DEC']) ? '--' : '++';
1592                    if (isset($flags['POST'])) {
[749]1593                        $resvar .= $opstr;
[1]1594                    }
1595                    else {
[749]1596                        $resvar = "$opstr$resvar";
[1]1597                    }
1598                    break;
1599                    // }}}
1600
1601                case XC_BEGIN_SILENCE: // {{{
1602                    $EX['silence'] ++;
1603                    break;
1604                    // }}}
1605                case XC_END_SILENCE: // {{{
1606                    $EX['silence'] --;
[744]1607                    $lastresvar = '@' . str($lastresvar, $EX);
[1]1608                    break;
1609                    // }}}
1610                case XC_CAST: // {{{
1611                    $type = $ext;
1612                    static $type2cast = array(
1613                            IS_LONG   => '(int)',
1614                            IS_DOUBLE => '(double)',
1615                            IS_STRING => '(string)',
1616                            IS_ARRAY  => '(array)',
1617                            IS_OBJECT => '(object)',
1618                            IS_BOOL   => '(bool)',
1619                            IS_NULL   => '(unset)',
1620                            );
1621                    assert(isset($type2cast[$type]));
1622                    $cast = $type2cast[$type];
1623                    $resvar = $cast . ' ' . $this->getOpVal($op1, $EX);
1624                    break;
1625                    // }}}
1626                case XC_EXT_STMT:
1627                case XC_EXT_FCALL_BEGIN:
1628                case XC_EXT_FCALL_END:
1629                case XC_EXT_NOP:
1630                    break;
[751]1631                case XC_DECLARE_FUNCTION:
1632                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1633                    break;
[752]1634                case XC_DECLARE_LAMBDA_FUNCTION: // {{{
[749]1635                    ob_start();
1636                    $this->dfunction($this->dc['function_table'][$op1['constant']], $EX['indent']);
1637                    $resvar = ob_get_clean();
1638                    $istmpres = true;
1639                    break;
[752]1640                    // }}}
1641                case XC_DECLARE_CONST:
[753]1642                    $name = $this->stripNamespace(unquoteName($this->getOpVal($op1, $EX), $EX));
1643                    $value = str($this->getOpVal($op2, $EX));
1644                    $resvar = 'const ' . $name . ' = ' . $value;
[752]1645                    break;
[1]1646                case XC_DECLARE_FUNCTION_OR_CLASS:
1647                    /* always removed by compiler */
1648                    break;
1649                case XC_TICKS:
1650                    $lastphpop['ticks'] = $this->getOpVal($op1, $EX);
1651                    // $EX['tickschanged'] = true;
1652                    break;
[749]1653                case XC_RAISE_ABSTRACT_ERROR:
1654                    // abstract function body is empty, don't need this code
1655                    break;
1656                case XC_USER_OPCODE:
1657                    echo '// ZEND_USER_OPCODE, impossible to decompile';
1658                    break;
1659                case XC_OP_DATA:
1660                    break;
[1]1661                default: // {{{
1662                    echo "\x1B[31m * TODO ", $opname, "\x1B[0m\n";
1663                    // }}}
1664                }
1665            }
1666            if (isset($resvar)) {
1667                if ($istmpres) {
[716]1668                    $T[$res['var']] = $resvar;
1669                    $lastresvar = &$T[$res['var']];
[1]1670                }
1671                else {
1672                    $op['php'] = $resvar;
1673                    $lastphpop = &$op;
1674                    $lastresvar = &$op['php'];
1675                }
1676            }
1677        }
1678        return $T;
1679    }
1680    // }}}
1681    function unquote($str, $st, $ed) // {{{
1682    {
1683        $l1 = strlen($st);
1684        $l2 = strlen($ed);
1685        if (substr($str, 0, $l1) === $st && substr($str, -$l2) === $ed) {
1686            $str = substr($str, $l1, -$l2);
1687        }
1688        return $str;
1689    }
1690    // }}}
1691    function popargs(&$EX, $n) // {{{
1692    {
1693        $args = array();
1694        for ($i = 0; $i < $n; $i ++) {
1695            $a = array_pop($EX['argstack']);
1696            if (is_array($a)) {
[744]1697                array_unshift($args, foldToCode($a, $EX));
[1]1698            }
1699            else {
1700                array_unshift($args, $a);
1701            }
1702        }
1703        return implode(', ', $args);
1704    }
1705    // }}}
1706    function dumpop($op, &$EX) // {{{
1707    {
1708        $op1 = $op['op1'];
1709        $op2 = $op['op2'];
1710        $d = array('opname' => xcache_get_opcode($op['opcode']), 'opcode' => $op['opcode']);
1711
1712        foreach (array('op1' => 'op1', 'op2' => 'op2', 'result' => 'res') as $k => $kk) {
1713            switch ($op[$k]['op_type']) {
1714            case XC_IS_UNUSED:
[716]1715                $d[$kk] = '*UNUSED* ' . $op[$k]['opline_num'];
[1]1716                break;
1717
1718            case XC_IS_VAR:
[716]1719                $d[$kk] = '$' . $op[$k]['var'];
[1]1720                if ($kk != 'res') {
[749]1721                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
[1]1722                }
1723                break;
1724
1725            case XC_IS_TMP_VAR:
[716]1726                $d[$kk] = '#' . $op[$k]['var'];
[1]1727                if ($kk != 'res') {
[749]1728                    $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
[1]1729                }
1730                break;
1731
1732            case XC_IS_CV:
1733                $d[$kk] = $this->getOpVal($op[$k], $EX);
1734                break;
1735
1736            default:
1737                if ($kk == 'res') {
[731]1738                    var_dump($op);
1739                    exit;
[1]1740                    assert(0);
1741                }
1742                else {
1743                    $d[$kk] = $this->getOpVal($op[$k], $EX);
1744                }
1745            }
1746        }
1747        $d['ext'] = $op['extended_value'];
1748
1749        var_dump($d);
1750    }
1751    // }}}
1752    function dargs(&$EX, $indent) // {{{
1753    {
1754        $op_array = &$EX['op_array'];
1755
1756        if (isset($op_array['num_args'])) {
1757            $c = $op_array['num_args'];
1758        }
1759        else if ($op_array['arg_types']) {
1760            $c = count($op_array['arg_types']);
1761        }
1762        else {
1763            // php4
1764            $c = count($EX['recvs']);
1765        }
1766
1767        $refrest = false;
1768        for ($i = 0; $i < $c; $i ++) {
1769            if ($i) {
1770                echo ', ';
1771            }
[736]1772            $arg = $EX['recvs'][$i + 1];
[1]1773            if (isset($op_array['arg_info'])) {
1774                $ai = $op_array['arg_info'][$i];
1775                if (!empty($ai['class_name'])) {
[753]1776                    echo $this->stripNamespace($ai['class_name']), ' ';
[736]1777                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
[1]1778                        echo 'or NULL ';
1779                    }
1780                }
1781                else if (!empty($ai['array_type_hint'])) {
1782                    echo 'array ';
[736]1783                    if (!ZEND_ENGINE_2_2 && $ai['allow_null']) {
[1]1784                        echo 'or NULL ';
1785                    }
1786                }
1787                if ($ai['pass_by_reference']) {
1788                    echo '&';
1789                }
1790                printf("\$%s", $ai['name']);
1791            }
1792            else {
1793                if ($refrest) {
1794                    echo '&';
1795                }
1796                else if (isset($op_array['arg_types'][$i])) {
1797                    switch ($op_array['arg_types'][$i]) {
1798                    case BYREF_FORCE_REST:
1799                        $refrest = true;
1800                        /* fall */
1801                    case BYREF_FORCE:
1802                        echo '&';
1803                        break;
1804
1805                    case BYREF_NONE:
1806                    case BYREF_ALLOW:
1807                        break;
1808                    default:
1809                        assert(0);
1810                    }
1811                }
[744]1812                echo str($arg[0], $indent);
[1]1813            }
[736]1814            if (isset($arg[1])) {
[744]1815                echo ' = ', str($arg[1], $indent);
[736]1816            }
[1]1817        }
1818    }
1819    // }}}
1820    function dfunction($func, $indent = '', $nobody = false) // {{{
1821    {
[753]1822        $this->detectNamespace($func['op_array']['function_name']);
1823
[1]1824        if ($nobody) {
1825            $EX = array();
1826            $EX['op_array'] = &$func['op_array'];
1827            $EX['recvs'] = array();
1828        }
1829        else {
1830            ob_start();
1831            $newindent = INDENT . $indent;
1832            $EX = &$this->dop_array($func['op_array'], $newindent);
1833            $body = ob_get_clean();
1834            if (!isset($EX['recvs'])) {
1835                $EX['recvs'] = array();
1836            }
1837        }
1838
[753]1839        $functionName = $this->stripNamespace($func['op_array']['function_name']);
[749]1840        if ($functionName == '{closure}') {
1841            $functionName = '';
1842        }
1843        echo 'function ', $functionName, '(';
[1]1844        $this->dargs($EX, $indent);
[749]1845        echo ")";
1846        if ($nobody) {
1847            echo ";\n";
1848        }
1849        else {
1850            if ($functionName !== '') {
1851                echo "\n";
1852                echo $indent, "{\n";
1853            }
1854            else {
1855                echo " {\n";
1856            }
1857
1858            echo $body;
1859            echo "$indent}";
1860            if ($functionName !== '') {
1861                echo "\n";
1862            }
1863        }
[1]1864    }
1865    // }}}
1866    function dclass($class, $indent = '') // {{{
1867    {
[753]1868        $this->detectNamespace($class['name']);
1869
[1]1870        // {{{ class decl
1871        if (!empty($class['doc_comment'])) {
1872            echo $indent;
1873            echo $class['doc_comment'];
1874            echo "\n";
1875        }
1876        $isinterface = false;
1877        if (!empty($class['ce_flags'])) {
1878            if ($class['ce_flags'] & ZEND_ACC_INTERFACE) {
1879                $isinterface = true;
1880            }
1881            else {
[749]1882                if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) {
[1]1883                    echo "abstract ";
1884                }
[749]1885                if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) {
[1]1886                    echo "final ";
1887                }
1888            }
1889        }
[753]1890        echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']);
[1]1891        if ($class['parent']) {
1892            echo ' extends ', $class['parent'];
1893        }
1894        /* TODO */
1895        if (!empty($class['interfaces'])) {
1896            echo ' implements ';
1897            echo implode(', ', $class['interfaces']);
1898        }
1899        echo "\n";
1900        echo $indent, "{";
1901        // }}}
1902        $newindent = INDENT . $indent;
1903        // {{{ const, static
1904        foreach (array('constants_table' => 'const '
1905                    , 'static_members' => 'static $') as $type => $prefix) {
1906            if (!empty($class[$type])) {
1907                echo "\n";
1908                // TODO: skip shadow?
1909                foreach ($class[$type] as $name => $v) {
1910                    echo $newindent;
1911                    echo $prefix, $name, ' = ';
[744]1912                    echo str(value($v), $newindent);
[1]1913                    echo ";\n";
1914                }
1915            }
1916        }
1917        // }}}
1918        // {{{ properties
[730]1919        $member_variables = isset($class['properties_info']) ? $class['properties_info'] : ($class['default_static_members'] + $class['default_properties']);
1920        if ($member_variables) {
[1]1921            echo "\n";
[713]1922            $infos = !empty($class['properties_info']) ? $class['properties_info'] : null;
[730]1923            foreach ($member_variables as $name => $dummy) {
[1]1924                $info = (isset($infos) && isset($infos[$name])) ? $infos[$name] : null;
1925                if (isset($info)) {
1926                    if (!empty($info['doc_comment'])) {
1927                        echo $newindent;
1928                        echo $info['doc_comment'];
1929                        echo "\n";
1930                    }
1931                }
1932
1933                echo $newindent;
[713]1934                $static = false;
1935                if (isset($info)) {
1936                    if ($info['flags'] & ZEND_ACC_STATIC) {
1937                        $static = true;
1938                    }
1939                }
1940                else if (isset($class['default_static_members'][$name])) {
1941                    $static = true;
1942                }
1943
1944                if ($static) {
1945                    echo "static ";
1946                }
1947
1948                $mangled = false;
[731]1949                if (!ZEND_ENGINE_2) {
[1]1950                    echo 'var ';
1951                }
1952                else if (!isset($info)) {
1953                    echo 'public ';
1954                }
1955                else {
1956                    if ($info['flags'] & ZEND_ACC_SHADOW) {
1957                        continue;
1958                    }
1959                    switch ($info['flags'] & ZEND_ACC_PPP_MASK) {
1960                    case ZEND_ACC_PUBLIC:
1961                        echo "public ";
1962                        break;
1963                    case ZEND_ACC_PRIVATE:
1964                        echo "private ";
[713]1965                        $mangled = true;
[1]1966                        break;
1967                    case ZEND_ACC_PROTECTED:
1968                        echo "protected ";
[713]1969                        $mangled = true;
[1]1970                        break;
1971                    }
1972                }
1973
1974                echo '$', $name;
[713]1975
[730]1976                if (isset($info['offset'])) {
1977                    $value = $class[$static ? 'default_static_members_table' : 'default_properties_table'][$info['offset']];
1978                }
1979                else {
1980                    $key = isset($info) ? $info['name'] . ($mangled ? "\000" : "") : $name;
[713]1981
[730]1982                    $value = $class[$static ? 'default_static_members' : 'default_properties'][$key];
1983                }
[713]1984                if (isset($value)) {
[1]1985                    echo ' = ';
[744]1986                    echo str(value($value), $newindent);
[1]1987                }
1988                echo ";\n";
1989            }
1990        }
1991        // }}}
1992        // {{{ function_table
1993        if (isset($class['function_table'])) {
1994            foreach ($class['function_table'] as $func) {
1995                if (!isset($func['scope']) || $func['scope'] == $class['name']) {
1996                    // TODO: skip shadow here
1997                    echo "\n";
1998                    $opa = $func['op_array'];
1999                    if (!empty($opa['doc_comment'])) {
2000                        echo $newindent;
2001                        echo $opa['doc_comment'];
2002                        echo "\n";
2003                    }
2004                    echo $newindent;
[749]2005                    $isAbstractMethod = false;
[1]2006                    if (isset($opa['fn_flags'])) {
[749]2007                        if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isinterface) {
[1]2008                            echo "abstract ";
[749]2009                            $isAbstractMethod = true;
[1]2010                        }
2011                        if ($opa['fn_flags'] & ZEND_ACC_FINAL) {
2012                            echo "final ";
2013                        }
2014                        if ($opa['fn_flags'] & ZEND_ACC_STATIC) {
2015                            echo "static ";
2016                        }
2017
2018                        switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) {
2019                            case ZEND_ACC_PUBLIC:
2020                                echo "public ";
2021                                break;
2022                            case ZEND_ACC_PRIVATE:
2023                                echo "private ";
2024                                break;
2025                            case ZEND_ACC_PROTECTED:
2026                                echo "protected ";
2027                                break;
2028                            default:
2029                                echo "<visibility error> ";
2030                                break;
2031                        }
2032                    }
[749]2033                    $this->dfunction($func, $newindent, $isinterface || $isAbstractMethod);
[1]2034                    if ($opa['function_name'] == 'Decompiler') {
2035                        //exit;
2036                    }
2037                }
2038            }
2039        }
2040        // }}}
2041        echo $indent, "}\n";
2042    }
2043    // }}}
2044    function decompileString($string) // {{{
2045    {
2046        $this->dc = xcache_dasm_string($string);
2047        if ($this->dc === false) {
2048            echo "error compling string\n";
2049            return false;
2050        }
2051    }
2052    // }}}
2053    function decompileFile($file) // {{{
2054    {
2055        $this->dc = xcache_dasm_file($file);
2056        if ($this->dc === false) {
2057            echo "error compling $file\n";
2058            return false;
2059        }
2060    }
2061    // }}}
2062    function output() // {{{
2063    {
[749]2064        echo "<?". "php\n\n";
[1]2065        foreach ($this->dc['class_table'] as $key => $class) {
2066            if ($key{0} != "\0") {
[749]2067                $this->dclass($class);
[1]2068                echo "\n";
2069            }
2070        }
2071
2072        foreach ($this->dc['function_table'] as $key => $func) {
2073            if ($key{0} != "\0") {
[749]2074                $this->dfunction($func);
[1]2075                echo "\n";
2076            }
2077        }
2078
2079        $this->dop_array($this->dc['op_array']);
2080        echo "\n?" . ">\n";
2081        return true;
2082    }
2083    // }}}
2084}
2085
2086// {{{ defines
[749]2087define('ZEND_ENGINE_2_4', PHP_VERSION >= "5.3.99");
2088define('ZEND_ENGINE_2_3', ZEND_ENGINE_2_4 || PHP_VERSION >= "5.3.");
2089define('ZEND_ENGINE_2_2', ZEND_ENGINE_2_3 || PHP_VERSION >= "5.2.");
2090define('ZEND_ENGINE_2_1', ZEND_ENGINE_2_2 || PHP_VERSION >= "5.1.");
2091define('ZEND_ENGINE_2',   ZEND_ENGINE_2_1 || PHP_VERSION >= "5.0.");
2092
[1]2093define('ZEND_ACC_STATIC',         0x01);
2094define('ZEND_ACC_ABSTRACT',       0x02);
2095define('ZEND_ACC_FINAL',          0x04);
2096define('ZEND_ACC_IMPLEMENTED_ABSTRACT',       0x08);
2097
2098define('ZEND_ACC_IMPLICIT_ABSTRACT_CLASS',    0x10);
2099define('ZEND_ACC_EXPLICIT_ABSTRACT_CLASS',    0x20);
2100define('ZEND_ACC_FINAL_CLASS',                0x40);
2101define('ZEND_ACC_INTERFACE',                  0x80);
[749]2102if (ZEND_ENGINE_2_4) {
2103    define('ZEND_ACC_TRAIT',                  0x120);
2104}
[1]2105define('ZEND_ACC_PUBLIC',     0x100);
2106define('ZEND_ACC_PROTECTED',  0x200);
2107define('ZEND_ACC_PRIVATE',    0x400);
2108define('ZEND_ACC_PPP_MASK',  (ZEND_ACC_PUBLIC | ZEND_ACC_PROTECTED | ZEND_ACC_PRIVATE));
2109
2110define('ZEND_ACC_CHANGED',    0x800);
2111define('ZEND_ACC_IMPLICIT_PUBLIC',    0x1000);
2112
2113define('ZEND_ACC_CTOR',       0x2000);
2114define('ZEND_ACC_DTOR',       0x4000);
2115define('ZEND_ACC_CLONE',      0x8000);
2116
2117define('ZEND_ACC_ALLOW_STATIC',   0x10000);
2118
2119define('ZEND_ACC_SHADOW', 0x2000);
2120
[731]2121if (ZEND_ENGINE_2_4) {
2122    define('ZEND_FETCH_GLOBAL',           0x00000000);
2123    define('ZEND_FETCH_LOCAL',            0x10000000);
2124    define('ZEND_FETCH_STATIC',           0x20000000);
2125    define('ZEND_FETCH_STATIC_MEMBER',    0x30000000);
2126    define('ZEND_FETCH_GLOBAL_LOCK',      0x40000000);
2127    define('ZEND_FETCH_LEXICAL',          0x50000000);
2128
2129    define('ZEND_FETCH_TYPE_MASK',        0x70000000);
2130}
2131else {
2132    define('ZEND_FETCH_GLOBAL',           0);
2133    define('ZEND_FETCH_LOCAL',            1);
2134    define('ZEND_FETCH_STATIC',           2);
2135    define('ZEND_FETCH_STATIC_MEMBER',    3);
2136    define('ZEND_FETCH_GLOBAL_LOCK',      4);
2137}
2138
[1]2139define('ZEND_FETCH_CLASS_DEFAULT',    0);
2140define('ZEND_FETCH_CLASS_SELF',       1);
2141define('ZEND_FETCH_CLASS_PARENT',     2);
2142define('ZEND_FETCH_CLASS_MAIN',       3);
2143define('ZEND_FETCH_CLASS_GLOBAL',     4);
2144define('ZEND_FETCH_CLASS_AUTO',       5);
2145define('ZEND_FETCH_CLASS_INTERFACE',  6);
[722]2146define('ZEND_FETCH_CLASS_STATIC',     7);
[731]2147if (ZEND_ENGINE_2_4) {
2148    define('ZEND_FETCH_CLASS_TRAIT',     14);
2149}
2150if (ZEND_ENGINE_2_3) {
2151    define('ZEND_FETCH_CLASS_MASK',     0xF);
2152}
[1]2153
2154define('ZEND_EVAL',               (1<<0));
2155define('ZEND_INCLUDE',            (1<<1));
2156define('ZEND_INCLUDE_ONCE',       (1<<2));
2157define('ZEND_REQUIRE',            (1<<3));
2158define('ZEND_REQUIRE_ONCE',       (1<<4));
2159
2160define('ZEND_ISSET',              (1<<0));
2161define('ZEND_ISEMPTY',            (1<<1));
[731]2162if (ZEND_ENGINE_2_4) {
2163    define('EXT_TYPE_UNUSED',     (1<<5));
2164}
2165else {
2166    define('EXT_TYPE_UNUSED',     (1<<0));
2167}
[1]2168
2169define('ZEND_FETCH_STANDARD',     0);
2170define('ZEND_FETCH_ADD_LOCK',     1);
2171
2172define('ZEND_FE_FETCH_BYREF',     1);
2173define('ZEND_FE_FETCH_WITH_KEY',  2);
2174
2175define('ZEND_MEMBER_FUNC_CALL',   1<<0);
2176define('ZEND_CTOR_CALL',          1<<1);
2177
2178define('ZEND_ARG_SEND_BY_REF',        (1<<0));
2179define('ZEND_ARG_COMPILE_TIME_BOUND', (1<<1));
2180define('ZEND_ARG_SEND_FUNCTION',      (1<<2));
2181
2182define('BYREF_NONE',       0);
2183define('BYREF_FORCE',      1);
2184define('BYREF_ALLOW',      2);
2185define('BYREF_FORCE_REST', 3);
2186define('IS_NULL',     0);
2187define('IS_LONG',     1);
2188define('IS_DOUBLE',   2);
2189define('IS_STRING',   3);
2190define('IS_ARRAY',    4);
2191define('IS_OBJECT',   5);
2192define('IS_BOOL',     6);
2193define('IS_RESOURCE', 7);
2194define('IS_CONSTANT', 8);
2195define('IS_CONSTANT_ARRAY',   9);
2196
2197@define('XC_IS_CV', 16);
2198
2199/*
2200if (preg_match_all('!XC_[A-Z_]+!', file_get_contents(__FILE__), $ms)) {
2201    $verdiff = array();
2202    foreach ($ms[0] as $k) {
2203        if (!defined($k)) {
2204            $verdiff[$k] = -1;
2205            define($k, -1);
2206        }
2207    }
2208    var_export($verdiff);
2209}
2210/*/
2211foreach (array (
2212    'XC_HANDLE_EXCEPTION' => -1,
2213    'XC_FETCH_CLASS' => -1,
2214    'XC_FETCH_' => -1,
2215    'XC_FETCH_DIM_' => -1,
2216    'XC_ASSIGN_DIM' => -1,
2217    'XC_UNSET_DIM' => -1,
[749]2218    'XC_UNSET_OBJ' => -1,
[1]2219    'XC_ASSIGN_OBJ' => -1,
2220    'XC_ISSET_ISEMPTY_DIM_OBJ' => -1,
2221    'XC_ISSET_ISEMPTY_PROP_OBJ' => -1,
2222    'XC_ISSET_ISEMPTY_VAR' => -1,
[720]2223    'XC_INIT_STATIC_METHOD_CALL' => -1,
[1]2224    'XC_INIT_METHOD_CALL' => -1,
2225    'XC_VERIFY_ABSTRACT_CLASS' => -1,
2226    'XC_DECLARE_CLASS' => -1,
2227    'XC_DECLARE_INHERITED_CLASS' => -1,
[714]2228    'XC_DECLARE_INHERITED_CLASS_DELAYED' => -1,
[1]2229    'XC_ADD_INTERFACE' => -1,
2230    'XC_POST_DEC_OBJ' => -1,
2231    'XC_POST_INC_OBJ' => -1,
2232    'XC_PRE_DEC_OBJ' => -1,
2233    'XC_PRE_INC_OBJ' => -1,
2234    'XC_UNSET_OBJ' => -1,
2235    'XC_JMP_NO_CTOR' => -1,
2236    'XC_FETCH_' => -1,
2237    'XC_FETCH_DIM_' => -1,
2238    'XC_UNSET_DIM_OBJ' => -1,
2239    'XC_ISSET_ISEMPTY' => -1,
2240    'XC_INIT_FCALL_BY_FUNC' => -1,
2241    'XC_DO_FCALL_BY_FUNC' => -1,
2242    'XC_DECLARE_FUNCTION_OR_CLASS' => -1,
[749]2243    'XC_INIT_NS_FCALL_BY_NAME' => -1,
2244    'XC_GOTO' => -1,
2245    'XC_CATCH' => -1,
2246    'XC_THROW' => -1,
2247    'XC_INSTANCEOF' => -1,
2248    'XC_DECLARE_FUNCTION' => -1,
2249    'XC_RAISE_ABSTRACT_ERROR' => -1,
2250    'XC_DECLARE_CONST' => -1,
2251    'XC_USER_OPCODE' => -1,
2252    'XC_JMP_SET' => -1,
2253    'XC_DECLARE_LAMBDA_FUNCTION' => -1,
[1]2254) as $k => $v) {
2255    if (!defined($k)) {
2256        define($k, $v);
2257    }
2258}
2259
[749]2260//* XC_UNDEF XC_OP_DATA
[1]2261$content = file_get_contents(__FILE__);
2262for ($i = 0; $opname = xcache_get_opcode($i); $i ++) {
2263    if (!preg_match("/\\bXC_" . $opname . "\\b(?!')/", $content)) {
2264        echo "not done ", $opname, "\n";
2265    }
2266}
2267// */
2268// }}}
2269
Note: See TracBrowser for help on using the repository browser.