Sun Studio 12: dbx コマンドによるデバッグ

第 2 章 dbx の起動

この章では、 dbx デバッグセッションを開始、実行、保存、復元、および終了する方法について説明します。この章の内容は次のとおりです。

デバッグセッションを開始する

dbx の起動方法は、デバッグの対象、現在の作業ディレクトリ、dbx で必要な実行内容、dbx の習熟度、および dbx 環境変数を設定したかどうかによって異なります。

dbx セッションを開始するもっとも簡単な方法は、dbx コマンドをシェルプロンプトで入力する方法です。


$ dbx

シェルから dbx を起動し、デバッグするプログラムを読み込むには、次のように入力します。


$ dbx program_name

dbx を起動して、Java コードおよび C JNI コードまたは C++ JNI コードが混在する プログラムを読み込むには、次のように入力します。


$ dbx program_name{.class | .jar}

Sun Studio ソフトウェアには、32 ビットプログラムのみをデバッグ可能な 32 ビット dbx、および 32 ビットプログラムと 64 ビットプログラムの両方をデバッグ可能な 64 ビット dbx の、2 つの dbx バイナリが付属しています。dbx を起動すると、どちらのバイナリを実行すべきか自動的に判定されます。64 ビット OS では、デフォルトは 64 ビット dbx です。64 ビット OS で 32 ビット dbx を起動するには、dbx コマンドを -x exec32 オプション付きで使用するか (「オプション」 参照)、環境変数 _DBX_EXEC_32 を設定します。


注 –

Linux OS では、64 ビットの dbx で 32 ビットプログラムをデバッグできません。Linux OS で 32 ビットプログラムをデバッグするには、32 ビットの dbx を起動します。



注 –

64 ビット Linux OS で 32 ビット dbx を使用する場合は、debug コマンドを使用しないでください。デバッグによって 64 ビットプログラムが実行される場合は、環境変数 follow_fork_mode を子に設定します。64 ビットプログラムをデバッグするには、dbx を終了してから 64 ビット dbx を起動します。


dbx コマンドおよび起動オプションについての詳細は、dbx コマンド」 および dbx(1) のマニュアルページを参照してください。

既存のコアファイルのデバッグ

コアダンプしたプログラムが共有ライブラリと動的にリンクしている場合、それが作成された同じオペレーティング環境でコアファイルをデバッグすることが重要です。dbx では、一致しないコアファイル (たとえば、バージョンまたはパッチレベルの異なる Solaris オペレーティングシステムで生成されたコアファイル) のデバッグに対しサポートが制限されます。


注 –

ネイティブコードのときと異なり、コアファイルから Java アプリケーションの状態情報を入手することはできません。


同じオペレーティング環境でのコアファイルのデバッグ

コアファイルをデバッグするには、次のように入力します。


$ dbx program_name core

dbx がすでに起動していれば、debug コマンドを使用してコアファイルをデバッグすることもできます。


(dbx) debug -c core program_name

プログラム名として - を指定すると、dbx はコアファイルからプログラム名を抽出します。実行可能ファイルのフルパス名をコアファイルから抽出できない場合は、実行可能ファイルを特定できないことがあります。この場合は、dbx でコアファイルを読み込むときに、バイナリの完全なパス名を指定します。

コアファイルが現在のディレクトリに存在しない場合、パス名を指定できます (/tmp/core など)。

プログラムがコアをダンプしたときにどこで実行されていたかを確認するには、where コマンド (where コマンド」を参照) を使用してください。

コアファイルをデバッグする場合、変数と式を評価して、プログラムがクラッシュした時点での値を確認することもできますが、関数呼び出しを行なった式を評価することはできません。ステップ実行したりブレークポイントを設定することはできません。

コアファイルが切り捨てられている場合

コアファイルの読み込みに問題がある場合は、コアファイルが切り捨てられているかどうかを確認してください。コアファイルの生成時に、コアファイルの最大サイズの設定が小さすぎる場合は、コアファイルが切り捨てられ、dbx で読み込めないことがあります。C シェルでは、limit コマンドを使用して、コアファイルの最大サイズを設定することができます (limit(1) マニュアルページを参照)。Bourne シェルおよび Korn シェルでは、ulimit コマンドを使用します (limit(1) マニュアルページを参照)。シェルの起動ファイルでコアファイルのサイズの上限を変更してその設定を有効にし、コアファイルを生成したプログラムを再実行すれば、完全なコアファイルが生成されます。

