JavaTM Debug Wire Protocol (JDWP) は、デバッガと、そのデバッガでデバッグする Java 仮想マシン (VM) (以下、ターゲット VM と呼びます) の間の通信に使用されるプロトコルです。これ以降、デバッグする VM のことを、ターゲット VM と呼びます。JDWP はオプションです。Java(TM) 2 SDK の実装によっては、使用できない場合があります。JDWP が存在することにより、同一のデバッガを次の環境で動作させることができます。
JDWP は、形式とレイアウトだけを詳細に定義し、トランスポートは定義していないという点で、多くのプロトコル仕様とは異なっています。JDWP 実装は、さまざまなトランスポートメカニズムを単純な API を介して受け入れるように設計できます。特定のトランスポートが、必ずしも上記のデバッガ/ターゲット VM の組み合わせすべてをサポートするわけではありません。
JDWP の設計は、簡単に実装できるよう十分に単純化されていますが、将来の拡張に対応する柔軟性もあります。
現在のところ、JDWP は、トランスポートを受け入れるためのメカニズムや、ディレクトリサービスを一切指定していません。これは将来変更される可能性がありますが、その点は別のドキュメントで扱われることになるでしょう。
JDWP は、Java Platform Debugger Architecture 内の 1 つの層を構成します。このアーキテクチャーには、より高レベルの Java Debug Interface (JDI) が含まれています。JDWP は、JDI で効率的に使用できるように設計されています。その機能の多くは、その目的に沿って調整されています。多くのデバッガツールにとって、JDWP よりも JDI の方が適しています。これは特に Java プログラミング言語で書かれたデバッガツールに言えることです。Java Platform Debugger Architecture の詳細については、このリリースに関する Java Platform Debugger Architecture のドキュメントを参照してください。
トランスポートの接続が確立されたあとは、パケットが送信される前に、接続の 2 つの側の間でハンドシェイクが行われます。
ハンドシェイクのプロセスには、次のステップがあります。
JDWP はパケットベースであり、ステートフルではありません。基本的なパケットタイプには、コマンドパケットと応答パケットの 2 種類があります。
コマンドパケットは、デバッガまたはターゲット VM のどちらかにより送信されます。コマンドパケットは、ターゲット VM から情報を要求するため、またはプログラムの実行を制御するために、デバッガにより使用されます。また、デバッガにターゲット VM 内のイベント (ブレークポイントや例外など) を通知するために、ターゲット VM からコマンドパケットが送信されます。
応答パケットは、コマンドパケットへの応答としてのみ送信され、いつも、コマンドの成功または失敗に関する情報を提供します。応答パケットは、コマンドで要求されたデータ (フィールドまたは変数の値など) を運ぶこともあります。現在のところ、ターゲット VM から送信されるイベントは、デバッガからの応答パケットを必要としません。
JDWP は非同期です。このため、最初の応答パケットを受信する前に、複数のコマンドパケットが送信される場合があります。
コマンドパケットおよび応答パケットのヘッダーは、同じサイズになっています。これは、トランスポートの実装および抽象化を容易にするためです。各パケットのレイアウトは、次のようになります。
JDWP 経由で送信されるすべてのフィールドおよびデータは、ビッグエンディアン形式である必要があります。ビッグエンディアンの定義については、Java 仮想マシンの仕様を参照してください。最初の 3 つのフィールドは、両方のパケットタイプで同一です。
ほとんどの実装では、ごく単純なカウンタで十分です。そのようなカウンタでも 2^32 個の一意な未処理パケットを識別できます。それが、もっとも単純な実装手段です。
0x80
応答ビットがセットされている場合は、それが応答パケットであることを示します。
コマンドセット空間は、次のように大別されます。
0 - 63
64 - 127
128 - 256
一般に、コマンドパケットまたは応答パケットのデータフィールドは、コマンドまたは応答データを定義する複数フィールドのグループを抽象化したものです。データフィールドの各サブフィールドは、ビッグエンディアン (Java) 形式でエンコードされます。各コマンドとその応答のデータフィールドの構成については、このセクションで詳述します。
さまざまな JDWP コマンドおよび応答の多くに共通の、一般的なデータ型がいくつかあります。それらについて、このあと説明します。
名前 | サイズ | 説明 |
---|---|---|
byte |
1 バイト | バイト値。 |
boolean |
1 バイト | ブール値。false の場合は 0、true の場合はゼロ以外の値としてエンコードされる。 |
int |
4 バイト | 4 バイトの整数値。整数は、符号付き (符号なしと明示されている場合を除く)。 |
long |
8 バイト | 8 バイトの整数値。値は、符号付き (符号なしと明示されている場合を除く)。 |
objectID |
ターゲット VM に固有。最大 8 バイト (表のあとの説明を参照) | ターゲット VM 内のオブジェクトを一意に識別する。特定のオブジェクトは、その存続期間中 (または、objectID が明示的に廃棄されるまで) ずっと、JDWP のコマンドおよび応答の中で、ただ 1 つの objectID によって識別される。ObjectID は、それが明示的に廃棄されないかぎり、参照されたオブジェクトがガベージコレクトされたかどうかにかかわらず、異なるオブジェクトの識別に再利用されることはない。0 という objectID は、null オブジェクトを表す。
objectID が存在しても、オブジェクトのガベージコレクションが妨げられることはない。ガベージコレクトされたオブジェクトを、objectID を使ってアクセスしようとすると、INVALID_OBJECT エラーコードが生成される。ガベージコレクションは、DisableCollection コマンドを使って無効にできるが、通常その必要はない。 |
tagged-objectID |
objectID のサイズ + 1 バイト | 最初のバイトは、オブジェクトの型を識別するためのシグニチャーバイト。このバイトに設定可能な値については、JDWP.Tag を参照。使用できるのはオブジェクトタグだけで、プリミティブタグは使用できない。そのバイトのあとに、objectID そのものが続く。 |
threadID |
objectID と同じ | スレッドとして認識されているターゲット VM 内のオブジェクトを一意に識別する |
threadGroupID |
objectID と同じ | スレッドグループとして認識されているターゲット VM 内のオブジェクトを一意に識別する |
stringID |
objectID と同じ | 文字列オブジェクトとして認識されているターゲット VM 内のオブジェクトを一意に識別する。注:これは、値としての文字列とはまったく異なる。 |
classLoaderID |
objectID と同じ | クラスローダーオブジェクトとして認識されているターゲット VM 内のオブジェクトを一意に識別する |
classObjectID |
objectID と同じ | クラスオブジェクトとして認識されているターゲット VM 内のオブジェクトを一意に識別する。 |
arrayID |
objectID と同じ | 配列として認識されているターゲット VM 内のオブジェクトを一意に識別する。 |
referenceTypeID |
objectID と同じ | ターゲット VM 内の参照型を一意に識別する。特定の 1 つのクラスについて、classObjectID と referenceTypeID が同一であると想定するべきではない。特定の参照型は、その存続期間中ずっと、JDWP のコマンドおよび応答の中で、ただ 1 つの ID によって識別される。referenceTypeID は、参照しているクラスがアンロードされたとしても、別の参照型を識別するために再利用されることはない。 |
classID |
referenceTypeID と同じ | クラス型として認識されているターゲット VM 内の参照型を一意に識別する。 |
interfaceID |
referenceTypeID と同じ | インタフェース型として認識されているターゲット VM 内の参照型を一意に識別する。 |
arrayTypeID |
referenceTypeID と同じ | 配列型として認識されているターゲット VM 内の参照型を一意に識別する。 |
methodID |
ターゲット VM に固有。最大 8 バイト (表のあとの説明を参照) | ターゲット VM 内のあるクラスのメソッドを一意に識別する。methodID は、クラス/インタフェース内のメソッド、またはそのサブクラス/サブインタフェース/実装者のいずれかを一意に識別する必要がある。methodID は、それ単独で必ずしも一意である必要はない。referenceTypeID と組み合わせたときに、1 つのメソッドを一意に識別していればよい。referenceTypeID では、メソッドの宣言型またはサブタイプを識別できる。 |
fieldID |
ターゲット VM に固有。最大 8 バイト (表のあとの説明を参照) | ターゲット VM 内のあるクラスのフィールドを一意に識別する。fieldID は、クラス/インタフェース内のメソッド、またはそのサブクラス/サブインタフェース/実装者のいずれかを一意に識別する必要がある。fieldID は、それ単独で必ずしも一意である必要はない。referenceTypeID と組み合わせたときに、1 つのフィールドを一意に識別していればよい。referenceTypeID では、フィールドの宣言型またはサブタイプを識別できる。 |
frameID |
ターゲット VM に固有。最大 8 バイト (表のあとの説明を参照) | ターゲット VM 内のフレームを一意に識別する。frameID は、VM 全体 (特定のスレッド内だけではない) のフレームを一意に識別する必要がある。frameID は、スレッドが中断されている間だけ有効であればよい。 |
location |
ターゲット VM に固有 | 実行可能ファイルの位置。位置は、1 バイトのタイプタグ + classID + methodID + 符号なしの 8 バイトインデックス (メソッド内の位置を識別する) により識別される。インデックス値には、次のような制限がある
タイプタグは、位置の classID がクラスとインタフェースのどちらを識別しているかを示すために必要。ほとんどすべての位置はクラス内に存在するが、インタフェースの静的な初期化子内に実行可能コードが存在することもある。 |
string |
可変 | UTF-8 でエンコードされた文字列。ゼロで終了する文字列ではなく、先頭に長さ (4 バイトの整数) が置かれる。 |
value |
可変 | ターゲット VM から取得された値。最初のバイトは、型を識別するためのシグニチャーバイト。このバイトに設定可能な値については、JDWP.Tag を参照。そのバイトのあとに、値そのものが続く。この値は、objectID (「ID サイズの取得」を参照) か、プリミティブ値 (1 から 8 バイト) のどちらか。それぞれの値型の詳細については、次の表を参照。 |
untagged-value |
可変 | 前述の value からシグニチャーバイトを除いたもの。この形式は、シグニチャー情報をコンテキストから判別できる場合に使用される。 |
arrayregion |
可変 | 一部の配列操作で使用される値のコンパクトな表現。最初のバイトは、型を識別するためのシグニチャーバイト。このバイトに設定可能な値については、JDWP.Tag を参照。次にくるのは、シーケンス内の値の数を示す 4 バイトの整数。そのあとに、それらの値そのものが続く。プリミティブ値は、untagged-values のシーケンスとしてエンコードされる。オブジェクト値は、values のシーケンスとしてエンコードされる。 |
オブジェクト ID、参照型 ID、フィールド ID、メソッド ID、およびフレーム ID は、ターゲット VM の実装によってサイズが異なります。一般に、そのサイズは、JNI および JVMDI 呼び出しの中で使用されるネイティブ識別子のサイズに対応しています。各型の最大サイズは、8 バイトです。VirtualMachine コマンドセットの IDSizes コマンドは、これらの各型のサイズを判別するためにデバッガによって使用されます。
debuggee は、実装されていないか、または認識されていないコマンドセットまたはコマンドを含むコマンドパケットを受信すると、NOT_IMPLEMENTED に設定されたエラーコードフィールドを含む応答パケットを返します (Error 定数を参照)。