Java Debug Wire Protocol (JDWP)は、デバッガと、そのデバッガでデバッグするJava仮想マシン(VM)(以下、ターゲットVMと呼びます)の間の通信に使用されるプロトコルです。これ以降、デバッグするVMのことを、ターゲットVMと呼びます。JDWPはオプションです。JDKの実装によっては、使用できない場合があります。JDWPが存在することにより、同一のデバッガを次の環境で動作させることができます。
JDWPは、形式とレイアウトだけを詳細に定義し、トランスポートは定義していないという点で、多くのプロトコル仕様とは異なっています。JDWP実装は、さまざまなトランスポート・メカニズムを単純なAPIを介して受け入れるように設計できます。特定のトランスポートが、必ずしも上記のデバッガ/ターゲットVMの組み合わせすべてをサポートするわけではありません。
JDWPの設計は、簡単に実装できるよう十分に単純化されていますが、将来の拡張に対応する柔軟性もあります。
現在のところ、JDWPは、トランスポートを受け入れるためのメカニズムや、ディレクトリ・サービスを一切指定していません。これは将来変更される可能性がありますが、その点は別のドキュメントで扱われることになるでしょう。
JDWPは、Java Platform Debugger Architecture (JPDA)内の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オブジェクトを表す。
オブジェクトIDが存在しても、オブジェクトのガベージ・コレクションが妨げられることはない。ガベージ・コレクトされたオブジェクトを、オブジェクトIDを使用してアクセスしようとすると、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定数を参照)。