001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 2002 Sable Research Group
003: *
004: * This library is free software; you can redistribute it and/or
005: * modify it under the terms of the GNU Lesser General Public
006: * License as published by the Free Software Foundation; either
007: * version 2.1 of the License, or (at your option) any later version.
008: *
009: * This library is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public
015: * License along with this library; if not, write to the
016: * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
017: * Boston, MA 02111-1307, USA.
018: */
019:
020: /*
021: * Modified by the Sable Research Group and others 2002-2003.
022: * See the 'credits' file distributed with Soot for the complete list of
023: * contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
024: */
025:
026: package soot.tools;
027:
028: import java.util.*;
029:
030: import soot.*;
031: import soot.jimple.JimpleBody;
032: import soot.toolkits.graph.*;
033: import soot.options.Options;
034: import soot.util.dot.DotGraph;
035: import soot.util.cfgcmd.AltClassLoader;
036: import soot.util.cfgcmd.CFGGraphType;
037: import soot.util.cfgcmd.CFGIntermediateRep;
038: import soot.util.cfgcmd.CFGToDotGraph;
039:
040: /**
041: * A utility class for generating dot graph file for a control flow graph
042: *
043: * @author Feng Qian
044: */
045: public class CFGViewer extends BodyTransformer {
046:
047: private static final String packToJoin = "jtp";
048: private static final String phaseSubname = "printcfg";
049: private static final String phaseFullname = packToJoin + '.'
050: + phaseSubname;
051: private static final String altClassPathOptionName = "alt-class-path";
052: private static final String graphTypeOptionName = "graph-type";
053: private static final String defaultGraph = "BriefUnitGraph";
054: private static final String irOptionName = "ir";
055: private static final String defaultIR = "jimple";
056: private static final String multipageOptionName = "multipages";
057: private static final String briefLabelOptionName = "brief";
058:
059: private CFGGraphType graphtype;
060: private CFGIntermediateRep ir;
061: private CFGToDotGraph drawer;
062: private Map methodsToPrint; // If the user specifies particular
063:
064: // methods to print, this is a map
065: // from method name to the class
066: // name declaring the method.
067:
068: protected void internalTransform(Body b, String phaseName,
069: Map options) {
070: initialize(options);
071: SootMethod meth = b.getMethod();
072:
073: if ((methodsToPrint == null)
074: || (meth.getDeclaringClass().getName() == methodsToPrint
075: .get(meth.getName()))) {
076: Body body = ir.getBody((JimpleBody) b);
077: print_cfg(body);
078: }
079: }
080:
081: public static void main(String[] args) {
082: CFGViewer viewer = new CFGViewer();
083: Transform printTransform = new Transform(phaseFullname, viewer);
084: printTransform.setDeclaredOptions("enabled "
085: + altClassPathOptionName + ' ' + graphTypeOptionName
086: + ' ' + irOptionName + ' ' + multipageOptionName + ' '
087: + briefLabelOptionName + ' ');
088: printTransform.setDefaultOptions("enabled "
089: + altClassPathOptionName + ": " + graphTypeOptionName
090: + ':' + defaultGraph + ' ' + irOptionName + ':'
091: + defaultIR + ' ' + multipageOptionName + ":false "
092: + ' ' + briefLabelOptionName + ":false ");
093: PackManager.v().getPack("jtp").add(printTransform);
094: args = viewer.parse_options(args);
095: if (args.length == 0) {
096: usage();
097: } else {
098: soot.Main.main(args);
099: }
100: }
101:
102: private static void usage() {
103: G.v().out
104: .println("Usage:\n"
105: + " java soot.util.CFGViewer [soot options] [CFGViewer options] [class[:method]]...\n\n"
106: + " CFGViewer options:\n"
107: + " (When specifying the value for an '=' option, you only\n"
108: + " need to type enough characters to specify the choice\n"
109: + " unambiguously, and case is ignored.)\n"
110: + "\n"
111: + " --alt-classpath PATH :\n"
112: + " specifies the classpath from which to load classes\n"
113: + " that implement graph types whose names begin with 'Alt'.\n"
114: + " --graph={"
115: + CFGGraphType.help(0, 70, " "
116: .length())
117: + "} :\n"
118: + " show the specified type of graph.\n"
119: + " Defaults to "
120: + defaultGraph
121: + ".\n"
122: + " --ir={"
123: + CFGIntermediateRep.help(0, 70,
124: " ".length())
125: + "} :\n"
126: + " create the CFG from the specified intermediate\n"
127: + " representation. Defaults to "
128: + defaultIR
129: + ".\n"
130: + " --brief :\n"
131: + " label nodes with the unit or block index,\n"
132: + " instead of the text of their statements.\n"
133: + " --multipages :\n"
134: + " produce dot file output for multiple 8.5x11\" pages.\n"
135: + " By default, a single page is produced.\n"
136: + " --help :\n"
137: + " print this message.\n"
138: + "\n"
139: + " Particularly relevant soot options (see \"soot --help\" for details):\n"
140: + " --soot-class-path PATH\n"
141: + " --show-exception-dests\n"
142: + " --throw-analysis {pedantic|unit}\n"
143: + " --omit-excepting-unit-edges\n"
144: + " --trim-cfgs\n");
145: }
146:
147: /**
148: * Parse the command line arguments specific to CFGViewer,
149: * and convert them into phase options for jtp.printcfg.
150: *
151: * @return an array of arguments to pass on to Soot.Main.main().
152: */
153: private String[] parse_options(String[] args) {
154: List sootArgs = new ArrayList(args.length);
155:
156: for (int i = 0, n = args.length; i < n; i++) {
157: if (args[i].equals("--alt-classpath")
158: || args[i].equals("--alt-class-path")) {
159: sootArgs.add("-p");
160: sootArgs.add(phaseFullname);
161: sootArgs.add(altClassPathOptionName + ':' + args[++i]);
162: } else if (args[i].startsWith("--graph=")) {
163: sootArgs.add("-p");
164: sootArgs.add(phaseFullname);
165: sootArgs.add(graphTypeOptionName + ':'
166: + args[i].substring("--graph=".length()));
167: } else if (args[i].startsWith("--ir=")) {
168: sootArgs.add("-p");
169: sootArgs.add(phaseFullname);
170: sootArgs.add(irOptionName + ':'
171: + args[i].substring("--ir=".length()));
172: } else if (args[i].equals("--brief")) {
173: sootArgs.add("-p");
174: sootArgs.add(phaseFullname);
175: sootArgs.add(briefLabelOptionName + ":true");
176: } else if (args[i].equals("--multipages")) {
177: sootArgs.add("-p");
178: sootArgs.add(phaseFullname);
179: sootArgs.add(multipageOptionName + ":true");
180: } else if (args[i].equals("--help")) {
181: return new String[0]; // This is a cheesy method to inveigle
182: // our caller into printing the help
183: // and exiting.
184: } else if (args[i].equals("--soot-class-path")
185: || args[i].equals("-soot-class-path")
186: || args[i].equals("--soot-classpath")
187: || args[i].equals("-soot-classpath")) {
188: // Pass classpaths without treating ":" as a method specifier.
189: sootArgs.add(args[i]);
190: sootArgs.add(args[++i]);
191: } else if (args[i].equals("-p")
192: || args[i].equals("--phase-option")
193: || args[i].equals("-phase-option")) {
194: // Pass phase options without treating ":" as a method specifier.
195: sootArgs.add(args[i]);
196: sootArgs.add(args[++i]);
197: sootArgs.add(args[++i]);
198: } else {
199: int smpos = args[i].indexOf(':');
200: if (smpos == -1) {
201: sootArgs.add(args[i]);
202: } else {
203: String clsname = args[i].substring(0, smpos);
204: sootArgs.add(clsname);
205: String methname = args[i].substring(smpos + 1);
206: if (methodsToPrint == null) {
207: methodsToPrint = new HashMap();
208: }
209: methodsToPrint.put(methname, clsname);
210: }
211: }
212: }
213: String[] sootArgsArray = new String[sootArgs.size()];
214: return (String[]) sootArgs.toArray(sootArgsArray);
215: }
216:
217: private void initialize(Map options) {
218: if (drawer == null) {
219: drawer = new CFGToDotGraph();
220: drawer.setBriefLabels(PhaseOptions.getBoolean(options,
221: briefLabelOptionName));
222: drawer.setOnePage(!PhaseOptions.getBoolean(options,
223: multipageOptionName));
224: drawer.setUnexceptionalControlFlowAttr("color", "black");
225: drawer.setExceptionalControlFlowAttr("color", "red");
226: drawer.setExceptionEdgeAttr("color", "lightgray");
227: drawer
228: .setShowExceptions(Options.v()
229: .show_exception_dests());
230: ir = CFGIntermediateRep.getIR(PhaseOptions.getString(
231: options, irOptionName));
232: graphtype = CFGGraphType.getGraphType(PhaseOptions
233: .getString(options, graphTypeOptionName));
234:
235: AltClassLoader.v().setAltClassPath(
236: PhaseOptions.getString(options,
237: altClassPathOptionName));
238: AltClassLoader.v().setAltClasses(
239: new String[] {
240: "soot.toolkits.graph.ArrayRefBlockGraph",
241: "soot.toolkits.graph.Block",
242: "soot.toolkits.graph.Block$AllMapTo",
243: "soot.toolkits.graph.BlockGraph",
244: "soot.toolkits.graph.BriefBlockGraph",
245: "soot.toolkits.graph.BriefUnitGraph",
246: "soot.toolkits.graph.CompleteBlockGraph",
247: "soot.toolkits.graph.CompleteUnitGraph",
248: "soot.toolkits.graph.TrapUnitGraph",
249: "soot.toolkits.graph.UnitGraph",
250: "soot.toolkits.graph.ZonedBlockGraph", });
251: }
252: }
253:
254: protected void print_cfg(Body body) {
255: DirectedGraph graph = graphtype.buildGraph(body);
256: DotGraph canvas = graphtype.drawGraph(drawer, graph, body);
257:
258: String methodname = body.getMethod().getSubSignature();
259: String filename = soot.SourceLocator.v().getOutputDir();
260: if (filename.length() > 0) {
261: filename = filename + java.io.File.separator;
262: }
263: filename = filename
264: + methodname.replace(java.io.File.separatorChar, '.')
265: + DotGraph.DOT_EXTENSION;
266:
267: G.v().out.println("Generate dot file in " + filename);
268: canvas.plot(filename);
269: }
270: }
|