コアファイルが不完全で、スタックセグメントが欠落している場合、スタックのトレース情報は利用できません。実行時リンカー情報が欠落している場合、ロードオブジェクトのリストは利用できません。この場合は、librtld_db.so が初期化されていないというエラーメッセージが表示されます。LWP のリストが欠落している場合、スレッド情報、lwp 情報、またはスタックトレース情報は利用できません。where コマンドを実行すると、プログラムがアクティブでないというエラーメッセージが表示されます。

一致しないコアファイルのデバッグ

特定のシステム (コアホスト) で作成されたコアファイルを、デバッグのためにそのファイルを別のマシン (dbx ホスト) に読み込む場合があります。この場合、ライブラリに関する 2 つの問題が発生する可能性があります。

ユーザーライブラリとシステムライブラリは、パッチや主要な Solaris オペレーティング環境のアップグレードで変更できるため、収集したコアファイルで dbx を実行する前にパッチをインストールした場合など、この問題が同一ホストでも発生する可能性があります。

dbx は、一致しないコアファイルを読み込むと、次のエラーメッセージを 1 つ以上表示することがあります。


dbx: コアファイル読み取りエラー: アドレス 0xff3dd1bc は利用できません
dbx: 警告: librtld_db.so.1 を初期化できませんでした -- trying libDP_rtld_db.so
dbx: 1 のスレッド情報を取得できません -- 一般的な libthread_db.so エラー
dbx: レジスタをフェッチしようとして失敗しました - スタックが破壊されました
dbx: (0xff363430) からのレジスタの読み取りに失敗しました -- デバッガは失敗しました

共有ライブラリ問題の回避

Procedureライブラリ問題を回避し、一致しないコアファイルを dbx でデバッグするには、次の手順を実行します。

  1. dbx 環境変数 core_lo_pathmapon に設定します。

  2. pathmap コマンドを使用して、コアファイルの正しいライブラリの配置場所を dbx に伝えます。

  3. debug コマンドを使用して、プログラムとコアファイルを読み込みます。

    たとえば、コアホストのルートパーティションが NFS を介してエクスポートされており、dbx ホストマシンの /net/core-host/ からアクセスできると仮定した場合、次のコマンドを使用して、プログラム prog とコアファイル prog.core をデバッグのために読み込みます。


    (dbx) dbxenv core_lo_pathmap on
    (dbx) pathmap /usr /net/core-host/usr
    (dbx) pathmap /appstuff /net/core-host/appstuff
    (dbx) debug prog prog.core
    

    コアホストのルートパーティションをエクスポートしていない場合、手動でライブラリをコピーする必要があります。シンボリックリンクを再作成する必要はありません (たとえば、libc.so から libc.so.1 へのリンクを作成する必要はありません。libc.so.1 が利用可能であることだけを確認してください)。

注意点

一致しないコアファイルをデバッグする際に、次の点に注意してください。

プロセス ID の使用

動作中のプロセスを dbx に接続できます。dbx コマンドに引数としてプロセス ID を指定します。


$ dbx program_name process_id

JavaTM コードと C JNI (Java Native Interface) コードまたは C++ JNI コードの混在する動作中のプロセスに dbx を接続するには、次のように入力します。


$ dbx program_name{.class | .jar} process_id

プログラムの名前を知らなくても、その ID を使用してプロセスに接続できます。


$ dbx - process_id

この場合、dbx はプログラムの名前を認識できないため、run コマンドの中でそのプロセスに引数を渡すことはできません。

詳細については、「動作中のプロセスに dbx を接続する」を参照してください。

dbx 起動時シーケンス

dbx を起動するときに、-S オプションを指定していない場合は、 dbx installation_directory/lib ディレクトリでインストール時の起動ファイル .dbxrc を検索します (デフォルトの installation_directory は、Solaris プラットフォームでは /opt/SUNWspro、Linux プラットフォームでは /opt/sun/sunstudio10u1 です)。Sun Studio ソフトウェアがデフォルトのディレクトリ installation_directory にインストールされていない場合、.dbxrc ファイルへのパスは、dbx 実行可能ファイルへのパスから取得します。

