diff --git a/jadx-core/src/main/java/jadx/api/Decompiler.java b/jadx-core/src/main/java/jadx/api/Decompiler.java index 4e7b4dded..afa3a7f77 100644 --- a/jadx-core/src/main/java/jadx/api/Decompiler.java +++ b/jadx-core/src/main/java/jadx/api/Decompiler.java @@ -8,7 +8,6 @@ import jadx.core.dex.nodes.RootNode; import jadx.core.dex.visitors.IDexTreeVisitor; import jadx.core.dex.visitors.SaveCode; import jadx.core.utils.ErrorsCounter; -import jadx.core.utils.exceptions.CodegenException; import jadx.core.utils.exceptions.DecodeException; import jadx.core.utils.exceptions.JadxRuntimeException; import jadx.core.utils.files.InputFile; @@ -116,21 +115,12 @@ public final class Decompiler { LOG.info("processing ..."); ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(threadsCount); for (final ClassNode cls : root.getClasses(false)) { - if (cls.getCode() == null) { - Runnable job = new Runnable() { - @Override - public void run() { - ProcessClass.process(cls, passList); - } - }; - executor.execute(job); - } else { - try { - savePass.visit(cls); - } catch (CodegenException e) { - LOG.error("Can't save class {}", cls, e); + executor.execute(new Runnable() { + @Override + public void run() { + ProcessClass.process(cls, passList); } - } + }); } executor.shutdown(); return executor; diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java b/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java index d1dbee386..b90521ea1 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/DotGraphVisitor.java @@ -23,15 +23,11 @@ import java.util.Set; public class DotGraphVisitor extends AbstractVisitor { private static final String NL = "\\l"; - private static final boolean PRINT_REGISTERS_STATES = false; private final File dir; private final boolean useRegions; private final boolean rawInsn; - private CodeWriter dot; - private CodeWriter conn; - public DotGraphVisitor(File outDir, boolean useRegions, boolean rawInsn) { this.dir = outDir; this.useRegions = useRegions; @@ -47,186 +43,179 @@ public class DotGraphVisitor extends AbstractVisitor { if (mth.isNoCode()) { return; } - dot = new CodeWriter(); - conn = new CodeWriter(); - - dot.startLine("digraph \"CFG for"); - dot.add(escape(mth.getParentClass().getFullName() + "." + mth.getMethodInfo().getShortId())); - dot.add("\" {"); - - if (useRegions) { - if (mth.getRegion() == null) { - return; - } - processMethodRegion(mth); - } else { - for (BlockNode block : mth.getBasicBlocks()) { - processBlock(mth, block); - } - } - - dot.startLine("MethodNode[shape=record,label=\"{"); - dot.add(escape(mth.getAccessFlags().makeString())); - dot.add(escape(mth.getReturnType() + " " - + mth.getParentClass().getFullName() + "." + mth.getName() - + "(" + Utils.listToString(mth.getArguments(true)) + ") ")); - - String attrs = attributesString(mth); - if (attrs.length() != 0) { - dot.add(" | ").add(attrs); - } - dot.add("}\"];"); - - dot.startLine("MethodNode -> ").add(makeName(mth.getEnterBlock())).add(';'); - - dot.add(conn.toString()); - - dot.startLine('}'); - dot.startLine(); - - String fileName = Utils.escape(mth.getMethodInfo().getShortId()) - + (useRegions ? ".regions" : "") - + (rawInsn ? ".raw" : "") - + ".dot"; - dot.save(dir, mth.getParentClass().getClassInfo().getFullPath() + "_graphs", fileName); + new DumpDotGraph().process(mth); } - private void processMethodRegion(MethodNode mth) { - processRegion(mth, mth.getRegion()); - for (ExceptionHandler h : mth.getExceptionHandlers()) { - if (h.getHandlerRegion() != null) { - processRegion(mth, h.getHandlerRegion()); - } - } - Set regionsBlocks = new HashSet(mth.getBasicBlocks().size()); - RegionUtils.getAllRegionBlocks(mth.getRegion(), regionsBlocks); - for (ExceptionHandler handler : mth.getExceptionHandlers()) { - IContainer handlerRegion = handler.getHandlerRegion(); - if (handlerRegion != null) { - RegionUtils.getAllRegionBlocks(handlerRegion, regionsBlocks); - } - } - for (BlockNode block : mth.getBasicBlocks()) { - if (!regionsBlocks.contains(block)) { - processBlock(mth, block, true); - } - } - } + private class DumpDotGraph { + private CodeWriter dot = new CodeWriter(); + private CodeWriter conn = new CodeWriter(); - private void processRegion(MethodNode mth, IContainer region) { - if (region instanceof IRegion) { - IRegion r = (IRegion) region; - dot.startLine("subgraph " + makeName(region) + " {"); - dot.startLine("label = \"").add(r); - String attrs = attributesString(r); + public void process(MethodNode mth) { + dot.startLine("digraph \"CFG for"); + dot.add(escape(mth.getParentClass().getFullName() + "." + mth.getMethodInfo().getShortId())); + dot.add("\" {"); + + if (useRegions) { + if (mth.getRegion() == null) { + return; + } + processMethodRegion(mth); + } else { + for (BlockNode block : mth.getBasicBlocks()) { + processBlock(mth, block, false); + } + } + + dot.startLine("MethodNode[shape=record,label=\"{"); + dot.add(escape(mth.getAccessFlags().makeString())); + dot.add(escape(mth.getReturnType() + " " + + mth.getParentClass().getFullName() + "." + mth.getName() + + "(" + Utils.listToString(mth.getArguments(true)) + ") ")); + + String attrs = attributesString(mth); if (attrs.length() != 0) { dot.add(" | ").add(attrs); } - dot.add("\";"); - dot.startLine("node [shape=record,color=blue];"); + dot.add("}\"];"); - for (IContainer c : r.getSubBlocks()) { - processRegion(mth, c); - } + dot.startLine("MethodNode -> ").add(makeName(mth.getEnterBlock())).add(';'); + + dot.add(conn.toString()); dot.startLine('}'); - } else if (region instanceof BlockNode) { - processBlock(mth, (BlockNode) region); + dot.startLine(); + + String fileName = Utils.escape(mth.getMethodInfo().getShortId()) + + (useRegions ? ".regions" : "") + + (rawInsn ? ".raw" : "") + + ".dot"; + dot.save(dir, mth.getParentClass().getClassInfo().getFullPath() + "_graphs", fileName); } - } - private void processBlock(MethodNode mth, BlockNode block) { - processBlock(mth, block, false); - } - - private void processBlock(MethodNode mth, BlockNode block, boolean error) { - String attrs = attributesString(block); - if (PRINT_REGISTERS_STATES) { - if (block.getStartState() != null) { - if (attrs.length() != 0) { - attrs += "|"; + private void processMethodRegion(MethodNode mth) { + processRegion(mth, mth.getRegion()); + for (ExceptionHandler h : mth.getExceptionHandlers()) { + if (h.getHandlerRegion() != null) { + processRegion(mth, h.getHandlerRegion()); + } + } + Set regionsBlocks = new HashSet(mth.getBasicBlocks().size()); + RegionUtils.getAllRegionBlocks(mth.getRegion(), regionsBlocks); + for (ExceptionHandler handler : mth.getExceptionHandlers()) { + IContainer handlerRegion = handler.getHandlerRegion(); + if (handlerRegion != null) { + RegionUtils.getAllRegionBlocks(handlerRegion, regionsBlocks); + } + } + for (BlockNode block : mth.getBasicBlocks()) { + if (!regionsBlocks.contains(block)) { + processBlock(mth, block, true); } - attrs += escape("RS: " + block.getStartState()) + NL; - attrs += escape("RE: " + block.getEndState()) + NL; } } - dot.startLine(makeName(block)); - dot.add(" [shape=record,"); - if (error) { - dot.add("color=red,"); - } - dot.add("label=\"{"); - dot.add(block.getId()).add("\\:\\ "); - dot.add(InsnUtils.formatOffset(block.getStartOffset())); - if (attrs.length() != 0) { - dot.add('|').add(attrs); - } - String insns = insertInsns(mth, block); - if (insns.length() != 0) { - dot.add('|').add(insns); - } - dot.add("}\"];"); - BlockNode falsePath = null; - List list = block.getInstructions(); - if (!list.isEmpty() && list.get(0).getType() == InsnType.IF) { - falsePath = ((IfNode) list.get(0)).getElseBlock(); - } - for (BlockNode next : block.getSuccessors()) { - conn.startLine(makeName(block)).add(" -> ").add(makeName(next)); - if (next == falsePath) { - conn.add("[style=dotted]"); + private void processRegion(MethodNode mth, IContainer region) { + if (region instanceof IRegion) { + IRegion r = (IRegion) region; + dot.startLine("subgraph " + makeName(region) + " {"); + dot.startLine("label = \"").add(r); + String attrs = attributesString(r); + if (attrs.length() != 0) { + dot.add(" | ").add(attrs); + } + dot.add("\";"); + dot.startLine("node [shape=record,color=blue];"); + + for (IContainer c : r.getSubBlocks()) { + processRegion(mth, c); + } + + dot.startLine('}'); + } else if (region instanceof BlockNode) { + processBlock(mth, (BlockNode) region, false); } - conn.add(';'); } - } - private String attributesString(IAttributeNode block) { - StringBuilder attrs = new StringBuilder(); - for (String attr : block.getAttributes().getAttributeStrings()) { - attrs.append(escape(attr)).append(NL); - } - return attrs.toString(); - } - - private static String makeName(IContainer c) { - String name; - if (c instanceof BlockNode) { - name = "Node_" + ((BlockNode) c).getId(); - } else { - name = "cluster_" + c.getClass().getSimpleName() + "_" + c.hashCode(); - } - return name; - } - - private String insertInsns(MethodNode mth, BlockNode block) { - if (rawInsn) { - StringBuilder str = new StringBuilder(); - for (InsnNode insn : block.getInstructions()) { - str.append(escape(insn + " " + insn.getAttributes())); - str.append(NL); + private void processBlock(MethodNode mth, BlockNode block, boolean error) { + String attrs = attributesString(block); + dot.startLine(makeName(block)); + dot.add(" [shape=record,"); + if (error) { + dot.add("color=red,"); } - return str.toString(); - } else { - CodeWriter code = new CodeWriter(0); - MethodGen.addFallbackInsns(code, mth, block.getInstructions(), false); - String str = escape(code.newLine().toString()); - if (str.startsWith(NL)) { - str = str.substring(NL.length()); + dot.add("label=\"{"); + dot.add(block.getId()).add("\\:\\ "); + dot.add(InsnUtils.formatOffset(block.getStartOffset())); + if (attrs.length() != 0) { + dot.add('|').add(attrs); } - return str; - } - } + String insns = insertInsns(mth, block); + if (insns.length() != 0) { + dot.add('|').add(insns); + } + dot.add("}\"];"); - private static String escape(String string) { - return string - .replace("\\", "") // TODO replace \" - .replace("/", "\\/") - .replace(">", "\\>").replace("<", "\\<") - .replace("{", "\\{").replace("}", "\\}") - .replace("\"", "\\\"") - .replace("-", "\\-") - .replace("|", "\\|") - .replace("\n", NL); + BlockNode falsePath = null; + List list = block.getInstructions(); + if (!list.isEmpty() && list.get(0).getType() == InsnType.IF) { + falsePath = ((IfNode) list.get(0)).getElseBlock(); + } + for (BlockNode next : block.getSuccessors()) { + conn.startLine(makeName(block)).add(" -> ").add(makeName(next)); + if (next == falsePath) { + conn.add("[style=dotted]"); + } + conn.add(';'); + } + } + + private String attributesString(IAttributeNode block) { + StringBuilder attrs = new StringBuilder(); + for (String attr : block.getAttributes().getAttributeStrings()) { + attrs.append(escape(attr)).append(NL); + } + return attrs.toString(); + } + + private String makeName(IContainer c) { + String name; + if (c instanceof BlockNode) { + name = "Node_" + ((BlockNode) c).getId(); + } else { + name = "cluster_" + c.getClass().getSimpleName() + "_" + c.hashCode(); + } + return name; + } + + private String insertInsns(MethodNode mth, BlockNode block) { + if (rawInsn) { + StringBuilder str = new StringBuilder(); + for (InsnNode insn : block.getInstructions()) { + str.append(escape(insn + " " + insn.getAttributes())); + str.append(NL); + } + return str.toString(); + } else { + CodeWriter code = new CodeWriter(0); + MethodGen.addFallbackInsns(code, mth, block.getInstructions(), false); + String str = escape(code.newLine().toString()); + if (str.startsWith(NL)) { + str = str.substring(NL.length()); + } + return str; + } + } + + private String escape(String string) { + return string + .replace("\\", "") // TODO replace \" + .replace("/", "\\/") + .replace(">", "\\>").replace("<", "\\<") + .replace("{", "\\{").replace("}", "\\}") + .replace("\"", "\\\"") + .replace("-", "\\-") + .replace("|", "\\|") + .replace("\n", NL); + } } }