diff --git a/JavassistTest/.classpath b/JavassistTest/.classpath new file mode 100644 index 0000000..5923d21 --- /dev/null +++ b/JavassistTest/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/JavassistTest/.project b/JavassistTest/.project new file mode 100644 index 0000000..be295c6 --- /dev/null +++ b/JavassistTest/.project @@ -0,0 +1,17 @@ + + + JavassistTest + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/JavassistTest/bin/.gitignore b/JavassistTest/bin/.gitignore new file mode 100644 index 0000000..bf8bba0 --- /dev/null +++ b/JavassistTest/bin/.gitignore @@ -0,0 +1,3 @@ +/instrumenter/ +/sample/ +/tracer/ diff --git a/JavassistTest/sample/F.class b/JavassistTest/sample/F.class new file mode 100644 index 0000000..eabeb80 --- /dev/null +++ b/JavassistTest/sample/F.class Binary files differ diff --git a/JavassistTest/src/instrumenter/Instrumenter.java b/JavassistTest/src/instrumenter/Instrumenter.java new file mode 100644 index 0000000..ec6015b --- /dev/null +++ b/JavassistTest/src/instrumenter/Instrumenter.java @@ -0,0 +1,67 @@ +package instrumenter; + +import java.io.IOException; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CodeConverter; +import javassist.CtClass; +import javassist.CtMethod; +import javassist.NotFoundException; +import javassist.bytecode.BadBytecode; +import javassist.bytecode.analysis.ControlFlow; +import javassist.bytecode.analysis.ControlFlow.Block; +import javassist.expr.ExprEditor; +import javassist.expr.MethodCall; + +public class Instrumenter { + + public static void main(String[] args) { + ClassPool cp = ClassPool.getDefault(); + CtClass cc; + try { + cc = cp.get("sample.F"); + CtMethod m = cc.getDeclaredMethod("getC"); + ControlFlow cf = new ControlFlow(m); + Block[] blocks = cf.basicBlocks(); + int block0 = m.getMethodInfo().getLineNumber(blocks[0].position()); + int block1 = m.getMethodInfo().getLineNumber(blocks[1].position()); + int block2 = m.getMethodInfo().getLineNumber(blocks[2].position()); + int block3 = m.getMethodInfo().getLineNumber(blocks[3].position()); + int block4 = m.getMethodInfo().getLineNumber(blocks[4].position()); + m.insertAt(block0, "System.out.println(\"block0:\" + " + block0 + ");"); + m.insertAt(block1, "System.out.println(\"block1:\" + " + block1 + ");"); + m.insertAt(block2, "System.out.println(\"block2:\" + " + block2 + ");"); + m.insertAt(block3, "System.out.println(\"block3:\" + " + block3 + ");"); + m.insertAt(block4, "System.out.println(\"block4:\" + " + block4 + ");"); + + +// int block0 = m.getMethodInfo().getLineNumber(blocks[0].position()); +// m.insertAt(block0, "System.out.println(\"block0\");"); +// m = cc.getDeclaredMethod("getC"); +// cf = new ControlFlow(m); +// blocks = cf.basicBlocks(); +// int block1 = m.getMethodInfo().getLineNumber(blocks[1].position()); +// m.insertAt(block1, "System.out.println(\"block1\");"); +// m = cc.getDeclaredMethod("getC"); +// cf = new ControlFlow(m); +// blocks = cf.basicBlocks(); +// int block2 = m.getMethodInfo().getLineNumber(blocks[2].position()); +// m.insertAt(block2, "System.out.println(\"block2\");"); + +// m.instrument(new ExprEditor() { +// public void edit(MethodCall m) throws CannotCompileException { +// if (m.getClassName().equals("Hello") +// && m.getMethodName().equals("say")) +// m.replace("$0.hi();"); +// } +// }); + cc.writeFile("bin"); + } catch (NotFoundException | BadBytecode | CannotCompileException | IOException e) { + e.printStackTrace(); +// } catch (CannotCompileException | IOException e) { +// e.printStackTrace(); + } + } + +} diff --git a/JavassistTest/src/sample/A2.java b/JavassistTest/src/sample/A2.java new file mode 100644 index 0000000..d05a07d --- /dev/null +++ b/JavassistTest/src/sample/A2.java @@ -0,0 +1,10 @@ +package sample; + +public class A2 { + F f = new F(); + D d = new D(); + + public void m() { + d.passB(f, 10); + } +} diff --git a/JavassistTest/src/sample/B.java b/JavassistTest/src/sample/B.java new file mode 100644 index 0000000..3c33693 --- /dev/null +++ b/JavassistTest/src/sample/B.java @@ -0,0 +1,9 @@ +package sample; + +public class B { + C c = new C(); + + public C getC() { + return c; + } +} diff --git a/JavassistTest/src/sample/C.java b/JavassistTest/src/sample/C.java new file mode 100644 index 0000000..731faaf --- /dev/null +++ b/JavassistTest/src/sample/C.java @@ -0,0 +1,5 @@ +package sample; + +public class C { + +} diff --git a/JavassistTest/src/sample/D.java b/JavassistTest/src/sample/D.java new file mode 100644 index 0000000..fe4e592 --- /dev/null +++ b/JavassistTest/src/sample/D.java @@ -0,0 +1,10 @@ +package sample; + +public class D { + E e = new E(); + B b = new B(); + public void passB(B b, int i) { + C c = b.getC(); + e.setC(c); + } +} diff --git a/JavassistTest/src/sample/E.java b/JavassistTest/src/sample/E.java new file mode 100644 index 0000000..1d110ed --- /dev/null +++ b/JavassistTest/src/sample/E.java @@ -0,0 +1,15 @@ +package sample; + +public class E { + C c = new C(); + C c2 = new C(); + + + public void setC(C c) { + System.out.println("this.c = "+this.c.toString() +"/ Argu c = "+ c.toString()); + System.out.println("this.c = "+this.c.hashCode() +"/ Argu c = "+ c.hashCode()); + this.c = c; + + } + +} diff --git a/JavassistTest/src/sample/F.java b/JavassistTest/src/sample/F.java new file mode 100644 index 0000000..2d04086 --- /dev/null +++ b/JavassistTest/src/sample/F.java @@ -0,0 +1,14 @@ +package sample; + +public class F extends B { + C c = null; + + public C getC() { + if (c == null) { + for (int n = 0; n < 3; n++) { + c = super.getC(); + } + } + return c; + } +} diff --git a/JavassistTest/src/sample/Main.java b/JavassistTest/src/sample/Main.java new file mode 100644 index 0000000..13862ea --- /dev/null +++ b/JavassistTest/src/sample/Main.java @@ -0,0 +1,16 @@ +package sample; + +public class Main { + + /** + * @param args + */ + public static void main(String[] args) { + // TODO Auto-generated method stub + A2 a = new A2(); + A2 b = new A2(); + a.m(); + b.m(); + } + +} diff --git a/JavassistTest/src/tracer/MyPrintStream.java b/JavassistTest/src/tracer/MyPrintStream.java new file mode 100644 index 0000000..c703ffb --- /dev/null +++ b/JavassistTest/src/tracer/MyPrintStream.java @@ -0,0 +1,92 @@ +package tracer; + +import java.util.ArrayList; + +public class MyPrintStream extends Thread { + private static MyPrintStream theInstance; + private static ArrayList output; + private static String s; +// private static boolean bFlushed = false; +// private static int count = 0; + + private static MyPrintStream getInstance() { + if (theInstance == null) { + theInstance = new MyPrintStream(); + output = new ArrayList(); + Runtime.getRuntime().addShutdownHook(theInstance); // �V���b�g�_�E���p +// theInstance.start(); + } + return theInstance; + } + + public static void print(int n) { + getInstance()._print(n); + } + + public static void print(String s) { + getInstance()._print(s); + } + + public static void println() { + getInstance()._println(); + } + + public static void println(String s) { + getInstance()._println(s); + } + + public void run() { +// if (count == 0) { +// // �ʏ�̃g���[�X�o�� +// count++; +// String s; +// Runtime.getRuntime().addShutdownHook(new MyPrintStream()); // �V���b�g�_�E���p�ɂ����ЂƂƒC���X�^���X���쐬���� +// while(!bFlushed) { +// try { +// Thread.sleep(10); +// if (output.size() > 0) { +// synchronized (output) { +// s = output.remove(0); +// } +// System.out.println(s); +// } +// } catch (InterruptedException e) { +// e.printStackTrace(); +// } +// } +// } else { + // �V���b�g�_�E�����Ƀo�b�t�@�Ɏc�����g���[�X���o�͂��؂� +// bFlushed = true; + for (int n = 0; n < output.size(); n++) { + System.out.println(output.get(n)); + } +// } + } + + private void _print(int n) { + if (s == null) s = new String(); + s += n; + } + + private void _print(String s1) { + if (s == null) s = new String(); + s += s1; + } + + private void _println() { + if (s == null) s = new String(); + synchronized (output) { + output.add(s); + } + s = new String(); + } + + private void _println(String s1) { + if (s == null) s = new String(); + s += s1; + synchronized (output) { + output.add(s); + } + s = new String(); + } +} diff --git a/JavassistTest/src/tracer/Tracer.java b/JavassistTest/src/tracer/Tracer.java new file mode 100644 index 0000000..dc4b908 --- /dev/null +++ b/JavassistTest/src/tracer/Tracer.java @@ -0,0 +1,194 @@ +package tracer; + +import java.io.File; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLDecoder; +import java.util.Enumeration; + +import javassist.CannotCompileException; +import javassist.ClassPool; +import javassist.CodeConverter; +import javassist.CodeConverter.ArrayAccessReplacementMethodNames; +import javassist.CtClass; +import javassist.CtField; +import javassist.CtMethod; +import javassist.Modifier; +import javassist.NotFoundException; +import javassist.bytecode.BadBytecode; +import javassist.bytecode.analysis.ControlFlow; +import javassist.bytecode.analysis.ControlFlow.Block; +import javassist.expr.ExprEditor; +import javassist.expr.FieldAccess; +import javassist.expr.MethodCall; + +public class Tracer { + + public static void main(String[] args) { + String packageName = "sample"; // �w�肵���p�b�P�[�W�����̑S�N���X�ɃC���X�g�D�������e�[�V�������s�� + ClassLoader loader = Thread.currentThread().getContextClassLoader(); + URL resource = loader.getResource(packageName); + File dir; + try { + dir = new File( URLDecoder.decode(resource.getPath(), "UTF-8")); + for (String file : dir.list()) { + if (file.endsWith(".class")) { + String className = packageName + "." + file.replace(".class", ""); + classInstrumentation(className); + } + } + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + + /** + * �w�肵���N���X�ɃC���X�g�D�������e�[�V�������s���i���j + * @param className �N���X�� + */ + private static void classInstrumentation(String className) { + ClassPool cp = ClassPool.getDefault(); + CtClass cc; + try { + cc = cp.get(className); + for (CtMethod m : cc.getDeclaredMethods()) { + ControlFlow cf = new ControlFlow(m); + String declaredClassName = cc.getName(); + String longName = m.getLongName(); + String methodSignature = m.getSignature(); + if ((m.getModifiers() & Modifier.STATIC) == 0) { + CtClass parameterClasses[] = m.getParameterTypes(); + String parameters = "\",{\""; + String delimiter = " + "; + int p = 1; + for (CtClass c: parameterClasses) { + if (!c.isPrimitive()) { + parameters += delimiter + "System.identityHashCode($" + p + ")"; + delimiter = " + \",\" + "; + } + p++; + } + // System.out.println("System.out.println(\"Method " + declaredClassName + "," + longName + ":\" + System.identityHashCode(this) + " + parameters + " + \"}:ThreadNo \" + Thread.currentThread().getId());"); + m.insertBefore("System.out.println(\"Method " + declaredClassName + "," + longName + ":\" + System.identityHashCode(this) + " + parameters + " + \"}:ThreadNo \" + Thread.currentThread().getId());"); + m.instrument(new ExprEditor() { + public void edit(FieldAccess f) throws CannotCompileException { + if (f.isReader()) { + f.replace("{$_ = $proceed(); System.out.println(\"FieldGet \" + System.identityHashCode($0) + \",\" + System.identityHashCode($_));}"); + } else { + f.replace("$proceed($$); System.out.println(\"FieldSet \" + System.identityHashCode($0) + \",\" + System.identityHashCode($1));"); + } + } + }); + m.insertAfter("System.out.println(\"Return:\" + System.identityHashCode($_));"); + // CodeConverter conv = new CodeConverter(); + // conv.replaceArrayAccess(cc, new ArrayAccessReplacementMethodNames() { + // @Override + // public String shortWrite() { + // return null; + // } + // @Override + // public String shortRead() { + // return null; + // } + // @Override + // public String objectWrite() { + // return null; + // } + // @Override + // public String objectRead() { + // return null; + // } + // @Override + // public String longWrite() { + // return null; + // } + // @Override + // public String longRead() { + // return null; + // } + // @Override + // public String intWrite() { + // return null; + // } + // @Override + // public String intRead() { + // return null; + // } + // @Override + // public String floatWrite() { + // return null; + // } + // @Override + // public String floatRead() { + // return null; + // } + // @Override + // public String doubleWrite() { + // return null; + // } + // @Override + // public String doubleRead() { + // return null; + // } + // @Override + // public String charWrite() { + // return null; + // } + // @Override + // public String charRead() { + // return null; + // } + // @Override + // public String byteOrBooleanWrite() { + // return null; + // } + // @Override + // public String byteOrBooleanRead() { + // return null; + // } + // }); + } + Block[] blocks = cf.basicBlocks(); + int block0 = m.getMethodInfo().getLineNumber(blocks[0].position()); + // int block1 = m.getMethodInfo().getLineNumber(blocks[1].position()); + // int block2 = m.getMethodInfo().getLineNumber(blocks[2].position()); + // int block3 = m.getMethodInfo().getLineNumber(blocks[3].position()); + // int block4 = m.getMethodInfo().getLineNumber(blocks[4].position()); + m.insertAt(block0, "System.out.println(\"block0:\" + " + block0 + ");"); + // m.insertAt(block1, "System.out.println(\"block1:\" + " + block1 + ");"); + // m.insertAt(block2, "System.out.println(\"block2:\" + " + block2 + ");"); + // m.insertAt(block3, "System.out.println(\"block3:\" + " + block3 + ");"); + // m.insertAt(block4, "System.out.println(\"block4:\" + " + block4 + ");"); + + + // int block0 = m.getMethodInfo().getLineNumber(blocks[0].position()); + // m.insertAt(block0, "System.out.println(\"block0\");"); + // m = cc.getDeclaredMethod("getC"); + // cf = new ControlFlow(m); + // blocks = cf.basicBlocks(); + // int block1 = m.getMethodInfo().getLineNumber(blocks[1].position()); + // m.insertAt(block1, "System.out.println(\"block1\");"); + // m = cc.getDeclaredMethod("getC"); + // cf = new ControlFlow(m); + // blocks = cf.basicBlocks(); + // int block2 = m.getMethodInfo().getLineNumber(blocks[2].position()); + // m.insertAt(block2, "System.out.println(\"block2\");"); + + // m.instrument(new ExprEditor() { + // public void edit(MethodCall m) throws CannotCompileException { + // if (m.getClassName().equals("Hello") + // && m.getMethodName().equals("say")) + // m.replace("$0.hi();"); + // } + // }); + } + cc.writeFile("bin"); + } catch (NotFoundException | BadBytecode | CannotCompileException | IOException e) { + e.printStackTrace(); +// } catch (CannotCompileException | IOException e) { +// e.printStackTrace(); + } + } + +}