Oracle Solaris Studio 12.2: dbx コマンドによるデバッグ

第 17 章 dbx による Java アプリケーションのデバッグ

この章では、dbx を使用して、Java コードと C JNI (Java Native Interface) コードまたは C++ JNI コードが混在するアプリケーションをデバッグする方法を説明します。

この章は次の節で構成されています。

dbx と Java コード

Oracle Solaris Studio の dbx を使い、Oracle Solaris OS および Linux OS で動作する混在コード (Java コードと C コードまたは C++ コード) をデバッグすることができます。

Java コードに対する dbx の機能

dbx で数種類の Java アプリケーションをデバッグすることができます (「Java アプリケーションのデバッグの開始」を参照)。大部分の dbx コマンドは、ネイティブコードと Java コードのどちらにも同様の働きをします。

Java コードのデバッグにおける dbx の制限事項

dbx は、Java コードをデバッグする場合、次の制限事項があります。

Java デバッグ用の環境変数

ここでは、dbx を使った Java アプリケーションデバッグの専用の環境変数を説明します。JAVASRCPATHCLASSPATHX、および jvm_invocation 環境変数を、dbx を起動する前にシェルプロンプトで設定するか、dbx コマンド行から設定します。jdbx_mode 環境変数の設定は、アプリケーションのデバッグ中に変化します。ただし、jon コマンド (jon コマンド」) と joff コマンド (joff コマンド」) を使って変更することも できます。

jdbx_mode

jdbx_mode 環境変数の設定は次のとおりです。javajni、または native。Java、JNI、ネイティブモードと、モードの変化の仕方および変化のタイミングについては、dbx の Java コードデバッグモード」を参照してください。デフォルトのモードは java です。

JAVASRCPATH

JAVASRCPATH 環境変数変数を使用して、dbx が Java ソースファイルを探すディレクトリを指定することができます。この変数は、Java ソースファイルが .class.jar ファイルと同じディレクトリにない場合に役立ちます。詳細については、「Java ソースファイルの格納場所の指定」を参照してください。

CLASSPATHX

CLASSPATHX 環境変数を使用して、独自のクラスローダーが読み込む Java クラスファイルのパスを dbx に指定することができます。詳細については、「独自のクラスローダーを使用するクラスファイルのパスの指定」を参照してください。

jvm_invocation

jvm_invocation 環境変数を使って、JVM ソフトウェアの起動方法をカスタマイズすることができます (JVM は Java virtual machine の略語で、Java プラットフォーム用の仮想マシンを意味します)。詳細については、「JVM ソフトウェアの起動方法のカスタマイズ」を参照してください。

Java アプリケーションのデバッグの開始

dbx では、次の種類の Java アプリケーションをデバッグすることができます。

dbx は、これらのどの場合もデバッグ対象が Java アプリケーションであることを認識します。

クラスファイルのデバッグ

次の例に示すように dbx を使用することによって、ファイル名拡張子が .class のファイルをデバッグすることができます。


(dbx) debug myclass.class

アプリケーションを定義しているクラスがパッケージに定義されている場合は、JVM ソフトウェアの制御下でアプリケーションを実行するときと同じで、次の例に示すように、パッケージのパスを指定する必要があります。


(dbx) debug java.pkg.Toy.class

クラスファイルのフルパス名を使用することもできます。この場合、dbx.class ファイル内を調べることによってクラスパスのパッケージ部分を自動的に特定し、フルパス名の残りの部分をクラスパスに追加します。たとえば次のパス名の場合、dbxpkg/Toy.class を主クラス名と判断し、クラスパスに /home/user/java を追加します。


(dbx) debug /home/user/java/pkg/Toy.class

JAR ファイルのデバッグ

Java アプリケーションは、JAR (Java Archive) ファイルにバンドルすることができます。JAR ファイルは、次の例に示すように dbxを使用することによってデバッグすることができます。


(dbx) debug myjar.jar

