001: /* Soot - a J*va Optimization Framework
002: * Copyright (C) 1997-1999 Raja Vallee-Rai
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 1997-1999.
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: /* Reference Version: $SootVersion: 1.beta.6.dev.51 $ */
027:
028: package ashes.examples.countgotos;
029:
030: import soot.*;
031: import soot.jimple.*;
032: import soot.util.*;
033: import java.io.*;
034: import java.util.*;
035:
036: /**
037: Example to instrument a classfile to produce goto counts.
038: */
039: public class Main {
040: public static void main(String[] args) {
041: if (args.length == 0) {
042: System.out
043: .println("Syntax: java ashes.examples.countgotos.Main [soot options]");
044: System.exit(0);
045: }
046:
047: PackManager.v().getPack("jtp")
048: .add(
049: new Transform("jtp.instrumenter",
050: GotoInstrumenter.v()));
051:
052: // Just in case, resolve the PrintStream SootClass.
053: Scene.v().addBasicClass("java.io.PrintStream",
054: SootClass.SIGNATURES);
055: soot.Main.main(args);
056: }
057: }
058:
059: /**
060: InstrumentClass example.
061:
062: Instruments the given class to print out the number of Jimple goto
063: statements executed.
064:
065: To enable this class, enable the given PackAdjuster by compiling it
066: separately, into the soot package.
067: */
068:
069: class GotoInstrumenter extends BodyTransformer {
070: private static GotoInstrumenter instance = new GotoInstrumenter();
071:
072: private GotoInstrumenter() {
073: }
074:
075: public static GotoInstrumenter v() {
076: return instance;
077: }
078:
079: private boolean addedFieldToMainClassAndLoadedPrintStream = false;
080: private SootClass javaIoPrintStream;
081:
082: private Local addTmpRef(Body body) {
083: Local tmpRef = Jimple.v().newLocal("tmpRef",
084: RefType.v("java.io.PrintStream"));
085: body.getLocals().add(tmpRef);
086: return tmpRef;
087: }
088:
089: private Local addTmpLong(Body body) {
090: Local tmpLong = Jimple.v().newLocal("tmpLong", LongType.v());
091: body.getLocals().add(tmpLong);
092: return tmpLong;
093: }
094:
095: private void addStmtsToBefore(Chain units, Stmt s,
096: SootField gotoCounter, Local tmpRef, Local tmpLong) {
097: // insert "tmpRef = java.lang.System.out;"
098: units
099: .insertBefore(
100: Jimple
101: .v()
102: .newAssignStmt(
103: tmpRef,
104: Jimple
105: .v()
106: .newStaticFieldRef(
107: Scene
108: .v()
109: .getField(
110: "<java.lang.System: java.io.PrintStream out>")
111: .makeRef())),
112: s);
113:
114: // insert "tmpLong = gotoCounter;"
115: units
116: .insertBefore(Jimple.v().newAssignStmt(
117: tmpLong,
118: Jimple.v().newStaticFieldRef(
119: gotoCounter.makeRef())), s);
120:
121: // insert "tmpRef.println(tmpLong);"
122: SootMethod toCall = javaIoPrintStream
123: .getMethod("void println(long)");
124: units.insertBefore(Jimple.v().newInvokeStmt(
125: Jimple.v().newVirtualInvokeExpr(tmpRef,
126: toCall.makeRef(), tmpLong)), s);
127: }
128:
129: protected void internalTransform(Body body, String phaseName,
130: Map options) {
131: SootClass sClass = body.getMethod().getDeclaringClass();
132: SootField gotoCounter = null;
133: boolean addedLocals = false;
134: Local tmpRef = null, tmpLong = null;
135: Chain units = body.getUnits();
136:
137: // Add code at the end of the main method to print out the
138: // gotoCounter (this only works in simple cases, because you may have multiple returns or System.exit()'s )
139: synchronized (this ) {
140: if (!Scene.v().getMainClass().declaresMethod(
141: "void main(java.lang.String[])"))
142: throw new RuntimeException(
143: "couldn't find main() in mainClass");
144:
145: if (addedFieldToMainClassAndLoadedPrintStream)
146: gotoCounter = Scene.v().getMainClass().getFieldByName(
147: "gotoCount");
148: else {
149: // Add gotoCounter field
150: gotoCounter = new SootField("gotoCount", LongType.v(),
151: Modifier.STATIC);
152: Scene.v().getMainClass().addField(gotoCounter);
153:
154: javaIoPrintStream = Scene.v().getSootClass(
155: "java.io.PrintStream");
156:
157: addedFieldToMainClassAndLoadedPrintStream = true;
158: }
159: }
160:
161: // Add code to increase goto counter each time a goto is encountered
162: {
163: boolean isMainMethod = body.getMethod().getSubSignature()
164: .equals("void main(java.lang.String[])");
165:
166: Local tmpLocal = Jimple.v().newLocal("tmp", LongType.v());
167: body.getLocals().add(tmpLocal);
168:
169: Iterator stmtIt = units.snapshotIterator();
170:
171: while (stmtIt.hasNext()) {
172: Stmt s = (Stmt) stmtIt.next();
173:
174: if (s instanceof GotoStmt) {
175: AssignStmt toAdd1 = Jimple.v().newAssignStmt(
176: tmpLocal,
177: Jimple.v().newStaticFieldRef(
178: gotoCounter.makeRef()));
179: AssignStmt toAdd2 = Jimple.v().newAssignStmt(
180: tmpLocal,
181: Jimple.v().newAddExpr(tmpLocal,
182: LongConstant.v(1L)));
183: AssignStmt toAdd3 = Jimple.v().newAssignStmt(
184: Jimple.v().newStaticFieldRef(
185: gotoCounter.makeRef()), tmpLocal);
186:
187: // insert "tmpLocal = gotoCounter;"
188: units.insertBefore(toAdd1, s);
189:
190: // insert "tmpLocal = tmpLocal + 1L;"
191: units.insertBefore(toAdd2, s);
192:
193: // insert "gotoCounter = tmpLocal;"
194: units.insertBefore(toAdd3, s);
195: } else if (s instanceof InvokeStmt) {
196: InvokeExpr iexpr = (InvokeExpr) ((InvokeStmt) s)
197: .getInvokeExpr();
198: if (iexpr instanceof StaticInvokeExpr) {
199: SootMethod target = ((StaticInvokeExpr) iexpr)
200: .getMethod();
201:
202: if (target.getSignature().equals(
203: "<java.lang.System: void exit(int)>")) {
204: if (!addedLocals) {
205: tmpRef = addTmpRef(body);
206: tmpLong = addTmpLong(body);
207: addedLocals = true;
208: }
209: addStmtsToBefore(units, s, gotoCounter,
210: tmpRef, tmpLong);
211: }
212: }
213: } else if (isMainMethod
214: && (s instanceof ReturnStmt || s instanceof ReturnVoidStmt)) {
215: if (!addedLocals) {
216: tmpRef = addTmpRef(body);
217: tmpLong = addTmpLong(body);
218: addedLocals = true;
219: }
220: addStmtsToBefore(units, s, gotoCounter, tmpRef,
221: tmpLong);
222: }
223: }
224: }
225: }
226: }
|