Pythonヘルパー・スクリプトを使用したネイティブ実行可能ファイルのデバッグ

GDBデバッグに加え、Pythonヘルパー・スクリプトgdb-debughelpers.pyを使用してnative-imageプロセスをデバッグできます。GDB Python APIを使用して、ネイティブ実行可能ファイルまたは共有ライブラリのデバッグに比較的良好なエクスペリエンスが提供されます。Python対応のGDBが必要です。デバッグ拡張はGDB 14.2に対してテストされ、JDK 17以降ではGraalVMで導入された新しいdebuginfo生成をサポートしています。

ノート: gdb-debughelpers.pyファイルは、gdbのバージョン14.2より古いバージョンや、GraalVM for JDK 17より古いバージョンでは動作しません。

Pythonスクリプトgdb-debughelpers.pyは、<GRAALVM_HOME>/lib/svm/debugディレクトリにあります。debuginfoの生成が有効になっている場合(デバッグ情報を使用したネイティブ実行可能ファイルのビルドを参照)、スクリプトはビルド・ディレクトリにコピーされます。native-imageツールはデバッグ情報ファイルにデバッグ・セクション.debug_gdb_scriptsを追加します。これにより、GDBは現在の作業ディレクトリからgdb-debughelpers.pyを自動的にロードします。

セキュリティ上の理由により、GDBは、特定のPythonファイルのロードをリクエストするネイティブ実行可能ファイルまたは共有ライブラリを初めて検出すると、警告を出力します:

warning: File "<CWD>/gdb-debughelpers.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".

To enable execution of this file add
        add-auto-load-safe-path <CWD>/gdb-debughelpers.py
line to your configuration file "<HOME>/.gdbinit".
To completely disable this security protection add
        add-auto-load-safe-path /
line to your configuration file "<HOME>/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual.  E.g., run from the shell:
        info "(gdb)Auto-loading safe path"

これを解決するには、次のように現在の作業ディレクトリを~/.gdbinitに追加します:

echo "add-auto-load-safe-path <CWD>/gdb-debughelpers.py" >> ~/.gdbinit

または、コマンドライン引数としてパスをgdbに渡します:

gdb -iex "set auto-load safe-path <CWD>/gdb-debughelpers.py" <binary-name>

どちらも、GDBが現在の作業ディレクトリからgdb-debughelpers.pyを自動ロードできるようにします。

スクリプトをGDBに提供するには、自動ロードをお薦めします。ただし、次のようにして、GDBからスクリプトを明示的にロードできます:

(gdb) source gdb-debughelpers.py

プリティ・プリントのサポート

gdb-debughelpers.pyをロードすると、GDBに新しいプリティ・プリンタが登録されます。これにより、ネイティブ実行可能ファイルまたは共有ライブラリをデバッグする際の利便性がさらに高まります。このプリティ・プリンタは、ネイティブ実行可能ファイルまたは共有ライブラリをデバッグするためのJavaオブジェクト、配列、文字列および列挙の出力を処理します。Javaアプリケーションで@CStructおよび@CPointer注釈を使用してCデータ構造にアクセスする場合、プリティ・プリンタはそれらをJavaデータ構造として出力するように試みます。プリティ・プリンタでCデータ構造を出力できない場合、GDBによって出力が実行されます。

プリティ・プリンタは、ボックス化されたプリミティブ(Javaオブジェクトではなく)のプリミティブ値も出力します。

printコマンドのp別名を使用して出力を行うたびに、プリティ・プリンタは、Javaオブジェクトの各ランタイム型への型キャストを実行するためにコールをインターセプトします。これは、p別名を使用する場合の自動補完にも適用されます。つまり、静的型がランタイム型と異なる場合、printコマンドでは静的型が使用され、ユーザーはランタイム型を検出して型キャストできます。また、p別名は、Javaオブジェクトに対するJavaフィールドおよび配列アクセスおよび関数コールを理解します。

制限事項

