lundi 2 mars 2015

Java bytecode instrumentation using ASM, MethodVisitor is null



So, with the code written below, my output is:



Starting application with the Agent
Visiting class: HelloWorld
Class Major Version: 51
Super class: java/lang/Object
Source: HelloWorld.java
Method: <init> desc = ()V cv = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method: main desc = ([Ljava/lang/String;)V cv = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method: foo desc = ()V cv = com.amir.agent.instrumentor.amirClassVisitor$1@79f1d448 and mv = null
Method ends here
Done instrumenting: HelloWorld


which is puzzling me. Why would my methodVisitor be null? The ASM source code seems to only return null for the methodVisitor when the classVisitor is null, which is not true in my case.



package com.amir.agent.instrumentor;

import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class amirClassVisitor {

private byte[] outData = null;

public amirClassVisitor() {
}

public void performInstrumentation(final String className,
final byte[] classAsBytes) {
final ClassVisitor cl = new ClassVisitor(Opcodes.ASM4) {
@Override
public void visit(final int version,
final int access,
final String name,
final String signature,
final String superName,
final String[] interfaces) {
System.out.println("Visiting class: "+name);
System.out.println("Class Major Version: "+version);
System.out.println("Super class: " + superName);
super.visit(version, access, name, signature, superName, interfaces);
}

@Override
public void visitOuterClass(final String owner,
final String name,
final String desc) {
System.out.println("Outer class: "+owner);
super.visitOuterClass(owner, name, desc);
}

@Override
public AnnotationVisitor visitAnnotation(final String desc,
final boolean visible) {
System.out.println("Annotation: "+desc);
return super.visitAnnotation(desc, visible);
}

@Override
public void visitAttribute(final Attribute attr) {
System.out.println("Class Attribute: " + attr.type);
super.visitAttribute(attr);
}

@Override
public void visitInnerClass(final String name,
final String outerName,
final String innerName,
final int access) {
System.out.println("Inner Class: " + innerName + " defined in " + outerName);
super.visitInnerClass(name, outerName, innerName, access);
}

@Override
public FieldVisitor visitField(final int access,
final String name,
final String desc,
final String signature,
final Object value) {
System.out.println("Field: "+name+" "+desc+" value:"+value);
return super.visitField(access, name, desc, signature, value);
}

@Override
public void visitEnd() {
System.out.println("Method ends here");
super.visitEnd();
}

@Override
public MethodVisitor visitMethod(final int access,
final String name,
final String desc,
final String signature,
final String[] exceptions) {
final MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
System.out.println("Method: " +name+ " desc = " +desc+ " cv = " +this+ " and mv = " +mv);
return mv;
}

@Override
public void visitSource(final String source,
final String debug) {
System.out.println("Source: "+source);
super.visitSource(source, debug);
}

};

final ClassReader classReader = new ClassReader(classAsBytes);
classReader.accept(cl, 0);
System.out.println("Done instrumenting: " +className);

}

public byte[] result() {
return outData;
}

}


EDIT:


I call this code like this:



public class ClassLoadInterceptor implements ClassFileTransformer {

@SuppressWarnings("unchecked")
public byte[] transform(final java.lang.ClassLoader loader,
final java.lang.String className,
final java.lang.Class classBeingRedefined,
final java.security.ProtectionDomain protectionDomain,
final byte[] classfileBuffer) throws IllegalClassFormatException {

if (!(className.startsWith("java") || className.startsWith("sun") || className.startsWith("com/workday/agent"))) {
WorkdayClassVisitor v = new WorkdayClassVisitor();
v.performInstrumentation(className, classfileBuffer);
System.out.println("\t Instrumenting : " +className);
byte[] instrumented_class = v.result();
writeOutClassFile("debug", className + ".class", classfileBuffer);
writeOutClassFile("debug", className + "_instrumented" + ".class", instrumented_class);
return instrumented_class;
}

return classfileBuffer;

}



Aucun commentaire:

Enregistrer un commentaire