dbx コマンドによるデバッグ

第 5 章 ブレークポイントとトレースの設定

この章では、ブレークポイントとトレースの設定方法とウォッチポイントの使用方法について説明します。

この章は、次の各節から構成されています。

概要

stop, when, trace コマンドを総称してイベント管理コマンドと呼びます。イベント管理は、デバッグ中のプログラムで特定のイベントが発生したときに特定のアクションを行う dbx の一般的な機能です。

ブレークポイントを設定する

ブレークポイントで動作するコマンドには次の 3 種類があります。

stop ブレークポイント

stop コマンドによって作成されたブレークポイントに到達すると、プログラムは停止します。停止したプログラムはほかの dbx コマンドを実行するまで再開されません。

when ブレークポイント

プログラムは停止し、dbx が 1 つまたは複数の dbx コマンドを実行した後、プログラムは再開します。プログラムは、コマンドの中に stop が含まれていない限り処理を続けます。

trace ブレークポイント

プログラムは停止し、イベント固有のトレース情報行を出力した後、プログラムは再開します。 

ソースコードの特定の行に stop ブレークポイントを設定する

dbxstop at コマンドを使用して、行番号にブレークポイントを設定できます。


(dbx) stop at filename: n

ここで、n はソースコードの行番号、filename はそのコードが含まれているソースファイルの名前 (省略可能) です。たとえば、次のようにします。


(dbx) stop at main.cc:3

stop または when コマンドに指定された行が、ソースコードの実行可能行ではない場合、dbx は次の有効な実行可能行にブレークポイントを設定します。

特定の行に when タイプのブレークポイントを設定する

when タイプのブレークポイントは、ほかの dbx コマンドを副作用コマンドとして利用できます。たとえば、whenlist コマンドを副作用コマンドとして用いれば、独自のトレースを実現することができます。


(dbx) when at 123 { list $lineno;}

whencont コマンドを暗黙指定して動作します。上の例の場合、現在行のコードを出力した後、プログラムの実行が続けられます。

動的にリンクされたライブラリにブレークポイントを設定する

実行時リンカーとの間でプログラムインタフェースを使用するコード、すなわち dlopen()dlclose()、およびそれらに関連する関数を呼び出すコードをデバッグするときは、dbx の全機能を利用できます。実行時リンカーは、プログラムの実行中に共有ライブラリをリンクしたり、そのリンクを解除したりします。dlopen()dlclose() のサポートにより、動的にリンクされている共有ライブラリの関数もプログラムの起動時にリンクされたライブラリの関数と同様に、ステップ実行したり、ブレークポイントを設定したりできます。

例外が 3 つあります。

C++ プログラムに複数のブレークポイントを設定する

異なるクラスのメンバー関数の呼び出し、特定のクラスのすべてのメンバー関数の呼び出し、または多重定義されたトップレベル関数の呼び出しに関連する問題が発生する可能性があります。このような場合に対処するために、inmemberinclassinfunction または inobject のキーワードのうちの 1 つを stop, when,または trace コマンドとともに使用することにより、1 回のコマンドで C++ コードに複数のブレークポイントを挿入できます。

異なるクラスのメンバー関数にブレークポイントを設定する

特定のメンバー関数のオブジェクト固有のもの (同じメンバー関数名でクラスの異なるもの) それぞれにブレークポイントを設定するには、stop inmember を使用します。

when ブレークポイントを設定するには、when コマンドをキーワード inmember とともに使用します。

たとえば、関数 draw が複数の異なるクラスに定義されている場合は、それぞれの関数ごとにブレークポイントを設定します。


(dbx) stop inmember draw

同じクラスのメンバー関数にブレークポイントを設定する

特定のクラスのすべてのメンバー関数にブレークポイントを設定するには、stop inclass コマンドを使用します。

when タイプのブレークポイントを設定する場合は、when コマンドをキーワード inclass とともに使用します。

クラス wedge のすべてのメンバー関数にブレークポイントを設定するには、次のように入力します。


(dbx) stop inclass wedge

ブレークポイントは、該当するクラスで定義されているクラスメンバー関数にだけ挿入されます。基底クラスから継承された関数には挿入されません。

stop inclass やほかのブレークポイントの選択によって挿入される多数のブレークポイントがあるため、必ず dbxenv step_eventson に設定して、stepnext の速度を上げる必要があります。

非メンバー関数に複数のブレークポイントを設定する

