summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/phpdc.phpr70
-rwxr-xr-xbin/phpdop.phpr142
-rwxr-xr-xdevel/run3
-rw-r--r--lib/Decompiler.class.php134
4 files changed, 145 insertions, 204 deletions
diff --git a/bin/phpdc.phpr b/bin/phpdc.phpr
index 969cbb5..0c1bc08 100755
--- a/bin/phpdc.phpr
+++ b/bin/phpdc.phpr
@@ -1,6 +1,9 @@
#! /usr/bin/php -dopen_basedir=
<?php
+// you should write your own phpdc.phpr file if you want to do batch decompile
+// using glob and/or Recursive Directory Iterator
+
$srcdir = dirname(__FILE__);
require_once("$srcdir/../lib/Decompiler.class.php");
if (file_exists("$srcdir/phpdc.debug.php")) {
@@ -9,19 +12,45 @@ if (file_exists("$srcdir/phpdc.debug.php")) {
if (!isset($argv)) {
$argv = $_SERVER['argv'];
- $argc = $_SERVER['argc'];
}
-$dc = new Decompiler();
-if (isset($argv[2])) {
- eval('$dc->decompileDasm(' . file_get_contents($argv[2]) . ');');
-}
-else if (isset($argv[1])) {
- if ($dc->decompileFile($argv[1]) === false) {
- exit(2);
+$inputType = 'php';
+$outputType = 'decompile';
+$files = array();
+
+reset($argv);
+while (($arg = next($argv)) !== false) {
+ switch ($arg) {
+ case '-h':
+ echo "Usage: phpdc.phpr [-dca] [filename]";
+ echo " -c: decompile into PHP code";
+ echo " -d: dump into opcode";
+ echo " -a: input file is dasm opcode return from xcache_dasm_*";
+ echo " -h: this help page";
+ break;
+
+ case '-c':
+ $outputType = 'php';
+ break;
+
+ case '-d':
+ $outputType = 'opcode';
+ break;
+
+ case '--':
+ break 2;
+
+ case '-a':
+ $inputType = 'opcode';
+ break;
+
+ default:
+ $files[] = $arg;
+ break;
}
}
-else {
+
+if (!$files) {
$phpcode = '';
if (!defined('stdin')) {
define('stdin', fopen('php://stdin', 'rb'));
@@ -29,9 +58,30 @@ else {
while (!feof(stdin)) {
$phpcode .= fgets(stdin);
}
+ $dc = new Decompiler($outputType);
if ($dc->decompileString($phpcode) === false) {
exit(2);
}
+ $dc->output();
+}
+else {
+ foreach ($files as $file) {
+ $dc = new Decompiler($outputType);
+ switch ($inputType) {
+ case 'opcode':
+ eval('$opcode = ' . file_get_contents($file) . ';');
+ if ($dc->decompileDasm($opcode) === false) {
+ exit(2);
+ }
+ break;
+
+ case 'php';
+ if ($dc->decompileFile($file) === false) {
+ exit(2);
+ }
+ break;
+ }
+ $dc->output();
+ }
}
-$dc->output();
diff --git a/bin/phpdop.phpr b/bin/phpdop.phpr
deleted file mode 100755
index 03d40d4..0000000
--- a/bin/phpdop.phpr
+++ /dev/null
@@ -1,142 +0,0 @@
-#! /usr/bin/php
-<?php
-
-$srcdir = dirname(__FILE__);
-require_once("$srcdir/../lib/Decompiler.class.php");
-if (file_exists("$srcdir/phpdc.debug.php")) {
- include("$srcdir/phpdc.debug.php");
-}
-
-function get_op($op, $which)
-{
- switch ($op[$which . '_type']) {
- case 1: // CONST
- return $op[$which . '.var'] . var_export($op[$which . '.constant'], true);
-
- case 2: // IS_TMP_VAR
- return 't@' . $op[$which . '.var'];
-
- case 4:
- return 'v$' . $op[$which . '.var'];
-
- case 8: // UNUSED
- if (isset($op[$which . '.opline_num'])) {
- return 'l#' . $op[$which . '.opline_num'];
- }
- else {
- return '-';
- }
-
- default:
- return $op[$which . '_type'] . '?' . $op[$which . '.var'];
- }
-}
-
-function dump_opcodes($op_array, $indent = '')
-{
- global $decompiler;
-
- $types = array('result' => 8, 'op1' => 20, 'op2' => 20);
- $opcodes = &$op_array['opcodes'];
- $decompiler->fixOpcode($opcodes);
- $decompiler->buildJmpInfo($op_array);
- foreach ($opcodes as $line => $op) {
- echo $indent;
- echo sprintf("%3d ", $op['lineno']);
- echo sprintf("%3d ", $line);
- $name = xcache_get_opcode($op['opcode']);
-
- if (substr($name, 0, 5) == 'ZEND_') {
- $name = substr($name, 5);
- }
- echo str_pad($name, 25);
-
- foreach ($types as $which => $len) {
- echo str_pad(get_op($op, $which), $len);
- }
- printf("%5s", isset($op['extended_value']) ? $op['extended_value'] : "");
- if (isset($op['jmpouts']) || isset($op['jmpins'])) {
- printf("%10s %10s"
- , (isset($op['jmpouts']) ? '>' . implode(',', $op['jmpouts']) : '')
- , (isset($op['jmpins']) ? '<' . implode(',', $op['jmpins']) : '')
- );
- }
- if (isset($op['isCatchBegin'])) {
- echo 'CB';
- }
-
- echo "\n";
- }
-}
-
-function dump_function($name, $func, $indent = '')
-{
- if (isset($func['op_array'])) {
- $op_array = $func['op_array'];
- unset($func['op_array']);
- }
- else {
- $op_array = null;
- }
- var_dump($func);
- echo $indent, 'function ', $name, "\n";
- if (isset($op_array)) {
- dump_opcodes($op_array, " " . $indent);
- }
-}
-
-function dump_class($name, $class, $indent = '')
-{
- if (isset($class['function_table'])) {
- $funcs = $class['function_table'];
- unset($class['function_table']);
- }
- else {
- $funcs = null;
- }
- echo $indent, 'class ', $name, "\n";
- if (isset($funcs)) {
- foreach ($funcs as $name => $func) {
- dump_function($name, $func, " " . $indent);
- }
- }
-}
-
-if (!isset($argv[1])) {
- die("Usage: $argv[0] <file>\n");
-}
-$decompiler = new Decompiler();
-if (isset($argv[2])) {
- eval('$pk = ' . file_get_contents($argv[2]) . ';');
-}
-else {
- $pk = xcache_dasm_file($argv[1]);
-}
-$op_array = $funcs = $classes = null;
-if (isset($pk['op_array'])) {
- $op_array = $pk['op_array'];
- unset($pk['op_array']);
-}
-if (isset($pk['function_table'])) {
- $funcs = $pk['function_table'];
- unset($pk['function_table']);
-}
-if (isset($pk['class_table'])) {
- $classes = $pk['class_table'];
- unset($pk['class_table']);
-}
-var_dump($pk);
-if (isset($classes)) {
- foreach ($classes as $name => $class) {
- dump_class($name, $class);
- }
-}
-if (isset($funcs)) {
- foreach ($funcs as $name => $func) {
- dump_function($name, $func);
- }
-}
-if (isset($op_array)) {
- dump_opcodes($op_array);
-}
-
diff --git a/devel/run b/devel/run
index bd6790d..fc98adc 100755
--- a/devel/run
+++ b/devel/run
@@ -313,7 +313,8 @@ run() {
dop)
shift
cmd=(./php-cli -c devel.ini)
- phpApp=(./bin/phpdop.phpr)
+ phpApp=(./bin/phpdc.phpr)
+ set -- -d "$@"
;;
fcgi)
shift
diff --git a/lib/Decompiler.class.php b/lib/Decompiler.class.php
index 93e72b0..dc843b8 100644
--- a/lib/Decompiler.class.php
+++ b/lib/Decompiler.class.php
@@ -591,9 +591,11 @@ class Decompiler
var $activeClass;
var $activeMethod;
var $activeFunction;
+ var $dumpOnly;
- function Decompiler()
+ function Decompiler($outputType)
{
+ $this->dumpOnly = $outputType == 'opcode';
$GLOBALS['__xcache_decompiler'] = $this;
// {{{ testing
// XC_UNDEF XC_OP_DATA
@@ -760,7 +762,10 @@ class Decompiler
case XC_IS_TMP_VAR:
$T = &$EX['Ts'];
if (!isset($T[$op['var']])) {
- printBacktrace();
+ if (!$this->dumpOnly) {
+ printBacktrace();
+ }
+ return null;
}
$ret = $T[$op['var']];
if ($free && empty($this->keepTs)) {
@@ -1536,16 +1541,30 @@ class Decompiler
$EX['value2constant'][$this->activeFunction] = '__FUNCTION__';
}
- /* dump whole array
- $this->keepTs = true;
- $this->dasmBasicBlock($EX, $range);
- for ($i = $range[0]; $i <= $range[1]; ++$i) {
- echo $i, "\t", $this->dumpop($opcodes[$i], $EX);
- }
- // */
- // decompile in a tree way
$range = array(0, count($opcodes) - 1);
- $this->recognizeAndDecompileClosedBlocks($EX, $range);
+ if ($this->dumpOnly) {
+ $this->keepTs = true;
+ $this->dasmBasicBlock($range);
+ $this->dumpRange($range);
+ }
+ else {
+ // decompile in a tree way
+ $this->recognizeAndDecompileClosedBlocks($range);
+ }
+ return $EX;
+ }
+ // }}}
+ function &dump_op_array($op_array, $indent = '') // {{{
+ {
+ $op_array['opcodes'] = $this->fixOpCode($op_array['opcodes']);
+ $this->buildJmpInfo($op_array);
+
+ $EX = array();
+ $EX['op_array'] = &$op_array;
+ $EX['opcodes'] = &$op_array['opcodes'];
+ $EX['indent'] = $indent;
+ $range = array(0, count($EX['opcodes']) - 1);
+ $this->dumpRange($EX, $range);
return $EX;
}
// }}}
@@ -1576,10 +1595,10 @@ class Decompiler
if ($opname == 'UNDEF' || !isset($opname)) {
echo '// UNDEF OP:';
- $this->dumpop($op, $EX);
+ $this->dumpOp($op, $EX);
continue;
}
- // echo $i, ' '; $this->dumpop($op, $EX); //var_dump($op);
+ // echo $i, ' '; $this->dumpOp($op, $EX); //var_dump($op);
$resvar = null;
unset($curResVar);
@@ -1734,7 +1753,7 @@ class Decompiler
$src = new Decompiler_ListBox($list);
if (!isset($op1['var'])) {
- $this->dumpop($op, $EX);
+ $this->dumpOp($op, $EX);
var_dump($op);
die('missing var');
}
@@ -2443,60 +2462,69 @@ class Decompiler
return implode(', ', $args);
}
// }}}
- function dumpop($op, &$EX) // {{{
+ function getOp($op, $which, &$EX) // {{{
{
- assert('isset($op)');
- $op1 = $op['op1'];
- $op2 = $op['op2'];
- $d = array(xcache_get_opcode($op['opcode']), $op['opcode']);
+ switch ($op['op_type']) {
+ case XC_IS_UNUSED:
+ return '?' . $op['opline_num'];
- foreach (array('op1' => '1:', 'op2' => '2:', 'result' => '>') as $k => $kk) {
- switch ($op[$k]['op_type']) {
- case XC_IS_UNUSED:
- $d[$kk] = 'U:' . $op[$k]['opline_num'];
- break;
+ case XC_IS_VAR:
+ $s = '$' . $op['var'];
+ if ($which != 'result' && isset($EX['Ts'])) {
+ $s .= ':' . str($this->getOpVal($op, $EX));
+ }
+ return $s;
- case XC_IS_VAR:
- $d[$kk] = '$' . $op[$k]['var'];
- if ($k != 'result') {
- $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
- }
- break;
+ case XC_IS_TMP_VAR:
+ $s = '#' . $op['var'];
+ if ($which != 'result' && isset($EX['Ts'])) {
+ $s .= ':' . str($this->getOpVal($op, $EX));
+ }
+ return $s;
- case XC_IS_TMP_VAR:
- $d[$kk] = '#' . $op[$k]['var'];
- if ($k != 'result') {
- $d[$kk] .= ':' . str($this->getOpVal($op[$k], $EX));
- }
- break;
+ case XC_IS_CONST:
+ return isset($EX['Ts']) ? str($this->getOpVal($op, $EX)) : $op['var'] . var_export($op['constant'], true);
- case XC_IS_CV:
- $d[$kk] = $this->getOpVal($op[$k], $EX);
- break;
+ default:
+ return isset($EX['Ts']) ? str($this->getOpVal($op, $EX)) : $op['op_type'] . '?' . $op['var'];
+ }
+ }
+ // }}}
+ function dumpOp($op, &$EX) // {{{
+ {
+ assert('isset($op)');
+ echo str_pad($op['lineno'], 4);
- default:
- $d[$kk] = $this->getOpVal($op[$k], $EX);
- }
+ $name = xcache_get_opcode($op['opcode']);
+
+ if (substr($name, 0, 5) == 'ZEND_') {
+ $name = substr($name, 5);
+ }
+ echo str_pad($name, 25);
+
+ $types = array('result' => 9, 'op1' => 20, 'op2' => 20);
+ foreach ($types as $which => $len) {
+ echo str_pad(($which == 'result' ? '>' : '') . $this->getOp($op[$which], $which, $EX), $len);
+ }
+ echo "\t;", $op['extended_value'];
+ if (isset($op['isCatchBegin'])) {
+ echo ' CB';
}
- $d[';'] = $op['extended_value'];
if (!empty($op['jmptos'])) {
- $d['>>'] = implode(',', $op['jmptos']);
+ echo "\t>>", implode(',', $op['jmptos']);
}
if (!empty($op['jmpfroms'])) {
- $d['<<'] = implode(',', $op['jmpfroms']);
+ echo "\t<<", implode(',', $op['jmpfroms']);
}
- foreach ($d as $k => $v) {
- echo is_int($k) ? '' : $k, str($v), "\t";
- }
echo PHP_EOL;
}
// }}}
function dumpRange(&$EX, $range) // {{{
{
for ($i = $range[0]; $i <= $range[1]; ++$i) {
- echo $EX['indent'], $i, "\t";
- $this->dumpop($EX['opcodes'][$i], $EX);
+ echo $EX['indent'], str_pad($i, 4);
+ $this->dumpOp($EX['opcodes'][$i], $EX);
}
echo $EX['indent'], "==", PHP_EOL;
}
@@ -2847,7 +2875,11 @@ class Decompiler
// }}}
function output() // {{{
{
- echo "<?". "php\n\n";
+ echo "<?". "php";
+ if ($this->dumpOnly) {
+ echo " // dump opcode only";
+ }
+ echo "\n\n";
foreach ($this->dc['class_table'] as $key => $class) {
if ($key{0} != "\0") {
$this->activeClass = $class['name'];