dbx は、.dbxrc ファイルを現在のディレクトリ、$HOME の順で検索します。-s を使用して、別の起動ファイルを明示的に指定することもできます。詳細については、dbx 初期化ファイルの使用」を参照してください。

起動ファイルには、任意の dbx コマンドが含まれることがあり、一般に alias コマンド、dbxenv コマンド、 pathmap コマンド、および Korn シェル関数定義が含まれます。ただし、特定のコマンドは、プログラムが読み込まれていること、またはプロセスが接続されていることを要求します。すべての起動ファイルは、プログラムまたはプロセスが読み込まれる前に読み込まれます。さらに起動ファイルは、source または . (ピリオド) コマンドを使用することにより、その他のファイルのソースとなることもできます。起動ファイルを使用して、ほかの dbx オプションを設定することもできます。

dbx がプログラム情報を読み込むと、 Filename の読み込み中などの一連のメッセージを出力します。

プログラムが読み込みを終了すると、dbx は準備状態となり、プログラム (C、C++ については、main()、Fortan 95 については、MAIN()) のメインブロックを表示します。一般に、ブレークポイントを設定し (例: stop in main)、C プログラムに対し run コマンドを実行します。

起動属性の設定

pathmap コマンド、dbxenv コマンド、および alias コマンドを使用して、dbx セッションに対する起動プロパティーを設定できます。

デバッグ時ディレクトリへのコンパイル時ディレクトリのマッピング

デフォルトでは、dbx はプログラムがコンパイルされたディレクトリに、デバッグ中のプログラムに関連するソースファイルがないかを探します。ソースファイルまたはオブジェクトファイルがそのディレクトリにないか、または使用中のマシンが同じパス名を使用していない場合は、dbx にその場所を知らせる必要があります。

ソースファイルまたはオブジェクトファイルを移動した場合、その新しい位置を検索パスに追加できます。pathmap コマンドは、ファイルシステムの現在のディレクトリと実行可能イメージ内の名前とのマッピングを作成します。このマッピングは、ソースパスとオブジェクトファイルパスに適用されます。

一般的なパスマップは、各自の .dbxrc ファイルに追加する必要があります。

ディレクトリ from から ディレクトリ to への新しいマッピングを確立するには、次のように入力します。


(dbx) pathmap [ -c ] from to

-c を使用すると、このマッピングは、現在の作業ディレクトリにも適用されます。

pathmap コマンドは、ホストによってベースパスの異なる、自動マウントされた明示的な NFS マウントファイルシステムを扱う場合にも役立ちます。-c は、現在の作業ディレクトリが自動マウントされたファイルシステム上で不正確なオートマウンタが原因で起こる問題を解決する場合に使用してください。

/tmp_mnt/ のマッピングはデフォルトで存在します。

詳細については、pathmap コマンド」を参照してください。

dbx 環境変数の設定

dbxenv コマンドを使用すると、dbx カスタマイズ変数を表示または設定できます。dbxenv コマンドは、各自の .dbxrc ファイルに入れることができます。変数を表示するには、次のように入力します。


$ dbxenv

dbx 環境変数は設定することもできます。.dbxrc ファイルおよびこれら変数の設定方法について詳しくは、replay を使用した保存と復元」を参照してください。

詳細については、dbx 環境変数の設定」および dbxenv コマンド」を参照してください。

ユーザー自身の dbx コマンドを作成

kalias または dalias コマンドを使用して、ユーザー自身の dbx コマンドを作成することができます。詳細については、dalias コマンド」を参照してください。

デバッグのためのプログラムのコンパイル

プログラムは -g または -g0 オプションでコンパイルし、dbx でデバッグする準備をします。

-g オプションでコンパイル

-g オプションは、コンパイル時にデバッグ情報を生成するよう、コンパイラに指示します。

たとえば、C++ を使用してコンパイルするには、次のように入力します。


% CC -g example_source.cc

C++ では、-g オプションは、デバッグをオンにし、関数のインライン化をオフにします。- g0 (ゼロ) オプションは、デバッグをオンにし、関数のインライン化には影響を与えません。-g0 オプションでインライン関数をデバッグすることはできません。-g0 オプションは、リンクタイムおよび dbx の起動時間を大幅に削減します (プログラムによるインライン関数の使用に依存)。

