Index: /trunk/decompilesample.php
===================================================================
--- /trunk/decompilesample.php	(revision 793)
+++ /trunk/decompilesample.php	(revision 795)
@@ -257,17 +257,21 @@
 $a = $b || $c;
 
-try {
-	echo 'outer try 1';
+do {
 	try {
-		echo 'inner try';
-	}
-	catch (InnerException $e) {
+		echo 'outer try 1';
+
+		try {
+			echo 'inner try';
+		}
+		catch (InnerException $e) {
+			echo $e;
+		}
+
+		echo 'outer try 2';
+	}
+	catch (OuterException $e) {
 		echo $e;
 	}
-	echo 'outer try 2';
-}
-catch (OuterException $e) {
-	echo $e;
-}
+} while (0);
 
 if (if_()) {
Index: /trunk/Decompiler.class.php
===================================================================
--- /trunk/Decompiler.class.php	(revision 791)
+++ /trunk/Decompiler.class.php	(revision 795)
@@ -615,5 +615,6 @@
 	function &fixOpcode($opcodes, $removeTailing = false, $defaultReturnValue = null) // {{{
 	{
-		for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
+		$last = count($opcodes) - 1;
+		for ($i = 0; $i <= $last; $i ++) {
 			if (function_exists('xcache_get_fixed_opcode')) {
 				$opcodes[$i]['opcode'] = xcache_get_fixed_opcode($opcodes[$i]['opcode'], $i);
@@ -706,4 +707,59 @@
 		$lastOp = &$opcodes[$last];
 
+		// {{{ try/catch
+		if (!empty($firstOp['jmpins']) && !empty($opcodes[$firstOp['jmpins'][0]]['isCatchBegin'])) {
+			$catchBlocks = array();
+			$catchFirst = $firstOp['jmpins'][0];
+
+			$tryFirst = $first;
+			$tryLast = $catchFirst - 1;
+
+			// search for XC_CATCH
+			$this->removeJmpInfo($EX, $catchFirst);
+			for ($i = $catchFirst; $i <= $last; ) {
+				if ($opcodes[$i]['opcode'] == XC_CATCH) {
+					$catchOpLine = $i;
+					$this->removeJmpInfo($EX, $catchOpLine);
+
+					$catchNext = $opcodes[$catchOpLine]['extended_value'];
+					$catchBodyLast = $catchNext - 1;
+					if ($opcodes[$catchBodyLast]['opcode'] == XC_JMP) {
+						--$catchBodyLast;
+					}
+
+					$catchBlocks[$catchFirst] = array($catchOpLine, $catchBodyLast);
+
+					$i = $catchFirst = $catchNext;
+				}
+				else {
+					++$i;
+				}
+			}
+
+			if ($opcodes[$tryLast]['opcode'] == XC_JMP) {
+				--$tryLast;
+			}
+
+			$this->beginComplexBlock($EX);
+			echo $indent, 'try {', PHP_EOL;
+			$this->recognizeAndDecompileClosedBlocks($EX, $tryFirst, $tryLast, $indent . INDENT);
+			echo $indent, '}', PHP_EOL;
+			foreach ($catchBlocks as $catchFirst => $catchInfo) {
+				list($catchOpLine, $catchBodyLast) = $catchInfo;
+				$catchBodyFirst = $catchOpLine + 1;
+				$this->recognizeAndDecompileClosedBlocks($EX, $catchFirst, $catchOpLine, $indent);
+				$catchOp = &$opcodes[$catchOpLine];
+				echo $indent, 'catch (', str($this->getOpVal($catchOp['op1'], $EX)), ' ', str($this->getOpVal($catchOp['op2'], $EX)), ') {', PHP_EOL;
+				unset($catchOp);
+
+				$EX['lastBlock'] = null;
+				$this->recognizeAndDecompileClosedBlocks($EX, $catchBodyFirst, $catchBodyLast, $indent . INDENT);
+				echo $indent, '}', PHP_EOL;
+			}
+			$this->endComplexBlock($EX);
+			return;
+		}
+		// }}}
+
 		if ($firstOp['opcode'] == XC_SWITCH_FREE && isset($T[$firstOp['op1']['var']])) {
 			// TODO: merge this code to CASE code. use SWITCH_FREE to detect begin of switch by using $Ts if possible
@@ -722,8 +778,7 @@
 		) {
 			$cases = array();
-			$caseNext = null;
 			$caseDefault = null;
 			$caseOp = null;
-			for ($i = $first; $i <= $last; ++$i) {
+			for ($i = $first; $i <= $last; ) {
 				$op = $opcodes[$i];
 				if ($op['opcode'] == XC_CASE) {
@@ -734,13 +789,16 @@
 					assert('$jmpz["opcode"] == XC_JMPZ');
 					$caseNext = $jmpz['jmpouts'][0];
-					$i = $cases[$i] = $caseNext - 1;
-				}
-				else if ($op['opcode'] == XC_JMP) {
+					$cases[$i] = $caseNext - 1;
+					$i = $caseNext;
+				}
+				else if ($op['opcode'] == XC_JMP && $op['jmpouts'][0] >= $i) {
 					// default
-					if ($op['jmpouts'][0] >= $i) {
-						$caseNext = $op['jmpouts'][0];
-						$caseDefault = $i;
-						$i = $cases[$i] = $caseNext - 1;
-					}
+					$caseNext = $op['jmpouts'][0];
+					$caseDefault = $i;
+					$cases[$i] = $caseNext - 1;
+					$i = $caseNext;
+				}
+				else {
+					++$i;
 				}
 			}
@@ -881,7 +939,6 @@
 
 		$starti = $first;
-		for ($i = $starti; $i <= $last; ++$i) {
-			$op = $opcodes[$i];
-			if (!empty($op['jmpins']) || !empty($op['jmpouts'])) {
+		for ($i = $starti; $i <= $last; ) {
+			if (!empty($opcodes[$i]['jmpins']) || !empty($opcodes[$i]['jmpouts'])) {
 				$blockFirst = $i;
 				$blockLast = -1;
@@ -902,5 +959,7 @@
 					++$j;
 				} while ($j <= $blockLast);
-				assert('$blockLast <= $last');
+				if (!assert('$blockLast <= $last')) {
+					var_dump($blockLast, $last);
+				}
 
 				if ($blockLast >= $blockFirst) {
@@ -910,7 +969,12 @@
 					$this->decompileComplexBlock($EX, $blockFirst, $blockLast, $indent);
 					$starti = $blockLast + 1;
-					$i = $starti - 1;
-					continue;
-				}
+					$i = $starti;
+				}
+				else {
+					++$i;
+				}
+			}
+			else {
+				++$i;
 			}
 		}
@@ -924,6 +988,7 @@
 		$op_array['opcodes'] = $this->fixOpcode($op_array['opcodes'], true, $indent == '' ? 1 : null);
 		$opcodes = &$op_array['opcodes'];
+		$last = count($opcodes) - 1;
 		// {{{ build jmpins/jmpouts to op_array
-		for ($i = 0, $cnt = count($opcodes); $i < $cnt; $i ++) {
+		for ($i = 0; $i <= $last; $i ++) {
 			$op = &$opcodes[$i];
 			$op['line'] = $i;
@@ -987,4 +1052,10 @@
 				$opcodes[$i + 2]['jmpins'][] = $i;
 				break;
+
+			case XC_CATCH:
+				$catchNext = $op['extended_value'];
+				$op['jmpouts'] = array($catchNext);
+				$opcodes[$catchNext]['jmpins'][] = $i;
+				break;
 			}
 			/*
@@ -995,9 +1066,18 @@
 		}
 		unset($op);
+		if ($op_array['try_catch_array']) {
+			foreach ($op_array['try_catch_array'] as $try_catch_element) {
+				$catch_op = $try_catch_element['catch_op'];
+				$try_op = $try_catch_element['try_op'];
+				$opcodes[$try_op]['jmpins'][] = $catch_op;
+				$opcodes[$catch_op]['jmpouts'][] = $try_op;
+				$opcodes[$catch_op]['isCatchBegin'] = true;
+			}
+		}
 		// }}}
 		// build semi-basic blocks
 		$nextbbs = array();
 		$starti = 0;
-		for ($i = 1, $cnt = count($opcodes); $i < $cnt; $i ++) {
+		for ($i = 1; $i <= $last; $i ++) {
 			if (isset($opcodes[$i]['jmpins'])
 			 || isset($opcodes[$i - 1]['jmpouts'])) {
@@ -1006,5 +1086,5 @@
 			}
 		}
-		$nextbbs[$starti] = $cnt;
+		$nextbbs[$starti] = $last + 1;
 
 		$EX = array();
@@ -1239,5 +1319,4 @@
 					// }}}
 				case XC_CATCH: // {{{
-					$resvar = 'catch (' . str($this->getOpVal($op1, $EX)) . ' ' . str($this->getOpVal($op2, $EX)) . ')';
 					break;
 					// }}}
@@ -2022,4 +2101,5 @@
 	function dumpop($op, &$EX) // {{{
 	{
+		assert('isset($op)');
 		$op1 = $op['op1'];
 		$op2 = $op['op2'];
@@ -2053,6 +2133,6 @@
 				if ($k == 'result') {
 					var_dump($op);
+					assert(0);
 					exit;
-					assert(0);
 				}
 				else {
@@ -2062,4 +2142,10 @@
 		}
 		$d[';'] = $op['extended_value'];
+		if (!empty($op['jmpouts'])) {
+			$d['>>'] = implode(',', $op['jmpouts']);
+		}
+		if (!empty($op['jmpins'])) {
+			$d['<<'] = implode(',', $op['jmpins']);
+		}
 
 		foreach ($d as $k => $v) {
