Java

JavaTM Debug Wire Protocol

JPDA

プロトコルの詳細

概要

Java TM Debug Wire Protocol (JDWP) は、デバッガと、デバッガでデバッグする Java 仮想マシン (VM) との間の通信に使用されるプロトコルです。これ以降、デバッグする VM のことを、ターゲット VM と呼びます。JDWP が存在することにより、同一のデバッガを次の環境で動作させることができます。

JDWP は、形式とレイアウトだけを詳細に定義し、トランスポートは定義していないという点で、多くのプロトコル仕様とは異なっています。JDWP 実装は、さまざまなトランスポート機構を単純な API を介して受け入れるように設計できます。特定のトランスポートが、必ずしも上記のデバッガ/ターゲット VM の組み合わせすべてをサポートするわけではありません。

JDWP の設計は、簡単に実装できるよう十分に単純化されていますが、将来の拡張に対応する柔軟性もあります。

現在のところ、JDWP は、トランスポートを受け入れるための機構や、ディレクトリサービスを一切指定していません。これは将来変更される可能性がありますが、その点は別のドキュメントで扱われることになるでしょう。

JVWP は、Java Platform Debugger Architecture 内の 1 つの層を構成します。このアーキテクチャには、より高レベルの Java Debug Interface (JDI) が含まれています。JDWP は、JDI で効率的に使用できるように設計されています。その機能の多くは、その目的に沿って調整されています。多くのデバッガツールにとって、JDWP よりも JDI のほうが適しています。これは特に Java プログラミング言語で書かれたデバッガツールに言えることです。Java Platform Debugger Architecture の詳細については、このリリースの Java Platform Debugger Architecture のドキュメントおよび Java Platform Debugger Architecture の Web サイトを参照してください。

JDWP の起動

トランスポートの接続が確立されたあとは、パケットが送信される前に、接続の 2 つの側の間でハンドシェイクが行われます。

ハンドシェイクのプロセスには、次のステップがあります。

JDWP のパケット

JDWP はパケットベースであり、ステートフルではありません。基本的なパケットタイプには、コマンドパケットと応答パケットの 2 種類があります。

コマンドパケットは、デバッガまたはターゲット VM のどちらかにより送信されます。コマンドパケットは、ターゲット VM から情報を要求するため、またはプログラムの実行を制御するために、デバッガにより使用されます。また、デバッガにターゲット VM 内のイベント (ブレークポイントや例外など) を通知するために、ターゲット VM からコマンドパケットが送信されます。

応答パケットは、コマンドパケットへの応答としてのみ送信され、いつも、コマンドの成功または失敗に関する情報を提供します。応答パケットは、コマンドで要求されたデータ (フィールドまたは変数の値など) を運ぶこともあります。現在のところ、ターゲット VM から送信されるイベントは、デバッガからの応答パケットを必要としません。

JDWP は非同期です。このため、最初の応答パケットを受信する前に、複数のコマンドパケットが送信される場合があります。

コマンドパケットおよび応答パケットのヘッダは、同じサイズになっています。これは、トランスポートの実装および抽象化を容易にするためです。各パケットのレイアウトは、次のようになります。

コマンドパケット
応答パケット

JDWP 経由で送信されるすべてのフィールドおよびデータは、ビッグエンディアン形式である必要があります。ビッグエンディアンの定義については、Java 仮想マシンの仕様を参照してください。最初の 3 つのフィールドは、両方のパケットタイプで同一です。

コマンドパケットと応答パケットのフィールド

共用されるヘッダフィールド
length
length フィールドは、パケット全体のサイズ (length フィールドを含む) をバイト単位で表します。ヘッダのサイズは 11 バイトなので、データを含まないパケットでは、このフィールドが 11 に設定されます。
id
id フィールドは、パケットのコマンド/応答の各ペアを一意に識別するために使用されます。応答パケットは、その応答対象であるコマンドパケットと同じ id を保持します。このため、非同期のコマンドと応答を対応付けることが可能になります。id フィールドは、1 つのソースから送信される未処理のコマンドすべての中で一意でなければなりません。デバッガから送信される未処理のコマンドでは、ターゲット VM から送信される未処理のコマンドと同じ id を使用できます。これ以外には、id の割り当てに関する要求事項はありません。