多重定義された名前を持つ非メンバー関数 (同じ名前を持ち、引数の型または数の異なるもの) に複数のブレークポイントを設定するには、stop infunction コマンドを使用します。

when タイプのブレークポイントを設定する場合は、when コマンドをキーワード infunction とともに使用します。

たとえば、C++ プログラムで sort() という名前の関数が 2 種類定義されていて、一方が int 型の引数、もう一方が float 型の引数をとる場合に、両方の関数にブレークポイントを置くためには、次のように入力します。


(dbx) when infunction sort {cmd;}

オブジェクトにブレークポイントを設定する

In Object ブレークポイントを設定して、特定オブジェクトに適用される演算を確認します。In Object ブレークポイントは、オブジェクトから呼び出されると、そのオブジェクトクラスのすべての非静的メンバー関数によるプログラムの実行を中断します。

オブジェクトにブレークポイントを設定するには、stop inobject コマンドを使用します。


(dbx) stop inobject foo

コードをトレースする

トレースにより、実行しようとしている行や呼び出そうとしている関数についての情報が表示されます。

トレースを設定する

コマンド行に trace コマンドを入力し、トレースを設定します。Failed Cross Reference Format は、設定できるトレースの各タイプのコマンド構文を示しています。トレースにより表示される情報は、そのトレースに対応づけられたイベントのタイプによって異なります。

表 5-1 trace コマンドの構文

コマンド 

出力される内容 

trace step

プログラムのすべての行をそれが実行されるときに表示する。 

trace next -in function

関数 function に制御が移っている間、各行で表示する。

trace at line_number

line_number で指定された行を次に実行する場合に、その行の行番号と内容。

trace in function

関数 function を呼び出した関数の名前、行番号、渡されたパラメータ、戻り値。

trace inmember member_function

すべてのクラスの member_function を呼び出した関数の名前、その行番号、渡されたパラメータ、その戻り値。

trace inclass class

クラス class 内のすべてのメンバー関数を呼び出した関数の名前、その行番号、渡されたパラメータ、その戻り値。

trace infunction function

C++ プログラム内の非メンバー関数 function を呼び出した関数の名前、その行番号、渡されたパラメータ、その戻り値。

trace change variable [-in function]

指定された関数 function 内の変数 variable の値が変更されたとき、その新しい値とその変数が変更された行。

トレース速度を制御する

多くのプログラムは高速に実行されるため、表示がよく見えません。環境変数 dbxenv trace_speed を使用して、トレーススコープ内の各行の実行間隔を制御することができます。デフォルトの実行間隔は 0.5 秒です。

トレース時の各行の実行間隔を設定するには、次のように入力します。


dbxenv trace_speed number

イベントハンドラのリストの表示とクリア

dbx セッション中にブレークポイントやトレースポイントを複数設定することがよくあります。dbx には、それらのポイントを表示したりクリアしたりするためのコマンドが用意されています。

ブレークポイントとトレースポイントの表示

すべての有効なブレークポイントのリストを表示するには、status コマンドを使用します。ブレークポイントは ID 番号付きで表示され、この番号はほかのコマンドで使用できます。

C++ の多重ブレークポイントのところでも説明したように、dbx はキーワード inmember、inclass、infunction で設定された多重ブレークポイントを、1 つのステータス ID 番号を使用してまとめて報告します。

ステータス ID 番号を使用して特定のブレークポイントを削除

status コマンドを使用してブレークポイントをリスト表示した場合、dbx は、各ブレークポイントの作成時に割り当てられた ID 番号を表示します。 delete コマンドを使用することで、ID 番号によってブレークポイントを削除したり、キーワード all により、プログラム内のあらゆる場所に現在設定されているブレークポイントをすべて削除することができます。

ブレークポイントを ID 番号 ID_number によって削除するには、次のように入力します。


(dbx) delete 3 5

dbx に現在読み込まれているプログラムに設定されているすべてのブレークポイントを削除するには、次のように入力します。


(dbx) delete all

ウォッチポイント

ウォッチポイントは、変数または式の値が変化したときにイベントを発生させる dbx の一般的な機能です。

アドレスの内容に書き込みが行われたときに実行を停止する

アドレスの内容に書き込みが行われたときにプログラムの実行を停止するには、次のように入力します。


(dbx) stop modify & variable

stop modify を使用するときの注意事項

指定した変数の値が変化したときに実行を停止する

指定した変数の値が変化したときにプログラムの実行を停止するには、次のように入力します。


(dbx) stop change variable

stop change を使用するときの注意事項

