ASM中的Java方法参数值

我试图获取Java程序的方法参数的值。 我正在使用ASM来检测字节码并获取这些值。 但是,我遇到了一些麻烦。

这是用于检测代码的visitCode()方法。 它正在做的是:

  1. 创建一个空数组以存储收集的参数。
  2. 对于每个参数,将其值加载到数组中。
  3. 将此数组发送到我的代理的OnMethodEntry方法(将使用值)。

@Override public void visitCode() { int paramLength = paramTypes.length; // Create array with length equal to number of parameters mv.visitIntInsn(Opcodes.BIPUSH, paramLength); mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); mv.visitVarInsn(Opcodes.ASTORE, paramLength); // Fill the created array with method parameters int i = 0; for (Type tp : paramTypes) { mv.visitVarInsn(Opcodes.ALOAD, paramLength); mv.visitIntInsn(Opcodes.BIPUSH, i); if (tp.equals(Type.BOOLEAN_TYPE) || tp.equals(Type.BYTE_TYPE) || tp.equals(Type.CHAR_TYPE) || tp.equals(Type.SHORT_TYPE) || tp.equals(Type.INT_TYPE)) mv.visitVarInsn(Opcodes.ILOAD, i); else if (tp.equals(Type.LONG_TYPE)) { mv.visitVarInsn(Opcodes.LLOAD, i); i++; } else if (tp.equals(Type.FLOAT_TYPE)) mv.visitVarInsn(Opcodes.FLOAD, i); else if (tp.equals(Type.DOUBLE_TYPE)) { mv.visitVarInsn(Opcodes.DLOAD, i); i++; } else mv.visitVarInsn(Opcodes.ALOAD, i); mv.visitInsn(Opcodes.AASTORE); i++; } // Load id, class name and method name this.visitLdcInsn(new Integer(this.methodID)); this.visitLdcInsn(this.className); this.visitLdcInsn(this.methodName); // Load the array of parameters that we created this.visitVarInsn(Opcodes.ALOAD, paramLength); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "jalen/MethodStats", "onMethodEntry", "(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V"); super.visitCode(); } 

但是,当显然该方法具有多个参数时,这不起作用。

获得的类文件显示如下:

 static void moveDisk(char arg0, char arg1, PrintStream arg2) { Object[] arrayOfObject = new Object[3]; arrayOfObject[0] = ???; arrayOfObject[1] = ???; Object localObject; arrayOfObject[2] = localObject; MethodStats.onMethodEntry(5, "hanoi/TowersOfHanoi", "moveDisk", arrayOfObject); 

创建2个本地对象而不是加载参数。

字节码没有显示任何奇怪的东西:

 static void moveDisk(char, char, java.io.PrintStream); Code: 0: bipush 3 2: anewarray #4 // class java/lang/Object 5: astore_3 6: aload_3 7: bipush 0 9: iload_0 10: aastore 11: aload_3 12: bipush 1 14: iload_1 15: aastore 16: aload_3 17: bipush 2 19: aload_2 20: aastore 21: ldc #118 // int 5 23: ldc #12 // String hanoi/TowersOfHanoi 25: ldc #119 // String moveDisk 27: aload_3 28: invokestatic #19 // Method jalen/MethodStats.onMethodEntry:(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V 

最后,显示的错误是(使用-noverify时):

 param: [Ljava.lang.String;@420e54f3 Exception in thread "Jalen Agent" java.lang.NullPointerException at hanoi.TowersOfHanoi.solveHanoi(TowersOfHanoi.java) at hanoi.TowersOfHanoi.main(TowersOfHanoi.java:29) 

否则,它是:

 Exception in thread "Jalen Agent" java.lang.VerifyError: (class: hanoi/TowersOfHanoi, method: moveDisk signature: (CCLjava/io/PrintStream;)V) Expecting to find object/array on stack at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2442) at java.lang.Class.getMethod0(Class.java:2685) at java.lang.Class.getMethod(Class.java:1620) at sun.launcher.LauncherHelper.getMainMethod(LauncherHelper.java:492) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:484) 

通常,这应该工作,因为我只是从堆栈框架加载信息。 我还尝试检查静态和非静态方法(截至此处解释的堆栈: http : //www.artima.com/insidejvm/ed2/jvm8.html ),但仍然没有成功。

有没有想过为什么会这样,或者可能是一个解决方案的想法?

谢谢 :)

编辑:

它现在正在装箱原始类型(感谢下面的int3的建议:))。 这是visitCode()方法的工作代码:

 @Override public void visitCode() { int paramLength = paramTypes.length; // Create array with length equal to number of parameters mv.visitIntInsn(Opcodes.BIPUSH, paramLength); mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object"); mv.visitVarInsn(Opcodes.ASTORE, paramLength); // Fill the created array with method parameters int i = 0; for (Type tp : paramTypes) { mv.visitVarInsn(Opcodes.ALOAD, paramLength); mv.visitIntInsn(Opcodes.BIPUSH, i); if (tp.equals(Type.BOOLEAN_TYPE)) { mv.visitVarInsn(Opcodes.ILOAD, i); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); } else if (tp.equals(Type.BYTE_TYPE)) { mv.visitVarInsn(Opcodes.ILOAD, i); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;"); } else if (tp.equals(Type.CHAR_TYPE)) { mv.visitVarInsn(Opcodes.ILOAD, i); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); } else if (tp.equals(Type.SHORT_TYPE)) { mv.visitVarInsn(Opcodes.ILOAD, i); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;"); } else if (tp.equals(Type.INT_TYPE)) { mv.visitVarInsn(Opcodes.ILOAD, i); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); } else if (tp.equals(Type.LONG_TYPE)) { mv.visitVarInsn(Opcodes.LLOAD, i); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;"); i++; } else if (tp.equals(Type.FLOAT_TYPE)) { mv.visitVarInsn(Opcodes.FLOAD, i); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); } else if (tp.equals(Type.DOUBLE_TYPE)) { mv.visitVarInsn(Opcodes.DLOAD, i); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); i++; } else mv.visitVarInsn(Opcodes.ALOAD, i); mv.visitInsn(Opcodes.AASTORE); i++; } // Load id, class name and method name this.visitLdcInsn(new Integer(this.methodID)); this.visitLdcInsn(this.className); this.visitLdcInsn(this.methodName); // Load the array of parameters that we created this.visitVarInsn(Opcodes.ALOAD, paramLength); mv.visitMethodInsn(Opcodes.INVOKESTATIC, "jalen/MethodStats", "onMethodEntry", "(ILjava/lang/String;Ljava/lang/String;[Ljava/lang/Object;)V"); super.visitCode(); } 

您正在使用aastorechar存储到对象数组中,这是一个类型错误。 aastore应该只用于存储对象和数组,这可能是错误说’堆栈上的预期对象/数组’的原因。 应使用castore将字符存储在char数组中。 但是,由于您希望这适用于任意签名,您可能希望将原始类型aastore成对象,然后您可以使用aastore – 例如, char应该在java.lang.Character对象中装箱。