|
|
@ -31,32 +31,32 @@ import org.jetbrains.java.decompiler.struct.StructMethod; |
|
|
|
|
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
import java.io.IOException; |
|
|
|
|
|
|
|
|
|
|
|
public class MethodProcessorThread implements Runnable { |
|
|
|
public class MethodProcessorRunnable implements Runnable { |
|
|
|
|
|
|
|
|
|
|
|
public final Object lock = new Object(); |
|
|
|
public final Object lock = new Object(); |
|
|
|
|
|
|
|
|
|
|
|
private final StructMethod method; |
|
|
|
private final StructMethod method; |
|
|
|
private final VarProcessor varproc; |
|
|
|
private final VarProcessor varProc; |
|
|
|
private final DecompilerContext parentContext; |
|
|
|
private final DecompilerContext parentContext; |
|
|
|
|
|
|
|
|
|
|
|
private volatile RootStatement root; |
|
|
|
private volatile RootStatement root; |
|
|
|
private volatile Throwable error; |
|
|
|
private volatile Throwable error; |
|
|
|
|
|
|
|
|
|
|
|
public MethodProcessorThread(StructMethod method, VarProcessor varproc, DecompilerContext parentContext) { |
|
|
|
public MethodProcessorRunnable(StructMethod method, VarProcessor varProc, DecompilerContext parentContext) { |
|
|
|
this.method = method; |
|
|
|
this.method = method; |
|
|
|
this.varproc = varproc; |
|
|
|
this.varProc = varProc; |
|
|
|
this.parentContext = parentContext; |
|
|
|
this.parentContext = parentContext; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
public void run() { |
|
|
|
public void run() { |
|
|
|
|
|
|
|
|
|
|
|
DecompilerContext.setCurrentContext(parentContext); |
|
|
|
DecompilerContext.setCurrentContext(parentContext); |
|
|
|
|
|
|
|
|
|
|
|
error = null; |
|
|
|
error = null; |
|
|
|
root = null; |
|
|
|
root = null; |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
root = codeToJava(method, varproc); |
|
|
|
root = codeToJava(method, varProc); |
|
|
|
|
|
|
|
|
|
|
|
synchronized (lock) { |
|
|
|
synchronized (lock) { |
|
|
|
lock.notifyAll(); |
|
|
|
lock.notifyAll(); |
|
|
@ -70,8 +70,7 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public static RootStatement codeToJava(StructMethod mt, VarProcessor varproc) throws IOException { |
|
|
|
public static RootStatement codeToJava(StructMethod mt, VarProcessor varProc) throws IOException { |
|
|
|
|
|
|
|
|
|
|
|
StructClass cl = mt.getClassStruct(); |
|
|
|
StructClass cl = mt.getClassStruct(); |
|
|
|
|
|
|
|
|
|
|
|
boolean isInitializer = "<clinit>".equals(mt.getName()); // for now static initializer only
|
|
|
|
boolean isInitializer = "<clinit>".equals(mt.getName()); // for now static initializer only
|
|
|
@ -80,29 +79,15 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
InstructionSequence seq = mt.getInstructionSequence(); |
|
|
|
InstructionSequence seq = mt.getInstructionSequence(); |
|
|
|
ControlFlowGraph graph = new ControlFlowGraph(seq); |
|
|
|
ControlFlowGraph graph = new ControlFlowGraph(seq); |
|
|
|
|
|
|
|
|
|
|
|
// System.out.println(graph.toString());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// if(mt.getName().endsWith("_getActiveServers")) {
|
|
|
|
|
|
|
|
// System.out.println();
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern1.dot"), true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
DeadCodeHelper.removeDeadBlocks(graph); |
|
|
|
DeadCodeHelper.removeDeadBlocks(graph); |
|
|
|
graph.inlineJsr(mt); |
|
|
|
graph.inlineJsr(mt); |
|
|
|
|
|
|
|
|
|
|
|
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern4.dot"), true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO: move to the start, before jsr inlining
|
|
|
|
// TODO: move to the start, before jsr inlining
|
|
|
|
DeadCodeHelper.connectDummyExitBlock(graph); |
|
|
|
DeadCodeHelper.connectDummyExitBlock(graph); |
|
|
|
|
|
|
|
|
|
|
|
DeadCodeHelper.removeGotos(graph); |
|
|
|
DeadCodeHelper.removeGotos(graph); |
|
|
|
ExceptionDeobfuscator.removeCircularRanges(graph); |
|
|
|
|
|
|
|
//DeadCodeHelper.removeCircularRanges(graph);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExceptionDeobfuscator.removeCircularRanges(graph); |
|
|
|
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ExceptionDeobfuscator.restorePopRanges(graph); |
|
|
|
ExceptionDeobfuscator.restorePopRanges(graph); |
|
|
|
|
|
|
|
|
|
|
@ -110,15 +95,11 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
ExceptionDeobfuscator.removeEmptyRanges(graph); |
|
|
|
ExceptionDeobfuscator.removeEmptyRanges(graph); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) { |
|
|
|
if (DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) { |
|
|
|
// special case: single return instruction outside of a protected range
|
|
|
|
// special case: single return instruction outside of a protected range
|
|
|
|
DeadCodeHelper.incorporateValueReturns(graph); |
|
|
|
DeadCodeHelper.incorporateValueReturns(graph); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern5.dot"), true);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ExceptionDeobfuscator.restorePopRanges(graph);
|
|
|
|
// ExceptionDeobfuscator.restorePopRanges(graph);
|
|
|
|
ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph); |
|
|
|
ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph); |
|
|
|
|
|
|
|
|
|
|
@ -126,22 +107,14 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
|
|
|
|
|
|
|
|
DecompilerContext.getCounterContainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables()); |
|
|
|
DecompilerContext.getCounterContainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables()); |
|
|
|
|
|
|
|
|
|
|
|
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
|
|
|
|
|
|
|
//System.out.println(graph.toString());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) { |
|
|
|
if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) { |
|
|
|
DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN); |
|
|
|
DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
RootStatement root = DomHelper.parseGraph(graph); |
|
|
|
RootStatement root = DomHelper.parseGraph(graph); |
|
|
|
|
|
|
|
|
|
|
|
FinallyProcessor fproc = new FinallyProcessor(varproc); |
|
|
|
FinallyProcessor fProc = new FinallyProcessor(varProc); |
|
|
|
while (fproc.iterateGraph(mt, root, graph)) { |
|
|
|
while (fProc.iterateGraph(mt, root, graph)) { |
|
|
|
|
|
|
|
|
|
|
|
//DotExporter.toDotFile(graph, new File("c:\\Temp\\fern2.dot"), true);
|
|
|
|
|
|
|
|
//System.out.println(graph.toString());
|
|
|
|
|
|
|
|
//System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
root = DomHelper.parseGraph(graph); |
|
|
|
root = DomHelper.parseGraph(graph); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -149,9 +122,6 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
// not until now because of comparison between synchronized statements in the finally cycle
|
|
|
|
// not until now because of comparison between synchronized statements in the finally cycle
|
|
|
|
DomHelper.removeSynchronizedHandler(root); |
|
|
|
DomHelper.removeSynchronizedHandler(root); |
|
|
|
|
|
|
|
|
|
|
|
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
|
|
|
|
|
|
|
// System.out.println(graph.toString());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
|
|
|
|
// LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());
|
|
|
|
|
|
|
|
|
|
|
|
SequenceHelper.condenseSequences(root); |
|
|
|
SequenceHelper.condenseSequences(root); |
|
|
@ -161,20 +131,11 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
ExprProcessor proc = new ExprProcessor(); |
|
|
|
ExprProcessor proc = new ExprProcessor(); |
|
|
|
proc.processStatement(root, cl); |
|
|
|
proc.processStatement(root, cl); |
|
|
|
|
|
|
|
|
|
|
|
// DotExporter.toDotFile(graph, new File("c:\\Temp\\fern3.dot"), true);
|
|
|
|
|
|
|
|
// System.out.println(graph.toString());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
StackVarsProcessor stackproc = new StackVarsProcessor(); |
|
|
|
StackVarsProcessor stackProc = new StackVarsProcessor(); |
|
|
|
stackproc.simplifyStackVars(root, mt, cl); |
|
|
|
stackProc.simplifyStackVars(root, mt, cl); |
|
|
|
|
|
|
|
|
|
|
|
//System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
varproc.setVarVersions(root); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
|
|
varProc.setVarVersions(root); |
|
|
|
|
|
|
|
|
|
|
|
if (!new PPandMMHelper().findPPandMM(root)) { |
|
|
|
if (!new PPandMMHelper().findPPandMM(root)) { |
|
|
|
break; |
|
|
|
break; |
|
|
@ -182,11 +143,9 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
|
|
|
|
|
|
|
|
LabelHelper.cleanUpEdges(root); |
|
|
|
LabelHelper.cleanUpEdges(root); |
|
|
|
|
|
|
|
|
|
|
|
while (true) { |
|
|
|
while (true) { |
|
|
|
|
|
|
|
|
|
|
|
MergeHelper.enhanceLoops(root); |
|
|
|
MergeHelper.enhanceLoops(root); |
|
|
|
|
|
|
|
|
|
|
|
if (LoopExtractHelper.extractLoops(root)) { |
|
|
|
if (LoopExtractHelper.extractLoops(root)) { |
|
|
@ -199,22 +158,18 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) { |
|
|
|
if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) { |
|
|
|
|
|
|
|
|
|
|
|
if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) { |
|
|
|
if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) { |
|
|
|
|
|
|
|
|
|
|
|
SequenceHelper.condenseSequences(root); |
|
|
|
SequenceHelper.condenseSequences(root); |
|
|
|
|
|
|
|
|
|
|
|
StackVarsProcessor stackproc = new StackVarsProcessor(); |
|
|
|
StackVarsProcessor stackProc = new StackVarsProcessor(); |
|
|
|
stackproc.simplifyStackVars(root, mt, cl); |
|
|
|
stackProc.simplifyStackVars(root, mt, cl); |
|
|
|
|
|
|
|
|
|
|
|
varproc.setVarVersions(root); |
|
|
|
varProc.setVarVersions(root); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
LabelHelper.identifyLabels(root); |
|
|
|
LabelHelper.identifyLabels(root); |
|
|
|
|
|
|
|
|
|
|
|
// System.out.println("~~~~~~~~~~~~~~~~~~~~~~ \r\n"+root.toJava());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (InlineSingleBlockHelper.inlineSingleBlocks(root)) { |
|
|
|
if (InlineSingleBlockHelper.inlineSingleBlocks(root)) { |
|
|
|
continue; |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
@ -234,7 +189,7 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
|
|
|
|
|
|
|
|
SecondaryFunctionsHelper.identifySecondaryFunctions(root); |
|
|
|
SecondaryFunctionsHelper.identifySecondaryFunctions(root); |
|
|
|
|
|
|
|
|
|
|
|
varproc.setVarDefinitions(root); |
|
|
|
varProc.setVarDefinitions(root); |
|
|
|
|
|
|
|
|
|
|
|
// must be the last invocation, because it makes the statement structure inconsistent
|
|
|
|
// must be the last invocation, because it makes the statement structure inconsistent
|
|
|
|
// FIXME: new edge type needed
|
|
|
|
// FIXME: new edge type needed
|
|
|
@ -242,8 +197,6 @@ public class MethodProcessorThread implements Runnable { |
|
|
|
|
|
|
|
|
|
|
|
mt.releaseResources(); |
|
|
|
mt.releaseResources(); |
|
|
|
|
|
|
|
|
|
|
|
// System.out.println("++++++++++++++++++++++/// \r\n"+root.toJava());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return root; |
|
|
|
return root; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|