package kr.ac.snu.selab.soot.callgraph; import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import kr.ac.snu.selab.soot.analyzer.MyMethod; import kr.ac.snu.selab.soot.graph.MyNode; import kr.ac.snu.selab.soot.util.MyUtil; import soot.Body; import soot.Hierarchy; import soot.SootClass; import soot.SootMethod; import soot.Unit; import soot.jimple.internal.JAssignStmt; import soot.jimple.internal.JInvokeStmt; public class SimpleCallGraph extends CallGraph { public SimpleCallGraph() { super(); } public SimpleCallGraph(List<SootClass> aClassList, HashMap<String, SootMethod> methodMap, Hierarchy aHierarchy) { super(); Map<String, MyNode> nodeMap = new HashMap<String, MyNode>(); for (Entry<String, SootMethod> anEntry : methodMap.entrySet()) { nodeMap.put(anEntry.getKey(), new MyMethod(anEntry.getValue())); } // This is a map that has keys of (class, subsignature of method) pair. Map<Map<SootClass, String>, SootMethod> methodMapBySubSignature = new HashMap<Map<SootClass, String>, SootMethod>(); for (SootClass aClass : aClassList) { for (SootMethod aMethod : aClass.getMethods()) { Map<SootClass, String> key = new HashMap<SootClass, String>(); key.put(aClass, aMethod.getSubSignature()); methodMapBySubSignature.put(key, aMethod); } } for (SootClass aClass : aClassList) { for (SootMethod aMethod : aClass.getMethods()) { List<Unit> unitList = new ArrayList<Unit>(); if (aMethod.hasActiveBody()) { Body body = aMethod.getActiveBody(); unitList.addAll(body.getUnits()); } for (Unit aUnit : unitList) { if (aUnit instanceof JInvokeStmt) { JInvokeStmt jInvokeStatement = (JInvokeStmt) aUnit; SootMethod invokedMethod = jInvokeStatement .getInvokeExpr().getMethod(); SootClass receiverClass = invokedMethod .getDeclaringClass(); if (aClassList.contains(receiverClass)) { addEdge(aMethod.toString(), invokedMethod.toString(), nodeMap); // If there is a call to abstract type class, its // subclass' methods should be added to a call // graph except it is a call of super class. if (!jInvokeStatement.getInvokeExpr().toString() .startsWith("specialinvoke")) { List<SootMethod> overrideMethodList = getOverrideMethodsOf( invokedMethod, aHierarchy, methodMapBySubSignature); for (SootMethod overrideMethod : overrideMethodList) { addEdge(aMethod.toString(), overrideMethod.toString(), nodeMap); } } } } if (aUnit instanceof JAssignStmt) { JAssignStmt jAssignStatement = (JAssignStmt) aUnit; if (jAssignStatement.containsInvokeExpr()) { SootMethod invokedMethod = jAssignStatement .getInvokeExpr().getMethod(); SootClass receiverClass = invokedMethod .getDeclaringClass(); if (aClassList.contains(receiverClass)) { addEdge(aMethod.toString(), invokedMethod.toString(), nodeMap); // If there is a call to abstract type class, // its // subclass' methods should be added to a call // graph except it is a call of super class. if (!jAssignStatement.getInvokeExpr() .toString().startsWith("specialinvoke")) { List<SootMethod> overrideMethodList = getOverrideMethodsOf( invokedMethod, aHierarchy, methodMapBySubSignature); for (SootMethod overrideMethod : overrideMethodList) { addEdge(aMethod.toString(), overrideMethod.toString(), nodeMap); } } } } } } } } } private void addEdge(String source, String target, Map<String, MyNode> nodeMap) { if (!nodeMap.containsKey(source) || !nodeMap.containsKey(target)) return; if (!sourceMap.containsKey(target)) { HashSet<MyNode> sourceSet = new HashSet<MyNode>(); sourceMap.put(target, sourceSet); } HashSet<MyNode> sourceSet = sourceMap.get(target); sourceSet.add(nodeMap.get(source)); if (!targetMap.containsKey(source)) { HashSet<MyNode> targetSet = new HashSet<MyNode>(); targetMap.put(source, targetSet); } HashSet<MyNode> targetSet = targetMap.get(source); targetSet.add(nodeMap.get(target)); } public SimpleCallGraph load(String filePath, Map<String, SootMethod> methodMap) { SimpleCallGraph g = new SimpleCallGraph(); BufferedReader reader = null; Map<String, MyNode> nodeMap = new HashMap<String, MyNode>(); for (Entry<String, SootMethod> anEntry : methodMap.entrySet()) { nodeMap.put(anEntry.getKey(), new MyMethod(anEntry.getValue())); } try { reader = new BufferedReader(new FileReader(filePath)); String line = null; while ((line = reader.readLine()) != null) { String[] tokens = line.split("\t"); if (tokens == null || tokens.length != 2) continue; g.addEdge(tokens[0], tokens[1], nodeMap); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) try { reader.close(); } catch (IOException e) { } } return g; } String toXML() { String result = ""; result = result + "<CallGraph>"; result = result + "<SourceToTargetSetList>"; for (Entry<String, HashSet<MyNode>> anEntry : targetMap.entrySet()) { result = result + "<SourceToTargetSet>"; result = result + "<Source>" + MyUtil.removeBracket(anEntry.getKey()) + "</Source>"; result = result + "<TargetSet>"; for (MyNode aNode : anEntry.getValue()) { result = result + "<Target>" + MyUtil.removeBracket(aNode.toString()) + "</Target>"; } result = result + "</TargetSet>"; result = result + "</SourceToTargetSet>"; } result = result + "</SourceToTargetSetList>"; result = result + "<TargetToSourceSetList>"; for (Entry<String, HashSet<MyNode>> anEntry : sourceMap.entrySet()) { result = result + "<TargetToSourceSet>"; result = result + "<Target>" + MyUtil.removeBracket(anEntry.getKey()) + "</Target>"; result = result + "<SourceSet>"; for (MyNode aNode : anEntry.getValue()) { result = result + "<Source>" + MyUtil.removeBracket(aNode.toString()) + "</Source>"; } result = result + "</SourceSet>"; result = result + "</TargetToSourceSet>"; } result = result + "</TargetToSourceSetList>"; result = result + "</CallGraph>"; return result; } }