package asmdeps;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.lang.instrument.Instrumentation;
import java.lang.instrument.UnmodifiableClassException;
import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
public class AgentWanat {
private static String at = " at ";
private static class CatchThrowTransformer implements ClassFileTransformer {
@Override
public byte[] transform(ClassLoader loader, String name,
Class<?> clazz, ProtectionDomain domain, byte[] bytecode)
throws IllegalClassFormatException {
ClassReader reader = new ClassReader(bytecode);
ClassWriter clsWrt = new ClassWriter(reader,
ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES);
final Collection<String> labels = new HashSet<String>();
reader.accept(new ClassVisitor(Opcodes.ASM4, clsWrt) {
@Override
public MethodVisitor visitMethod(int access, String name,
String desc, String signature, String[] exceptions) {
MethodVisitor mVisitor = super.visitMethod(access, name,
desc, signature, exceptions);
return new MethodVisitor(Opcodes.ASM4, mVisitor) {
@Override
public void visitInsn(int opcode) {
if (opcode == Opcodes.ATHROW) {
super.visitInsn(Opcodes.DUP);
super.visitMethodInsn(Opcodes.INVOKESTATIC,
Type.getInternalName(AgentWanat.class),
"printThrow", Type.getMethodDescriptor(
Type.VOID_TYPE,
Type.getType(Throwable.class)));
}
super.visitInsn(opcode);
}
@Override
public void visitTryCatchBlock(Label start, Label end,
Label handler, String type) {
labels.add(handler.toString());
super.visitTryCatchBlock(start, end, handler, type);
}
@Override
public void visitLabel(Label label) {
super.visitLabel(label);
if (labels.contains(label.toString())) {
super.visitInsn(Opcodes.DUP);
super.visitMethodInsn(Opcodes.INVOKESTATIC,
Type.getInternalName(AgentWanat.class),
"printCatch", Type.getMethodDescriptor(
Type.VOID_TYPE,
Type.getType(Throwable.class)));
}
}
};
}
}, 0);
return clsWrt.toByteArray();
}
}
public static void print(Throwable t) {
StackTraceElement[] x = Thread.currentThread().getStackTrace();
for (int i = 0; i < x.length - 3; ++i) {
System.out.println(String.format("%s%s", at, x[i + 3]));
}
}
public static void printThrow(Throwable t) {
System.out.println(String.format("thrown %s", t.toString()));
print(t);
}
public static void printCatch(Throwable t) {
System.out.println(String.format("caught %s", t.toString()));
print(t);
}
public static void premain(String args, Instrumentation instrumentation) {
instrumentation.addTransformer(new CatchThrowTransformer(), true);
// gather previously loaded (modifiable) classes
ArrayList<Class<?>> classes = new ArrayList<Class<?>>();
for (Class<?> clazz : instrumentation.getAllLoadedClasses())
if (instrumentation.isModifiableClass(clazz))
classes.add(clazz);
// transform them all at once
try {
instrumentation
.retransformClasses(classes.toArray(new Class<?>[0]));
} catch (UnmodifiableClassException e) {
// this should NOT happen
throw new RuntimeException(e);
}
}
}