8

静的分析を行うツールを試しています。このツールは、ソース コードではなくバイトコードで動作します。(ただし、ソースコードも持っています)。

このツールはバイトコードからいくつかの行番号を出力するので、ソース コードに戻す簡単な方法が必要です。Netbeans/Eclipse は常にこれを行っているため (含まれているライブラリのメソッドをクリックすると、IDE がソース (利用可能な場合) に移動します)、これが可能であることはわかっています。私はそれを行う方法を理解できませんでした。

例として、次の hello world プログラムを考えてみましょう。

package mypackage;
import java.io.*;
class MyMainClass {
  public static void main(String[] args) { 
    BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); 
    String name0 = "Alice";
    String name1 = "Bob";
    try {
        name0 = in.readLine();
    }
    catch(Exception e) {
        System.out.println("Caught an exception!"); 
    }       
    System.out.println("Hello " + name0 + "!"); 
    System.out.println("Hello " + name1 + "!"); 
  }
}

生成されたバイトコード (javap から取得) は次のとおりです。

Compiled from "MyMainClass.java"
class mypackage.MyMainClass extends java.lang.Object{
mypackage.MyMainClass();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   new     #2; //class java/io/BufferedReader
   3:   dup
   4:   new     #3; //class java/io/InputStreamReader
   7:   dup
   8:   getstatic       #4; //Field java/lang/System.in:Ljava/io/InputStream;
   11:  invokespecial   #5; //Method java/io/InputStreamReader."<init>":(Ljava/io/InputStream;)V
   14:  invokespecial   #6; //Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V
   17:  astore_1
   18:  ldc     #7; //String Alice
   20:  astore_2
   21:  ldc     #8; //String Bob
   23:  astore_3
   24:  aload_1
   25:  invokevirtual   #9; //Method java/io/BufferedReader.readLine:()Ljava/lang/String;
   28:  astore_2
   29:  goto    42
   32:  astore  4
   34:  getstatic       #11; //Field java/lang/System.out:Ljava/io/PrintStream;
   37:  ldc     #12; //String Caught an exception!
   39:  invokevirtual   #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   42:  getstatic       #11; //Field java/lang/System.out:Ljava/io/PrintStream;
   45:  new     #14; //class java/lang/StringBuilder
   48:  dup
   49:  invokespecial   #15; //Method java/lang/StringBuilder."<init>":()V
   52:  ldc     #16; //String Hello
   54:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   57:  aload_2
   58:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   61:  ldc     #18; //String !
   63:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   66:  invokevirtual   #19; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   69:  invokevirtual   #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   72:  getstatic       #11; //Field java/lang/System.out:Ljava/io/PrintStream;
   75:  new     #14; //class java/lang/StringBuilder
   78:  dup
   79:  invokespecial   #15; //Method java/lang/StringBuilder."<init>":()V
   82:  ldc     #16; //String Hello
   84:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   87:  aload_3
   88:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   91:  ldc     #18; //String !
   93:  invokevirtual   #17; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   96:  invokevirtual   #19; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   99:  invokevirtual   #13; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   102: return
  Exception table:
   from   to  target type
    24    29    32   Class java/lang/Exception


}

ツールの出力は次のようになります。

<mypackage.MyMainClass> 39, 69, 99

これらはバイトコードの行番号に対応しています。手動で、行がソース コードの次の行に対応している必要があることがわかります。

System.out.println("Caught an exception!"); 
System.out.println("Hello " + name0 + "!"); 
System.out.println("Hello " + name1 + "!"); 

ただし、このプロセスを自動化する必要があります。どんな助けでも大歓迎です。

4

4 に答える 4

3

ソース ファイルと適切な行番号の両方にアクセスできる場合、タスクは、ファイルを行ごとにロードし、その行番号に対応するファイルを選択するだけで済みます。

あなたのアプローチの問題は、属性の形式で、classファイル形式に従ってコンパイルされたコードに格納されているオプションのメタデータに依存していることです。問題の 2 つ、つまりとはどちらもオプションです。つまり、それらがコードに存在するという保証はありません。分析しているクラス ファイルがこの情報を含むようにコンパイルされていることを確認してください。SourceFileLineNumberTable

注: これらの同じ属性は、 を介してスタック トレースの情報を提供するために使用されますThrowable.getStackTrace

于 2012-05-24T19:32:21.237 に答える
1

すすがこれを行います。Soot を介してクラス ファイルを実行すると、それが に変換されます。その後、コードの任意の行をJimple要求できます。メソッドがあります。ドキュメントによると、ソースの行番号または列番号を返します。コード。ValueBox.getJavaSourceStartLineNumber().getJavaSourceStartColumnNumber()

これは、これを行うための最も簡単な方法です。すすは、Java 用に明示的に構築された静的分析ツールです。

于 2015-06-24T17:10:34.150 に答える
1

考慮すべきもう 1 つのオプションは、FindBugs などの既存の静的分析ツールを利用することです。これには、コードのフラグ付きセクションの行番号を表示したり、素敵な HTML レポートを生成したりする機能がたくさんあります。独自のバイトコード分析で FindBugs を比較的簡単に拡張できます。ここのチュートリアルに成功しました: http://www.ibm.com/developerworks/library/j-findbug2/

于 2012-05-21T08:05:03.507 に答える
-1

目的に応じてJDを使用できます。ツールを入手したら、次を使用してプロンプトから逆コンパイルできます。

jdi-gui.exe YourClassFile.class.

クラスsubprocessを使用して開始し、ファイルを逆コンパイルしてから、それぞれの行番号で新しいファイルを書き直すことができます。次に、ツールから返された行番号のみを選択します。Process.class

于 2012-05-21T07:28:03.737 に答える