/* Soot - a J*va Optimization Framework * Copyright (C) 2004 Jennifer Lhotak * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ package ca.mcgill.sable.soot.cfg; import soot.toolkits.graph.*; import ca.mcgill.sable.soot.cfg.model.*; import java.util.*; import ca.mcgill.sable.soot.*; import org.eclipse.ui.*; import org.eclipse.core.runtime.*; import org.eclipse.core.resources.*; import soot.toolkits.graph.interaction.*; import soot.toolkits.scalar.*; import soot.*; public class ModelCreator { private DirectedGraph sootGraph; private CFGGraph model; private IResource resource; private String edName = "CFG Editor"; private HashMap nodeMap = new HashMap(); public ModelCreator() { } public void buildModel(CFGGraph cfgGraph){ cfgGraph.setResource(getResource()); Iterator nodesIt = getSootGraph().iterator(); ArrayList nodeList = new ArrayList(); ArrayList edgeList = new ArrayList(); boolean isExceptions = false; ArrayList exceptHeads = null; if (getSootGraph().getHeads().size() > 1) { isExceptions = true; } // handle graphs that have exceptions if (getSootGraph() instanceof UnitGraph){ UnitGraph unitGraph = (UnitGraph)getSootGraph(); if (isExceptions){ exceptHeads = findExceptionBlockHeads(unitGraph.getBody()); } } while (nodesIt.hasNext()){ Object node = nodesIt.next(); CFGNode cfgNode; if (!getNodeMap().containsKey(node)){ cfgNode = new CFGNode(); initializeNode(node, cfgNode, cfgGraph); getNodeMap().put(node, cfgNode); } else { cfgNode = (CFGNode)getNodeMap().get(node); } Iterator succIt = getSootGraph().getSuccsOf(node).iterator(); while (succIt.hasNext()){ Object succ = succIt.next(); CFGNode cfgSucc; if (!getNodeMap().containsKey(succ)){ cfgSucc = new CFGNode(); initializeNode(succ, cfgSucc, cfgGraph); getNodeMap().put(succ, cfgSucc); } else { cfgSucc = (CFGNode)getNodeMap().get(succ); } CFGEdge cfgEdge = new CFGEdge(cfgNode, cfgSucc); } } Iterator headsIt = getSootGraph().getHeads().iterator(); while (headsIt.hasNext()){ Object next = headsIt.next(); CFGNode node = (CFGNode)getNodeMap().get(next); if ((exceptHeads != null) && exceptHeads.contains(next)) continue; node.getData().setHead(true); } Iterator tailsIt = getSootGraph().getTails().iterator(); while (tailsIt.hasNext()){ Object next = tailsIt.next(); CFGNode node = (CFGNode)getNodeMap().get(next); node.getData().setTail(true); } setModel(cfgGraph); } private boolean canFit(CFGPartialFlowData pFlow, int length){ Iterator it = pFlow.getChildren().iterator(); int total = 0; while (it.hasNext()){ String next = ((CFGFlowInfo)it.next()).getText(); total += next.length(); } if (total + length < 60) return true; return false; } public void highlightNode(soot.Unit u){ Iterator it = getNodeMap().keySet().iterator(); while (it.hasNext()){ Object next = it.next(); if (next.equals(u)){ CFGNode node = (CFGNode)getNodeMap().get(next); node.handleHighlightEvent(next); } } } public ArrayList findExceptionBlockHeads(Body b){ ArrayList exceptHeads = new ArrayList(); Iterator trapsIt = b.getTraps().iterator(); while (trapsIt.hasNext()){ Trap trap = (Trap)trapsIt.next(); exceptHeads.add(trap.getBeginUnit()); } return exceptHeads; } public void updateNode(FlowInfo fi){ Iterator it = getNodeMap().keySet().iterator(); while (it.hasNext()){ Object next = it.next(); if (next.equals(fi.unit())){ CFGNode node = (CFGNode)getNodeMap().get(next); getModel().newFlowData(); CFGFlowData data = new CFGFlowData(); if (fi.isBefore()){ node.setBefore(data); } else{ node.setAfter(data); } if (fi.info() instanceof FlowSet){ FlowSet fs = (FlowSet)fi.info(); Iterator fsIt = fs.iterator(); CFGFlowInfo startBrace = new CFGFlowInfo(); CFGPartialFlowData nextFlow = new CFGPartialFlowData(); data.addChild(nextFlow); nextFlow.addChild(startBrace); startBrace.setText("{"); while (fsIt.hasNext()){ Object elem = fsIt.next(); CFGFlowInfo info = new CFGFlowInfo(); if (canFit(nextFlow, elem.toString().length())){ nextFlow.addChild(info); } else { nextFlow = new CFGPartialFlowData(); data.addChild(nextFlow); nextFlow.addChild(info); } info.setText(elem.toString()); if(fsIt.hasNext()){ CFGFlowInfo comma = new CFGFlowInfo(); nextFlow.addChild(comma); comma.setText(", "); } } CFGFlowInfo endBrace = new CFGFlowInfo(); nextFlow.addChild(endBrace); endBrace.setText("}"); } else { String text = fi.info().toString(); ArrayList textGroups = new ArrayList(); int last = 0; for (int i = 0; i < text.length()/50; i++){ if (last+50 < text.length()){ int nextComma = text.indexOf(",", last+50); if (nextComma != -1){ textGroups.add(text.substring(last, nextComma+1)); last = nextComma+2; } } } if (last < text.length()){ textGroups.add(text.substring(last)); } Iterator itg = textGroups.iterator(); while (itg.hasNext()){ String nextGroup = (String)itg.next(); CFGFlowInfo info = new CFGFlowInfo(); CFGPartialFlowData pFlow = new CFGPartialFlowData(); data.addChild(pFlow); pFlow.addChild(info); info.setText(nextGroup); } } } } } private void initializeNode(Object sootNode, CFGNode cfgNode, CFGGraph cfgGraph){ ArrayList textList = new ArrayList(); int width = 0; if (sootNode instanceof soot.toolkits.graph.Block){ soot.toolkits.graph.Block block = (soot.toolkits.graph.Block)sootNode; Iterator it = block.iterator(); while (it.hasNext()){ soot.Unit u = (soot.Unit)it.next(); if (width < u.toString().length()){ width = u.toString().length(); } textList.add(u); } } else { textList.add(sootNode); width = sootNode.toString().length(); } cfgGraph.addChild(cfgNode); CFGNodeData nodeData = new CFGNodeData(); cfgNode.setData(nodeData); nodeData.setText(textList); } IEditorPart part; public void displayModel(){ IWorkbenchPage page = SootPlugin.getDefault().getWorkbench().getActiveWorkbenchWindow().getActivePage(); try{ CFGGraph cfgGraph = new CFGGraph(); cfgGraph.setName("cfgGraph"); part = page.openEditor(cfgGraph, "ca.mcgill.sable.soot.cfg.CFGEditor"); if (part instanceof CFGEditor){ ((CFGEditor)part).setTitle(getEdName()); ((CFGEditor)part).setTitleTooltip(getEdName()); } buildModel(cfgGraph); } catch (PartInitException ex){ System.out.println("error message: "+ex.getMessage()); System.out.println("part kind: "+part.getClass()); ex.printStackTrace(); } catch(Exception e){ System.out.println("exception error msg: "+e.getMessage()); System.out.println("error type: "+e.getClass()); e.printStackTrace(); } } public void setEditorName(String name){ edName = name; } public String getEditorName(){ return edName; } /** * @return */ public DirectedGraph getSootGraph() { return sootGraph; } /** * @param graph */ public void setSootGraph(DirectedGraph graph) { sootGraph = graph; } /** * @return */ public CFGGraph getModel() { return model; } /** * @param graph */ public void setModel(CFGGraph graph) { model = graph; } /** * @return */ public IResource getResource() { return resource; } /** * @param resource */ public void setResource(IResource resource) { this.resource = resource; } /** * @return */ public String getEdName() { return edName; } /** * @return */ public HashMap getNodeMap() { return nodeMap; } /** * @param string */ public void setEdName(String string) { edName = string; } /** * @param map */ public void setNodeMap(HashMap map) { nodeMap = map; } }