上書きする方法がないため、printコマンドは、デフォルトのprintコマンドの機能を維持しながら、デフォルトの実装を使用します。オーバーライドすると、Java以外のオブジェクトの出力が正しく機能しなくなります。したがって、ユーザーがデフォルトのGDB printコマンドを引き続き使用できるように、printコマンドのp別名のみがプリティ・プリンタによって上書きされます。

プリティ・プリンタの動作を制御するオプション

拡張されたp別名に加えて、gdb-debughelpers.pyには、プリティ・プリンタの動作をカスタマイズするためのいくつかのGDBパラメータが導入されています。GDBのパラメータは、set <param> <value>およびshow <param>コマンドで制御できるため、GDBのカスタマイズ・オプションと統合できます。

このコマンドを使用して、プリティ・プリンタを有効または無効にします。これにより、printコマンドの別名pもデフォルトの動作にリセットされます。または、GDBのprintコマンドのraw出力オプションを使用して、プリティ・プリントを抑制できます:

(gdb) show svm-print
The current value of 'svm-print' is "on".

(gdb) print str
$1 = "string"

(gdb) print/r str
$2 = (java.lang.String *) 0x7ffff689d2d0

(gdb) set svm-print off
1 printer disabled
1 of 2 printers enabled

(gdb) print str
$3 = (java.lang.String *) 0x7ffff689d2d0

Java文字列をプリティ・プリントするための最大長をカスタマイズします。デフォルト値は200です。Java文字列を無制限に出力する場合は、-1またはunlimitedに設定します。これは、C文字列の上限は変更しません。C文字列の上限は、GDBのset print charactersコマンドで制御できます。

Java配列、ArrayListおよびHashMapをプリティ・プリントするための要素の最大数をカスタマイズします。デフォルト値は10です。要素を無制限に出力するには、-1またはunlimitedに設定します。これは、C配列の上限は変更しません。C配列の上限は、GDBのset print elementsコマンドで制御できます。ただし、GDBのパラメータprint elementssvm-print-element-limitの上限です。

Javaオブジェクトのプリティ・プリント・フィールドの最大要素数をカスタマイズします。デフォルト値は50です。無制限の数のフィールドを出力するには、-1またはunlimitedに設定します。GDBのパラメータprint elementsが、svm-print-field-limitの上限です。

再帰的なプリティ・プリントの最大深度をカスタマイズします。デフォルト値は1です。直接の子の子が出力されます(ボックス化された値の内容を表示するための正常なデフォルト)。深さを無制限に出力するには、-1またはunlimitedに設定します。GDBのパラメータprint max-depthが、svm-print-depth-limitの上限です。

高レベル表現のプリティ・プリントを有効/無効にします。リストやマップなどの既知の内部構造を持つ一部のJavaデータ構造について、よりデータ指向のビューを提供します。現在、ArrayListおよびHashMapがサポートされています。

高レベル表現の汎用型を推測するために考慮される要素の数をカスタマイズします。デフォルト値は10です。汎用型を推測しない場合は0、すべての要素の汎用型を推測する場合は-1またはunlimitedに設定します。

通常のプリティ・プリントに加えて、アドレスの印刷を有効/無効にします。absoluteモードを使用する場合、圧縮参照も絶対アドレスとして表示されます。アドレスを印刷することは、デフォルトでは無効です。

Javaオブジェクトの静的フィールドの出力を有効または無効にします。静的フィールドの印刷は、デフォルトでは無効になっています。

拡張されたp別名の静的フィールド・メンバーの自動補完を有効または無効にします。静的フィールドの自動補完は、デフォルトで有効になっています。

データ構造の自己参照チェックを有効または無効にします。プリティ・プリンタは、自己参照型のデータ構造を検出し、無限の再帰を避けるためにさらなる拡張を防ぎます。自己参照チェックはデフォルトで有効になっています。テストでは、この機能は一時的に無効にできます(通常は無効にしません)。