soot.util.cfgcmd.CFGToDotGraph Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of soot Show documentation
Show all versions of soot Show documentation
A Java Optimization Framework
package soot.util.cfgcmd;
/*-
* #%L
* Soot - a J*va Optimization Framework
* %%
* Copyright (C) 2003 John Jorgensen
* %%
* This program 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 program 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 General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import soot.Body;
import soot.BriefUnitPrinter;
import soot.LabeledUnitPrinter;
import soot.Unit;
import soot.toolkits.exceptions.ThrowableSet;
import soot.toolkits.graph.Block;
import soot.toolkits.graph.BlockGraph;
import soot.toolkits.graph.DirectedGraph;
import soot.toolkits.graph.DominatorNode;
import soot.toolkits.graph.ExceptionalGraph;
import soot.toolkits.graph.ExceptionalGraph.ExceptionDest;
import soot.toolkits.graph.UnitGraph;
import soot.util.dot.DotGraph;
import soot.util.dot.DotGraphAttribute;
import soot.util.dot.DotGraphConstants;
import soot.util.dot.DotGraphEdge;
import soot.util.dot.DotGraphNode;
/**
* Class that creates a {@link DotGraph} visualization of a control flow graph.
*/
public class CFGToDotGraph {
private boolean onePage; // in one or several 8.5x11 pages.
private boolean isBrief;
private boolean showExceptions;
private DotGraphAttribute unexceptionalControlFlowAttr;
private DotGraphAttribute exceptionalControlFlowAttr;
private DotGraphAttribute exceptionEdgeAttr;
private DotGraphAttribute headAttr;
private DotGraphAttribute tailAttr;
/**
*
* Returns a CFGToDotGraph converter which will draw the graph as a single arbitrarily-sized page, with full-length node
* labels.
*
*
*
* If asked to draw a ExceptionalGraph
, the converter will identify the exceptions that will be thrown. By
* default, it will distinguish different edges by coloring regular control flow edges black, exceptional control flow
* edges red, and thrown exception edges light gray. Head and tail nodes are filled in, head nodes with gray, and tail
* nodes with light gray.
*
*/
public CFGToDotGraph() {
setOnePage(true);
setBriefLabels(false);
setShowExceptions(true);
setUnexceptionalControlFlowAttr("color", "black");
setExceptionalControlFlowAttr("color", "red");
setExceptionEdgeAttr("color", "lightgray");
setHeadAttr("fillcolor", "gray");
setTailAttr("fillcolor", "lightgray");
}
/**
* Specify whether to split the graph into pages.
*
* @param onePage
* indicates whether to produce the graph as a single, arbitrarily-sized page (if onePage
is
* true
) or several 8.5x11-inch pages (if onePage
is false
).
*/
public void setOnePage(boolean onePage) {
this.onePage = onePage;
}
/**
* Specify whether to abbreviate the text in node labels. This is most relevant when the nodes represent basic blocks:
* abbreviated node labels contain only a numeric label for the block, while unabbreviated labels contain the code of its
* instructions.
*
* @param useBrief
* indicates whether to abbreviate the text of node labels.
*/
public void setBriefLabels(boolean useBrief) {
this.isBrief = useBrief;
}
/**
* Specify whether the graph should depict the exceptions which each node may throw, in the form of an edge from the
* throwing node to the handler (if any), labeled with the possible exception types. This parameter has an effect only when
* drawing ExceptionalGraph
s.
*
* @param showExceptions
* indicates whether to show possible exceptions and their handlers.
*/
public void setShowExceptions(boolean showExceptions) {
this.showExceptions = showExceptions;
}
/**
* Specify the dot graph attribute to use for regular control flow edges. This parameter has an effect only when drawing
* ExceptionalGraph
s.
*
* @param id
* The attribute name, for example "style" or "color".
*
* @param value
* The attribute value, for example "solid" or "black".
*
* @see "Drawing graphs with dot"
*/
public void setUnexceptionalControlFlowAttr(String id, String value) {
unexceptionalControlFlowAttr = new DotGraphAttribute(id, value);
}
/**
* Specify the dot graph attribute to use for exceptional control flow edges. This parameter has an effect only when
* drawing ExceptionalGraph
s.
*
* @param id
* The attribute name, for example "style" or "color".
*
* @param value
* The attribute value, for example "dashed" or "red".
*
* @see "Drawing graphs with dot"
*/
public void setExceptionalControlFlowAttr(String id, String value) {
exceptionalControlFlowAttr = new DotGraphAttribute(id, value);
}
/**
* Specify the dot graph attribute to use for edges depicting the exceptions each node may throw, and their handlers. This
* parameter has an effect only when drawing ExceptionalGraph
s.
*
* @param id
* The attribute name, for example "style" or "color".
*
* @param value
* The attribute value, for example "dotted" or "lightgray".
*
* @see "Drawing graphs with dot"
*/
public void setExceptionEdgeAttr(String id, String value) {
exceptionEdgeAttr = new DotGraphAttribute(id, value);
}
/**
* Specify the dot graph attribute to use for head nodes (in addition to filling in the nodes).
*
* @param id
* The attribute name, for example "fillcolor".
*
* @param value
* The attribute value, for example "gray".
*
* @see "Drawing graphs with dot"
*/
public void setHeadAttr(String id, String value) {
headAttr = new DotGraphAttribute(id, value);
}
/**
* Specify the dot graph attribute to use for tail nodes (in addition to filling in the nodes).
*
* @param id
* The attribute name, for example "fillcolor".
*
* @param value
* The attribute value, for example "lightgray".
*
* @see "Drawing graphs with dot"
*/
public void setTailAttr(String id, String value) {
tailAttr = new DotGraphAttribute(id, value);
}
/**
* Returns an {@link Iterator} over a {@link Collection} which iterates over its elements in a specified order. Used to
* order lists of destination nodes consistently before adding the corresponding edges to the graph. (Maintaining a
* consistent ordering of edges makes it easier to diff the dot files output for different graphs of a given method.)
*
* @param coll
* The collection to iterator over.
*
* @param comp
* The comparator for the ordering.
*
* @return An iterator which presents the elements of coll
in the order specified by comp
.
*/
private static Iterator sortedIterator(Collection coll, Comparator super T> comp) {
if (coll.size() <= 1) {
return coll.iterator();
} else {
ArrayList list = new ArrayList(coll);
Collections.sort(list, comp);
return list.iterator();
}
}
/**
* Comparator used to order a list of nodes by the order in which they were labeled.
*/
private static class NodeComparator implements Comparator {
private final DotNamer namer;
NodeComparator(DotNamer namer) {
this.namer = namer;
}
@Override
public int compare(T o1, T o2) {
return (namer.getNumber(o1) - namer.getNumber(o2));
}
public boolean equal(T o1, T o2) {
return (namer.getNumber(o1) == namer.getNumber(o2));
}
}
/**
* Comparator used to order a list of ExceptionDests by the order in which their handler nodes were labeled.
*/
private static class ExceptionDestComparator implements Comparator> {
private final DotNamer namer;
ExceptionDestComparator(DotNamer namer) {
this.namer = namer;
}
private int getValue(ExceptionDest o) {
T handler = o.getHandlerNode();
if (handler == null) {
return Integer.MAX_VALUE;
} else {
return namer.getNumber(handler);
}
}
@Override
public int compare(ExceptionDest o1, ExceptionDest o2) {
return (getValue(o1) - getValue(o2));
}
public boolean equal(ExceptionDest o1, ExceptionDest o2) {
return (getValue(o1) == getValue(o2));
}
}
/**
* Create a DotGraph
whose nodes and edges depict a control flow graph without distinguished exceptional
* edges.
*
* @param graph
* a DirectedGraph
representing a CFG (probably an instance of {@link UnitGraph}, {@link BlockGraph},
* or one of their subclasses).
*
* @param body
* the Body
represented by graph
(used to format the text within nodes). If no body is
* available, pass null
.
*
* @return a visualization of graph
.
*/
public DotGraph drawCFG(DirectedGraph graph, Body body) {
DotGraph canvas = initDotGraph(body);
DotNamer namer = new DotNamer((int) (graph.size() / 0.7f), 0.7f);
NodeComparator comparator = new NodeComparator(namer);
// To facilitate comparisons between different graphs of the same
// method, prelabel the nodes in the order they appear
// in the iterator, rather than the order that they appear in the
// graph traversal (so that corresponding nodes are more likely
// to have the same label in different graphs of a given method).
for (N node : graph) {
namer.getName(node);
}
for (N node : graph) {
canvas.drawNode(namer.getName(node));
for (Iterator succsIt = sortedIterator(graph.getSuccsOf(node), comparator); succsIt.hasNext();) {
N succ = succsIt.next();
canvas.drawEdge(namer.getName(node), namer.getName(succ));
}
}
setStyle(graph.getHeads(), canvas, namer, DotGraphConstants.NODE_STYLE_FILLED, headAttr);
setStyle(graph.getTails(), canvas, namer, DotGraphConstants.NODE_STYLE_FILLED, tailAttr);
if (!isBrief) {
formatNodeText(body, canvas, namer);
}
return canvas;
}
/**
* Create a DotGraph
whose nodes and edges depict the control flow in a ExceptionalGraph
, with
* distinguished edges for exceptional control flow.
*
* @param graph
* the control flow graph
*
* @return a visualization of graph
.
*/
public DotGraph drawCFG(ExceptionalGraph graph) {
Body body = graph.getBody();
DotGraph canvas = initDotGraph(body);
DotNamer