dbx で使用するため、最適化コードをコンパイルするには、-O (大文字 O) と -g オプションの両方でソースコードをコンパイルします。

別のデバッグファイルの使用

dbx により、 実行可能ファイルから別のデバッグファイルにデバッグ情報をコピーし、実行可能ファイルからその情報をストリップし、これらの 2 ファイル間にリンクを作成するために、Linux プラットフォームでは objcopy コマンド、Solaris プラットフォームでは gobjcopy コマンドのオプションを使用できます。

dbx は、次の順序で別のデバッグファイルを検索し、最初に見つかったファイルからデバッグ情報を読み取ります。

たとえば、実行可能ファイル a.out に対して別のデバッグファイルを作成するには、次のことを行います。

Procedure別のデバッグファイルの作成

  1. デバッグ情報を含む、a.out.debug という名前の別のデバッグファイルを作成します。

  2. a.out からデバッグ情報をストリップします。

  3. 2 つのファイル間にリンクを作成します。Solaris プラットフォームの場合、gobjcopy コマンドを使用します。Linux プラットフォームの場合、objcopy コマンドを使用します。

    Linux プラットフォームでは、objcopy コマンドの -help オプションを使用して、プラットフォームで -add-gnu-debuglink オプションがサポートされているかどうかを調べることができます。 objcopy コマンドの -only-keep-debug オプションは、a.out.debug を完全な実行可能ファイルにすることができる cp a.out a.out.debug コマンドに置き換えることができます。

最適化コードのデバッグ

dbx は、最適化コードのデバッグを部分的にサポートしています。サポートの範囲は、プログラムのコンパイル方法によって大幅に異なります。

最適化コードを分析する場合、次のことができます。

最適化によりプログラムがコンパイルされ、同時に (-O -g オプションを使用して) デバッグが有効になると、dbx は制限されたモードで操作します。

どのような環境下でどのコンパイラがどの種類のシンボリック情報を発行したかについての詳細は、不安定なインタフェースとみなされ、リリース移行時に変更される可能性があります。

ソース行についての情報が提供されます。 ただし最適化プログラムについては、1 つのソース行に対するコードが複数の異なる場所で表示される場合があります。 そのため、ソース行ごとにプログラムをステップすると、オプティマイザによってどのようにコードがスケジュールされたかに依存して、ソースファイルの周りで現在の行のジャンプが発生します。

末尾呼び出しを最適化すると、関数の最後の有効な操作が別の関数への呼び出しである場合、スタックフレームがなくなります。

通常、パラメータ、局所変数、および大域変数のシンボリック情報は、最適化プログラムで利用できます。構造体、共用体、および C++ クラスの型情報と局所変数、大域変数、およびパラメータの型と名前を利用できるはずです。C++ コンパイラは、局所変数のシンボリック型情報を提供しません。 ただし、C コンパイラは、それらの情報を提供します。

パラメータと局所変数の位置に関する情報は、最適化コード内で欠落していることがよくあります。コンパイラが DWRF 位置リストを生成する場合、dbx はこの情報を使用して局所変数とパラメータの値を出力します。最適化関数の最初の命令で停止する場合、パラメータの値は ABI 適合レジスタまたはスタックの位置に格納されるため、dbx はその値を出力できます。局所変数の値を調べるには、dbx の環境変数 optim_local_vars の設定が必要な場合もあります。

デバッグ情報内の単純位置は、1 つのレジスタまたはスタックの位置を示しています。位置リストは、コード内の異なるところにある変数の別の位置を記述しており、最適化コードを記述するのにより適しています。

Sun Studio 12 以降のリリースの Sun Studio コンパイラは、位置リストを生成しませんが、一部の最適化コード用に単純位置を生成します。新しいバージョンの GNU コンパイラは、フレームポインタおよび一部のパラメータや局所変数を記述するのに位置リストを使用します。コンパイラがこの情報を記録する方法は、リリースによって異なる可能性があります。

最後のレジスタからメモリーへのストアがまだ発生していない場合、値は正確でない可能性がありますが、大域変数は表示したり、値を割り当てたりできます。

