プログラムで JDB を操作しようとしています。正常なデバッガとは異なり、JDB はソース ファイル名の代わりにクラス名を使用してソース コードを参照します。バイトコードを単一のファイルではなく複数の .class ファイルに格納することに関連していると思います(-g
フラグを使用してコンパイルすると、ソースファイルへの参照が生成されると予想されますが、物事を簡単にするのはJavaの方法ではありません... )
JDB がクラスを参照する場合、通常は文字列操作をいくつか行い、ソース ファイル名を調べて、どのソース ファイルが関連するクラスを宣言しているかを判断します。ブレークポイントのクラス名を指定する必要がある場合は、ファイルを読み取ってパッケージ名を取得し、そのファイル名をクラス名として使用して、その方法で完全なクラス名を生成できます。これらの2つのケースは、私がそれらを機能させました。
問題は内部クラスと匿名クラスから始まります。それらは独自のクラス ファイルに存在し、それらの名前はそれらを含むクラスのマングル バージョンです。そこにブレークポイントを設定するには、マングルされた名前が必要です。
例-これはMain.java
(+行番号)です:
1: public class Main{
2: public static void main(String[] args){
3: new Object(){
4: @Override public String toString(){
5: System.out.println("hi");
6: return "";
7: }
8: }.toString();
9: }
10:}
を使用してコンパイルしjavac -g Main.java
、 を取得Main.class
しMain$1.class
ました。私は走っていjdb
ます:
Initializing jdb ...
> stop on Main.main
Deferring breakpoint Main.main.
It will be set after the class is loaded.
> run Main
run Main
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: Set deferred breakpoint Main.main
Breakpoint hit: "thread=main", Main.main(), line=3 bci=0
3 new Object(){
(その部分をロードする必要がありました。Main.class
そうしないと、すべてのブレークポイント設定の試行に対して、「クラスがロードされた後に設定されます。 」と表示されます。)
8 行目にブレークポイントを設定すると、正しく動作します。
main[1] stop at Main:8
Set breakpoint Main:8
匿名クラスの一部である 5 行目にブレークポイントを設定すると、エラーが発生します。
main[1] stop at Main:5
Unable to set breakpoint Main:5 : No code at line 5 in Main
行 5 には明らかにコードが含まれています。問題は、コードが にコンパイルされていないことです。コードは にコンパイルされMain.class
てMain$1.class
いるため、代わりに次のように記述する必要があります。
main[1] stop at Main$1:5
Deferring breakpoint Main$1:5.
It will be set after the class is loaded.
さて、Java がバイトコードを .class ファイルに分割する方法は決定論的であり、この単純な例では、人間の目で調べると、何がどこにあるのかを簡単に把握できますが、マングルされたクラス名をプログラムで把握する方法が必要です( VimScript を使用) 実際のソース ファイルの場合。ソース ファイルを構文的に分析し、どれが複雑すぎるのかを突き止めようとしています。もっと簡単な方法があるはずです。
おそらく、.class ファイルからその情報を抽出するか、それについて JDB に質問するか、JDB に、正常な言語の正常なデバッガーのようにソース ファイル名を使用させることさえできます...