问题
I want to extract the return value that type is org.apache.commons.dbcp.BasicDataSource How can I achieve this in asm?
I have to get the instance of the class, org.apache.commons.dbcp.BasicDataSource right after it is created in createDataSource(). So I will visit this method and put some bytecode for getting the return value.
回答1:
I used Advice Adapter to get the return value from a method. A method either return a value or throw exception.Hope below code helps you.
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.commons.AdviceAdapter;
public class MyMethodVisitor extends AdviceAdapter{
Label startFinally = new Label();
public MyMethodVisitor(int access , MethodVisitor mv , String methodName, String description, String className) {
super(Opcodes.ASM5 , mv, access, methodName, description);
}
public void visitCode() {
super.visitCode();
mv.visitLabel(startFinally);
}
public void visitMaxs(int maxStack, int maxLocals) {
Label endFinally = new Label();
mv.visitTryCatchBlock(startFinally, endFinally, endFinally, null);
mv.visitLabel(endFinally);
onFinally(Opcodes.ATHROW);
mv.visitInsn(Opcodes.ATHROW);
super.visitMaxs(maxStack, maxLocals);
}
protected void onMethodEnter(){
// If required, add some code when a method begin
}
protected void onMethodExit(int opcode){
if(opcode!=ATHROW) {
onFinally(opcode);
}
}
private void onFinally(int opcode) {
if(opcode == Opcodes.ATHROW){
mv.visitInsn(Opcodes.DUP); // Exception thrown by the method
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "abc/xyz/CatchError", "recordException", "(Ljava/lang/Object)V", false);
}
else{
mv.visitInsn(Opcodes.DUP); // Return object
mv.visitMethodInsn(Opcodes.INVOKESTATIC, "abc/xyz/CatchError", "getReturnObject", "(Ljava/lang/Object)V", false);
}
}
}
The line actually gives the return type - mv.visitInsn(Opcodes.DUP); // Return object
回答2:
To get the actual value, you'd need to execute or interpret the bytecode. To change what a method returns, the last two instructions in the method should be:
xload_#
xreturn
where x is the type
examples:
//returning an object
aload
areturn
//returning an int
iload
ireturn
and # is the index of the variable in the current frame
The methods you may want to look at are visitBasicVarInstruction/visitVarInstruction (for the load instruction) visitBasicInstruction (for the return instruction)
If you want to go the execution route. In ASM you can create a stub class that contains only the method you want to execute, and the local class fields that method references. Then using the ClassWriter, visit the stub class you created and write it to a file retrieving the bytes.
Then use the URLClassLoader to load that file into the jvm, create an instance of that object and invoke the method via reflection (if you want to create the class at runtime); or write out the file and include in your build path to use it while programming.
The execution option is GREATLY oversimplified, but it is doable (the software I'm writing write now does it). Hopefully I'll be able to opensource it, or at the very least release the binaries publicly.
来源:https://stackoverflow.com/questions/33887368/how-to-get-the-return-value-in-asm