Разобрать приемник вызова метода Java на уровне байт-кода

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

Возьмите байт-код ниже, например, есть два члена поля: _caller1 и _caller2

public Class MyClass{
  test.code.jit.asm.classInline.CI_Caller1 _caller1;
    flags: 

  test.code.jit.asm.classInline.CI_Caller1 _caller2;
    flags: 

  public int test(java.lang.String, java.lang.String, test.code.jit.asm.classInline.CI_Caller1);
    flags: ACC_PUBLIC
    Code:
      stack=4, locals=5, args_size=3
         0: aload_0       
         1: getfield      #14                 // Field _caller1:Ltest/code/jit/asm/classInline/CI_Caller1;
         4: invokevirtual #26                 // Method test/code/jit/asm/classInline/CI_Caller1.test_two_fields_callee:()I
         7: istore_3      
         8: aload_0       
         9: getfield      #16                 // Field _caller2:Ltest/code/jit/asm/classInline/CI_Caller1;
        12: invokevirtual #26                 // Method test/code/jit/asm/classInline/CI_Caller1.test_two_fields_callee:()I
        15: istore        4
        17: getstatic     #32                 // Field java/lang/System.out:Ljava/io/PrintStream;
        20: new           #38                 // class java/lang/StringBuilder
        23: dup           
         .....
        72: ireturn       

Что я хочу знать, так это то, как я могу распознать правильных получателей вызовов методов в #4, #12. Являются ли члены поля класса получателей (какой именно) или аргументы метода? Это относительно легко для чтения человеческим глазом, но как я реализую его с помощью кода Java (лучше, если уже есть существующий инструмент).

В настоящее время я использую среду Java ASM для анализа последовательностей байт-кода класса. Было бы признательно, если бы некоторые идеи могли быть предоставлены (кажется, я должен построить AST байт-кода здесь), или некоторые полезные/связанные ссылки Java также будут полезны.


person shijie xu    schedule 22.07.2015    source источник


Ответы (1)


Когда invokevirtual выполняется, все аргументы извлекаются из стека, после чего извлекается объект-получатель. Таким образом, ваш пример является самым тривиальным: у метода нет аргументов для выталкивания, поэтому инструкция прямо перед тем, как она предоставляет получателю, но даже для метода без аргументов это самый тривиальный случай, поскольку теоретически может быть Независимая от стека последовательность инструкций между инструкцией, предоставляющей получателя, и вызовом. Кроме того, предыдущее чтение поля является наиболее тривиальным случаем, так как ему, к счастью, предшествует инструкция aload_0, которая предоставляет экземпляр, чье поле читается. И пока нет предшествующей записи в переменную 0, она по-прежнему будет содержать экземпляр this, если мы смотрим на метод, отличный от static

После перечисления всех удачных совпадений следует отметить, что для обычного Java-кода и основных компиляторов большинство из этих предпосылок будут выполняться, поэтому, если вы можете жить с покрытием, скажем, 99% всего кода, самые большие препятствия — это аргументы. над стеком, который может быть создан произвольными выражениями, в том числе условными, поэтому код между поставщиком экземпляра получателя и фактическим вызовом может быть довольно длинным.

Единственный способ вернуться к инструкции, которая подтолкнула приемник метода, — это просмотреть код вперед и смоделировать стек операндов как стек объектов, хранящих свою исходную инструкцию, и интерпретировать все влияние инструкции на этот стек операндов. Обратите внимание, что основа для такого интерпретатора уже существует.

person Holger    schedule 22.07.2015