指定した条件が発生した場合に実行を停止する

条件文が真になったときにプログラムの実行を停止するには、次のように入力します。


(dbx) stop cond condition

高速 modify イベント

ウォッチポイントは、modify コマンドを使用すると簡単に設定できます。このコマンドは、プログラムを自動的にステップ実行する代わりに、はるかに高速のページ保護構造を使用します。処理速度は、デバッグ中のプログラムのシステム呼び出し率だけでなく、監視中の変数の存在するページが何回修正されるかによって異なります。

ブレークポイントフィルタを設定する

dbx では、イベント管理コマンドのほとんどで (省略可能な) イベントフィルタの修飾文も利用することができます。最も単純なフィルタは次のいずれかの時点で、dbx に対してある特定の条件をテストするように指示します。

このフィルタ条件が真 (非 0) と評価されると、イベントコマンドが適用されます。条件が偽 (0) と評価されると、dbx はイベントが発生しなかったかのようにプログラムの実行を続けます。

条件つきフィルタを含む行または関数にブレークポイントを設定するためには、-if condition 指示子文を stop コマンドまたは trace コマンドの終わりに追加します。

condition には、任意の有効な式を指定できます。コマンドの入力時に有効だった言語で書かれた、ブール値または整数値を返す関数呼び出しも有効な式に含まれます。


注 -

inat など位置にもとづくブレークポイントでは、スコープはブレークポイント位置のスコープになります。それ以外の場合、イベントではなくエントリ発生時のスコープになります。スコープを正確に指定する構文を使用しなければならないことがあります。


次の 2 つのフィルタは異なります。


stop in foo -if a>5
stop cond a>5

前者は foo にブレークポイントが設定され、条件を検査します。後者は自動的に条件を検査します。

最初のうちは、条件つきイベントコマンド (watch タイプのコマンド) の設定とフィルタの使用とを混乱してしまうかもしれません。watch タイプのコマンドは、各行の実行前の前提条件の検査に用いられます (watch のスコープ内で)。しかし、このような条件つきブレークポイントに対してもフィルタを利用することができます。

次に具体的な例を示します。


(dbx) stop modify &speed -if speed==fast_enough

このコマンドは、変数 speed を監視するように dbx に指令します。speed に書き込みが行われると、-if フィルタが有効になります。dbxspeed の新しい値が fast_enough と等しいかどうかチェックします。等しくない場合、プログラムは実行を継続し、stop を「無視」します。

dbx 構文では、フィルタはブレークの「事後」、構文の最後で [-if condition] 文の形式で指定されます。


stop in function [-if condition]

イベント効率

デバッグ中のプログラムの実行時間に関するオーバーヘッドの量はイベントの種類によって異なります。最も単純なブレークポイントのように、実際はオーバーヘッドが何もないイベントもあります。1 つのブレークポイントしかないイベントも、オーバーヘッドは最小です。

実際のブレークポイントがときには何百にもなることのある多重ブレークポイント (inclass など) は、コマンド発行時にのみオーバーヘッドがあります。これは、dbx が永続的ブレークポイントを使用するためです。永続的ブレークポイントは、プロセスに常に保持され、停止するたびに取り除かれたり、cont のたびに置かれたりすることはありません。


注 -

step および next の場合、デフォルトでは、プロセスが再開される前にすべてのブレークポイントが取り除かれ、ステップが完了するとそれらは再び挿入されます。したがって、多くのブレークポイントを使用したり、多くのクラスで多重ブレークポイントを使用したりしているとき、step および next の速度は大幅に低下します。dbxenv 変数 step_events を使用して、stepnext のたびにブレークポイントを取り除いたり、挿入し直したりするかどうかを制御することができます。


自動ステップ実行を利用するイベントは最も低速です。これは、各ソース行をステップ実行する単純な trace step コマンドの場合と同様にはっきりしています。一方、stop change expressiontrace cond variable (ウォッチポイントと呼ばれるイベントのクラス) のようなイベントは、自動的にステップ実行するだけでなく、各ステップで式 expression や変数 variable を評価する必要があります。

これらのイベントは非常に低速ですが、イベントと修飾語 -in を使用した関数とを結び付けることで、効率が上がることがよくあります。たとえば、次のようにします。


trace next -in mumble
stop change clobbered_variable -in lookup

trace -in main を使用しないでください。これは、main によって呼び出された関数の中でも、トレースが有効になるためです。関数 lookup() が変数の値を頻繁に変更すると思われる場合には、この方法を使用してください。