ほとんどの実装では、ごく単純なカウンタで十分なはずです。そのようなカウンタでも 2^32 個の一意な未処理パケットを識別できます。それが、もっとも単純な実装手段です。

flags
flags は、コマンドをキューに入れて処理する方法を変更するため、およびターゲット VM から送信されたコマンドパケットをタグ付けするために使用されます。現在のところ、1 フラグビットが定義されています。将来のバージョンのプロトコルでは、フラグがさらに定義される可能性があります。

0x80
応答パケット

応答ビットがセットされている場合は、それが応答パケットであることを示します。

コマンドパケットのヘッダフィールド
command set
このフィールドは、有意義な方法でコマンドをグループ化する手段として有用です。Sun が定義したコマンドセットは、サポートしている JDI のインタフェースごとにコマンドをグループ化する場合に使用します。たとえば、JDI VirtualMachine インタフェースをサポートするすべてのコマンドは、VirtualMachine コマンドセットとしてグループ化されます。

コマンドセット空間は、次のように大別されます。

0 - 63
ターゲット VM に送信されるコマンドのセット
64 - 127
デバッガに送信されるコマンドのセット
128 - 256
ベンダーにより定義されたコマンドおよび拡張機能
command
このフィールドは、コマンドセット内の特定のコマンドを識別します。このフィールドは、コマンドセットフィールドとともに、コマンドパケットの処理方法を示すのに使用されます。つまり、何を実行するべきかを受信側に伝えます。個々のコマンドについては、このドキュメントで後述します。
応答パケットのヘッダフィールド
error code
このフィールドは、応答しているコマンドパケットの処理が成功したかどうかを示すのに使用されます。値がゼロの場合は成功を、ゼロ以外の場合はエラーを示します。返されるエラーコードは、各コマンドセットまたはコマンドに固有の場合もありますが、多くの場合は JVMDI エラーコードに対応しています。
データ
データフィールドは、各コマンドセットまたはコマンドに固有です。また、コマンドパケットと応答パケットのペアの間でも異なります。たとえば、フィールド値を要求するコマンドパケットのデータフィールドには、オブジェクトへの参照と、取得したい値のフィールド ID が含まれます。それに対する応答パケットのデータフィールドには、要求されたフィールドの値が含まれます。

コマンドの詳細情報

一般に、コマンドパケットまたは応答パケットのデータフィールドは、コマンドまたは応答データを定義する複数フィールドのグループを抽象化したものです。データフィールドの各サブフィールドは、ビッグエンディアン (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 つのクラスについて、classObjectIDreferenceTypeID が同一であると想定するべきではない。特定の参照型は、その存続期間中ずっと、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 内のあるクラスのフィールドを一意に識別する。methodID は、クラス/インタフェース内のメソッド、またはそのサブクラス/サブインタフェース/実装者のいずれかを一意に識別する必要がある。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-value のシーケンスとして符号化される。オブジェクト値は、value のシーケンスとして符号化される

オブジェクト ID、参照型 ID、フィールド ID、メソッド ID、およびフレーム ID は、ターゲット VM の実装によってサイズが異なります。一般に、そのサイズは、JNI および JVMDI 呼び出しの中で使用されるネイティブ識別子のサイズに対応しています。各型の最大サイズは、8 バイトです。VirtualMachine コマンドセットの IDSizes コマンドは、これらの各型のサイズを判別するためにデバッガによって使用されます。

debuggee が、実装されていないコマンドセットまたはコマンドや認識されていないコマンドセットまたはコマンドを使用したコマンドパケットを受け取った場合、エラーコードフィールドが NOT_IMPLEMENTED に設定された応答パケットを返します (Error 定数 を参照)。

プロトコルの詳細


Copyright © 2004 Sun Microsystems, Inc.All Rights Reserved. 

コメントの送付先: java-debugger@sun.com 

Sun