package jqian.sootex.util.graph; import java.util.*; import jqian.sootex.util.CFGEntry; import jqian.sootex.util.CFGExit; import soot.*; import soot.util.*; import soot.toolkits.graph.*; /** * Check path relation using basic block graph * TODO A Block already has an index with it in Soot, so a more effecient version * may be derived using such information */ @SuppressWarnings({ "rawtypes", "unchecked" }) public class BlockPathTable implements IPathQuery { public BlockPathTable(UnitGraph graph){ BlockGraph blockGraph=null; if(graph instanceof BriefUnitGraph){ blockGraph=new BriefBlockGraph((BriefUnitGraph)graph); }else{ throw new RuntimeException(graph.getClass().toString() +" is currently not supported!"); } this._blkNum=blockGraph.size(); Collection heads=blockGraph.getHeads(); this._entrys=new int[heads.size()]; int headCount=0; for(Iterator it=heads.iterator();it.hasNext();headCount++){ Block blk=(Block)it.next(); _entrys[headCount]=blk.getIndexInMethod(); } this._pathTbl=new BitVector[_blkNum]; this._unit2Id=new HashMap(graph.size()*2+ 1, 0.7f); for(Iterator it=blockGraph.iterator();it.hasNext();){ Block blk=(Block)it.next(); int blkId=blk.getIndexInMethod(); //init statement to index map int i=0; for(Iterator blkIt=blk.iterator();blkIt.hasNext();i++){ Unit unit=(Unit)blkIt.next(); _unit2Id.put(unit,new Id(blkId,i)); } //init path table _pathTbl[blkId]=new BitVector(_blkNum); List succs = blockGraph.getSuccsOf(blk); for (Iterator succIt = succs.iterator(); succIt.hasNext();) { Block toBlk=(Block)succIt.next(); int toBlkId=toBlk.getIndexInMethod(); _pathTbl[blkId].set(toBlkId); } } //Use floyd-warshall algortihm to build a path table for (int i = 0; i <_blkNum; i++){ for (int j = 0; j <_blkNum; j++) { if (_pathTbl[j].get(i)) { _pathTbl[j].or(_pathTbl[i]); } } } } /** * Checking whether there exist at least a path from a node to another * @param src * @param dest * @return */ public boolean hasPath(Object src,Object dest){ Unit entry=CFGEntry.v(),exit=CFGExit.v(); if(src==entry && dest==exit){ return true; } else if(src==exit || dest==entry){ return false; } else if(src==entry){ Id id=(Id)_unit2Id.get(dest); return reachableFromHead(id._blkId); } else if(dest==exit){ Id id=(Id)_unit2Id.get(src); return reachableFromHead(id._blkId); } Id srcId=(Id)_unit2Id.get(src); Id destId=(Id)_unit2Id.get(dest); //if in the same block if(src!=dest && srcId._blkId==destId._blkId){ return srcId._inBlkId<destId._inBlkId; } return _pathTbl[srcId._blkId].get(destId._blkId); } public String toString(){ String str="\n--------------------Path Table----------------------\n "; for(int i=0;i<_blkNum;i++) { str+=" "+formatString(2,i); } for(int i=0;i<_blkNum;i++){ str+="\n"+formatString(2,i); for(int j=0;j<_blkNum;j++){ char c=_pathTbl[i].get(j)? 'X':' '; str+=" "+c; } } str+="\n--------------------End Table-----------------------"; return str; } private String formatString(int setw,int val){ String str=String.valueOf(val); while(str.length()<setw){ str=" "+str; //fill the left with blank } return str; } private boolean reachableFromHead(int nodeId){ int entryNum=_entrys.length; for(int i=0;i<entryNum;i++){ if(nodeId==i) return true; if(_pathTbl[i].get(nodeId)) return true; } return false; } ///////////////////////////////////////////////////////// private BitVector _pathTbl[]; private int _blkNum; private Map/*<Unit,Integer>*/ _unit2Id; private int[] _entrys; private class Id{ public Id(int blkId,int inBlkId){ this._blkId=blkId; this._inBlkId=inBlkId; } public int _blkId; public int _inBlkId; } }