ファイル名が .jar で終わるファイルのデバッグを開始すると、dbx は、その JAR ファイルのマニフェストに指定されている Main_Class 属性を使って主クラスを特定します (主クラスは、アプリケーションのエントリポイントになっている、JAR ファイル内のクラスです)。フルパス名または相対パス名を使って JAR ファイルが指定された場合、dbxMain-Class 属性のクラスパスの前にそのディレクトリ名を追加します。

Main-Class 属性を持たない JAR ファイルをデバッグする場合、JAR URL 構文 jar:<url>!/{entry} を使用できます。この構文は、次の例のように、主クラスの名前を指定するために JarURLConnection (Java 2 Platform, Standard Edition のクラス) で指定されています。


(dbx) debug jar:myjar.jar!/myclass.class
(dbx) debug jar:/a/b/c/d/e.jar!/x/y/z.class
(dbx) debug jar:file:/a/b/c/d.jar!/myclass.class

これらの例のどの場合も、dbx は次のことを行います。

ラッパーを持つ Java アプリケーションのデバッグ

通常 Java アプリケーションには、環境変数を設定するためのラッパーがあります。Java アプリケーションにラッパーがある場合は、jvm_invocation 環境変数を設定することによって、ラッパースクリプトを使用することを dbx に知らせる必要があります (「JVM ソフトウェアの起動方法のカスタマイズ」を参照)。

動作中の Java アプリケーションへの dbx の接続

dbx を動作中の Java アプリケーションに接続するには、アプリケーションを起動するときに次の例に示すオプションを指定します。アプリケーションが起動すると、動作中のプロセスのプロセス ID を指定して dbx コマンドを実行することによって、デバッグを開始することができます (dbx コマンド」を参照)。


$ java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent myclass.class
$ dbx - 2345

JVM ソフトウェアが libdbx_agent.so を見つけられるようにするには、Java アプリケーションを実行する前に正しいパスを LD_LIBRARY_PATH に追加する必要があります。

installation_directory は Oracle Solaris Studio ソフトウェアがインストールされている場所です。

動作中のアプリケーションに dbx を接続すると、dbx は Java モードでアプリケーションのデバッグを開始します。

Java アプリケーションが 64 ビットのオブジェクトライブラリを必要とする場合は、アプリケーションを起動するときに -d64 オプションを追加してください。この場合、dbx はアプリケーションが動作している 64 ビットの JVM ソフトウェアを使用します。


$ java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent -d64 myclass.class
$ dbx - 2345

Java アプリケーションを埋め込む C/C++ アプリケーションのデバッグ

JNI_CreateJavaVM インタフェースを使って Java アプリケーションを埋め込む C あるいは C++ アプリケーションをデバッグすることができます。この場合、C/C++ アプリケーションは、JVM ソフトウェアに次のオプションを指定することによって Java アプリケーションを起動することができます。


-Xdebug -Xnoagent -Xrundbx_agent

JVM ソフトウェアが libdbx_agent.so を見つけられるようにするには、Java アプリケーションを実行する前に正しいパスを LD_LIBRARY_PATH に追加する必要があります。

installation_directory は Oracle Solaris Studio ソフトウェアがインストールされている場所です。

JVM ソフトウェアへの引数の引き渡し

Java モードで run コマンドを使用した場合、指定した引数は、JVM ソフトウェアではなく、アプリケーションに渡されます。 JVM ソフトウェアに引数を渡す方法については、「JVM ソフトウェアの起動方法のカスタマイズ」を参照してください。

Java ソースファイルの格納場所の指定

Java ソースファイルが、.class.jar ファイルと異なるディレクトリに置かれていることがあります。その場合は、$JAVASRCPATH 環境変数を使って、dbx が Java ソースファイルを探すディレクトリを指定することができます。たとえば、JAVASRCPATH=.:/mydir/mysrc:/mydir/mylibsrc:/mydir/myutils の場合、dbx は指定されたディレクトリで、デバッグ対象のクラスファイルに対応するソースファイルを探します。

