package jqian.sootex.util.callgraph; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.Stack; import jqian.sootex.util.SootUtils; import jqian.util.dot.DotViewer; import jqian.util.dot.GrappaGraph; import soot.SootMethod; import soot.jimple.toolkits.callgraph.CallGraph; import soot.jimple.toolkits.callgraph.Edge; import att.grappa.GrappaConstants; import att.grappa.Node; /** * @author bruteforce * */ public class CallGraphDotter { private static Node assureMethodNode(GrappaGraph graph,Node[] method2node,SootMethod m){ int id = m.getNumber(); Node node = method2node[id]; if(node==null){ String nodeName = m.toString(); node = new Node(graph,nodeName); node.setAttribute(GrappaConstants.FONTSIZE_ATTR,"9"); graph.addNode(node); method2node[id] = node; } return node; } static class MethodBox{ MethodBox(SootMethod m,int depth){ this.method = m; this.depth = depth; } SootMethod method; int depth; } public static void dot(CallGraph cg, SootMethod entry, int depth, String dotpath, String file){ Node[] method2node = new Node[SootUtils.getMethodCount()]; GrappaGraph graph = new GrappaGraph("Call Graph"); graph.setAttribute("fontsize","8"); Set<SootMethod> processed = new HashSet<SootMethod>(); Stack<MethodBox> stack = new Stack<MethodBox>(); MethodBox box = new MethodBox(entry,0); stack.add(box); while (!stack.isEmpty()) { box = stack.pop(); SootMethod m = box.method; int curDepth = box.depth; Node from = assureMethodNode(graph,method2node,m); // if already processed or reach depth limitation if (!processed.add(m) || curDepth>depth) { continue; } curDepth++; for (Iterator<Edge> it = cg.edgesOutOf(m); it.hasNext();) { Edge e = (Edge) it.next(); SootMethod tgt = e.tgt(); Node to= assureMethodNode(graph,method2node,tgt); graph.addEdge(new att.grappa.Edge(graph,from,to)); if (!processed.contains(tgt)) { box = new MethodBox(tgt,curDepth); stack.add(box); } } } //save to dot file graph.saveToDot(file); //Convert .dot to .jpg file DotViewer dot=new DotViewer(dotpath, file, "jpg"); dot.dotIt(); } }