|
|
@ -19,10 +19,7 @@ |
|
|
|
|
|
|
|
|
|
|
|
package jode.flow; |
|
|
|
package jode.flow; |
|
|
|
import java.util.*; |
|
|
|
import java.util.*; |
|
|
|
import jode.TabbedPrintWriter; |
|
|
|
import jode.*; |
|
|
|
import jode.Expression; |
|
|
|
|
|
|
|
import jode.CodeAnalyzer; |
|
|
|
|
|
|
|
import jode.Decompiler; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* A flow block is the structure of which the flow graph consists. A |
|
|
|
* A flow block is the structure of which the flow graph consists. A |
|
|
@ -112,35 +109,11 @@ public class FlowBlock { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public int getNextAddr() { |
|
|
|
public int getNextAddr() { |
|
|
|
return addr+length; |
|
|
|
if (block instanceof RawTryCatchBlock) |
|
|
|
} |
|
|
|
return ((RawTryCatchBlock)block).getTryBlock() |
|
|
|
|
|
|
|
.jump.destination.getNextAddr(); |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Create a Catch- resp. FinallyBlock (maybe even SynchronizedBlock) |
|
|
|
|
|
|
|
* @param sequBlock a SequentialBlock whose first sub block is a |
|
|
|
|
|
|
|
* RawTryCatchBlock. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public StructuredBlock createCatchBlock(SequentialBlock sequBlock) { |
|
|
|
|
|
|
|
RawTryCatchBlock tryBlock = (RawTryCatchBlock) sequBlock.subBlocks[0]; |
|
|
|
|
|
|
|
StructuredBlock catchBlock = sequBlock.subBlocks[1]; |
|
|
|
|
|
|
|
if (tryBlock.type != null) { |
|
|
|
|
|
|
|
/*XXX crude hack */ |
|
|
|
|
|
|
|
catchBlock.replace(sequBlock, tryBlock); |
|
|
|
|
|
|
|
CatchBlock newBlock = new CatchBlock(tryBlock); |
|
|
|
|
|
|
|
newBlock.replace(catchBlock, catchBlock); |
|
|
|
|
|
|
|
newBlock.setCatchBlock(catchBlock); |
|
|
|
|
|
|
|
if (sequBlock.jump != null) { |
|
|
|
|
|
|
|
if (newBlock.catchBlock.jump == null) |
|
|
|
|
|
|
|
newBlock.catchBlock.moveJump(sequBlock.jump); |
|
|
|
|
|
|
|
else |
|
|
|
else |
|
|
|
sequBlock.removeJump(); |
|
|
|
return addr+length; |
|
|
|
} |
|
|
|
|
|
|
|
return newBlock; |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
/* XXX implement finally */ |
|
|
|
|
|
|
|
return sequBlock; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
@ -659,16 +632,6 @@ public class FlowBlock { |
|
|
|
|
|
|
|
|
|
|
|
while (!appendBlock.contains(jump.prev)) { |
|
|
|
while (!appendBlock.contains(jump.prev)) { |
|
|
|
appendBlock = appendBlock.outer; |
|
|
|
appendBlock = appendBlock.outer; |
|
|
|
if (appendBlock instanceof SequentialBlock |
|
|
|
|
|
|
|
&& appendBlock.getSubBlocks()[0] |
|
|
|
|
|
|
|
instanceof RawTryCatchBlock) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* We leave the catch block of a raw-try-catch-block. |
|
|
|
|
|
|
|
* We shall now create the Catch- resp. FinallyBlock. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
appendBlock = |
|
|
|
|
|
|
|
createCatchBlock((SequentialBlock)appendBlock); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
/* appendBlock can't be null now, because the |
|
|
|
/* appendBlock can't be null now, because the |
|
|
|
* outermost block contains every structured block. |
|
|
|
* outermost block contains every structured block. |
|
|
@ -813,20 +776,11 @@ public class FlowBlock { |
|
|
|
updateInOut(this, false); |
|
|
|
updateInOut(this, false); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (lastModified != block) { |
|
|
|
while (lastModified != block) |
|
|
|
lastModified = lastModified.outer; |
|
|
|
lastModified = lastModified.outer; |
|
|
|
if (lastModified instanceof SequentialBlock |
|
|
|
|
|
|
|
&& lastModified.getSubBlocks()[0] |
|
|
|
|
|
|
|
instanceof RawTryCatchBlock) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* We leave the catch block of a raw-try-catch-block. |
|
|
|
|
|
|
|
* We shall now create the Catch- resp. FinallyBlock. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
lastModified = |
|
|
|
|
|
|
|
createCatchBlock((SequentialBlock)lastModified); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transformation: |
|
|
|
|
|
|
|
do { |
|
|
|
/* If there is only one jump to the beginning and it is the |
|
|
|
/* If there is only one jump to the beginning and it is the |
|
|
|
* last jump and (there is a do/while(0) block surrounding |
|
|
|
* last jump and (there is a do/while(0) block surrounding |
|
|
|
* everything but the last instruction, or the last |
|
|
|
* everything but the last instruction, or the last |
|
|
@ -834,9 +788,82 @@ public class FlowBlock { |
|
|
|
* do/while(0) with a for(;;last_instr) resp. create a new one |
|
|
|
* do/while(0) with a for(;;last_instr) resp. create a new one |
|
|
|
* and replace breaks to do/while with continue to for. |
|
|
|
* and replace breaks to do/while with continue to for. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
/* XXX implement above */ |
|
|
|
|
|
|
|
|
|
|
|
Jump onlyJump = null; |
|
|
|
|
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
|
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (jump == null || jump.destination != this) |
|
|
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
if (onlyJump == null) |
|
|
|
|
|
|
|
onlyJump = jump; |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
onlyJump = null; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (onlyJump != null && |
|
|
|
|
|
|
|
onlyJump.prev instanceof InstructionBlock) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
InstructionBlock prev = (InstructionBlock) onlyJump.prev; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (prev.outer != null && prev.outer.outer == null |
|
|
|
|
|
|
|
&& prev.outer instanceof SequentialBlock |
|
|
|
|
|
|
|
&& prev.outer.getSubBlocks()[0] instanceof LoopBlock) { |
|
|
|
|
|
|
|
LoopBlock lb = (LoopBlock) prev.outer.getSubBlocks()[0]; |
|
|
|
|
|
|
|
if (lb.cond == lb.FALSE && lb.type == lb.DOWHILE) { |
|
|
|
|
|
|
|
/* Replace the do/while(0) with a |
|
|
|
|
|
|
|
* for(;;last_instr) and replace breaks to |
|
|
|
|
|
|
|
* do/while with continue to for. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lb.type = lb.FOR; |
|
|
|
|
|
|
|
lb.cond = lb.TRUE; |
|
|
|
|
|
|
|
lb.incr = prev.getInstruction(); |
|
|
|
|
|
|
|
lb.init = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
lb.replaceBreakContinue(); |
|
|
|
|
|
|
|
lb.replace(prev.outer, prev); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prev.removeJump(); |
|
|
|
|
|
|
|
lastModified = lb; |
|
|
|
|
|
|
|
break transformation; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
StructuredBlock sb = prev; |
|
|
|
|
|
|
|
while (sb.outer != null |
|
|
|
|
|
|
|
&& sb.outer instanceof SequentialBlock |
|
|
|
|
|
|
|
&& sb.outer.getSubBlocks()[1] == sb) |
|
|
|
|
|
|
|
sb = sb.outer; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Instruction instr = prev.getInstruction(); |
|
|
|
|
|
|
|
Operator op; |
|
|
|
|
|
|
|
if (instr instanceof Expression |
|
|
|
|
|
|
|
&& ((op = ((Expression)instr).getOperator()) |
|
|
|
|
|
|
|
instanceof jode.StoreInstruction |
|
|
|
|
|
|
|
|| op instanceof jode.IIncOperator) |
|
|
|
|
|
|
|
&& sb.outer == null) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* The only jump is the jump of the last |
|
|
|
|
|
|
|
* instruction prev */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
LoopBlock forBlock = |
|
|
|
|
|
|
|
new LoopBlock(LoopBlock.FOR, LoopBlock.TRUE); |
|
|
|
|
|
|
|
forBlock.replace(sb, sb); |
|
|
|
|
|
|
|
forBlock.setBody(sb); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prev.outer.getSubBlocks()[0].replace(prev.outer, null); |
|
|
|
|
|
|
|
forBlock.incr = instr; |
|
|
|
|
|
|
|
prev.removeJump(); |
|
|
|
|
|
|
|
lastModified = forBlock; |
|
|
|
|
|
|
|
break transformation; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* XXX condition for do/while(cond) blocks */ |
|
|
|
/* XXX condition for do/while(cond) blocks */ |
|
|
|
{ |
|
|
|
|
|
|
|
/* Otherwise: */ |
|
|
|
/* Otherwise: */ |
|
|
|
|
|
|
|
|
|
|
|
/* create a new while(true) block. |
|
|
|
/* create a new while(true) block. |
|
|
@ -864,7 +891,7 @@ public class FlowBlock { |
|
|
|
/* if there are further jumps to this, replace every jump with a |
|
|
|
/* if there are further jumps to this, replace every jump with a |
|
|
|
* continue to while block and return true. |
|
|
|
* continue to while block and return true. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
enum = successors.elements(); |
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
|
|
|
|
|
|
|
@ -905,7 +932,7 @@ public class FlowBlock { |
|
|
|
bodyBlock.removeJump(); |
|
|
|
bodyBlock.removeJump(); |
|
|
|
|
|
|
|
|
|
|
|
lastModified = whileBlock; |
|
|
|
lastModified = whileBlock; |
|
|
|
} |
|
|
|
} while (false); |
|
|
|
|
|
|
|
|
|
|
|
/* remove ourself from the predecessor list. |
|
|
|
/* remove ourself from the predecessor list. |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -934,19 +961,9 @@ public class FlowBlock { |
|
|
|
if (jump == null || jump.destination != END_OF_METHOD) |
|
|
|
if (jump == null || jump.destination != END_OF_METHOD) |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
|
|
while (!appendBlock.contains(jump.prev)) { |
|
|
|
while (!appendBlock.contains(jump.prev)) |
|
|
|
appendBlock = appendBlock.outer; |
|
|
|
appendBlock = appendBlock.outer; |
|
|
|
if (appendBlock instanceof SequentialBlock |
|
|
|
|
|
|
|
&& appendBlock.getSubBlocks()[0] |
|
|
|
|
|
|
|
instanceof RawTryCatchBlock) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* We leave the catch block of a raw-try-catch-block. |
|
|
|
|
|
|
|
* We shall now create the Catch- resp. FinallyBlock. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
appendBlock = |
|
|
|
|
|
|
|
createCatchBlock((SequentialBlock)appendBlock); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* appendBlock can't be null now, because the |
|
|
|
/* appendBlock can't be null now, because the |
|
|
|
* outermost block contains every structured block. |
|
|
|
* outermost block contains every structured block. |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -1007,12 +1024,13 @@ public class FlowBlock { |
|
|
|
static Transformation[] exprTrafos = { |
|
|
|
static Transformation[] exprTrafos = { |
|
|
|
new RemoveEmpty(), |
|
|
|
new RemoveEmpty(), |
|
|
|
new CreateExpression(), |
|
|
|
new CreateExpression(), |
|
|
|
new CreatePostIncExpression(), |
|
|
|
new CreatePrePostIncExpression(), |
|
|
|
new CreateAssignExpression(), |
|
|
|
new CreateAssignExpression(), |
|
|
|
new CreateNewConstructor(), |
|
|
|
new CreateNewConstructor(), |
|
|
|
new CombineIfGotoExpressions(), |
|
|
|
new CombineIfGotoExpressions(), |
|
|
|
new CreateIfThenElseOperator(), |
|
|
|
new CreateIfThenElseOperator(), |
|
|
|
new CreateConstantArray(), |
|
|
|
new CreateConstantArray(), |
|
|
|
|
|
|
|
new CreateForInitializer(), |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1060,6 +1078,8 @@ public class FlowBlock { |
|
|
|
* @param end the end of the address range. |
|
|
|
* @param end the end of the address range. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public boolean analyze(int start, int end) { |
|
|
|
public boolean analyze(int start, int end) { |
|
|
|
|
|
|
|
if (Decompiler.debugAnalyze) |
|
|
|
|
|
|
|
System.err.println("analyze("+start+", "+end+")"); |
|
|
|
try { |
|
|
|
try { |
|
|
|
jode.TabbedPrintWriter writer = null; |
|
|
|
jode.TabbedPrintWriter writer = null; |
|
|
|
if (Decompiler.isFlowDebugging) |
|
|
|
if (Decompiler.isFlowDebugging) |
|
|
@ -1067,6 +1087,13 @@ public class FlowBlock { |
|
|
|
|
|
|
|
|
|
|
|
boolean changed = false; |
|
|
|
boolean changed = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (block instanceof RawTryCatchBlock) { |
|
|
|
|
|
|
|
/* analyze the try and catch blocks separately |
|
|
|
|
|
|
|
* and create a new CatchBlock afterwards. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
changed |= analyzeCatchBlock(start, end); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
|
|
|
|
|
|
|
|
if (Decompiler.isFlowDebugging) { |
|
|
|
if (Decompiler.isFlowDebugging) { |
|
|
@ -1101,6 +1128,9 @@ public class FlowBlock { |
|
|
|
writer.untab(); |
|
|
|
writer.untab(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (Decompiler.debugAnalyze) |
|
|
|
|
|
|
|
System.err.println("T2("+addr+","+(addr+length) |
|
|
|
|
|
|
|
+") succeeded"); |
|
|
|
/* T2 transformation succeeded. This may |
|
|
|
/* T2 transformation succeeded. This may |
|
|
|
* make another T1 analysis in the previous |
|
|
|
* make another T1 analysis in the previous |
|
|
|
* block possible. |
|
|
|
* block possible. |
|
|
@ -1115,18 +1145,16 @@ public class FlowBlock { |
|
|
|
/* the Block has no successor where t1 is applicable. |
|
|
|
/* the Block has no successor where t1 is applicable. |
|
|
|
* Finish this analyzation. |
|
|
|
* Finish this analyzation. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
if (Decompiler.isFlowDebugging) { |
|
|
|
if (Decompiler.debugAnalyze) |
|
|
|
writer.println("No more successors applicable: " |
|
|
|
System.err.println |
|
|
|
|
|
|
|
("No more successors applicable: " |
|
|
|
+ start + " - " + end + "; " |
|
|
|
+ start + " - " + end + "; " |
|
|
|
+ addr + " - " + (addr+length)); |
|
|
|
+ addr + " - " + (addr+length)); |
|
|
|
} |
|
|
|
|
|
|
|
return changed; |
|
|
|
return changed; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
/* Only do T1 transformation if the blocks are |
|
|
|
|
|
|
|
* adjacent. */ |
|
|
|
|
|
|
|
if (succ.block instanceof SwitchBlock) { |
|
|
|
if (succ.block instanceof SwitchBlock) { |
|
|
|
/* analyze succ, the new region is the |
|
|
|
/* analyze succ, the new region is the |
|
|
|
* continous region of |
|
|
|
* continuous region of |
|
|
|
* [start,end) \cap \compl [addr, addr+length) |
|
|
|
* [start,end) \cap \compl [addr, addr+length) |
|
|
|
* where succ.addr lies in. |
|
|
|
* where succ.addr lies in. |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -1137,8 +1165,23 @@ public class FlowBlock { |
|
|
|
if (succ.analyzeSwitch(newStart, newEnd)) |
|
|
|
if (succ.analyzeSwitch(newStart, newEnd)) |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
} if ((succ.addr == addr+length |
|
|
|
} |
|
|
|
|
|
|
|
if (succ.block instanceof RawTryCatchBlock) { |
|
|
|
|
|
|
|
/* analyze the try and catch blocks separately |
|
|
|
|
|
|
|
* and create a new CatchBlock afterwards. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
int newStart = (succ.addr > addr) |
|
|
|
|
|
|
|
? addr+length : start; |
|
|
|
|
|
|
|
int newEnd = (succ.addr > addr) |
|
|
|
|
|
|
|
? end : addr; |
|
|
|
|
|
|
|
if (succ.analyzeCatchBlock(newStart, newEnd)) { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if ((succ.addr == addr+length |
|
|
|
|| succ.addr+succ.length == addr) |
|
|
|
|| succ.addr+succ.length == addr) |
|
|
|
|
|
|
|
/* Only do T1 transformation if the blocks are |
|
|
|
|
|
|
|
* adjacent. */ |
|
|
|
&& doT1(succ)) { |
|
|
|
&& doT1(succ)) { |
|
|
|
/* T1 transformation succeeded. */ |
|
|
|
/* T1 transformation succeeded. */ |
|
|
|
changed = true; |
|
|
|
changed = true; |
|
|
@ -1150,9 +1193,27 @@ public class FlowBlock { |
|
|
|
writer.untab(); |
|
|
|
writer.untab(); |
|
|
|
} |
|
|
|
} |
|
|
|
break; |
|
|
|
break; |
|
|
|
} else { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Check if all predecessors of succ |
|
|
|
|
|
|
|
* lie in range [start,end). Otherwise |
|
|
|
|
|
|
|
* we have no chance to combine succ |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
Enumeration enum = succ.predecessors.elements(); |
|
|
|
|
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
|
|
|
int predAddr = |
|
|
|
|
|
|
|
((FlowBlock)enum.nextElement()).addr; |
|
|
|
|
|
|
|
if (predAddr < start || predAddr >= end) { |
|
|
|
|
|
|
|
if (Decompiler.debugAnalyze) |
|
|
|
|
|
|
|
System.err.println |
|
|
|
|
|
|
|
("breaking analyze(" |
|
|
|
|
|
|
|
+ start + ", " + end + "); " |
|
|
|
|
|
|
|
+ addr + " - " + (addr+length)); |
|
|
|
|
|
|
|
return changed; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
/* analyze succ, the new region is the |
|
|
|
/* analyze succ, the new region is the |
|
|
|
* continous region of |
|
|
|
* continuous region of |
|
|
|
* [start,end) \cap \compl [addr, addr+length) |
|
|
|
* [start,end) \cap \compl [addr, addr+length) |
|
|
|
* where succ.addr lies in. |
|
|
|
* where succ.addr lies in. |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -1163,7 +1224,6 @@ public class FlowBlock { |
|
|
|
if (succ.analyze(newStart, newEnd)) |
|
|
|
if (succ.analyze(newStart, newEnd)) |
|
|
|
break; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Try the next successor. |
|
|
|
/* Try the next successor. |
|
|
|
*/ |
|
|
|
*/ |
|
|
@ -1171,7 +1231,181 @@ public class FlowBlock { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (java.io.IOException ioex) { |
|
|
|
} catch (java.io.IOException ioex) { |
|
|
|
return false; |
|
|
|
throw new AssertError(ioex.toString()); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Create a Catch- resp. FinallyBlock (maybe even SynchronizedBlock). |
|
|
|
|
|
|
|
* The root block MUST be a RawTryCatchBlock. |
|
|
|
|
|
|
|
* @param start the start address |
|
|
|
|
|
|
|
* @param end and the end address of FlowBlocks, we may use. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public boolean analyzeCatchBlock(int start, int end) { |
|
|
|
|
|
|
|
if (Decompiler.debugAnalyze) |
|
|
|
|
|
|
|
System.err.println("analyzeCatch("+start+", "+end+")"); |
|
|
|
|
|
|
|
RawTryCatchBlock rawBlock = (RawTryCatchBlock) block; |
|
|
|
|
|
|
|
FlowBlock tryFlow = rawBlock.tryBlock.jump.destination; |
|
|
|
|
|
|
|
FlowBlock catchFlow = rawBlock.catchBlock.jump.destination; |
|
|
|
|
|
|
|
boolean changed = false; |
|
|
|
|
|
|
|
tryFlow.analyze(addr, catchFlow.addr); |
|
|
|
|
|
|
|
catchFlow.analyze(catchFlow.addr, end); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updateInOut(tryFlow, true); |
|
|
|
|
|
|
|
rawBlock.tryBlock.removeJump(); |
|
|
|
|
|
|
|
tryFlow.getBlock().replace(rawBlock.tryBlock, null); |
|
|
|
|
|
|
|
mergeSuccessors(tryFlow); |
|
|
|
|
|
|
|
length += tryFlow.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
updateInOut(catchFlow, true); |
|
|
|
|
|
|
|
rawBlock.catchBlock.removeJump(); |
|
|
|
|
|
|
|
catchFlow.block.replace(rawBlock.catchBlock, null); |
|
|
|
|
|
|
|
mergeSuccessors(catchFlow); |
|
|
|
|
|
|
|
length += catchFlow.length; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (rawBlock.type != null) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CatchBlock newBlock = new CatchBlock(rawBlock.type); |
|
|
|
|
|
|
|
newBlock.replace(rawBlock, rawBlock); |
|
|
|
|
|
|
|
newBlock.setTryBlock(rawBlock.tryBlock); |
|
|
|
|
|
|
|
newBlock.setCatchBlock(rawBlock.catchBlock); |
|
|
|
|
|
|
|
lastModified = newBlock; |
|
|
|
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
} else if (catchFlow.block instanceof SequentialBlock) { |
|
|
|
|
|
|
|
SequentialBlock catchBlock = null; |
|
|
|
|
|
|
|
int type = 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
catchBlock = (SequentialBlock) catchFlow.block; |
|
|
|
|
|
|
|
if (((Expression)((InstructionBlock)catchBlock.subBlocks[0]) |
|
|
|
|
|
|
|
.instr).getOperator() instanceof jode.MonitorExitOperator |
|
|
|
|
|
|
|
&& ((ThrowBlock)catchBlock.subBlocks[1]).instr |
|
|
|
|
|
|
|
instanceof jode.NopOperator) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is a synchronized block */ |
|
|
|
|
|
|
|
type = 2; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else if |
|
|
|
|
|
|
|
(((SequentialBlock)catchBlock.subBlocks[1]).subBlocks[0] |
|
|
|
|
|
|
|
instanceof JsrBlock |
|
|
|
|
|
|
|
&& ((LocalStoreOperator) |
|
|
|
|
|
|
|
((Expression) |
|
|
|
|
|
|
|
((InstructionBlock)catchBlock.subBlocks[0]) |
|
|
|
|
|
|
|
.instr).getOperator()) |
|
|
|
|
|
|
|
.matches((LocalLoadOperator) |
|
|
|
|
|
|
|
((Expression) |
|
|
|
|
|
|
|
((ThrowBlock) |
|
|
|
|
|
|
|
((SequentialBlock)catchBlock.subBlocks[1]). |
|
|
|
|
|
|
|
subBlocks[1]) |
|
|
|
|
|
|
|
.instr).getOperator())) |
|
|
|
|
|
|
|
/* Wow that was complicated :-) |
|
|
|
|
|
|
|
* But now we know that the catch block looks |
|
|
|
|
|
|
|
* exactly like we exspected. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
type = 1; |
|
|
|
|
|
|
|
} catch (ClassCastException ex) { |
|
|
|
|
|
|
|
/* don't do transformations */ |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (type == 2) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* This is a synchronized block */ |
|
|
|
|
|
|
|
throw new AssertError ("Synchronized not implemented yet"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if (type == 1) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Finally block */ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
FlowBlock subRoutine = |
|
|
|
|
|
|
|
((JsrBlock)catchBlock.subBlocks[1].getSubBlocks()[0]) |
|
|
|
|
|
|
|
.innerBlock.jump.destination; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subRoutine.analyzeSubRoutine(addr+length, end); |
|
|
|
|
|
|
|
updateInOut(subRoutine, true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
length += subRoutine.length; |
|
|
|
|
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
|
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
|
|
|
|
Jump jump = (Jump)enum.nextElement(); |
|
|
|
|
|
|
|
if (jump != null && jump.destination == subRoutine) { |
|
|
|
|
|
|
|
if (jump.prev instanceof EmptyBlock |
|
|
|
|
|
|
|
&& jump.prev.outer instanceof JsrBlock) { |
|
|
|
|
|
|
|
/* XXX |
|
|
|
|
|
|
|
* Could check much more here! |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
StructuredBlock prevBlock = null; |
|
|
|
|
|
|
|
StructuredBlock jsrBlock = jump.prev.outer; |
|
|
|
|
|
|
|
if (jsrBlock.outer instanceof SequentialBlock) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (jsrBlock.outer.getSubBlocks()[1] |
|
|
|
|
|
|
|
== jsrBlock) { |
|
|
|
|
|
|
|
prevBlock = |
|
|
|
|
|
|
|
jsrBlock.outer.getSubBlocks()[0]; |
|
|
|
|
|
|
|
prevBlock.replace(jsrBlock.outer, |
|
|
|
|
|
|
|
jsrBlock.outer); |
|
|
|
|
|
|
|
} else if (jsrBlock.outer.outer instanceof |
|
|
|
|
|
|
|
SequentialBlock) { |
|
|
|
|
|
|
|
prevBlock = |
|
|
|
|
|
|
|
jsrBlock.outer.outer |
|
|
|
|
|
|
|
.getSubBlocks()[0]; |
|
|
|
|
|
|
|
jsrBlock.outer.getSubBlocks()[1] |
|
|
|
|
|
|
|
.replace(jsrBlock.outer, |
|
|
|
|
|
|
|
jsrBlock.outer); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (prevBlock != null) { |
|
|
|
|
|
|
|
if (prevBlock.jump == null) |
|
|
|
|
|
|
|
prevBlock.moveJump(jsrBlock.jump); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
jsrBlock.removeJump(); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
EmptyBlock eb = new EmptyBlock(); |
|
|
|
|
|
|
|
eb.moveJump(jsrBlock.jump); |
|
|
|
|
|
|
|
eb.replace(jsrBlock, jump.prev); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
jump.prev.removeJump(); |
|
|
|
|
|
|
|
} else |
|
|
|
|
|
|
|
throw new AssertError("wrong jsr"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CatchFinallyBlock newBlock = new CatchFinallyBlock(); |
|
|
|
|
|
|
|
newBlock.replace(rawBlock, rawBlock); |
|
|
|
|
|
|
|
newBlock.setTryBlock(rawBlock.tryBlock); |
|
|
|
|
|
|
|
newBlock.setFinallyBlock(subRoutine.block); |
|
|
|
|
|
|
|
lastModified = newBlock; |
|
|
|
|
|
|
|
changed = true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
checkConsistent(); |
|
|
|
|
|
|
|
if (Decompiler.debugAnalyze) |
|
|
|
|
|
|
|
System.err.println("analyzeCatch("+start+", "+end+") " |
|
|
|
|
|
|
|
+(changed?"succeeded":"failed") |
|
|
|
|
|
|
|
+"; "+addr+","+(addr+length)); |
|
|
|
|
|
|
|
return changed; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void analyzeSubRoutine(int start, int end) { |
|
|
|
|
|
|
|
analyze(start, end); |
|
|
|
|
|
|
|
/* throws ClassCastException if something isn't as exspected. */ |
|
|
|
|
|
|
|
SequentialBlock sequBlock = (SequentialBlock) block; |
|
|
|
|
|
|
|
LocalStoreOperator store = (LocalStoreOperator) |
|
|
|
|
|
|
|
((Expression)((InstructionBlock)sequBlock.subBlocks[0]).instr) |
|
|
|
|
|
|
|
.getOperator(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (sequBlock.subBlocks[1] instanceof SequentialBlock) |
|
|
|
|
|
|
|
sequBlock = (SequentialBlock) sequBlock.subBlocks[1]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (! ((RetBlock)sequBlock.subBlocks[1]).local |
|
|
|
|
|
|
|
.equals(store.getLocalInfo())) |
|
|
|
|
|
|
|
throw new AssertError("Ret doesn't match"); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (sequBlock.outer == null) { |
|
|
|
|
|
|
|
new EmptyBlock().replace(sequBlock, sequBlock); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
sequBlock.subBlocks[0].replace(sequBlock, sequBlock); |
|
|
|
|
|
|
|
block.getSubBlocks()[1].replace(block, block); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -1260,19 +1494,23 @@ public class FlowBlock { |
|
|
|
* Resolves the destinations of all jumps. |
|
|
|
* Resolves the destinations of all jumps. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public void resolveJumps(FlowBlock[] instr) { |
|
|
|
public void resolveJumps(FlowBlock[] instr) { |
|
|
|
|
|
|
|
if (block instanceof RawTryCatchBlock) { |
|
|
|
|
|
|
|
((RawTryCatchBlock)block).getTryBlock() |
|
|
|
|
|
|
|
.jump.destination.resolveJumps(instr); |
|
|
|
|
|
|
|
} |
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
Enumeration enum = successors.elements(); |
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
while (enum.hasMoreElements()) { |
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
Jump jump = (Jump) enum.nextElement(); |
|
|
|
if (jump != null) { |
|
|
|
if (jump != null && jump.destination == null) { |
|
|
|
if (jump.destAddr == -1) |
|
|
|
if (jump.destAddr == -1) |
|
|
|
jump.destination = END_OF_METHOD; |
|
|
|
jump.destination = END_OF_METHOD; |
|
|
|
else |
|
|
|
else |
|
|
|
jump.destination = instr[jump.destAddr]; |
|
|
|
jump.destination = instr[jump.destAddr]; |
|
|
|
|
|
|
|
} |
|
|
|
if (!jump.destination.predecessors.contains(this)) |
|
|
|
if (!jump.destination.predecessors.contains(this)) |
|
|
|
jump.destination.predecessors.addElement(this); |
|
|
|
jump.destination.predecessors.addElement(this); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Mark the flow block as first flow block in a method. |
|
|
|
* Mark the flow block as first flow block in a method. |
|
|
@ -1347,4 +1585,18 @@ public class FlowBlock { |
|
|
|
public StructuredBlock getBlock() { |
|
|
|
public StructuredBlock getBlock() { |
|
|
|
return block; |
|
|
|
return block; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public String toString() { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
java.io.StringWriter strw = new java.io.StringWriter(); |
|
|
|
|
|
|
|
jode.TabbedPrintWriter writer = |
|
|
|
|
|
|
|
new jode.TabbedPrintWriter(strw, " "); |
|
|
|
|
|
|
|
writer.println(super.toString()); |
|
|
|
|
|
|
|
writer.tab(); |
|
|
|
|
|
|
|
dumpSource(writer); |
|
|
|
|
|
|
|
return strw.toString(); |
|
|
|
|
|
|
|
} catch (java.io.IOException ex) { |
|
|
|
|
|
|
|
return super.toString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|