Sun Studio 11 パフォーマンスアナライザのマニュアルの 8 章には、最適化プログラムのデバッグ時に役立つ、コンパイラの最適化に関する情報が含まれています。

OpenMP プログラムの場合、-xopenmp=noopt オプションを使用してコンパイルすると、コンパイラは最適化を適用しないように指示されます。ただし、オプティマイザは OpenMp 指令を実装するために引き続きコードを処理するので、記述された問題のいくつかは、-xopenmp=noopt を使用してコンパイルされたプログラムで発生する可能性があります。

-g オプションを使用しないでコンパイルされたコード

ほとんどのデバッグサポートでは、-g を使用してプログラムをコンパイルすることを要求していますが、dbx では、-g を使用しないでコンパイルされたコードに対し、次のレベルのサポートを提供しています。

ただし、dbx では、-g オプションでコンパイルされたコードを除いては、ソースコードを表示できません。これは、strip -x が適用されたコードについてもあてはまります。

dbx を完全にサポートするために -g オプションを必要とする共有ライブラリ

完全なサポートを提供するためには、共有ライブラリも -g オプションを使用してコンパイルする必要があります。-g オプションを使用してコンパイルされていない共有ライブラリモジュールを使用してプログラムを作成した場合でも、そのプログラムをデバッグすることはできます。ただし、これらのライブラリモジュールに関する情報が生成されていないため、dbx の機能を完全に使用することはできません。

完全にストリップされたプログラム

dbx は、完全にストリップされた (制御データなどが取り除かれた) プログラムをデバッグすることができます。これらのプログラムには、プログラムをデバッグするために使用できる情報がいくつか含まれますが、外部から識別できる関数しか使用できません。一部の実行時検査は、ストリップされたプログラムまたはロードオブジェクトに対して動作します。メモリー使用状況検査およびアクセス検査は、strip -x でストリップされたコードに対して動作します。ただし、strip でストリップされたコードに対しては動作しません。

デバッグセッションを終了する

dbx の起動から終了までが 1 つの dbx セッションになります。1 つの dbx セッション中に、任意の数のプログラムを連続してデバッグできます。

dbx セッションを終了するには、dbx プロンプトで quit と入力します。


(dbx) quit

起動時にプロセス ID オプションを使用してデバッガを動作中のプロセスに接続した場合、デバッグセッションを終了しても、そのプロセスは終了しないで動作を続けます。すなわち、dbx はセッションを終了する前に自動的に detach コマンドを実行します。

プロセス実行の停止

Ctrl + C を使用すると、dbx を終了しないでいつでもプロセスの実行を停止できます。

dbx からのプロセスの切り離し

dbx をあるプロセスに接続した場合、detach コマンドを使用すると、そのプロセスおよび dbx セッションを終了せずに、そのプロセスを dbx から切り離すことができます。

プロセスを終了せずに dbx から切り離すには、次のように入力します。


(dbx) detach

dbx が占有アクセスしているときにブロックされるほかの /proc ベースのデバッグツールを一時的に適用している間に、プロセスを切り離して停止状態にすることができます。詳細については、「プロセスから dbx を切り離す」を参照してください。

detach コマンドの詳細については、detach コマンド」を参照してください。

セッションを終了せずにプログラムを終了する

dbxkill コマンドは、プロセスを終了するとともに、現在のプロセスのデバッグも終了します。ただし、kill コマンドは、dbx セッション自体を維持したまま、dbx で別のプログラムをデバッグできる状態にします。

プログラムを終了すると、dbx を終了しないで、デバッグ中のプログラムの残りを除去することができます。

dbx で実行中のプログラムを終了するには、次のように入力します。


(dbx) kill

詳細については、kill コマンド」を参照してください。

デバッグ実行の保存と復元

dbx には、コマンドデバッグ実行の全部または一部を保存して、それをあとで再現するためのコマンドが 3 つあります。

save コマンドの使用

save コマンドは、直前に実行された run コマンド、rerun コマンド、または debug コマンドから save コマンドまでに発行されたデバッグコマンドをすべてファイルに保存します。このデバッグセッションのセグメントは、「デバッグ実行」と呼ばれます。

