001: /*
002: * Bytecode Analysis Framework
003: * Copyright (C) 2003,2004 University of Maryland
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
018: */
019:
020: package edu.umd.cs.findbugs.ba;
021:
022: import java.io.FileOutputStream;
023: import java.io.PrintStream;
024: import java.util.Iterator;
025:
026: import org.apache.bcel.classfile.ClassParser;
027: import org.apache.bcel.classfile.JavaClass;
028: import org.apache.bcel.classfile.Method;
029: import org.apache.bcel.generic.CodeExceptionGen;
030: import org.apache.bcel.generic.InstructionHandle;
031: import org.apache.bcel.generic.MethodGen;
032:
033: import edu.umd.cs.findbugs.SystemProperties;
034:
035: /**
036: * Print out a representation of a control-flow graph.
037: * For debugging.
038: *
039: * @see CFG
040: * @see CFGBuilder
041: */
042: public class CFGPrinter {
043: private CFG cfg;
044: private boolean isForwards;
045:
046: public CFGPrinter(CFG cfg) {
047: this .cfg = cfg;
048: this .isForwards = true;
049: }
050:
051: public void setIsForwards(boolean isForwards) {
052: this .isForwards = isForwards;
053: }
054:
055: /**
056: * @return Returns the isForwards.
057: */
058: public boolean isForwards() {
059: return isForwards;
060: }
061:
062: public void print(PrintStream out) {
063: Iterator<BasicBlock> i = cfg.blockIterator();
064: while (i.hasNext()) {
065: BasicBlock bb = i.next();
066: out.println();
067: out.println("BASIC BLOCK: "
068: + bb.getLabel()
069: + (bb.isExceptionThrower() ? " [EXCEPTION THROWER]"
070: : "") + blockStartAnnotate(bb));
071: if (bb.isExceptionThrower()) {
072: out.println(" Exception thrower: "
073: + bb.getExceptionThrower());
074: }
075: CodeExceptionGen exceptionGen = bb.getExceptionGen();
076: if (exceptionGen != null) {
077: out.println(" CATCHES " + exceptionGen.getCatchType());
078: }
079: Iterator<InstructionHandle> j = instructionIterator(bb);
080: while (j.hasNext()) {
081: InstructionHandle handle = j.next();
082: out.println(handle + instructionAnnotate(handle, bb));
083: }
084: out.println("END" + blockAnnotate(bb));
085: Iterator<Edge> edgeIter = isForwards ? cfg
086: .outgoingEdgeIterator(bb) : cfg
087: .incomingEdgeIterator(bb);
088: while (edgeIter.hasNext()) {
089: Edge edge = edgeIter.next();
090: out.println(" " + edge.formatAsString(!isForwards)
091: + " " + edgeAnnotate(edge));
092: }
093: }
094: }
095:
096: public String edgeAnnotate(Edge edge) {
097: return "";
098: }
099:
100: public String blockStartAnnotate(BasicBlock block) {
101: return "";
102: }
103:
104: public String blockAnnotate(BasicBlock block) {
105: return "";
106: }
107:
108: public String instructionAnnotate(InstructionHandle handle,
109: BasicBlock bb) {
110: return "";
111: }
112:
113: protected Iterator<InstructionHandle> instructionIterator(
114: BasicBlock bb) {
115: if (isForwards)
116: return bb.instructionIterator();
117: else
118: return bb.instructionReverseIterator();
119: }
120:
121: public static void main(String[] argv) throws Exception {
122:
123: if (argv.length == 0 || argv.length > 2) {
124: System.out.println("Usage: " + CFGPrinter.class.getName()
125: + " <class file> [outputFile]");
126: System.exit(1);
127: }
128:
129: String className = argv[0];
130: JavaClass cls = new ClassParser(className).parse();
131: RepositoryLookupFailureCallback lookupFailureCallback = new DebugRepositoryLookupFailureCallback();
132:
133: AnalysisContext analysisContext = AnalysisContext
134: .create(lookupFailureCallback);
135: ClassContext classContext = analysisContext
136: .getClassContext(cls);
137:
138: Method[] methods = cls.getMethods();
139: String methodName = SystemProperties.getProperty("cfg.method");
140: PrintStream out = System.err;
141: if (argv.length == 2)
142: out = new PrintStream(new FileOutputStream(argv[1]));
143: for (Method method : methods) {
144: MethodGen methodGen = classContext.getMethodGen(method);
145: if (methodGen == null)
146: continue;
147:
148: if (methodName != null
149: && !method.getName().equals(methodName))
150: continue;
151:
152: out.println();
153: out
154: .println("----------------------------------------------------------------------------");
155: out.println("Method "
156: + SignatureConverter
157: .convertMethodSignature(methodGen));
158: out
159: .println("----------------------------------------------------------------------------");
160:
161: CFG cfg = classContext.getCFG(method);
162: CFGPrinter printer = new CFGPrinter(cfg);
163: printer.print(out);
164: }
165: }
166: }
167:
168: // vim:ts=4
|