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

第 2 章 dbx の起動

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

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

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

dbx 全体をターミナルウィンドウのコマンド行から使用することができます。また、dbxtool (dbx 用グラフィカルユーザーインターフェース) を実行することもできます。dbxtool の詳細については、dbxtool のマニュアルページまたは dbxtool 内のオンラインヘルプを参照してください。

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


$ dbx

または


$ dbxtool

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


$ dbx program_name

または


$ dbxtool program_name

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


$ dbx program_name{.class | .jar}

Oracle Solaris Studio ソフトウェアには、2 つの dbx バイナリが付属しています。1 つは 32 ビットプログラムのみをデバッグ可能な 32 ビット dbx、もう 1 つは 32 ビットプログラムと 64 ビットプログラムの両方をデバッグ可能な 64 ビット dbx です。dbx を起動すると、どちらのバイナリを実行すべきか自動的に判定されます。64 ビット OS では、デフォルトは 64 ビット dbx です。


注 –

Linux OS では、64 ビットの dbx で 32 ビットプログラムをデバッグできません。32 ビットプログラムを Linux OS 上でデバッグするには、32 ビット dbxdbx コマンドオプション -xexec32 を付けて起動するか、DBX_EXEC_32 環境変数を設定する必要があります。



注 –

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

または


$ dbxtool program_name core

次のように入力すると、dbxprogram_name をコアファイルから決定します。


$ dbx - core

または


$ dbxtool - 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: core file read error: address 0xff3dd1bc not available
dbx: warning: could not initialize librtld_db.so.1 -- trying libDP_rtld_db.so
dbx: cannot get thread info for 1 -- generic libthread_db.so error
dbx: attempt to fetch registers failed - stack corrupted
dbx: read of registers from (0xff363430) failed -- debugger service failed

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

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 または dbxtool コマンドに引数としてプロセス ID を指定します。


$ dbx program_name process_id

または


dbxtool program_name process_id

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


$ dbx program_name{.class | .jar} process_id

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


$ dbx - process_id

または


$ dbxtool - process_id

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

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

dbx 起動時シーケンス

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

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

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

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

プログラムが読み込みを終了すると、dbx は準備状態となり、プログラムの「メイン」ブロック (C と C++ については main()、Fortran 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 コマンド」を参照してください。

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

dbx でデバッグを行う準備として、プログラムを -g または -g0 オプションを使用してコンパイルする必要があります。

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

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

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


% CC -g example_source.cc

C++ コンパイラの場合:

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

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

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

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

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

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

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


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


    objcopy --strip-debug a.out
    
  3. 2 つのファイル間にリンクを作成します。


    objcopy --add-gnu-debuglink=a.out.debug a.out
    

    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 つのソース行に対するコードが複数の異なる場所で表示される場合があります。そのため、ソース行ごとにプログラムをステップすると、オプティマイザによってどのようにコードがスケジュールされたかに依存して、ソースファイルの周りで現在の行のジャンプが発生します。

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

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

パラメータと変数

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

パラメータと局所変数の位置に関する情報は、最適化コード内で欠落していることがあります。dbx が値を発見できない場合、発見できないことが報告されます。値は一時的に消失する場合があるため、再びシングルステップおよび出力を実行してください。

SPARC ベースシステムおよび x86 ベースシステム向けの Oracle Solaris Studio 12.2 コンパイラは、パラメータおよびローカル変数の場所を特定するための情報を提供しています。GNU コンパイラの最近のバージョンも、この情報を提供しています。

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

インライン関数

SPARC プラットフォームで dbx を使用すると、インライン関数にブレークポイントを設定できます。呼び出し側で、インライン関数からの最初の命令の停止を制御します。インライン関数で、非インライン関数と同様に dbx 操作 (stepnextlist コマンドなど) を実行できます。

where コマンドを実行すると、呼び出しスタックがインライン関数とともに表示されます。また、インラインパラメータの場所情報がある場合は、パラメータも表示されます。

呼び出しスタックを上下に移動する up および down コマンドも、インライン関数でサポートされています。

呼び出し側からのローカル変数は、インラインフレームにはありません。

レジスタがある場合は、これらは呼び出し側のウィンドウから表示されます。

コンパイラがインライン化する関数には、C++ インライン関数、C99 インラインキーワードを持つ C 関数、およびパフォーマンスにメリットがあるとコンパイラによって判断されたその他の関数が含まれます。

マニュアル『パフォーマンスアナライザ』の第 8 章にあるセクション「関数のインライン化」および「並列化」には、最適化されたプログラムをデバッグするために役立つ情報が含まれています。

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

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

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

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

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

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

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

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

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

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


(dbx) quit

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

プロセス実行の停止

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

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

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

プロセスを終了せずに 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 は、保存ファイル内にあるこれらの情報を使用します。

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

完了した実行を保存する save コマンド、および最後の 2 ステップを除く実行を保存する save -2 コマンド

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


注 –

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


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


(dbx) save

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


(dbx) save -number

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

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

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

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


(dbx) save filename

保存された実行の復元

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


注 –

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


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


注 –

セグメントを保存してから、runrerun、または debug コマンドを、restore を実行する前に発行すると、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