C/C++ ソースファイルの格納場所の指定

次の場合は、dbx が C/C++ ソースファイルを見つけられないことがあります。

このような場合、dbx がファイルを見つけられるよう、pathmap コマンドを使ってパス名を別のパス名に対応づけてください (pathmap コマンド」を参照)。

独自のクラスローダーを使用するクラスファイルのパスの指定

通常のクラスパスに含まれてない場所からクラスファイルを読み込む独自のクラスローダーが、アプリケーションに存在することがあります。そのような場合、dbx はクラスファイルを見つけられません。CLASSPATHX 環境変数を使って、独自のクラスローダーが読み込む Java クラスファイルのパスを指定することができます。たとえば、CLASSPATHX=.:/myloader/myclass:/mydir/mycustom の場合、dbx は指定されたディレクトリでクラスファイルを探そうとします。

Java メソッドにブレークポイントを設定する

ネイティブアプリケーションとは異なり、Java アプリケーションには容易にアクセスできる名前のインデックスがありません。そのため、次のように簡単に入力することはできません。


(dbx) stop in myMethod

代わりに、メソッドへのフルパスを使用する必要があります。


(dbx) stop in com.any.library.MyClass.myMethod

例外は、MyClass の何らかのメソッドで停止した場合で、その場合は myMethod で十分です。

フルパスをメソッドに含めることを防ぐ 1 つの方法は、stop inmethod を使用することです。


(dbx) stop inmethod myMethod

しかしそうすると、複数メソッド名 myMethod で停止してしまう場合があります。

ネイティブ (JNI) コードでブレークポイントを設定する

JNI C または C++ コードを含む共有ライブラリは JVM によって動的に読み込まれ、それらにブレークポイントを設定するには、いくつかの追加のステップが必要です。詳しくは、「動的にロードされたライブラリにブレークポイントを設定する」を参照してください。

JVM ソフトウェアの起動方法のカスタマイズ

次のことを行うために、dbx からの JVM ソフトウェアの起動方法のカスタマイズが必要になることがあります。

JVM ソフトウェアの起動方法のカスタマイズは、jvm_invocation 環境変数を使って行うことができます。jvm_invocation 環境変数が定義されていない場合、デフォルトでは dbx は次の設定で JVM ソフトウェアを起動します。


java -Xdebug -Xnoagent -Xrundbx_agent:syncpid

jvm_invocation 環境変数が定義されている場合は、その変数の値を使って JVM ソフトウェアを起動します。

jvm_invocation 環境変数の定義には、-Xdebug オプションを含める必要があります。dbx は、-Xdebug を内部オプションの -Xdebug Xnoagent -Xrundbxagent::sync に展開します。

次の例に示すように -Xdebug オプションが定義に含まれていない場合は、dbx からエラーメッセージが発行されます。


jvm_invocation="/set/java/javasoft/sparc-S2/jdk1.2/bin/java"