save コマンドは、発行されたデバッグコマンドのリスト以外のものも保存します。実行開始時のプログラムの状態に関するデバッグ情報、つまり、ブレークポイント、表示リストなども保存されます。保存された実行を復元するとき、dbx は、保存ファイル内にあるこれらの情報を使用します。

デバッグ実行の一部、つまり、入力されたコマンドのうち指定する数だけ最後から除いたものを保存することもできます。

 

debug

 

debug

 

stop at line

 

stop at line

 

run

 

run

 

next

 

next

 

next

 

next

すべての実行を保存 

stop at line

実行の保存から 

stop at line

 

continue

最後の 2 ステップを除く 

continue

 

next

 

next

 

next

 

next

 

step

 

step

 

next

 

next

 

save

 

save-2

       

保存する実行の終了位置がわからない場合は、history コマンドを使用して、セッション開始以降に発行されたデバッグコマンドのリストを確認してください。


注 –

デフォルトで、save コマンドは特別な保存ファイルへ情報を書き込みます。デバッグ実行後に復元可能なファイルへ保存する場合は、save コマンドでファイル名を指定することができます。「一連のデバッグ実行をチェックポイントとして保存する」 を参照してください。


save コマンドまでのデバッグ実行のすべてを保存するには、次のように入力します。


(dbx) save

デバッグ実行の一部を保存するには、save number コマンドを使用します。 number は、save コマンドの直前の、保存しないコマンドの数を示します。


(dbx) save -number

一連のデバッグ実行をチェックポイントとして保存する

ファイル名を指定しないでデバッグ実行を保存すると、情報は特殊な保存ファイルに書き込まれます。保存のたびに、dbx はこの保存ファイルを上書きします。しかし、ファイル名引数を save コマンドに指定すると、あるデバッグ実行をこのファイル名に保存後、別のデバッグ実行を保存しても、前の内容を復元することができます。

一連の実行を保存すると、1 組のチェックポイントが与えられます。各チェックポイントは、セッションのさらにあとから始まります。保存されたこれらの実行は任意に復元して続行し、さらに、以前の実行で保存されたプログラム位置と状態に dbx をリセットすることができます。

デバッグ実行を、デフォルトの保存ファイル以外のファイルに保存するには、次のように入力します。


(dbx) save filename

保存された実行の復元

実行を保存したら、restore コマンドを使用して実行を復元できます。dbx は、保存ファイル内の情報を使用します。実行を復元すると、 dbx は、まず内部状態をその実行の開始時の状態にリセットしてから、保存された実行内の各デバッグコマンドを再発行します。


注 –

source コマンドは、ファイル内に保存された一連のコマンドを再発行しますが、 dbx の状態をリセットはしません。 これは、現在のプログラム位置からコマンドの一覧を再発行するだけです。


保存された実行の正確な復元に必要な条件

保存されたデバッグ実行を正確に復元するには、run タイプコマンドへの引数、手動入力、およびファイル入力などの、実行での入力すべてが正確に同じである必要があります。


注 –

セグメントを保存してから、restore を実行する前に runrerun、または debug コマンドを発行すると、restore は 2 番目の引数を使用して、runrerun、または debug コマンドをあとで保存します。これらの引数が異なる場合、正確な復元が得られない可能性があります。


保存されたデバッグ実行を復元するには、次のように入力します。


(dbx) restore

デバッグ実行を、デフォルトの保存ファイル以外のファイルに保存するには、次のように入力します。


(dbx) restore filename

replay を使用した保存と復元

replay コマンドは組み合せのコマンドで、save -1 に続けて restore を発行するのと同じです。replay コマンドは負の number 引数をとります。これは、コマンドの save 部分に渡されるものです。デフォルトで、-number の値は -1 になるため、replay は取り消しコマンドとして働き、直前に発行されたコマンドまで (ただしこのコマンドは除く) の前回の実行を復元します。

現在のデバッグ実行から、最後に発行されたデバッグコマンドを除くものを再現するには、次のように入力します。


(dbx) replay

現在のデバッグ実行を再現して、指定のコマンドの前で実行を停止するには、dbxreplay コマンドを使用します。 ここで、number は、最後のデバッグコマンドから数えていくつめのコマンドで停止するかその数を示します。


(dbx) replay -number