Changeset 811 for trunk/Decompiler.class.php
- Timestamp:
- 2011-04-27T09:55:20+02:00 (2 years ago)
- File:
-
- 1 edited
-
trunk/Decompiler.class.php (modified) (37 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Decompiler.class.php
r810 r811 559 559 } 560 560 // }}} 561 function outputPhp(&$EX, $range , $indent) // {{{561 function outputPhp(&$EX, $range) // {{{ 562 562 { 563 563 $needBlankline = isset($EX['lastBlock']); 564 $ origindent = $indent;564 $indent = $EX['indent']; 565 565 $curticks = 0; 566 566 for ($i = $range[0]; $i <= $range[1]; $i ++) { … … 579 579 $curticks = $toticks; 580 580 if (!$curticks) { 581 echo $ origindent, "}\n\n";582 $indent = $ origindent;581 echo $EX['indent'], "}\n\n"; 582 $indent = $EX['indent']; 583 583 } 584 584 else { 585 585 if ($oldticks) { 586 echo $ origindent, "}\n\n";586 echo $EX['indent'], "}\n\n"; 587 587 } 588 588 else if (!$oldticks) { … … 593 593 echo PHP_EOL; 594 594 } 595 echo $ origindent, "declare (ticks=$curticks) {\n";595 echo $EX['indent'], "declare (ticks=$curticks) {\n"; 596 596 } 597 597 } … … 605 605 } 606 606 if ($curticks) { 607 echo $ origindent, "}\n";607 echo $EX['indent'], "}\n"; 608 608 } 609 609 } … … 700 700 } 701 701 // }}} 702 function decompileBasicBlock(&$EX, $range, $ indent, $unhandled = false) // {{{702 function decompileBasicBlock(&$EX, $range, $unhandled = false) // {{{ 703 703 { 704 704 $this->dasmBasicBlock($EX, $range); 705 705 if ($unhandled) { 706 $this->dumpRange($EX, $range , $indent);707 } 708 $this->outputPhp($EX, $range , $indent);706 $this->dumpRange($EX, $range); 707 } 708 $this->outputPhp($EX, $range); 709 709 } 710 710 // }}} … … 731 731 } 732 732 // }}} 733 function beginScope(&$EX, $doIndent = true) // {{{ 734 { 735 array_push($EX['scopeStack'], array($EX['lastBlock'], $EX['indent'])); 736 if ($doIndent) { 737 $EX['indent'] .= INDENT; 738 } 739 $EX['lastBlock'] = null; 740 } 741 // }}} 742 function endScope(&$EX) // {{{ 743 { 744 list($EX['lastBlock'], $EX['indent']) = array_pop($EX['scopeStack']); 745 } 746 // }}} 733 747 function beginComplexBlock(&$EX) // {{{ 734 748 { … … 744 758 } 745 759 // }}} 746 function decompileComplexBlock(&$EX, $range , $indent) // {{{760 function decompileComplexBlock(&$EX, $range) // {{{ 747 761 { 748 762 $T = &$EX['Ts']; 749 763 $opcodes = &$EX['opcodes']; 764 $indent = $EX['indent']; 750 765 751 766 $firstOp = &$opcodes[$range[0]]; … … 760 775 $this->removeJmpInfo($EX, $range[0]); 761 776 762 $this->recognizeAndDecompileClosedBlocks($EX, array($range[0], $range[0]) , $indent . INDENT);777 $this->recognizeAndDecompileClosedBlocks($EX, array($range[0], $range[0])); 763 778 $op1 = $this->getOpVal($firstOp['result'], $EX, true); 764 779 765 $this->recognizeAndDecompileClosedBlocks($EX, array($range[0] + 1, $range[1]) , $indent . INDENT);780 $this->recognizeAndDecompileClosedBlocks($EX, array($range[0] + 1, $range[1])); 766 781 $op2 = $this->getOpVal($lastOp['result'], $EX, true); 767 782 … … 782 797 783 798 $condition = $this->getOpVal($firstOp['op1'], $EX); 784 $this->recognizeAndDecompileClosedBlocks($EX, $trueRange , $indent . INDENT);799 $this->recognizeAndDecompileClosedBlocks($EX, $trueRange); 785 800 $trueValue = $this->getOpVal($opcodes[$trueRange[1]]['result'], $EX, true); 786 $this->recognizeAndDecompileClosedBlocks($EX, $falseRange , $indent . INDENT);801 $this->recognizeAndDecompileClosedBlocks($EX, $falseRange); 787 802 $falseValue = $this->getOpVal($opcodes[$falseRange[1]]['result'], $EX, true); 788 803 $T[$opcodes[$trueRange[1]]['result']['var']] = new Decompiler_TriOp($condition, $trueValue, $falseValue); … … 798 813 $opcodes[$target]['gofrom'][] = $range[0]; 799 814 800 $this->recognizeAndDecompileClosedBlocks($EX, $range , $indent);815 $this->recognizeAndDecompileClosedBlocks($EX, $range); 801 816 return false; 802 817 } … … 814 829 815 830 $initial = ''; 816 $this->dasmBasicBlock($EX, $conditionRange, $indent . INDENT); 831 $this->beginScope($EX); 832 $this->dasmBasicBlock($EX, $conditionRange); 817 833 $conditionCodes = array(); 818 834 for ($i = $conditionRange[0]; $i <= $conditionRange[1]; ++$i) { … … 825 841 $conditionCodes = array(); 826 842 } 827 828 $this->dasmBasicBlock($EX, $nextRange, $indent . INDENT); 843 $this->endScope($EX); 844 845 $this->beginScope($EX); 846 $this->dasmBasicBlock($EX, $nextRange); 829 847 $nextCodes = array(); 830 848 for ($i = $nextRange[0]; $i <= $nextRange[1]; ++$i) { … … 833 851 } 834 852 } 853 $this->endScope($EX); 854 835 855 $this->beginComplexBlock($EX); 836 856 echo $indent, 'for (', str($initial, $EX), '; ', implode(', ', $conditionCodes), '; ', implode(', ', $nextCodes), ') ', '{', PHP_EOL; 837 $this->recognizeAndDecompileClosedBlocks($EX, $bodyRange, $indent . INDENT); 857 $this->beginScope($EX); 858 $this->recognizeAndDecompileClosedBlocks($EX, $bodyRange); 859 $this->endScope($EX); 838 860 echo $indent, '}', PHP_EOL; 839 861 $this->endComplexBlock($EX); … … 852 874 853 875 echo $indent, $isElseIf ? 'else if' : 'if', ' (', str($condition, $EX), ') ', '{', PHP_EOL; 854 $this->recognizeAndDecompileClosedBlocks($EX, $ifRange, $indent . INDENT); 876 $this->beginScope($EX); 877 $this->recognizeAndDecompileClosedBlocks($EX, $ifRange); 878 $this->endScope($EX); 855 879 $EX['lastBlock'] = null; 856 880 echo $indent, '}', PHP_EOL; … … 873 897 $elseRange = array($ifRange[1], $range[1]); 874 898 echo $indent, 'else ', '{', PHP_EOL; 875 $this->recognizeAndDecompileClosedBlocks($EX, $elseRange, $indent . INDENT); 899 $this->beginScope($EX); 900 $this->recognizeAndDecompileClosedBlocks($EX, $elseRange); 901 $this->endScope($EX); 876 902 $EX['lastBlock'] = null; 877 903 echo $indent, '}', PHP_EOL; … … 916 942 $this->beginComplexBlock($EX); 917 943 echo $indent, "try {", PHP_EOL; 918 $this->recognizeAndDecompileClosedBlocks($EX, $tryRange, $indent . INDENT); 944 $this->beginScope($EX); 945 $this->recognizeAndDecompileClosedBlocks($EX, $tryRange); 946 $this->endScope($EX); 919 947 echo $indent, '}', PHP_EOL; 920 948 foreach ($catchBlocks as $catchFirst => $catchInfo) { 921 949 list($catchOpLine, $catchBodyLast) = $catchInfo; 922 950 $catchBodyFirst = $catchOpLine + 1; 923 $this-> recognizeAndDecompileClosedBlocks($EX, array($catchFirst, $catchOpLine), $indent);951 $this->dasmBasicBlock($EX, array($catchFirst, $catchOpLine)); 924 952 $catchOp = &$opcodes[$catchOpLine]; 925 953 echo $indent, 'catch (', str($this->getOpVal($catchOp['op1'], $EX)), ' ', str($this->getOpVal($catchOp['op2'], $EX)), ") {", PHP_EOL; … … 927 955 928 956 $EX['lastBlock'] = null; 929 $this->recognizeAndDecompileClosedBlocks($EX, array($catchBodyFirst, $catchBodyLast), $indent . INDENT); 957 $this->beginScope($EX); 958 $this->recognizeAndDecompileClosedBlocks($EX, array($catchBodyFirst, $catchBodyLast)); 959 $this->endScope($EX); 930 960 echo $indent, '}', PHP_EOL; 931 961 } … … 982 1012 $caseIsOut = false; 983 1013 foreach ($cases as $caseFirst => $caseLast) { 984 if ($caseIsOut && !empty($EX['lastBlock']) &&empty($lastCaseFall)) {1014 if ($caseIsOut && empty($lastCaseFall)) { 985 1015 echo PHP_EOL; 986 1016 } 987 unset($EX['lastBlock']);988 1017 989 1018 $caseOp = $opcodes[$caseFirst]; … … 1025 1054 } 1026 1055 1027 $this->recognizeAndDecompileClosedBlocks($EX, array($caseFirst, $caseLast), $indent . INDENT); 1056 $this->beginScope($EX); 1057 $this->recognizeAndDecompileClosedBlocks($EX, array($caseFirst, $caseLast)); 1058 $this->endScope($EX); 1028 1059 $caseIsOut = true; 1029 1060 } … … 1041 1072 1042 1073 echo $indent, "do {", PHP_EOL; 1043 $this->recognizeAndDecompileClosedBlocks($EX, $range, $indent . INDENT); 1074 $this->beginScope($EX); 1075 $this->recognizeAndDecompileClosedBlocks($EX, $range); 1076 $this->endScope($EX); 1044 1077 echo $indent, "} while (", str($this->getOpVal($lastOp['op1'], $EX)), ');', PHP_EOL; 1045 1078 … … 1072 1105 1073 1106 ob_start(); 1074 $this->recognizeAndDecompileClosedBlocks($EX, $range, $indent . INDENT); 1107 $this->beginScope($EX); 1108 $this->recognizeAndDecompileClosedBlocks($EX, $range); 1109 $this->endScope($EX); 1075 1110 $body = ob_get_clean(); 1076 1111 … … 1094 1129 1095 1130 ob_start(); 1096 $this->recognizeAndDecompileClosedBlocks($EX, $range, $indent . INDENT); 1131 $this->beginScope($EX); 1132 $this->recognizeAndDecompileClosedBlocks($EX, $range); 1133 $this->endScope($EX); 1097 1134 $body = ob_get_clean(); 1098 1135 … … 1114 1151 // }}} 1115 1152 1116 $this->decompileBasicBlock($EX, $range, $indent,true);1117 } 1118 // }}} 1119 function recognizeAndDecompileClosedBlocks(&$EX, $range , $indent) // {{{ decompile in a tree way1153 $this->decompileBasicBlock($EX, $range, true); 1154 } 1155 // }}} 1156 function recognizeAndDecompileClosedBlocks(&$EX, $range) // {{{ decompile in a tree way 1120 1157 { 1121 1158 $opcodes = &$EX['opcodes']; … … 1148 1185 if ($blockLast >= $blockFirst) { 1149 1186 if ($blockFirst > $starti) { 1150 $this->decompileBasicBlock($EX, array($starti, $blockFirst - 1) , $indent);1151 } 1152 if ($this->decompileComplexBlock($EX, array($blockFirst, $blockLast) , $indent) === false) {1187 $this->decompileBasicBlock($EX, array($starti, $blockFirst - 1)); 1188 } 1189 if ($this->decompileComplexBlock($EX, array($blockFirst, $blockLast)) === false) { 1153 1190 if ($EX['lastBlock'] == 'complex') { 1154 1191 echo PHP_EOL; … … 1168 1205 } 1169 1206 if ($starti <= $range[1]) { 1170 $this->decompileBasicBlock($EX, array($starti, $range[1]) , $indent);1207 $this->decompileBasicBlock($EX, array($starti, $range[1])); 1171 1208 } 1172 1209 } … … 1289 1326 $EX['argstack'] = array(); 1290 1327 $EX['arg_types_stack'] = array(); 1328 $EX['scopeStack'] = array(); 1291 1329 $EX['silence'] = 0; 1292 1330 $EX['recvs'] = array(); … … 1304 1342 $this->recognizeAndDecompileClosedBlocks($EX, $EX['range'], $EX['indent']); 1305 1343 return $EX; 1306 }1307 // }}}1308 function outputCode(&$EX, $range, $indent, $loop = false) // {{{1309 {1310 $op = &$EX['opcodes'][$range[0]];1311 $next = $EX['nextbbs'][$range[0]];1312 1313 $end = $next - 1;1314 if ($end > $range[1]) {1315 $end = $range[1];1316 }1317 1318 if (isset($op['jmpins'])) {1319 echo "\nline", $op['line'], ":\n";1320 }1321 else {1322 // echo ";;;\n";1323 }1324 $this->dasmBasicBlock($EX, array($opline, $end));1325 $this->outputPhp($EX, array($opline, $end), $indent);1326 // jmpout op1327 $op = &$EX['opcodes'][$end];1328 $op1 = $op['op1'];1329 $op2 = $op['op2'];1330 $ext = $op['extended_value'];1331 $line = $op['line'];1332 1333 if (isset($EX['opcodes'][$next])) {1334 if (isset($range[1]) && $next > $range[1]) {1335 $next = null;1336 }1337 }1338 else {1339 $next = null;1340 }1341 /*1342 if ($op['opcode'] == XC_JMPZ) {1343 $target = $op2['opline_num'];1344 if ($line + 1) {1345 $nextblock = $EX['nextbbs'][$next];1346 $jmpop = end($nextblock);1347 if ($jmpop['opcode'] == XC_JMP) {1348 $ifendline = $op2['opline_num'];1349 if ($ifendline >= $line) {1350 $cond = $op['cond'];1351 echo "{$indent}if ($cond) {\n";1352 $this->outputCode($EX, $next, $range[1], INDENT . $indent);1353 echo "$indent}\n";1354 $this->outputCode($EX, $target, $range[1], $indent);1355 return;1356 }1357 }1358 }1359 }1360 */1361 if (!isset($next)) {1362 return;1363 }1364 if (isset($op['jmpouts']) && isset($op['isjmp'])) {1365 if (isset($op['cond'])) {1366 echo "{$indent}check (" . str($op["cond"]) . ") {\n";1367 echo INDENT;1368 }1369 switch ($op['opcode']) {1370 case XC_CONT:1371 case XC_BRK:1372 break;1373 1374 default:1375 echo $indent;1376 echo xcache_get_opcode($op['opcode']), ' line', $op['jmpouts'][0];1377 if (isset($op['jmpouts'][1])) {1378 echo ', line', $op['jmpouts'][1];1379 }1380 echo ";";1381 // echo ' // <- line', $op['line'];1382 echo "\n";1383 }1384 if (isset($op['cond'])) echo "$indent}\n";1385 }1386 1387 // proces JMPZ_EX/JMPNZ_EX for AND,OR1388 $op = &$EX['opcodes'][$next];1389 /*1390 if (isset($op['jmpins'])) {1391 foreach (array_reverse($op['jmpins']) as $fromline) {1392 $fromop = $EX['opcodes'][$fromline];1393 switch ($fromop['opcode']) {1394 case XC_JMPZ_EX: $opstr = 'and'; break;1395 case XC_JMPNZ_EX: $opstr = 'or'; break;1396 case XC_JMPZNZ: var_dump($fromop); exit;1397 default: continue 2;1398 }1399 1400 $var = $fromop['result']['var'];1401 var_dump($EX['Ts'][$var]);1402 $EX['Ts'][$var] = '(' . $fromop['and_or'] . " $opstr " . $EX['Ts'][$var] . ')';1403 }1404 #$this->outputCode($EX, $next, $range[1], $indent);1405 #return;1406 }1407 */1408 if (isset($op['cond_false'])) {1409 // $this->dumpop($op, $EX);1410 // any true comes here, so it's a "or"1411 $cond = implode(' and ', str($op['cond_false']));1412 // var_dump($op['cond'] = $cond);1413 /*1414 $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;1415 unset($op['cond_true']);1416 */1417 }1418 1419 $nextRange = array($next, $range[1]);1420 if ($loop) {1421 return $nextRange;1422 }1423 $this->outputCode($EX, $nextRange, $indent);1424 1344 } 1425 1345 // }}} … … 1921 1841 $i += 2; 1922 1842 } 1923 $this->dclass($class );1843 $this->dclass($class, $EX['indent']); 1924 1844 echo "\n"; 1925 1845 unset($class); … … 2070 1990 case XC_JMPZNZ: // for 2071 1991 case XC_JMPZ: // {{{ 2072 if ($opc == XC_JMP_NO_CTOR && $EX['object']) {2073 $rvalue = $EX['object'];2074 }2075 else {2076 $rvalue = $this->getOpVal($op1, $EX);2077 }2078 2079 if (isset($op['cond_true'])) {2080 // any true comes here, so it's a "or"2081 $rvalue = implode(' or ', $op['cond_true']) . ' or ' . $rvalue;2082 unset($op['cond_true']);2083 }2084 if (isset($op['cond_false'])) {2085 echo "TODO(cond_false):\n";2086 var_dump($op);// exit;2087 }2088 $op['cond'] = $rvalue;2089 $op['isjmp'] = true;2090 1992 break; 2091 1993 // }}} 2092 1994 case XC_CONT: 2093 1995 case XC_BRK: 2094 $op['cond'] = null;2095 $op['isjmp'] = true;2096 1996 $resvar = $opc == XC_CONT ? 'continue' : 'break'; 2097 1997 $count = str($this->getOpVal($op2, $EX)); … … 2106 2006 2107 2007 case XC_JMP: // {{{ 2108 $op['cond'] = null;2109 $op['isjmp'] = true;2110 2008 break; 2111 2009 // }}} … … 2342 2240 } 2343 2241 // }}} 2344 function dumpRange(&$EX, $range , $indent = '') // {{{2242 function dumpRange(&$EX, $range) // {{{ 2345 2243 { 2346 2244 for ($i = $range[0]; $i <= $range[1]; ++$i) { 2347 echo $ indent, $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX);2348 } 2349 echo $ indent, "==", PHP_EOL;2350 } 2351 // }}} 2352 function dargs(&$EX , $indent) // {{{2245 echo $EX['indent'], $i, "\t"; $this->dumpop($EX['opcodes'][$i], $EX); 2246 } 2247 echo $EX['indent'], "==", PHP_EOL; 2248 } 2249 // }}} 2250 function dargs(&$EX) // {{{ 2353 2251 { 2354 2252 $op_array = &$EX['op_array']; … … 2410 2308 } 2411 2309 } 2412 echo str($arg[0], $ indent);2310 echo str($arg[0], $EX); 2413 2311 } 2414 2312 if (isset($arg[1])) { 2415 echo ' = ', str($arg[1], $ indent);2416 } 2417 } 2418 } 2419 // }}} 2420 function duses(&$EX , $indent) // {{{2313 echo ' = ', str($arg[1], $EX); 2314 } 2315 } 2316 } 2317 // }}} 2318 function duses(&$EX) // {{{ 2421 2319 { 2422 2320 if ($EX['uses']) { … … 2425 2323 } 2426 2324 // }}} 2427 function dfunction($func, $indent = '', $ nobody = false) // {{{2325 function dfunction($func, $indent = '', $decorations = array(), $nobody = false) // {{{ 2428 2326 { 2429 2327 $this->detectNamespace($func['op_array']['function_name']); … … 2437 2335 else { 2438 2336 ob_start(); 2439 $newindent = INDENT . $indent; 2440 $EX = &$this->dop_array($func['op_array'], $newindent); 2337 $EX = &$this->dop_array($func['op_array'], $indent . INDENT); 2441 2338 $body = ob_get_clean(); 2442 2339 } 2443 2340 2444 2341 $functionName = $this->stripNamespace($func['op_array']['function_name']); 2342 $isExpression = false; 2445 2343 if ($functionName == '{closure}') { 2446 2344 $functionName = ''; 2345 $isExpression = true; 2346 } 2347 echo $isExpression ? '' : $indent; 2348 if ($decorations) { 2349 echo implode(' ', $decorations), ' '; 2447 2350 } 2448 2351 echo 'function', $functionName ? ' ' . $functionName : '', '('; 2449 $this->dargs($EX , $indent);2352 $this->dargs($EX); 2450 2353 echo ")"; 2451 $this->duses($EX , $indent);2354 $this->duses($EX); 2452 2355 if ($nobody) { 2453 2356 echo ";\n"; 2454 2357 } 2455 2358 else { 2456 if ( $functionName !== '') {2359 if (!$isExpression) { 2457 2360 echo "\n"; 2458 2361 echo $indent, "{\n"; … … 2464 2367 echo $body; 2465 2368 echo "$indent}"; 2466 if ( $functionName !== '') {2369 if (!$isExpression) { 2467 2370 echo "\n"; 2468 2371 } … … 2480 2383 echo "\n"; 2481 2384 } 2482 $isinterface = false; 2385 $isInterface = false; 2386 $decorations = array(); 2483 2387 if (!empty($class['ce_flags'])) { 2484 2388 if ($class['ce_flags'] & ZEND_ACC_INTERFACE) { 2485 $is interface = true;2389 $isInterface = true; 2486 2390 } 2487 2391 else { 2488 2392 if ($class['ce_flags'] & ZEND_ACC_IMPLICIT_ABSTRACT_CLASS) { 2489 echo "abstract";2393 $decorations[] = "abstract"; 2490 2394 } 2491 2395 if ($class['ce_flags'] & ZEND_ACC_FINAL_CLASS) { 2492 echo "final "; 2493 } 2494 } 2495 } 2496 echo $isinterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']); 2396 $decorations[] = "final"; 2397 } 2398 } 2399 } 2400 2401 echo $indent; 2402 if ($decorations) { 2403 echo implode(' ', $decorations), ' '; 2404 } 2405 echo $isInterface ? 'interface ' : 'class ', $this->stripNamespace($class['name']); 2497 2406 if ($class['parent']) { 2498 2407 echo ' extends ', $class['parent']; … … 2608 2517 echo "\n"; 2609 2518 } 2610 echo $newindent;2611 2519 $isAbstractMethod = false; 2520 $decorations = array(); 2612 2521 if (isset($opa['fn_flags'])) { 2613 if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$is interface) {2614 echo "abstract";2522 if (($opa['fn_flags'] & ZEND_ACC_ABSTRACT) && !$isInterface) { 2523 $decorations[] = "abstract"; 2615 2524 $isAbstractMethod = true; 2616 2525 } 2617 2526 if ($opa['fn_flags'] & ZEND_ACC_FINAL) { 2618 echo "final";2527 $decorations[] = "final"; 2619 2528 } 2620 2529 if ($opa['fn_flags'] & ZEND_ACC_STATIC) { 2621 echo "static";2530 $decorations[] = "static"; 2622 2531 } 2623 2532 2624 2533 switch ($opa['fn_flags'] & ZEND_ACC_PPP_MASK) { 2625 2534 case ZEND_ACC_PUBLIC: 2626 echo "public";2535 $decorations[] = "public"; 2627 2536 break; 2628 2537 case ZEND_ACC_PRIVATE: 2629 echo "private";2538 $decorations[] = "private"; 2630 2539 break; 2631 2540 case ZEND_ACC_PROTECTED: 2632 echo "protected";2541 $decorations[] = "protected"; 2633 2542 break; 2634 2543 default: 2635 echo "<visibility error>";2544 $decorations[] = "<visibility error>"; 2636 2545 break; 2637 2546 } 2638 2547 } 2639 $this->dfunction($func, $newindent, $ isinterface || $isAbstractMethod);2548 $this->dfunction($func, $newindent, $decorations, $isInterface || $isAbstractMethod); 2640 2549 if ($opa['function_name'] == 'Decompiler') { 2641 2550 //exit;
Note: See TracChangeset
for help on using the changeset viewer.

