4

私の目標は、一部の Java バイトコードのすべての基本ブロックの先頭に少量のコードを実装することです。目的は、基本ブロックの実行パスを記録することです。現在、Javassist を使用してメソッドの最初と最後にいくつかのコードを計測していますが、より細かいバイトコードの場所を計測する際に Javassist API で壁にぶつかりました。

Javassist は、メソッド内のすべての基本ブロックを表す Block[] を提供してくれます。基本ブロックはバイトコードの場所を報告できるため、インストルメンテーションが必要な場所を把握できます。私が使用したかったJavassistのインストルメンテーションはCtMethod.insertAt(int sourceCodeLineNumber,String newSourceCode)でしたが、これはバイトコードの行番号ではなくソースコードの行番号を使用しているため、この質問に示されている問題が発生します(この時点でその問題を修正します)。

質問:変数自体が Javassist instrumentation からのものである場合、 instrumentation を使用してメソッド内の変数に値を割り当てるにはどうすればよいですか。できれば他のツールを使用する必要はありませんが、この時点で得られるあらゆる支援を受けています。

変数は、Javassist を使用して次のように宣言されます。

//m is a CtMethod           
try { m.addLocalVariable("someVar", ClassPool.getDefault().get("SomePackage.SomeClass")); } 
catch (NotFoundException e) { e.printStackTrace(); }

私の最悪のシナリオは、javassist が計測するスタック変数を推定し、メソッド/クラス全体を通過するイテレータを使用してバイトコードを挿入することですが、それは本当に厄介なことです。私のメソッドには整数入力 (ブロック ID) と void 出力しかないため、Java バイトコードはすべての基本ブロックの先頭で次のようになります。

ALOAD 6 //6 is my new Javassist variable ID, however I don't think I can get Javassist to actually tell it to me
ICONST_1 //My parameters, which is an int.  I'd have to switch statement between ICONST, SIPUSH, and ALOAD depending on basic block's index size
INVOKEVIRTUAL SomePackage/SomeClass.SomeMethod(I)V
4

1 に答える 1

1

ConstPool テーブルから変数 ID を取得するために私が見つけた最良の方法は、変数を挿入した後に最大サイズをテストすることです

    try { m.addLocalVariable(mse, ClassPool.getDefault().get("org.javadynamicanalyzer.MethodStackEntry")); } 
    catch (NotFoundException e) { e.printStackTrace(); }

    int mseCSindex=m.getMethodInfo().getCodeAttribute().getMaxLocals()-1;

次に、テーブルからの invokevirtual インデックスが必要でした。これは見つけるのが少し面倒でした。以下のコードは、探している関数を ConstPool テーブルで検索します。私が探している機能は にありorg.javadyanmicanalyzer.MethodStackEntry.setBlockID(int)ます。

        int virtFunIndex=-1;
        boolean found=false;
        while(found==false){
            ++virtFunIndex;
            try{ 
                int id=cp.isMember("org.javadynamicanalyzer.MethodStackEntry", "setBlockIndex", virtFunIndex);
                if(id!=0){
                    found=true;
                }
            }
            catch(NullPointerException | ClassCastException e){}
        }

最後に、各ブロックの先頭を計測する必要がありました。

        int len=new ControlFlow(m).basicBlocks().length;
        for(int i=0; i<len; ++i){
            Block thisbb=new ControlFlow(m).basicBlocks()[i]; //we have to re-evaluate the control flow every time we add new code
            CodeIterator itr=m.getMethodInfo().getCodeAttribute().iterator();

            int pos=thisbb.position();
            byte[] newCode=new byte[]{Bytecode.ALOAD, //loads the mse class
                                      mseCSindex, //my mse local variable
                                      Bytecode.ICONST_0, //the input to the virtual function
                                      Bytecode.INVOKEVIRTUAL, //execute the virtual function
                                      (byte) virtFunIndex>>8, //virtual function's address
                                      (byte) virtFunIndex && 0xFF};

            int n = itr.insertAt(pos, newCode);
        }

散らかっていて、それ自体を完全に破壊する可能性がありますが、うまくいきました!

于 2013-04-30T02:43:23.717 に答える