提交 4c4af792 编写于 作者: S Skylot

core: fix dot graph dump

上级 a0d8d9fc
......@@ -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;
......
......@@ -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();
new DumpDotGraph().process(mth);
}
dot.startLine("digraph \"CFG for");
dot.add(escape(mth.getParentClass().getFullName() + "." + mth.getMethodInfo().getShortId()));
dot.add("\" {");
private class DumpDotGraph {
private CodeWriter dot = new CodeWriter();
private CodeWriter conn = new CodeWriter();
if (useRegions) {
if (mth.getRegion() == null) {
return;
}
processMethodRegion(mth);
} else {
for (BlockNode block : mth.getBasicBlocks()) {
processBlock(mth, block);
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)) + ") "));
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("}\"];");
String attrs = attributesString(mth);
if (attrs.length() != 0) {
dot.add(" | ").add(attrs);
}
dot.add("}\"];");
dot.startLine("MethodNode -> ").add(makeName(mth.getEnterBlock())).add(';');
dot.startLine("MethodNode -> ").add(makeName(mth.getEnterBlock())).add(';');
dot.add(conn.toString());
dot.add(conn.toString());
dot.startLine('}');
dot.startLine();
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);
}
String fileName = Utils.escape(mth.getMethodInfo().getShortId())
+ (useRegions ? ".regions" : "")
+ (rawInsn ? ".raw" : "")
+ ".dot";
dot.save(dir, mth.getParentClass().getClassInfo().getFullPath() + "_graphs", fileName);
}
private void processMethodRegion(MethodNode mth) {
processRegion(mth, mth.getRegion());
for (ExceptionHandler h : mth.getExceptionHandlers()) {
if (h.getHandlerRegion() != null) {
processRegion(mth, h.getHandlerRegion());
private void processMethodRegion(MethodNode mth) {
processRegion(mth, mth.getRegion());
for (ExceptionHandler h : mth.getExceptionHandlers()) {
if (h.getHandlerRegion() != null) {
processRegion(mth, h.getHandlerRegion());
}
}
}
Set<BlockNode> regionsBlocks = new HashSet<BlockNode>(mth.getBasicBlocks().size());
RegionUtils.getAllRegionBlocks(mth.getRegion(), regionsBlocks);
for (ExceptionHandler handler : mth.getExceptionHandlers()) {
IContainer handlerRegion = handler.getHandlerRegion();
if (handlerRegion != null) {
RegionUtils.getAllRegionBlocks(handlerRegion, regionsBlocks);
Set<BlockNode> regionsBlocks = new HashSet<BlockNode>(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);
for (BlockNode block : mth.getBasicBlocks()) {
if (!regionsBlocks.contains(block)) {
processBlock(mth, block, true);
}
}
}
}
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];");
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);
}
for (IContainer c : r.getSubBlocks()) {
processRegion(mth, c);
}
dot.startLine('}');
} else if (region instanceof BlockNode) {
processBlock(mth, (BlockNode) region);
dot.startLine('}');
} else if (region instanceof BlockNode) {
processBlock(mth, (BlockNode) region, false);
}
}
}
private void processBlock(MethodNode mth, BlockNode block) {
processBlock(mth, block, false);
}
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,");
}
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("}\"];");
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 += "|";
BlockNode falsePath = null;
List<InsnNode> 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]");
}
attrs += escape("RS: " + block.getStartState()) + NL;
attrs += escape("RE: " + block.getEndState()) + NL;
conn.add(';');
}
}
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<InsnNode> 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 String attributesString(IAttributeNode block) {
StringBuilder attrs = new StringBuilder();
for (String attr : block.getAttributes().getAttributeStrings()) {
attrs.append(escape(attr)).append(NL);
}
conn.add(';');
return attrs.toString();
}
}
private String attributesString(IAttributeNode block) {
StringBuilder attrs = new StringBuilder();
for (String attr : block.getAttributes().getAttributeStrings()) {
attrs.append(escape(attr)).append(NL);
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;
}
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);
}
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());
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;
}
return str;
}
}
private static String escape(String string) {
return string
.replace("\\", "") // TODO replace \"
.replace("/", "\\/")
.replace(">", "\\>").replace("<", "\\<")
.replace("{", "\\{").replace("}", "\\}")
.replace("\"", "\\\"")
.replace("-", "\\-")
.replace("|", "\\|")
.replace("\n", NL);
private String escape(String string) {
return string
.replace("\\", "") // TODO replace \"
.replace("/", "\\/")
.replace(">", "\\>").replace("<", "\\<")
.replace("{", "\\{").replace("}", "\\}")
.replace("\"", "\\\"")
.replace("-", "\\-")
.replace("|", "\\|")
.replace("\n", NL);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册