0

単純なクラスを使用して javassist でバイトコードを分析しようとしていますMyData:

class MyData {
    private Collection<String> strings = new ArrayList<String>();

        // .....................    
    public void add(String str) {
        strings.add(str); // line number 35
    }
        // .....................    
}

このクラスに対して実行しているコードは次のとおりです。

ClassFile cf = new ClassFile(new DataInputStream(TryJavassist.class.getResourceAsStream("MyData.class")));
MethodInfo minfo = cf.getMethod("add");  
CodeAttribute ca = minfo.getCodeAttribute();
for (CodeIterator ci = ca.iterator(); ci.hasNext();) {
    int index = ci.next();
    int op = ci.byteAt(index);

    System.out.println(op + "=" + Mnemonic.OPCODE[op] + ": " + minfo.getLineNumber(index));
}

それは動作し、印刷します:

42=aload_0: 35
180=getfield: 35
43=aload_1: 35
185=invokeinterface: 35
87=pop: 35
177=return: 36

35 行add()目で、 という名前のコレクションのメソッドを呼び出しますstrings。私が投稿したコード スニペットはinvokeinterface、35 行目のみを取得します。OK、それがクラス フィールド ( ) であることがわかりgetfieldます。

残りの情報を取得する方法を知りたいです。

  • フィールド名はstrings
  • 呼び出されるインターフェースメソッドはadd()

これまでのところ、グーグルでも API ドキュメントを読んでも、肯定的な結果は得られていません。

4

1 に答える 1

2

JVM クラスの形式と命令セットを理解する必要があるため、大変な作業です。どの回答も部分的なデータしか提供できません。特にJavassistでは。命令では、通常、1 つのパラメーターが定数プール内のインデックスであり、名前へのインデックスと型へのインデックスを持つオブジェクトが存在します。ですから、あなたが何に夢中になっているかに注意してください。

クラスがデバッグ情報を使用してコンパイルされている場合、プライベート フィールド名にアクセスできます (ClassFile.getFields)。

javassist がパックされた便利な Dump ツールがあります。

private void dumpMyDataClass() throws IOException, BadBytecode, Exception {
    ClassFile cf = new ClassFile(new DataInputStream(getClass().getResourceAsStream("MyData.class")));

    // Dump fields:
    for (Object fieldInfoObj : cf.getFields()) {
        FieldInfo fieldInfo = (FieldInfo) fieldInfoObj;
        System.out.printf("Field %s; %s%n", fieldInfo.getName(), fieldInfo.getDescriptor());
    }

    MethodInfo minfo = cf.getMethod("add");
    CodeAttribute ca = minfo.getCodeAttribute();
    for (CodeIterator ci = ca.iterator(); ci.hasNext();) {
        int address = ci.next();
        int op = ci.byteAt(address);

        String params = "";
        switch (op) {
            case Opcode.INVOKEINTERFACE:
                int a1 = ci.s16bitAt(address + 1);
                params += " " + cf.getConstPool().getInterfaceMethodrefName(a1);
                System.out.println("a1 = " + a1);
                break;
        }

        System.out.printf("Line %4d. Address %7d: %s%s%n", minfo.getLineNumber(address), address, Mnemonic.OPCODE[op], params);
    }

    // Command line tool of javassist:
    String pathToClass = System.getProperty("user.dir") + "/target/classes/jeggen/test2/MyData.class";
    Dump.main(new String[] { pathToClass });
}
于 2012-02-28T20:32:04.877 に答える