core: move debug code to separate class
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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<BlockNode> blocksInRegions = new HashSet<BlockNode>();
|
||||
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<IRegion> regions = new LinkedHashSet<IRegion>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<IRegion> regions = new LinkedHashSet<IRegion>();
|
||||
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<PhiInsn> phis = new ArrayList<PhiInsn>();
|
||||
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<PhiInsn> 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user