diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/shrike/DynamicCallGraphTests.java b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/shrike/DynamicCallGraphTests.java index d831c1108..e82d3cd14 100644 --- a/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/shrike/DynamicCallGraphTests.java +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/core/tests/shrike/DynamicCallGraphTests.java @@ -2,14 +2,16 @@ package com.ibm.wala.core.tests.shrike; import java.io.BufferedReader; import java.io.File; -import java.io.FileReader; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStreamReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; import java.util.Set; import java.util.StringTokenizer; +import java.util.zip.GZIPInputStream; import org.junit.Assert; import org.junit.Test; @@ -77,7 +79,7 @@ public class DynamicCallGraphTests extends WalaTestCase { } private void check(CallGraph staticCG) throws IOException { - BufferedReader dynamicEdgesFile = new BufferedReader(new FileReader(System.getProperty("dynamicCGFile"))); + BufferedReader dynamicEdgesFile = new BufferedReader(new InputStreamReader(new GZIPInputStream(new FileInputStream(System.getProperty("dynamicCGFile"))))); String line; while ((line = dynamicEdgesFile.readLine()) != null) { StringTokenizer edge = new StringTokenizer(line, "\t"); diff --git a/com.ibm.wala.shrike/src/com/ibm/wala/shrike/cg/DynamicCallGraph.java b/com.ibm.wala.shrike/src/com/ibm/wala/shrike/cg/DynamicCallGraph.java index 5cebb9cf7..6eca05696 100644 --- a/com.ibm.wala.shrike/src/com/ibm/wala/shrike/cg/DynamicCallGraph.java +++ b/com.ibm.wala.shrike/src/com/ibm/wala/shrike/cg/DynamicCallGraph.java @@ -43,9 +43,6 @@ import com.ibm.wala.util.config.SetOfClasses; * System.err.println() at ever method call, and a System.err.println() at every * method entry. * - * In Unix, I run it like this: java -cp ~/dev/shrike/shrike - * com.ibm.dynHLRace.shrikeInstrumentor test.jar -o output.jar - * * The instrumented classes are placed in the directory "output" under the * current directory. Disassembled code is written to the file "report" under * the current directory. @@ -90,7 +87,7 @@ public class DynamicCallGraph { private static void doClass(final ClassInstrumenter ci, Writer w) throws InvalidClassFileException, IOException, FailureException { final String className = ci.getReader().getName(); - if (filter != null && ! filter.contains(className)) { + if (filter != null && filter.contains(className)) { return; } w.write("Class: " + className + "\n"); @@ -102,6 +99,10 @@ public class DynamicCallGraph { // d could be null, e.g., if the method is abstract or native if (d != null) { + if (filter != null && filter.contains(className + "." + ci.getReader().getMethodName(m))) { + return; + } + w.write("Instrumenting " + ci.getReader().getMethodName(m) + " " + ci.getReader().getMethodType(m) + ":\n"); w.flush(); @@ -131,7 +132,8 @@ public class DynamicCallGraph { if (nonStatic && !isConstructor) w.emit(LoadInstruction.make(Constants.TYPE_Object, 0)); //load this else - w.emit(ConstantInstruction.make(Constants.TYPE_null, null)); + w.emit(Util.makeGet(runtime, "NULL_TAG")); + // w.emit(ConstantInstruction.make(Constants.TYPE_null, null)); w.emit(Util.makeInvoke(runtime, "execution", new Class[] {String.class, String.class, Object.class})); } }); @@ -147,7 +149,8 @@ public class DynamicCallGraph { if (nonStatic) w.emit(LoadInstruction.make(Constants.TYPE_Object, 0)); //load this else - w.emit(ConstantInstruction.make(Constants.TYPE_null, null)); + w.emit(Util.makeGet(runtime, "NULL_TAG")); + // w.emit(ConstantInstruction.make(Constants.TYPE, null)); w.emit(ConstantInstruction.make(0)); // false w.emit(Util.makeInvoke(runtime, "termination", new Class[] {String.class, String.class, Object.class, boolean.class})); } @@ -164,7 +167,8 @@ public class DynamicCallGraph { if (nonStatic) w.emit(LoadInstruction.make(Constants.TYPE_Object, 0)); //load this else - w.emit(ConstantInstruction.make(Constants.TYPE_null, null)); + w.emit(Util.makeGet(runtime, "NULL_TAG")); + // w.emit(ConstantInstruction.make(Constants.TYPE_null, null)); w.emit(ConstantInstruction.make(1)); // true w.emit(Util.makeInvoke(runtime, "termination", new Class[] {String.class, String.class, Object.class, boolean.class})); } @@ -190,7 +194,8 @@ public class DynamicCallGraph { w.emit(ConstantInstruction.makeString(calleeClass)); w.emit(ConstantInstruction.makeString(calleeMethod)); // target unknown - w.emit(ConstantInstruction.make(Constants.TYPE_null, null)); + w.emit(Util.makeGet(runtime, "NULL_TAG")); + // w.emit(ConstantInstruction.make(Constants.TYPE_null, null)); w.emit(Util.makeInvoke(runtime, "addToCallStack", new Class[] {String.class, String.class, Object.class})); } }); diff --git a/com.ibm.wala.shrike/src/com/ibm/wala/shrike/cg/Runtime.java b/com.ibm.wala.shrike/src/com/ibm/wala/shrike/cg/Runtime.java index f00acf656..0de1612c9 100644 --- a/com.ibm.wala.shrike/src/com/ibm/wala/shrike/cg/Runtime.java +++ b/com.ibm.wala.shrike/src/com/ibm/wala/shrike/cg/Runtime.java @@ -1,10 +1,12 @@ package com.ibm.wala.shrike.cg; import java.io.FileInputStream; -import java.io.FileWriter; +import java.io.FileOutputStream; import java.io.IOException; +import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.util.Stack; +import java.util.zip.GZIPOutputStream; import com.ibm.wala.util.config.FileOfClasses; import com.ibm.wala.util.config.SetOfClasses; @@ -29,16 +31,22 @@ public class Runtime { } try { - output = new PrintWriter(new FileWriter(fileName)); + output = new PrintWriter(new OutputStreamWriter(new GZIPOutputStream(new FileOutputStream(fileName)))); } catch (IOException e) { output = new PrintWriter(System.err); } } + public static Object NULL_TAG = new Object() { + @Override + public String toString() { + return "NULL TAG"; + } + }; + public static void execution(String klass, String method, Object receiver) { if (runtime.filter == null || ! runtime.filter.contains(klass)) { runtime.output.printf(runtime.callStack.peek() + "\t" + klass + "\t" + method + "\n"); - runtime.output.flush(); } runtime.callStack.push(klass + "\t" + method); @@ -46,6 +54,9 @@ public class Runtime { public static void termination(String klass, String method, Object receiver, boolean exception) { runtime.callStack.pop(); + if ("root".equals(runtime.callStack.peek())) { + runtime.output.close(); + } } public static void pop(String klass, String method) { diff --git a/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/shrikeCT/ClassInstrumenter.java b/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/shrikeCT/ClassInstrumenter.java index 36d66c6cf..777d6d6c3 100644 --- a/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/shrikeCT/ClassInstrumenter.java +++ b/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/shrikeCT/ClassInstrumenter.java @@ -52,13 +52,22 @@ final public class ClassInstrumenter { private int fakeLineOffset; + private final String inputName; + /** * Create a class instrumenter from raw bytes. */ - public ClassInstrumenter(byte[] bytes) throws InvalidClassFileException { - this(new ClassReader(bytes)); + public ClassInstrumenter(String inputName, byte[] bytes) throws InvalidClassFileException { + this(inputName, new ClassReader(bytes)); } + /** + * @return name of resource from which this class was read + */ + public String getInputName() { + return inputName; + } + /** * Calling this means that methods without line numbers get fake line numbers added: each bytecode instruction is treated as at * line 'offset' + the offset of the instruction. @@ -73,7 +82,7 @@ final public class ClassInstrumenter { * * @throws IllegalArgumentException if cr is null */ - public ClassInstrumenter(ClassReader cr) throws InvalidClassFileException { + public ClassInstrumenter(String inputName, ClassReader cr) throws InvalidClassFileException { if (cr == null) { throw new IllegalArgumentException("cr is null"); } @@ -82,6 +91,7 @@ final public class ClassInstrumenter { oldCode = new CodeReader[methods.length]; cpr = CTDecoder.makeConstantPoolReader(cr); deletedMethods = new boolean[methods.length]; + this.inputName = inputName; } /** diff --git a/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/shrikeCT/OfflineInstrumenter.java b/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/shrikeCT/OfflineInstrumenter.java index dddb601e6..90a2476af 100644 --- a/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/shrikeCT/OfflineInstrumenter.java +++ b/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/shrikeCT/OfflineInstrumenter.java @@ -31,11 +31,11 @@ final public class OfflineInstrumenter extends OfflineInstrumenterBase { } @Override - protected Object makeClassFromStream(BufferedInputStream s) throws IOException { + protected Object makeClassFromStream(String inputName, BufferedInputStream s) throws IOException { byte[] bytes = new byte[s.available()]; Util.readFully(s, bytes); try { - return new ClassInstrumenter(bytes); + return new ClassInstrumenter(inputName, bytes); } catch (InvalidClassFileException e) { throw new IOException("Class is invalid: " + e.getMessage()); } @@ -73,7 +73,7 @@ final public class OfflineInstrumenter extends OfflineInstrumenterBase { * methods to 'code' (or make other changes) before calling this method. */ public void outputModifiedClass(ClassInstrumenter out, ClassWriter code) throws IllegalStateException, IOException { - internalOutputModifiedClass(out, code); + internalOutputModifiedClass(out, out.getInputName(), code); } /** @@ -84,7 +84,7 @@ final public class OfflineInstrumenter extends OfflineInstrumenterBase { throw new IllegalArgumentException(); } try { - internalOutputModifiedClass(out, out.emitClass()); + internalOutputModifiedClass(out, out.getInputName(), out.emitClass()); } catch (InvalidClassFileException e) { e.printStackTrace(); throw new IOException("Invalid class file"); diff --git a/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/tools/OfflineInstrumenterBase.java b/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/tools/OfflineInstrumenterBase.java index a7710d9ff..057ce162e 100644 --- a/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/tools/OfflineInstrumenterBase.java +++ b/com.ibm.wala.shrike/src/com/ibm/wala/shrikeBT/tools/OfflineInstrumenterBase.java @@ -89,6 +89,11 @@ public abstract class OfflineInstrumenterBase { return className; } + /** + * get name of resource used for input + */ + public abstract String getInputName(); + /** * Open the resource for reading as a stream. */ @@ -135,6 +140,11 @@ public abstract class OfflineInstrumenterBase { return name.endsWith(".class"); } + @Override + public String getInputName() { + return name; + } + /** * Get the underlying ZipEntry corresponding to this resource. */ @@ -181,6 +191,11 @@ public abstract class OfflineInstrumenterBase { public String toString() { return file.getPath(); } + + @Override + public String getInputName() { + return file.getPath(); + } } protected OfflineInstrumenterBase() { @@ -360,7 +375,7 @@ public abstract class OfflineInstrumenterBase { inputIndex = 0; } - protected abstract Object makeClassFromStream(BufferedInputStream s) throws IOException; + protected abstract Object makeClassFromStream(String inputName, BufferedInputStream s) throws IOException; protected abstract String getClassName(Object cl); @@ -378,7 +393,7 @@ public abstract class OfflineInstrumenterBase { } BufferedInputStream s = new BufferedInputStream(in.open()); try { - Object r = makeClassFromStream(s); + Object r = makeClassFromStream(in.getInputName(), s); String name = getClassName(r); in.setClassName(name); return r; @@ -415,9 +430,8 @@ public abstract class OfflineInstrumenterBase { return outputFile; } - final protected boolean internalOutputModifiedClass(Object cf, Object mods) throws IOException { + final protected boolean internalOutputModifiedClass(Object cf, String name, Object mods) throws IOException { makeOutputJar(); - String name = toEntryName(getClassName(cf)); if (entryNames.contains(name)) { return false; } else { @@ -549,7 +563,7 @@ public abstract class OfflineInstrumenterBase { if (name == null) { BufferedInputStream s = new BufferedInputStream(in.open(), 65536); try { - Object cl = makeClassFromStream(s); + Object cl = makeClassFromStream(in.getInputName(), s); String entryName = toEntryName(getClassName(cl)); if (!entryNames.contains(entryName)) { putNextEntry(new ZipEntry(entryName));