dbx を使用すると、イベント発生時に、プロセスの停止、任意のコマンドの発行、または情報を表示することができます。イベントのもっとも簡単な例はブレークポイントです。その他のイベントの例として、障害、シグナル、システムコール、dlopen() の呼び出し、データ変更などがあります。
トレースは、変数の値の変更など、プログラム内のイベントに関する情報を表示します。トレースの動作はブレークポイントと異なりますが、トレースとブレークポイントは類似したイベントハンドラを共有します (「イベントハンドラ」を参照)。
この章では、ブレークポイントとトレースを設定、クリア、およびリストする方法について説明します。ブレークポイントおよびトレースの設定に使用できるイベント仕 様の完全な詳細については、「イベント指定の設定」を参照してください。
この章は次の節で構成されています。
dbx では、ブレークポイントを設定するため、3 種類のコマンドを使用することができます。
stop ブレークポイント。stop コマンドによって作成されたブレークポイントに到達すると、プログラムは停止します。停止したプログラムはほかの dbx コマンドを実行するまで再開されません。
when ブレークポイント。プログラムは、when コマンドで作成されたブレークポイントに到達すると処理を停止し、1 つまたは複数のデバッグコマンドの実行後に処理を再開します。プログラムは、実行コマンドに stop が含まれていないかぎり処理を継続します。
trace ブレークポイント。プログラムは、trace コマンドで作成されたブレークポイントに到達すると処理を停止し、イベント固有のトレース情報行を出力したあと、処理を再開します。
stop、when、および trace コマンドはすべて、イベントの指定を引数として取ります。 イベントの指定は、ブレークポイントのベースとなるイベントを説明しています。イベント指定の詳細については、「イベント指定の設定」を参照してください。
マシンレベルのブレークポイントを設定するには、stopi、 wheni、および tracei コマンドを使用します (第 18 章「機械命令レベルでのデバッグ」 を参照)。
JavaTM コードと C JNI (Java Native Interface) コードまたは C++ JNI コードの混在するアプリケーションをデバッグする場合に、まだ読み込まれていないコードでブレークポイントを設定することができます。このようなコードでブレークポイントを設定する方法については、「JVM ソフトウェアによって読み込まれていないコードに対するブレークポイントの設定」を参照してください。
stop at コマンドを使用して、行番号にブレークポイントを設定します。 ここで、n はソースコードの行番号、filename は任意のプログラムファイル名修飾子です。
(dbx) stop at filename: n |
次に例を示します。
(dbx) stop at main.cc:3 : |
指定された行が、ソースコードの実行可能行ではない場合、dbx は次の有効な実行可能行にブレークポイントを設定します。実行可能な行がない場合、dbx はエラーを出します。
停止場所を確認するには、 file コマンドで現在のファイルを設定し、list コマンドで停止場所とする関数を表示させます。次に、stop at コマンドを使用してソース行にブレークポイントを設定します。
(dbx) file t.c (dbx) list main 10 main(int argc, char *argv[]) 11 { 12 char *msg = "hello world\n"; 13 printit(msg); 14 } (dbx) stop at 13 |
at an location イベントを指定する詳細については、「at [filename: ]line_number」を参照してください。
stop in コマンドを使用して、関数にブレークポイントを設定します。
(dbx) stop in function |
指定関数中で停止するブレークポイントは、プロシージャまたは関数の最初のソース行の冒頭でプログラムの実行を中断します。
dbx は、次の場合を除いては、ユーザーが参照している変数または関数を決定します。
名前のみで、オーバーロードした関数を参照する場合
先頭に ` が付く関数または変数を参照する場合
次の宣言を考えてみましょう。
int foo(double); int foo(int); int bar(); class x { int bar(); }; |
メンバーでない関数で停止する場合、次のように入力して、
stop in foo(int) |
グローバル関数 foo(int) にブレークポイントを設定します。
メンバー関数にブレークポイントを設定するには、次のコマンドを使用します。
stop in x::bar() |
次のように入力すると、
stop in foo |
dbx は、ユーザーがグローバル関数 foo(int)、グローバル関数 foo(double) のどちらを意味しているのかを判断することができず、明確にするため、オーバーロードしたメニューを表示する場合があります。
次のように入力すると、
stop in `bar |
dbx は、ユーザーがグローバル関数 bar()、メンバー関数 bar() のどちらを意味しているのかを判断することができないため、オーバーロードしたメニューを表示します。
in function イベントを指定する詳細については、「in function」を参照してください。
異なるクラスのメンバー関数の呼び出し、特定のクラスのすべてのメンバー関数の呼び出し、または多重定義されたトップレベル関数の呼び出しに関連する問題が発生する可能性があります。このような場合に対処するために、inmember、inclass、infunction または inobject のキーワードのうちの 1 つを stop、when、または trace コマンドとともに使用することにより、1 回のコマンドで C++ コードに複数のブレークポイントを挿入できます。
特定のメンバー関数のオブジェクト固有のもの (同じメンバー関数名でクラスの異なるもの) それぞれにブレークポイントを設定するには、stop inmember を使用します。
たとえば、関数 draw が複数の異なるクラスに定義されている場合は、それぞれの関数ごとにブレークポイントを設定します。
(dbx) stop inmember draw |
inmember または inmethod イベントを指定する詳細については、 「inmember function inmethod function」を参照してください。
特定のクラスのすべてのメンバー関数にブレークポイントを設定するには、stop inclass コマンドを使用します。
デフォルトでは、ブレークポイントはクラスで定義されたクラスメンバー関数だけに挿入され、ベースクラスから継承した関数には挿入されません。ベースクラスから継承した関数にもブレークポイントを挿入するには、-recurse オプションを指定します。
クラス shape で定義されたすべてのメンバー関数にブレークポイントを設定するには、次のように入力します。
(dbx) stop inclass shape |
クラス shape で定義されたすべてのメンバー関数およびクラスから継承する関数にブレークポイントを設定するには、次のように入力します。
(dbx) stop inclass shape -recurse |
inclass イベントを指定する詳細については、「inclass classname [-recurse | -norecurse]」および 「stop コマンド」を参照してください。
stop inclass およびその他のブレークポイントを選択することにより、大量のブレークポイントが挿入される場合があるため、dbx 環境変数 step_events を必ず on に設定し、step および next コマンドの実行速度を上げるようにしてください (「イベント効率」参照)。
多重定義された名前を持つ非メンバー関数 (同じ名前を持ち、引数の型または数の異なるもの) に複数のブレークポイントを設定するには、stop infunction コマンドを使用します。
たとえば、C++ プログラムで sort() という名前の関数が 2 種類定義されていて、一方が int 型の引数、もう一方が float 型の引数をとる場合に、両方の関数にブレークポイントを置くためには、次のように入力します。
(dbx) stop infunction sort [command;] |
infunction イベントを指定する詳細については、「infunction function」を参照してください。
In Object ブレークポイントを設定し、特定のオブジェクトインスタンスに適用する操作をチェックします。
デフォルトでは、In Object ブレークポイントは、オブジェクトからの呼び出し時に、オブジェクトのクラス (継承されたクラスも含む) のすべての非静的メンバー関数でプログラムを中断します。継承クラスを除くオブジェクトのクラスで定義された非静的メンバー関数だけでプログラムの実行を中断するには、-norecurse オプションを指定します。
オブジェクト foo のベースクラスで定義されたすべての非静的メンバー関数と、オブジ ェクト foo の継承クラスで定義されたすべての非静的メンバー関数にブレークポイントを設定するには、次のように入力します。
(dbx) stop inobject &foo |
オブジェクト foo の継承クラスを除く、オブジェクト foo のクラスで定義されたすべての非静的メンバー関数だけにブレークポイントを設定するには、次のように入力します。
(dbx) stop inobject &foo -norecurse |
inobject イベントの指定方法の詳細については、「inobject object-expression [-recurse | -norecurse]」および 「stop コマンド」を参照してください。
dbx でデータ変更ブレークポイントを使用すると、変数値や式がいつ変更されたかをメモしておくことができます。
特定のメモリーアドレスがアクセスされたときにプログラムを停止するには、次のように入力します。
(dbx) stop access mode address-expression [, byte-size-expression] |
mode はメモリーのアクセス方法を指定します。次の文字 (複数可) で構成されます。
指定したアドレスのメモリーが読み取られたことを示します。
メモリーへの書き込みが実行されたことを示します。
メモリーが実行されたことを示します。
さらに mode には、次のいずれかの文字も指定することができます。
アクセス後にプロセスを停止します (デフォルト)。
アクセス前にプロセスを停止します。
いずれの場合も、プログラムカウンタは副作用アクションの前後で違反している命令をポイントします。「前」と「後」は副作用を指しています。
address-expression は、その評価によりアドレスを生成できる任意の式です。シンボル式を使用すると、監視される領域のサイズが自動的に推定されます。 このサイズは、byte-size-expression を指定することにより、上書されます。シンボルを使用しない、型を持たないアドレス式を使用することもできますが、その場合はサイズを指定する必要があります。
次の例では、メモリーアドレス 0x4762 が読み取られたあとにプログラムが停止します。
(dbx) stop access r 0x4762 : |
次の例では、変数 speed に書き込みが行われる前にプログラムが停止します。
(dbx) stop access wb &speed |
stop access コマンドを使用する場合、次の点に注意してください。
変数に同じ値が書き込まれてもイベントが発生します。
デフォルトにより、変数に書き込まれた命令の実行後にイベントが発生します。命令が実行される前にイベントを発生させるには、モードを b に指定します。
access イベントを指定する詳細については、「access mode address-expression [, byte-size-expression ]」および 「stop コマンド」を参照してください。
指定した変数の値が変更された場合にプログラム実行を停止するには、次のように入力します。
(dbx) stop change variable |
stop change コマンドを使用する場合、次の点に注意してください。
dbx は、指定の変数の値に変更が発生した行の次の行でプログラムを停止します。
variable が関数に対しローカルである場合、関数が初めて呼び出されて variable の記憶領域が割り当てられた時点で、変数に変更が生じたものとみなされます。パラメータについても同じことが言えます。
このコマンドは、マルチスレッドのアプリケーションに対し機能しません。
change イベントを指定する詳細については、「change variable」および 「stop コマンド」を参照してください。
dbx は、自動シングルステップを実行し、各ステップで値をチェックすることにより、stop change を実装します。ライブラリが -g オプションでコンパイルされていない場合、ステップ実行においてライブラリの呼び出しが省略されます。そのため、制御が次のように流れていく場合、 dbx はネストされた user_routine2 をトレースしません。トレースにおいて、ライブラリの呼び出しとネストされた user_routine2 の呼び出しが省略されるからです。
user_routine calls library_routine, which calls user_routine2, which changes variable |
variable の値の変更は、user_routin2 が実行されている最中ではなく、ライブラリが呼び出しから戻ったあとに発生したように見えます。
dbx は、ブロック局所変数 ({} でネストされている変数) の変更に対しブレークポイントを設定できません。「ネスト」されたブロック局所変数でブレークポイントまたはトレースを設定しようとすると、その操作を実行できない旨を伝えるエラーメッセージが表示されます。
change イベントよりも access イベントを使用した方が、迅速にデータ変更をチェックできます。access イベントは、自動的にプログラムをシングルステップする代わりに、はるかに迅速なページ保護スキーマを使用するからです。
条件文が真と評価された場合にプログラムを停止するには、次のように入力します。
(dbx) stop cond condition |
condition が発生すると、プログラムは処理を停止します。
stop cond コマンドを使用する場合、次の点に注意してください。
dbx は、条件が真と評価された行の次の行でプログラムを停止します。
このコマンドは、マルチスレッドのアプリケーションに対し機能しません。
condition イベントを指定する詳細については、「cond condition-expression」および 「stop コマンド」を参照してください。
dbx では、ほとんどのイベント管理コマンドが event filter 修飾子をオプションでサポートします。もっとも単純なフィルタは、プログラムがブレークポイントかトレースハンドラに到達したあと、またはウォッチ条件の発生したあとに、dbx に対してある特定の条件をテストするように指示します。
このフィルタの条件が真 (非 0) と評価された場合、イベントコマンドが適用され、プログラムはブレークポイントで停止します。条件が偽 (0) と評価された場合、dbx は、イベントが発生しなかったかのようにプログラムの実行を継続します。
フィルタを含む行または関数にブレークポイントを設定するには、オプションの -if condition 修飾文を stop コマンドまたは trace コマンドの末尾に追加します。
condition には、任意の有効な式を指定できます。コマンドの入力時に有効だった言語で書かれた、ブール値または整数値を返す関数呼び出しも有効な式に含まれます。
in や at など位置に基づくブレークポイントでは、スコープはブレークポイント位置のスコープになります。それ以外の場合、イベントではなくエントリ発生時のスコープになります。スコープを正確に指定するために逆引用符演算子 (「逆引用符演算子」を参照) を使用する必要があることがあります。
たとえば、次の 2 つのフィルタは異なります。
stop in foo -if a>5 stop cond a>5 |
前者は foo にブレークポイントが設定され、条件を検査します。後者は自動的に条件を検査します。
関数呼び出しをブレークポイントフィルタとして使用できます。次の例では、文字列 str の値が abcde の場合、プログラムが関数 foo() で停止します。
(dbx) stop in foo -if !strcmp("abcde",str) |
ブレークポイントフィルタの設定に変数スコープを使用できます。この例で、現在のスコープは関数 foo() にあり、local は main() で定義された局所変数です。
(dbx) stop access w &main`local -if pr(main`local) -in main |
最初のうちは、条件付イベントコマンド (watch タイプのコマンド) の設定と、フィルタの使用とを混同してしまうかもしれません。概念的には、watch タイプのコマンドは、各行の実行前に検査される「前提条件」を作成します (watch のスコープ内で)。ただし、条件付トリガーのあるブレークポイントコマンドでも、それに接続するフィルタを持つことができます。
次に具体的な例を示します。
(dbx) stop access w &speed -if speed==fast_enough |
このコマンドは、変数 speed を監視するように dbx に指令します。speed に書き込みが行われると (watch 部分)、-if フィルタが有効になります。dbx は speed の新しい値が fast_enough と等しいかどうかチェックします。等しくない場合、プログラムは実行を継続し、 stop を「無視」します。
dbx 構文では、フィルタはブレークの「事後」、構文の最後で [-if condition] 文の形式で指定されます。
stop in function [-if condition] |
マルチスレッドプログラムでブレークポイントに関数呼び出しを含むフィルタを設定すると、dbx がブレークポイントに達するとすべてのスレッドの実行が停止し、条件が評価されます。条件が合致して関数が呼び出されると、dbx がその呼び出し中すべてのスレッドを再開します。
たとえば、次のブレークポイントを、多くのスレッドが lookup() を呼び出すマルチスレッドアプリケーションで設定する場合があります。
(dbx) stop in lookup -if strcmp(name, "troublesome") == 0 |
dbx は、スレッド t@1 が lookup() を呼び出して条件を評価すると停止し、strcmp() を呼び出してすべてのスレッドを再開します。dbx が関数呼び出し中に別のスレッドでブレークポイントに達すると、次のいずれかの警告が表示されます。
イベント無限ループにより次のハンドラ中でイベントの取りこぼしが起きます。 ... |
イベントの再入 最初のイベント BPT(VID 6m TID 6, PC echo+0x8) 2 番目のイベント BPT*VID 10, TID 10, PC echo+0x8) 以下のハンドラはイベントを処理しません: ... |
そのような場合、条件式内で呼び出された関数が mutex を取得しないことを確認できる場合は、-resumeone イベント指定修飾子を使用して、dbx がブレークポイントに達した最初のスレッドのみを再開させることができます。たとえば、次のブレークポイントを設定する場合があります。
(dbx) stop in lookup -resumeone -if strcmp(name, "troublesome") == 0 |
-resumeone 修飾子はすべての場合において問題を防ぐことはしません。たとえば、次の場合にも何も行いません。
条件が再帰的に lookup() を呼び出すことにより、最初のスレッドと同じスレッドで lookup() で 2 回目のブレークポイントに達した場合。
条件実行が別のスレッドへの制御を放棄するスレッド。
イベント修飾子の詳細については、「イベント指定のための修飾子」を参照してください。
トレースは、プログラムの処理状況に関する情報を収集して表示します。プログラムが、trace コマンドで作成されたブレークポイントに到達すると、プログラムの処理が停止され、イベント固有のトレース情報行が出力されたあと、処理が再開されます。
トレースは、ソースコードの各行を実行直前に表示します。極めて単純なプログラムを除くすべてのプログラムで、このトレースは大量の出力を生成します。
さらに便利なトレースは、フィルタを利用してプログラムのイベント情報を表示します。たとえば、関数の各呼び出し、特定の名前のすべてのメンバー関数、クラス内のすべての関数、または関数の各 exit をトレースできます。また、変数の変更もトレースできます。
コマンド行に trace コマンドを入力することにより、トレースを設定します。trace コマンドの基本構文は次のとおりです。
trace event-specification [ modifier ] |
trace コマンドの完全な構文については、「trace コマンド」を参照してください。
トレースで提供される情報は、トレースに関連する event の型に依存します (「イベント指定の設定」を参照)。
トレースの出力が速すぎる場合がよくあります。dbx 環境変数trace_speed を使用すると、各トレースの出力後の遅延を制御できます。デフォルトの遅延は 0.5 秒です。
トレース時の各行の実行間隔を秒単位で設定するには、次のように入力します。
dbxenv trace_speed number |
-file filename オプションを使用すると、トレース出力をファイルに転送できます。たとえば、次のコマンドはトレース出力をファイル trace1 に転送します。
(dbx) trace -file trace1 |
トレース出力を標準出力に戻すには、filename の代わりに - を使用します。トレース出力は常に filename に追加されます。トレース出力は、dbx がプロンプト表示するたび、またアプリケーションが終了するたびにフラッシュされます。dbx 接続後にプログラムの実行を再開するか新たに実行を開始すると、filename が常に開きます。
when ブレークポイントコマンドは list などその他の dbx コマンドを受け付けるため、ユーザーは独自のトレースを作成できます。
(dbx) when at 123 {list $lineno;} |
when コマンドは暗黙の cont コマンドとともに機能します。前述の例では、現在の行のソースコードをリストしたあと、プログラムが実行を継続します。list コマンドのあとに stop コマンドが含まれていた場合、プログラムの実行は継続されません。
when コマンドの完全な構文については、「when コマンド」を参照してください。イベント修飾子の詳細については、「イベント指定のための修飾子」を参照してください。
dbx は、実行時リンカーにおけるプログムを呼び出すインタフェースを使用しているコード (dlopen()、dlclose()、および関連関数を呼び出すコード) について完全なデバッグサポートを提供します。実行時リンカーは、プログラム実行の最中、共有ライブラリを結合および結合解除します。dlopen() / dlclose() デバッグサポートが提供されているため、ユーザーは関数内部を操作したり、 プログラムの起動時にリンクされたライブラリの場合と同様に、動的な共有ライブラリの関数にブレークポイントを設定することができます。
ただし、例外もあります。dbx は、dlopen() などで読み込まれていないロードオブジェクトにブレークポイントを配置できません。
dlopen() で読み込まれる前のライブラリにブレークポイントを設定できません。
ライブラリの最初の関数が呼び出されるまで、dlopen() で読み込まれるフィルタライブラリにブレークポイントを設定できません。
loadobject コマンドを使用すると、事前読み込みリストにそれらのロードオブジェクトの名前を配置できます (「loadobject コマンド」を参照)。
dbx は、dlopen() で読み込まれたロードオブジェクトを確実に管理します。たとえば、新たに読み込まれたロードオブジェクトに設定されたブレークポイントは、次の run コマンドが実行されるまで維持されます。これは、ロードオブジェクトが dlclose() でロード解除されたあと、再度 dlopen() で読み込まれた場合も同様です。
dbx セッション中にブレークポイントやトレースポイントを複数設定することがよくあります。dbx には、それらのポイントを表示したりクリアしたりするためのコマンドが用意されています。
すべての有効なブレークポイントのリストを表示するには、status コマンドを使用します。 ブレークポイントは ID 番号付きで表示され、この番号はほかのコマンドで使用できます。
C++ の多重ブレークポイントのところでも説明したように、dbx はキーワード inmember、inclass、infunction で設定された多重ブレークポイントを、1 つのステータス ID 番号を使用してまとめて報告します。
status コマンドを使用してブレークポイントをリスト表示した場合、dbx は、各ブレークポイントの作成時に割り当てられた ID 番号を表示します。delete コマンドを使用することで、ID 番号によってブレークポイントを削除したり、キーワード all により、プログラム内のあらゆる場所に現在設定されているブレークポイントをすべて削除することができます。
ブレークポイントを ID 番号 ID_number (この場合 3 と 5) によって削除するには、次のように入力します。
(dbx) delete 3 5 |
dbx に現在読み込まれているプログラムに設定されているすべてのブレークポイントを削除するには、次のように入力します。
(dbx) delete all |
詳細については、「delete コマンド」を参照してください。
ブレークポイントの設定に使用するイベント管理コマンド (stop、trace、 when) は、イベントハンドラを作成します (「イベントハンドラ」を参照)。これらの各コマンドは、ハンドラ ID (hid) として認識される番号を返します。ハンドラ ID は、ブレークポイントを有効または無効にする handler コマンド (「handler コマンド」を参照) の引数として利用できます。
デバッグ中のプログラムの実行時間に関するオーバーヘッドの量はイベントの種類によって異なります。もっとも単純なブレークポイントのように、実際はオーバーヘッドが何もないイベントもあります。1 つのブレークポイントしかないイベントも、オーバーヘッドは最小です。
実際のブレークポイントがときには何百にもなることのある多重ブレークポイント (inclass など) は、コマンド発行時にのみオーバーヘッドがあります。これは、dbx が永続的ブレークポイントを使用するためです。 永続的ブレークポイントは、プロセスに常に保持され、停止するたびに取り除かれたり、cont コマンドのたびに置かれたりすることはありません。
step コマンドおよび next コマンドの場合、デフォルトでは、プロセスが再開される前にすべてのブレークポイントが取り除かれ、ステップが完了するとそれらは再び挿入されます。したがって、多くのブレークポイントを使用したり、多くのクラスで多重ブレークポイントを使用したりしているとき、step コマンドおよび next コマンドの速度は大幅に低下します。dbxenv 変数 step_events を使用して、 step や next のたびにブレークポイントを取り除いたり、挿入し直したりするかどうかを制御することができます。
自動ステップ実行を利用するイベントはもっとも低速です。これは、各ソース行をステップ実行する単純な trace step コマンドの場合と同様にはっきりしています。一方、stop change expression や trace cond variable のようなイベントは、自動的にステップ実行するだけでなく、各ステップで式や変数を評価する必要があります。
これらのイベントは非常に低速ですが、イベントと修飾語 -in を使用した関数とを結び付けることで、効率が上がることがよくあります。たとえば、次のようにします。
trace next -in mumble stop change clobbered_variable -in lookup |
trace -in main を使用しないでください。これは main によって呼び出された関数の中でも、トレースが有効になるためです。関数 lookup() が変数の値を頻繁に変更すると思われる場合には、この方法を使用してください。