Байт-код ASM получает значения, передаваемые в качестве аргументов при вызове некоторых методов.

Бьюсь с ASM уже 5 дней и никак не могу решить свою проблему. Требование состоит в том, чтобы получить все значения, переданные в качестве аргументов при вызове метода. Я знаю, что есть много инструментов для этого. Я пошел на ASM (не знаю, правильно ли я принял решение)

Например, если у меня есть эти методы

     public void test2(String a, int b , String c, boolean ba, long d, String e){

      }
     public String giveMeAString(){
        return "oneString";
     }

     public String giveMeAnotherString(){
       return "anotherString";
     }

     public void test(){
         test2("firstParameter", 2907, giveMeAString(),true, 1992, giveMeAnotherString());
     }

Я хотел бы сохранить ["firstParameter",2907, "oneString", true, 1992, "anotherString"]

Я уже читал эти темы:

Как получить возвращаемое значение в asm?

Значения параметров метода Java в ASM

Трассировка аргументов вызова метода в байт-коде с использованием ASM

получить значения аргументов функции, используя java asm для проверка байт-кода

Что объясняет размещение аргументов в локальных переменных, но как я могу получить к ним доступ?

Как я могу получить ЗНАЧЕНИЯ этих аргументов? Я не понимаю, как я могу получить эти аргументы. Я не знаю, напечатать их, например. Есть идеи? Когда они в стеке, я не понимаю, как можно скопировать значение в переменную.

Благодарю вас !

Вот код, который я использую:

    public static class ClassPrinterVisitor extends ClassVisitor {
    private String name;
    private String desc;
    private String signature;

    private Type[] paramTypes;
    private boolean isStatic;
    private String className;
    private String methodName;
    private String methodDesc;
    private String owner;
    private int access;

    public ClassPrinterVisitor(int api, ClassVisitor cv) {
        super(api, cv);
    }

    public ClassPrinterVisitor(int api) {
        super(api);
    }


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

        MethodVisitor oriMv = new MethodVisitor(Opcodes.ASM4) {
        };

        final MethodVisitor instMv2 = new MethodPrinterVisitor(access, desc, oriMv, Type.getArgumentTypes(desc), (access & Opcodes.ACC_STATIC) != 0, className,
                name, desc);
        return instMv2;
    }


    private class MethodPrinterVisitor extends MethodVisitor {

        List<Object> params = new ArrayList<>();
        List<Object> params2 = new ArrayList<>();

        private Type[] paramTypes;
        private boolean isStatic;
        private String className;
        private String methodName;
        private String methodDesc;

        public MethodPrinterVisitor(int api, MethodVisitor mv) {
            super(api, mv);
        }


        public MethodPrinterVisitor(int access, String desc, MethodVisitor mv, Type[] paramTypes, boolean isStatic, String classname,
                                    String methodname, String methoddesc) {
            super(Opcodes.ASM4, mv);
            this.paramTypes = paramTypes;
            this.isStatic = isStatic;
            this.className = classname;
            this.methodName = methodname;
            this.methodDesc = methoddesc;

        }


        @Override
        public void visitLdcInsn(Object var1) {
            if (var1 != null) {
                params.add(var1);
                super.visitLdcInsn(var1);
                System.out.printf("arg: %s %n", var1.toString());

            }

        }
        @Override
        public void visitInsn(int var1) {
            if(this.mv != null) {
                this.mv.visitInsn(var1);
            }

        }
        @Override
        public void visitIntInsn(int var1, int var2) {
            if(this.mv != null) {
                this.mv.visitIntInsn(var1, var2);
            }

        }
        @Override
        public void visitVarInsn(int var1, int var2) {
            if(this.mv != null) {
                this.mv.visitVarInsn(var1, var2);
            }

        }

        @Override
        public void visitMethodInsn(int opcode, String owner, String name, String desc) {
            Pattern pattern = Pattern.compile("[a-zA-Z0-9._]*");

            System.out.printf("---------------------------%n");
            System.out.printf("Class %s calls method %s from class %s%n", ClassPrinterVisitor.this.name, name, owner);
            System.out.printf("Desc: %s signature: %s%n", ClassPrinterVisitor.this.desc, ClassPrinterVisitor.this.signature);
            for (Object p : params) {
                Matcher matcher = pattern.matcher(p.toString());
                if (!p.toString().isEmpty() && !p.toString().startsWith(".") && matcher.matches()) {
                    System.out.printf("visitLdcInsn: %s %n", p);
                }
            }
            System.out.printf("---------------------------%n%n");
            params = new ArrayList<>();
        }

        @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, className, name, signature);
            super.visitCode();
        }


    }

}

person Nicolas Garcia    schedule 25.07.2016    source источник


Ответы (2)


Вам необходимо внедрить анализ потока данных, для вашего случая это будет Обратный анализ потока данных.

Взгляните на SourceInterpreter ASM и этот ТАК ответ https://stackoverflow.com/a/48806265/573057

Из-за потока управления для одного аргумента может быть несколько возможных значений. Из-за внешнего ввода вы не сможете определить значение (хотя вы можете определить такие вещи, как нулевое значение, из более широкого контекста).

Не так сложно для приведенного примера, когда только константы или вызовы методов одного и того же класса дают константы, но расширение до общего случая, вероятно, потребует значительной работы. Возможно, стоит взглянуть на фреймворки типа «проверка», которые выполняют статический анализ кода.

person earcam    schedule 09.04.2019

Вы не можете «получить значения, переданные в качестве аргументов при вызове некоторых методов» при посещении байт-кода метода с помощью ASM, и я думаю, что вы могли неправильно понять эти ссылки.

ASM — это всего лишь библиотека для манипулирования байт-кодом. Во время манипулирования методом число, отображаемое в байт-коде, является только индексом локальной переменной (параметры и локальные переменные), у вас нет возможности получить ЗНАЧЕНИЕ, на которое ссылается переменная (если оно не является константой).

Единственная возможность получить ЗНАЧЕНИЯ этих индексов локальных переменных — выполнить посещаемый байт-код. Байт-код метода является статическим, а значения ссылок на индексы этих переменных НЕИЗВЕСТНЫ. При выполнении байт-кода метода эти индексы ссылаются на некоторые объекты, и виртуальная машина знает об этом.

person shijie xu    schedule 29.07.2016