views:

409

answers:

2

I've created a JVMTI agent that does the following at a high level:

  • onClassLoadHook send the bytecodes for the loaded class to a separate Java process that will instrument the class using ASM

  • get the bytecodes back and load them

In my seperate java process that instruments the loaded Java class I do the following :

.. ..

    cr = new ClassReader(inBytes, offset, inLen);
    cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);

    ClassAdapter ca = new ClassAdapter(cw) {
    ..
    ..

        @Override
        public MethodVisitor visitMethod(final int access,
                                         final String name,
                                         final String desc,
                                         String signature,
                                         String[] exceptions) {

            return new MethodAdapter(mv) {

                @Override
                public void visitCode() {

                    mv.visitVarInsn(Opcodes.ALOAD, 0);
                    mv.visitMethodInsn(Opcodes.INVOKESTATIC, "com/amir/Tester", "callTestStatic3", "(Ljava/lang/Object;)V");
                    mv.visitCode();

                }

            }
        }

When I try to decompile the class that is written after this instrumentation using Java Decompiler - I see the following decompiled function which I know is wrong :

  public void func1(int arg1, int arg2)
  {
    int b;
    Tester.callTestStatic3(???); 
    System.out.println("arg = " + a + " b = " + b);

  }

because my function actually looks like this :

public void func1(int a, int b) 
{

    System.out.println("arg = " +a + " b = " +b);

}

Can anyone tell me if I did something wrong here? My only clue is that if instead of passing in as an argument to my function the THIS pointer, if I pass in primitive types, everything works out finie. Is there something special about the THIS pointer that I need to manage? I've compared the bytecodes, and I've used ASMIFIER to get a clue as to what statements I need to use to generate the right bytecodes.

+1  A: 

Perhaps it does not matter, but shouldn't you be calling super.visitCode()?

@Override
public void visitCode() {
  super.visitCode();
  ...

I'd use TraceClassVisitor to check exactly what was being generated.

McDowell
I do have the super.visitCode() call - I just forgot to add it to the example. Good catch. Any other ideas? When I run the instrumented code it works, it just decompiles poorly. Thanks for the response.
Amir Afghani
I do an mv.visitCode, not a super.visitCode. I dont' think thats an issue though.
Amir Afghani
Another discovery -- DJ Decompiler reports the correct decompiled code.
Amir Afghani
+1  A: 

It looks like your code is correct, with mv.visitCode(). javap shows the expected bytecodes. I guess your original decompiler just wasn't doing the right thing.

JZeeb
Thanks for the response. It turns out you are right, the decompiler is free and not the greatest indicator. Since writing this original thread, I've started using JAD decompiler, which seems reliable.
Amir Afghani