dbx: Value of `$jvm_invocation’ must include an option to invoke the VM in debug mode

JVM ソフトウェアのパス名の指定

デフォルトでは、JVM ソフトウェアにパス名を指定しなかった場合、dbx はパス内の JVM ソフトウェアを起動します。

JVM ソフトウェアのパス名を指定するには、次の例に示すように、jvm_invocation 環境変数に適切なパス名を設定します。


jvm_invocation="/myjava/java -Xdebug"

この設定の場合、dbx は次の設定で JVM ソフトウェアを起動します。


/myjava/java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent:sync

JVM ソフトウェアへの実行引数の引き渡し

JVM ソフトウェアに実行引数を渡すには、次の例に示すように jvm_invocation 環境変数を設定することによって、それらの引数を付けて JVM ソフトウェアを起動します。


jvm_invocation="java -Xdebug -Xms512 -Xmx1024 -Xcheck:jni"

この場合、dbx は次の設定で JVM ソフトウェアを起動します。


java -Djava.compiler=NONE -Xdebug -Xnoagent -Xrundbx_agent:sync= -Xms512 -Xmx1024 -Xcheck:jni

Java アプリケーション用の独自のラッパーの指定

Java アプリケーションは起動時に独自のラッパーを使用することができます。その場合は、次の例に示すように jvm_invocation 環境変数を使って、利用するラッパーを指定します。


jvm_invocation="/export/siva-a/forte4j/bin/forte4j.sh -J-Xdebug"

この場合、dbx は次の設定で JVM ソフトウェアを起動します。


/export/siva-a/forte4j/bin/forte4j.sh - -J-Xdebug -J-Xnoagent -J-Xrundbxagent:sync=process_id

コマンド行オプションを受け付ける独自のラッパーの利用

次のラッパースクリプト (xyz) は複数の環境変数を設定して、コマンド行オプションを受け付けます。


#!/bin/sh
CPATH=/mydir/myclass:/mydir/myjar.jar; export CPATH
JARGS="-verbose:gc -verbose:jni -DXYZ=/mydir/xyz"
ARGS=
while [ $# -gt 0 ] ; do
    case "$1" in
        -userdir) shift; if [ $# -gt 0 ]
; then userdir=$1; fi;;
        -J*) jopt=`expr $1 : ’-J<.*>’`
; JARGS="$JARGS ’$jopt’";;
        *) ARGS="$ARGS ’$1’" ;;
    esac
    shift
done
java $JARGS -cp $CPATH $ARGS

このスクリプトは、JVM ソフトウェアとユーザーアプリケーション用のコマンド行オプションを受け付けます。この形式のラッパースクリプトに対しては、次のように jvm_invocation 環境変数を設定して、dbx を起動します。


% jvm_invocation="xyz -J-Xdebug -Jany other java options"
% dbx myclass.class -Dide=visual

コマンド行オプションを受け付けない独自のラッパーの利用

次のラッパースクリプト (xyz) は複数の環境変数を設定して、JVM ソフトウェアを起動しますが、コマンド行オプションやクラス名を受け付けません。


#!/bin/sh
CLASSPATH=/mydir/myclass:/mydir/myjar.jar; export CLASSPATH
ABC=/mydir/abc; export ABC
java <options> myclass

このようなスクリプトを次のいずれかの方法で利用し、dbx を使ってラッパーをデバッグすることもできます。

64 ビット JVM ソフトウェアの指定

dbx で 64 ビットの JVM ソフトウェアを起動して、64 ビットのオブジェクトライブラリを必要とするアプリケーションをデバッグするには、jvm_invocation 環境変数の定義に -d64 オプションを含めます。


jvm_invocation="/myjava/java -Xdebug -d64"

dbx の Java コードデバッグモード

Java アプリケーションのデバッグの場合、dbx は次の 3 つのモードのいずれかで動作します。

Java または JNI (Java Native Interface) モードでは、JNI コードを含めて Java アプリケーションの状態を調べ、コードの実行を制御することができます。ネイティブモードでは、C または C++ JNI コードの状態を調べることができます。現在のモード (javajninative) は、jdbx_mode 環境変数に記憶されます。

Java モードでは、Java 構文を使用して dbx と対話します。dbx も Java 構文を使用して情報を提供します。このモードは、純粋な Java コードか、Java コードと C JNI または C++ JNI コードが混在するアプリケーション内の Java コードのデバッグに使用します。

JNI モードでは、dbx はネイティブの構文を使用して、ネイティブコードにだけ作用しますが、コマンドの出力には、ネイティブの状態ばかりでなく、Java 関係の状態も示されるため、JNI モードは「混在」モードです。このモードは、Java コードと C JNI または C++ JNI コードが混在するアプリケーションのネイティブ部分のデバッグに使用します。

ネイティブモードでは、dbx コマンドはネイティブのプログラムにだけ作用し、Java 関係の機能はすべて無効になります。このモードは Java が関係しないプログラムのデバッグに使用します。

Java アプリケーションを実行すると、dbx は状況に応じて Java モードと JNI モードを自動的に切り替えます。たとえば、Java ブレークポイントを検出すると、dbx は Java モードに切り替わり、Java コードから JNI コードに入ると、JNI モードに切り替わります。

Java または JNI モードからネイティブモードへの切り替え

dbx は、自動的にはネイティブモードに切り替わりません。Java または JNI モードからネイティブモードへは joff コマンド、ネイティブモードから Java モードへは jon コマンドを使って明示的に切り替えることができます。

実行中断時のモードの切り替え

たとえば Ctrl-C を使って Java アプリケーションの実行が中断された場合、dbx はアプリケーションを安全な状態にして、すべてのスレッドを一時停止することによって、自動的にモードを Java/JNI モードに切り替えようとします。

アプリケーションを一時停止して Java/JNI モードに切り替えることができない場合、dbx はネイティブモードに切り替わります。 この場合でも、jon コマンドを使用して、Java モードに切り替え、プログラムの状態を調べることができます。

Java モードにおける dbx コマンドの使用法

Java コードとネイティブコードが混在するアプリケーションのデバッグに使用する dbx コマンドは、次のように分類することができます。

どの分類にも属さないコマンドはすべてネイティブモードでのみ動作します。

dbx コマンドにおける Java の式の評価

大部分の dbx コマンドで使用される Java の式の評価機能は次の構造をサポートしています。

サポートされていない構造は次のとおりです。

Java アプリケーションの状態を調べるうえで特に有用なのは、IDE または dbxtool の監視機能を利用する方法です。

データを調べる以上の操作を行う式に対して正確な値解釈を依存します。

dbx コマンドが利用する静的および動的情報

通常、Java アプリケーションに関する情報の多くは、JVM ソフトウェアが起動してからのみ利用でき、終了すると利用できなくなります。ただし、Java アプリケーションのデバッグでは、dbx は、JVM ソフトウェアを起動する前にシステムクラスパスとユーザークラスパスに含まれているクラスファイルと JAR ファイルから必要な情報の一部を収集します。この情報のおかげで dbx は、アプリケーションの実行前にブレークポイントで綿密なエラー検査を行うことができます。

一部 Java クラスとその属性に、クラスパスからアクセスできないことがあります。dbx はそうしたクラスを調べて、ステップ実行することができ、式パーサーはそれらが読み込まれてからアクセスできるようになります。ただし、dbx が収集する情報は一時的な情報であり、JVM ソフトウェアが終了すると利用できなくなります。

Java アプリケーションのデバッグに dbx が必要とする情報はどこにも記録されません。このため dbx は、Java のソースファイルを読み取り、コードをデバッグしながらその情報を取得しようとします。

構文と機能が Java モードとネイティブモードで完全に同じコマンド

ここでは、構文と行う処理が Java モードとネイティブモードで完全に同じ dbx コマンドをまとめています。

コマンド  

機能  

attach

動作中のプロセスに dbx を接続します。プログラムは停止して、デバッグの制御下に置かれます。

cont

プロセスが実行を再開します。 

dbxenv

dbx 環境変数を一覧表示するか、設定します。

delete

ブレークポイントとその他のイベントを削除します。 

down

呼び出しスタックを下方向に移動します (main の逆方向)。

dump

プロシージャまたはメソッドにローカルなすべての変数を表示します。 

file

現在のファイルを表示するか、変更します。 

frame

現在のスタックフレーム番号を表示するか、変更します。 

handler

イベントハンドラ (ブレークポイント) を変更します。 

import

dbx コマンドライブラリからコマンドをインポートします。

line

現在の行番号を表示するか、変更します。 

list

現在の行番号を表示するか、変更します。 

next

ソース行を 1 行ステップ実行します (呼び出しをステップオーバー)。 

pathmap

ソースファイルなどを検索するために、パス名を別のパス名に対応づけます。 

proc

現在のプロセスの状態を表示します。 

prog

デバッグ対象のプログラムとその属性を管理します。 

quit

dbx を終了します。

rerun

引数なしでプログラムを実行します。 

runargs

ターゲットプロセスの引数を変更します。 

status

イベントハンドラ (ブレークポイント) を一覧表示します。 

step up

ステップアップして、現在の関数またはメソッドを出ます。 

stepi

機械命令を 1 つステップ実行します (呼び出しにステップイン)。 

up

呼び出し方向を上方向に移動します (main 方向)

whereami

現在のソース行を表示します。 

Java モードで構文が異なる dbx コマンド

ここでは、Java のデバッグとネイティブコードのデバッグで構文が異なる dbx コマンドをまとめています。これらのコマンドは、Java モードとネイティブモードで動作が異なります。

コマンド  

ネイティブモードでの機能  

Java モードでの機能  

assign

プログラム変数に新しい値を代入します。 

局所変数またはパラメータに新しい値を代入します。 

call

手続きを呼び出します。 

メソッドを呼び出します。 

dbx

dbx を起動します。

dbx を起動します。

debug

指定されたアプリケーションを読み込んで、アプリケーションのデバッグを開始します。 

指定された Java アプリケーションを読み込んで、クラスファイルの有無を調べ、アプリケーションのデバッグを開始します。 

detach

dbx の制御下にあるターゲットプロセスを解放します。

dbx の制御下にあるターゲットプロセスを解放します。

display

あらゆる停止点で式を評価して表示します。 

あらゆる停止点で式か局所変数、パラメータを評価して表示します。 

files

正規表現に一致するファイル名を一覧表示します。 

dbx が認識しているすべての Java ソースファイルを一覧表示します。

func

現在の関数を表示するか、変更します。 

現在のメソッドを表示するか、変更します。 

next

ソースを 1 行ステップ実行します (呼び出しをステップオーバー)。 

ソースを 1 行ステップ実行します (呼び出しをステップオーバー)。 

print

式の値を表示します。 

式か局所変数、パラメータの値を表示します。 

run

引数を付けてプログラムを実行します。 

引数を付けてプログラムを実行します。 

step

ソースを 1 行か 1 文ステップ実行します (呼び出しにステップイン)。 

ソースを 1 行か 1 文ステップ実行します (呼び出しにステップイン)。 

stop

ソースレベルのブレークポイントを設定します。 

ソースレベルのブレークポイントを設定します。 

thread

現在のスレッドを表示するか、変更します。 

現在のスレッドを表示するか、変更します。 

threads

すべてのスレッドを一覧表示します。 

すべてのスレッドを一覧表示します。 

trace

実行されたソース行か関数呼び出し、変数の変更を表示します。 

実行されたソース行か関数呼び出し、変数の変更を表示します。 

undisplay

display コマンドを取り消します。

display コマンドを取り消します。

whatis

式の型または型の宣言を表示します。 

識別子の宣言を表示します。 

when

指定されたイベントが発生したときにコマンドを実行します。 

指定されたイベントが発生したときにコマンドを実行します。 

where

呼び出しスタックを表示します。 

呼び出しスタックを表示します。 

Java モードでのみ有効なコマンド

ここでは、Java または JNI モードでのみ有効な dbx コマンドをまとめています。

コマンド  

機能  

java

dbx が JNI モードのときに、指定したコマンドの Java 版を実行するよう指示するときに使用します。

javaclasses

コマンドが入力された時点で dbx が認識しているすべての Java クラス名を表示します。

joff

Java または JNI モードからネイティブモードに dbx を切り替えます。

jon

ネイティブモードから Java モードに dbx を切り替えます。

jpkgs

コマンドが入力された時点で dbx が認識しているすべての Java パッケージ名を表示します。

native

Java モードのときに、指定したコマンドのネイティブ版を実行するよう指示するときに使用します。