From fa8f9ccfaa1de2892c59d4b2462809185ffa86bd Mon Sep 17 00:00:00 2001 From: Skylot Date: Sat, 7 Mar 2015 17:46:59 +0300 Subject: [PATCH] core: move debug code to separate class --- .../java/jadx/core/codegen/MethodGen.java | 2 +- .../dex/visitors/regions/CheckRegions.java | 34 ---- .../main/java/jadx/core/utils/DebugUtils.java | 185 ++++++++++++++++++ 3 files changed, 186 insertions(+), 35 deletions(-) create mode 100644 jadx-core/src/main/java/jadx/core/utils/DebugUtils.java diff --git a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java index 5c7d5885..7849b447 100644 --- a/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java +++ b/jadx-core/src/main/java/jadx/core/codegen/MethodGen.java @@ -234,7 +234,7 @@ public class MethodGen { /** * Return fallback variant of method codegen */ - static MethodGen getFallbackMethodGen(MethodNode mth) { + public static MethodGen getFallbackMethodGen(MethodNode mth) { ClassGen clsGen = new ClassGen(mth.getParentClass(), null, true); return new MethodGen(clsGen, mth); } diff --git a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java index 416b12f4..9c4b0243 100644 --- a/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java +++ b/jadx-core/src/main/java/jadx/core/dex/visitors/regions/CheckRegions.java @@ -4,7 +4,6 @@ import jadx.core.dex.attributes.AFlag; import jadx.core.dex.attributes.AType; import jadx.core.dex.nodes.BlockNode; import jadx.core.dex.nodes.IBlock; -import jadx.core.dex.nodes.IContainer; import jadx.core.dex.nodes.IRegion; import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.regions.loops.LoopRegion; @@ -13,7 +12,6 @@ import jadx.core.utils.ErrorsCounter; import jadx.core.utils.exceptions.JadxException; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.Set; import org.slf4j.Logger; @@ -30,8 +28,6 @@ public class CheckRegions extends AbstractVisitor { return; } - // printRegion(mth); - // check if all blocks included in regions final Set blocksInRegions = new HashSet(); DepthRegionTraversal.traverse(mth, new AbstractRegionVisitor() { @@ -51,7 +47,6 @@ public class CheckRegions extends AbstractVisitor { // TODO // mth.add(AFlag.INCONSISTENT_CODE); LOG.debug(" Duplicated block: {} in {}", block, mth); - // printRegionsWithBlock(mth, block); } } }); @@ -79,33 +74,4 @@ public class CheckRegions extends AbstractVisitor { } }); } - - private static void printRegionsWithBlock(MethodNode mth, final BlockNode block) { - final Set regions = new LinkedHashSet(); - DepthRegionTraversal.traverse(mth, new TracedRegionVisitor() { - @Override - public void processBlockTraced(MethodNode mth, IBlock container, IRegion currentRegion) { - if (block.equals(container)) { - regions.add(currentRegion); - } - } - }); - LOG.debug(" Found block: {} in regions: {}", block, regions); - } - - private void printRegion(MethodNode mth) { - LOG.debug("|{}", mth.toString()); - printRegion(mth, mth.getRegion(), "| "); - } - - private void printRegion(MethodNode mth, IRegion region, String indent) { - LOG.debug("{}{}", indent, region); - for (IContainer container : region.getSubBlocks()) { - if (container instanceof IRegion) { - printRegion(mth, (IRegion) container, indent + " "); - } else { - LOG.debug("{} {}", indent, container); - } - } - } } diff --git a/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java new file mode 100644 index 00000000..7a4e52e9 --- /dev/null +++ b/jadx-core/src/main/java/jadx/core/utils/DebugUtils.java @@ -0,0 +1,185 @@ +package jadx.core.utils; + +import jadx.core.codegen.CodeWriter; +import jadx.core.codegen.InsnGen; +import jadx.core.codegen.MethodGen; +import jadx.core.dex.attributes.AType; +import jadx.core.dex.attributes.nodes.PhiListAttr; +import jadx.core.dex.instructions.InsnType; +import jadx.core.dex.instructions.PhiInsn; +import jadx.core.dex.instructions.args.InsnArg; +import jadx.core.dex.instructions.args.RegisterArg; +import jadx.core.dex.instructions.args.SSAVar; +import jadx.core.dex.nodes.BlockNode; +import jadx.core.dex.nodes.IBlock; +import jadx.core.dex.nodes.IContainer; +import jadx.core.dex.nodes.IRegion; +import jadx.core.dex.nodes.InsnNode; +import jadx.core.dex.nodes.MethodNode; +import jadx.core.dex.visitors.DotGraphVisitor; +import jadx.core.dex.visitors.regions.DepthRegionTraversal; +import jadx.core.dex.visitors.regions.TracedRegionVisitor; +import jadx.core.utils.exceptions.CodegenException; +import jadx.core.utils.exceptions.JadxRuntimeException; + +import java.io.File; +import java.util.ArrayList; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +@Deprecated +public class DebugUtils { + private static final Logger LOG = LoggerFactory.getLogger(DebugUtils.class); + + public static void dump(MethodNode mth) { + File out = new File("test-graph-tmp"); + DotGraphVisitor.dump(out).visit(mth); + DotGraphVisitor.dumpRaw(out).visit(mth); + DotGraphVisitor.dumpRegions(out).visit(mth); + } + + public static void printRegionsWithBlock(MethodNode mth, final BlockNode block) { + final Set regions = new LinkedHashSet(); + DepthRegionTraversal.traverse(mth, new TracedRegionVisitor() { + @Override + public void processBlockTraced(MethodNode mth, IBlock container, IRegion currentRegion) { + if (block.equals(container)) { + regions.add(currentRegion); + } + } + }); + LOG.debug(" Found block: {} in regions: {}", block, regions); + } + + public static void printRegions(MethodNode mth) { + printRegions(mth, false); + } + + public static void printRegions(MethodNode mth, boolean printInsns) { + LOG.debug("|{}", mth.toString()); + printRegion(mth, mth.getRegion(), "| ", printInsns); + } + + private static void printRegion(MethodNode mth, IRegion region, String indent, boolean printInsns) { + LOG.debug("{}{}", indent, region); + indent += "| "; + for (IContainer container : region.getSubBlocks()) { + if (container instanceof IRegion) { + printRegion(mth, (IRegion) container, indent, printInsns); + } else { + LOG.debug("{}{}", indent, container); + if (printInsns && container instanceof IBlock) { + IBlock block = (IBlock) container; + printInsns(mth, indent, block); + } + } + } + } + + private static void printInsns(MethodNode mth, String indent, IBlock block) { + for (InsnNode insn : block.getInstructions()) { + try { + MethodGen mg = MethodGen.getFallbackMethodGen(mth); + InsnGen ig = new InsnGen(mg, true); + CodeWriter code = new CodeWriter(); + ig.makeInsn(insn, code); + String insnStr = code.toString().substring(CodeWriter.NL.length()); + LOG.debug("{} - {}", indent, insnStr); + } catch (CodegenException e) { + LOG.debug("{} - {}", indent, insn); + } + } + } + + public static void checkSSA(MethodNode mth) { + for (BlockNode block : mth.getBasicBlocks()) { + for (InsnNode insn : block.getInstructions()) { + if (insn.getResult() != null) { + checkSSAVar(mth, insn, insn.getResult()); + } + for (InsnArg arg : insn.getArguments()) { + if (arg instanceof RegisterArg) { + checkSSAVar(mth, insn, ((RegisterArg) arg)); + } + } + } + } + checkPHI(mth); + } + + private static void checkSSAVar(MethodNode mth, InsnNode insn, RegisterArg reg) { + SSAVar sVar = reg.getSVar(); + if (sVar == null) { + throw new JadxRuntimeException("Null SSA var in " + insn + ", mth: " + mth); + } + for (RegisterArg useArg : sVar.getUseList()) { + InsnNode parentInsn = useArg.getParentInsn(); + if (parentInsn != null) { + if (!parentInsn.containsArg(useArg)) { + throw new JadxRuntimeException("Incorrect use info in PHI insn"); + } + } + } + } + + private static void checkPHI(MethodNode mth) { + for (BlockNode block : mth.getBasicBlocks()) { + List phis = new ArrayList(); + for (InsnNode insn : block.getInstructions()) { + if (insn.getType() == InsnType.PHI) { + PhiInsn phi = ((PhiInsn) insn); + phis.add(phi); + if (phi.getArgsCount() != phi.getBlockBinds().size()) { + throw new JadxRuntimeException("Incorrect args and binds in PHI"); + } + if (phi.getArgsCount() == 0) { + throw new JadxRuntimeException("No args and binds in PHI"); + } + for (InsnArg arg : insn.getArguments()) { + if (arg instanceof RegisterArg) { + BlockNode b = phi.getBlockByArg((RegisterArg) arg); + if (b == null) { + throw new JadxRuntimeException("Predecessor block not found"); + } + } else { + throw new JadxRuntimeException("Not register in phi insn"); + } + } + } + } + PhiListAttr phiListAttr = block.get(AType.PHI_LIST); + if (phiListAttr == null) { + if (!phis.isEmpty()) { + throw new JadxRuntimeException("Missing PHI list attribute"); + } + } else { + List phiList = phiListAttr.getList(); + if (phiList.isEmpty()) { + throw new JadxRuntimeException("Empty PHI list attribute"); + } + if (!phis.containsAll(phiList) || !phiList.containsAll(phis)) { + throw new JadxRuntimeException("Instructions not match"); + } + } + } + for (SSAVar ssaVar : mth.getSVars()) { + PhiInsn usedInPhi = ssaVar.getUsedInPhi(); + if (usedInPhi != null) { + boolean found = false; + for (RegisterArg useArg : ssaVar.getUseList()) { + InsnNode parentInsn = useArg.getParentInsn(); + if (parentInsn != null && parentInsn == usedInPhi) { + found = true; + } + } + if (!found) { + throw new JadxRuntimeException("Used in phi incorrect"); + } + } + } + } +} -- GitLab