All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boomerang.scene.wala.WALAControlFlowGraph Maven / Gradle / Ivy

There is a newer version: 3.2.2
Show newest version
/**
 * ***************************************************************************** Copyright (c) 2020
 * CodeShield GmbH, Paderborn, Germany. This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * 

SPDX-License-Identifier: EPL-2.0 * *

Contributors: Johannes Spaeth - initial API and implementation * ***************************************************************************** */ package boomerang.scene.wala; import boomerang.scene.ControlFlowGraph; import boomerang.scene.Method; import boomerang.scene.Statement; import boomerang.scene.Val; import com.google.common.base.Joiner; import com.google.common.collect.HashMultimap; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.ibm.wala.classLoader.IClass; import com.ibm.wala.classLoader.IField; import com.ibm.wala.ipa.cha.IClassHierarchy; import com.ibm.wala.ssa.ISSABasicBlock; import com.ibm.wala.ssa.SSACFG; import com.ibm.wala.ssa.SSACFG.BasicBlock; import com.ibm.wala.ssa.SSAInstruction; import com.ibm.wala.ssa.SSAPutInstruction; import com.ibm.wala.types.FieldReference; import com.ibm.wala.types.TypeReference; import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; public class WALAControlFlowGraph implements ControlFlowGraph { private Method method; private SSACFG cfg; private IClassHierarchy cha; private Map basicBlockToFirstStmt = Maps.newHashMap(); public WALAControlFlowGraph(WALAMethod method, IClassHierarchy cha) { this.method = method; this.cha = cha; this.cfg = method.getIR().getControlFlowGraph(); buildCache(); } private boolean cacheBuild = false; private List startPointCache = Lists.newArrayList(); private List endPointCache = Lists.newArrayList(); private Multimap succsOfCache = HashMultimap.create(); private Multimap predsOfCache = HashMultimap.create(); private List statements = Lists.newArrayList(); public Collection getStartPoints() { buildCache(); return startPointCache; } private void buildCache() { if (cacheBuild) return; cacheBuild = true; Set emptyBasicBlocks = Sets.newHashSet(); Map basicBlockToLastStmt = Maps.newHashMap(); Iterator bbIt = cfg.iterator(); // Convert each basic block. while (bbIt.hasNext()) { ISSABasicBlock next = bbIt.next(); BasicBlock n = (BasicBlock) next; List allInstructions = n.getAllInstructions(); List allStatements = convert(allInstructions); Statement last = null; Statement first = null; for (Statement curr : allStatements) { statements.add(curr); if (last == null) { last = curr; first = curr; } else { succsOfCache.put(last, curr); predsOfCache.put(curr, last); last = curr; } } if (last == null) { emptyBasicBlocks.add(next); } else { if (first == null) { throw new RuntimeException("Unexpected behaviour!"); } basicBlockToFirstStmt.put(next, first); basicBlockToLastStmt.put(next, last); } } Graph bbGraph = buildDirectedGraph(); for (ISSABasicBlock eBB : emptyBasicBlocks) { bbGraph.removeNode(eBB); } Set visited = Sets.newHashSet(); LinkedList worklist = Lists.newLinkedList(); worklist.addAll(bbGraph.entries); while (!worklist.isEmpty()) { ISSABasicBlock curr = worklist.poll(); if (emptyBasicBlocks.contains(curr)) { throw new RuntimeException("Unexpected behaviour!"); } else if (!basicBlockToFirstStmt.containsKey(curr)) { throw new RuntimeException("Unexpected behaviour!"); } else if (!basicBlockToLastStmt.containsKey(curr)) { throw new RuntimeException("Unexpected behaviour!"); } if (!visited.add(curr)) { continue; } Collection succNodes = bbGraph.outEdges.get(curr); for (ISSABasicBlock next : succNodes) { if (emptyBasicBlocks.contains(next)) { throw new RuntimeException("Unexpected behaviour!"); } Statement firstOfNextBB = basicBlockToFirstStmt.get(next); Statement lastOfPrevBB = basicBlockToLastStmt.get(curr); succsOfCache.put(lastOfPrevBB, firstOfNextBB); predsOfCache.put(firstOfNextBB, lastOfPrevBB); worklist.add(next); } } WALAStatement entryStatement = new WALAStatement("NOP", method) { @Override public int hashCode() { return System.identityHashCode(this); } @Override public boolean equals(Object obj) { return this == obj; } }; List entries = Lists.newArrayList(); for (Statement s : statements) { if (predsOfCache.get(s).isEmpty()) { entries.add(s); } } statements.add(0, entryStatement); LinkedList entryStatements = addUnitializedFields(); if (!entryStatements.isEmpty()) { predsOfCache.put(entryStatements.getFirst(), entryStatement); succsOfCache.put(entryStatement, entryStatements.getLast()); for (Statement s : entries) { predsOfCache.put(s, entryStatements.getLast()); succsOfCache.put(entryStatements.getLast(), s); } } else { for (Statement s : entries) { predsOfCache.put(s, entryStatement); succsOfCache.put(entryStatement, s); } } for (Statement s : statements) { if (succsOfCache.get(s).isEmpty()) { endPointCache.add(s); } if (predsOfCache.get(s).isEmpty()) { startPointCache.add(s); } } for (Statement s : statements) { if (s.containsInvokeExpr()) { if (s instanceof WALAStatement) { throw new RuntimeException( "The statement must be split into CallSite and ReturnSiteStatement"); } } } for (Statement s : succsOfCache.values()) { if (s.containsInvokeExpr()) { if (s instanceof WALAStatement) { throw new RuntimeException( "The statement must be split into CallSite and ReturnSiteStatement"); } } } } private List convert(List allInstructions) { List res = Lists.newArrayList(); for (SSAInstruction ins : allInstructions) { res.addAll(convert(ins)); } // TODO Auto-generated method stub return res; } private Collection convert(SSAInstruction ins) { List res = Lists.newArrayList(); WALAStatement curr = new WALAStatement(ins, method); // TODO for PhiNodes as well. if (curr.containsInvokeExpr()) { res.addAll(handleCallSite(curr)); } else if (curr.isFieldStore() && curr.getRightOp().isNull()) { res.add(new WALADummyNullStatement(curr.getRightOp(), method)); res.add(curr); } else { res.add(curr); } return res; } private LinkedList addUnitializedFields() { LinkedList uninitializedStatements = Lists.newLinkedList(); if (!method.isConstructor()) return uninitializedStatements; TypeReference delegate = (TypeReference) method.getDeclaringClass().getDelegate(); IClass c = cha.lookupClass(delegate); Collection allFields = c.getAllFields(); List allDeclaredFields = computeInitializedFields(); for (IField f : allFields) { allDeclaredFields.add(f.getReference()); } List definedFields = computeInitializedFields(); allDeclaredFields.removeAll(definedFields); for (FieldReference ref : allDeclaredFields) { WALADummyVal dummyVal = new WALADummyVal((WALAMethod) method); uninitializedStatements.add(new WALADummyNullStatement(dummyVal, method)); uninitializedStatements.add( new WALAUnitializedFieldStatement( new WALAField(ref), (WALAMethod) method, method.getThisLocal(), dummyVal)); } addListOfStmts(uninitializedStatements); return uninitializedStatements; } private List computeInitializedFields() { List refs = Lists.newArrayList(); for (Statement s : statements) { if (s.isFieldStore()) { WALAStatement del = (WALAStatement) s; SSAPutInstruction ssaInstruction = (SSAPutInstruction) del.getSSAInstruction(); FieldReference declaredFieldType = ssaInstruction.getDeclaredField(); refs.add(declaredFieldType); } } return refs; } private void addListOfStmts(List stmts) { Statement last = null; for (Statement curr : stmts) { statements.add(curr); if (last == null) { last = curr; } else { succsOfCache.put(last, curr); predsOfCache.put(curr, last); last = curr; } } } private LinkedList handleCallSite(WALAStatement call) { LinkedList res = Lists.newLinkedList(); containsNullVariables(call, res); // addListOfStmts(res); return res; } private void containsNullVariables(WALAStatement call, List res) { List args = call.getInvokeExpr().getArgs(); for (Val a : args) { if (a.isNull()) { res.add(new WALADummyNullStatement(a, call.getMethod())); } } res.add(call); } private Graph buildDirectedGraph() { Graph graph = new Graph<>(); Set visited = Sets.newHashSet(); LinkedList worklist = Lists.newLinkedList(); worklist.add(cfg.entry()); graph.addEntry(cfg.entry()); while (!worklist.isEmpty()) { ISSABasicBlock curr = worklist.poll(); if (!visited.add(curr)) { continue; } Iterator succNodes = cfg.getSuccNodes(curr); while (succNodes.hasNext()) { ISSABasicBlock next = succNodes.next(); graph.addEdge(curr, next); worklist.add(next); } } return graph; } private static class Graph { Multimap outEdges = HashMultimap.create(); Multimap inEdges = HashMultimap.create(); Set entries = Sets.newHashSet(); public void removeNode(N bb) { Collection out = outEdges.get(bb); Collection in = inEdges.get(bb); for (N o : out) { for (N i : in) { addEdge(i, o); } } if (entries.contains(bb)) { entries.remove(bb); for (N newEntries : out) { entries.add(newEntries); } } for (N tgt : out) { inEdges.remove(tgt, bb); } for (N src : in) { outEdges.remove(src, bb); } outEdges.removeAll(bb); inEdges.removeAll(bb); } public void addEntry(N entry) { entries.add(entry); } private void addEdge(N src, N tgt) { outEdges.put(src, tgt); inEdges.put(tgt, src); } } public Collection getEndPoints() { buildCache(); return endPointCache; } public Collection getSuccsOf(Statement curr) { buildCache(); return succsOfCache.get(curr); } public Collection getPredsOf(Statement curr) { buildCache(); return predsOfCache.get(curr); } public List getStatements() { buildCache(); return statements; } @Override public String toString() { String s = "============================="; s += "Control Flow Graph for " + method; s += "Entries:\n " + Joiner.on("\n").join(startPointCache); s += "\nExit:\n " + Joiner.on("\n").join(endPointCache); s += "\nSucc:\n "; for (Statement e : succsOfCache.keySet()) { s += " from " + e + " \n "; for (Statement v : succsOfCache.get(e)) { s += "\t \t to : " + v + "\n"; } } s += "============================="; return s; } public Statement getBranchTarget(int targetIndex) { BasicBlock blockForInstruction = cfg.getBlockForInstruction(targetIndex); return basicBlockToFirstStmt.get(blockForInstruction); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy