package jqian.sootex.dependency.pdg.builder; import java.util.*; import soot.*; import soot.jimple.*; import soot.toolkits.graph.*; import jqian.sootex.du.*; import jqian.sootex.location.*; import jqian.sootex.ptsto.IPtsToQuery; import jqian.sootex.ptsto.PtsToHelper; import jqian.sootex.util.CFGEntry; import jqian.sootex.util.CFGExit; import jqian.sootex.dependency.DependencyHelper; import jqian.sootex.dependency.pdg.*; /** * Constructing a procedural dependence graph. */ public abstract class AbstractPDGBuilder { protected PDG _pdg; protected SootMethod _method; protected HeapAbstraction _heapAbstraction; /*Temporal reference*/ protected DepGraphOptions _pdgOptions; protected IPtsToQuery _ptsto; protected IReachingDUQuery _rd; protected UnitGraph _cfg; /** * @param cfg The CFG graph of the analyzed method. Used for flexible PDG construction. * @param ptsTo Used to query the points-to information * @param rd Used to query the reaching definition information */ public AbstractPDGBuilder(SootMethod m, UnitGraph cfg, DepGraphOptions dgOptions, IPtsToQuery ptsTo, HeapAbstraction heapAbstraction, IReachingDUQuery rd){ this._method = m; this._pdgOptions = dgOptions; this._pdg = new PDG(m); this._ptsto = ptsTo; this._rd = rd; this._cfg = cfg; this._heapAbstraction = heapAbstraction; } public PDG getPDG(){ return _pdg; } public void build(){ Collection<Unit> stmts = collectStmts(); initializeNodes(stmts); if(_pdgOptions.withCtrlDependence()){ buildCtrlDependences(_cfg,stmts); } buildDataDependence(stmts); clearTemporals(); } //collect statements for dependence graph construction protected Collection<Unit> collectStmts(){ // XXX: only build dependences for nodes in the CFG // Collection<Unit> stmts = _method.getActiveBody().getUnits(); Collection<Unit> stmts = new HashSet<Unit>(); for(Iterator<Unit> it=_cfg.iterator();it.hasNext();){ Unit u = it.next(); // do not create node for CFGEntry and CFGExit // the PDG already has an entry, and there is no need for an exit if(u instanceof CFGEntry || u instanceof CFGExit){ continue; } stmts.add(u); } return stmts; } /**Collect the dependence graph nodes for each statement */ private void initializeNodes(Collection<Unit> stmts){ // nodes for normal statements for(Unit s :stmts){ if(s instanceof IdentityStmt) continue; if(s instanceof Stmt && ((Stmt)s).containsInvokeExpr()){ buildNodesForCall(s); } else{ JimpleStmtNode node = new JimpleStmtNode(_method, s); _pdg.addNode(node); } } //build formal -in/-out nodes buildFormals(); } /** Any PDG builder needing formal nodes should overwrite this method. */ protected abstract void buildFormals(); /** Build nodes for call. */ protected abstract void buildNodesForCall(Unit callsite); protected abstract void buildFormalInDependences(); protected abstract void buildFormalOutDependences(); protected abstract void buildDepForInvoke(Unit curStmt,DependenceNode curNode); protected void buildCtrlDependences(UnitGraph cfg,Collection<Unit> stmts){ Map<Unit,Collection<Unit>> unit2depends = DependencyHelper.calcCtrlDependences(cfg); DependenceNode entry = _pdg.entry(); for (Unit s : stmts) { if(s instanceof IdentityStmt){ continue; } //if(s instanceof CFGEntry){ // continue; //} DependenceNode to = _pdg.getStmtBindingNode(s); Collection<Unit> depends = unit2depends.get(s); for (Unit d : depends) { DependenceNode from; if (d instanceof CFGEntry) { from = entry; } else { from = _pdg.getStmtBindingNode(d); } DependenceEdge edge = new CtrlDependenceEdge(from, to); _pdg.addEdge(edge); } } } protected void buildDataDependence(Collection<Unit> stmts){ for(Unit s: stmts){ DependenceNode dest= _pdg.getStmtBindingNode(s); if(s instanceof Stmt && ((Stmt)s).containsInvokeExpr()){ //invoke_stmt or assign_stmt with invoke_expr buildDepForInvoke(s, dest); } else{ //Including: assign_stmt, return_void_stmt, if_stmt, lookup_switch_stmt, // table_switch_stmt, throw_stmt, ret_stmt, return_stmt, enter_monitor_stmt //No dependence: breakpoint_stmt, goto_stmt, nop_stmt buildDepForNormalStmt(s, dest); } } buildFormalInDependences(); buildFormalOutDependences(); } private void buildDepForNormalStmt(Unit stmt,DependenceNode dest){ // include use in left hand side and right hand side of the statement List<ValueBox> useBoxes = stmt.getUseBoxes(); for(ValueBox vb: useBoxes){ Value use = vb.getValue(); //not a direct box containing variables if(use instanceof Local){ Location loc = Location.valueToLocation(use); buildDepForLocation(stmt,loc,dest); } else if(use instanceof StaticFieldRef){ StaticFieldRef ref = (StaticFieldRef)use; Location loc = Location.getGlobalLocation(ref.getField()); buildDepForLocation(stmt,loc,dest); } else if(use instanceof InstanceFieldRef){ AccessPath ap = AccessPath.valueToAccessPath(_method, stmt, use); buildDepForRef(stmt,dest,ap); } else if(use instanceof ArrayRef){ AccessPath ap = AccessPath.valueToAccessPath(_method, stmt, use); buildDepForRef(stmt,dest,ap); } else{ //Ignored immediate: Constant //Ignore expressions, e.g., binop_expr, instance_of_expr, unop_expr, cast_expr, //new_expr, new_array_expr, new_multi_array_expr } } } /** build dependence edge from an abstract location. */ protected void buildDepForLocation(Unit curStmt,Location loc,DependenceNode dest){ Collection<Unit> defs = _rd.getReachingDUSites(curStmt, null, loc); for(Unit defStmt: defs){ addDataDep(dest,defStmt,loc); } } /** * Collect the dependences of instance field or array element access. * The dependencies of the based variable is not considered here. * TODO: �������ܻ��кܴ���Ż���� */ protected void buildDepForRef(Unit curStmt,DependenceNode curNode,AccessPath ap){ Collection<Location> locations = PtsToHelper.getAccessedLocations(_ptsto, _heapAbstraction, curStmt, ap); Collection<Unit> defSites = _rd.getReachingDUSites(curStmt, ap, locations); //TODO �������� for(Unit defStmt: defSites){ Collection<Location> defs = _rd.getDULocations(defStmt); for(Location loc: locations){ if(defs.contains(loc)){ addDataDep(curNode,defStmt,loc); } } } } /** * Get the dependence graph nodes corresponding to the definition of location <code>loc</code> * at statement <code>stmt</code>, so that dependence edges between def-use sites can be added. */ protected Collection<DependenceNode> getDefinitionNodes(Unit stmt, Location loc){ Collection<DependenceNode> nodes = new ArrayList<DependenceNode>(1); DependenceNode src = _pdg.getStmtBindingNode(stmt); nodes.add(src); return nodes; } /** Add a data dependence edge. */ protected void addDataDep(DependenceNode dest,Unit srcStmt,Location loc){ Collection<DependenceNode> srcNodes = getDefinitionNodes(srcStmt,loc); for(DependenceNode src: srcNodes){ DependenceEdge edge = null; if(_pdgOptions.withDependReason()){ edge = new DataDependenceEdge(src,dest,loc); }else{ if(loc instanceof StackLocation){ edge = new DataDependenceEdge(src,dest,loc); } else{ edge = new DataDependenceEdge(src,dest,null); } } _pdg.addEdge(edge); } } protected void clearTemporals(){ _cfg = null; _ptsto = null; _rd = null; _pdgOptions = null; } }