この章では、dbx による呼び出しスタックの使用方法と、呼び出しスタックを処理するときの where、hide、unhide、および pop コマンドの使用方法について説明します。
マルチスレッドのプログラムにおいて、これらのコマンドは現在のスレッドの呼び出しスタックに対して作用します。現在のスレッドの変更方法の詳細については、「thread コマンド」を参照してください。
呼び出しスタックは、呼び出されたあと呼び出し側にまだ戻っていない、現在活動状態にあるルーチンすべてを示します。スタックフレームは、単一関数に割り当てられる呼び出しスタックのセクションです。
呼び出しスタックがメモリー上位 (上位アドレス) からメモリー下位に成長すること から、up は呼び出し側 (最終的には main() またはスレッドの開始関数) のフレームに向かうこと、そして down は呼び出された関数 (最終的には現在の関数) のフレームに向かうことを意味します。プログラムの現在位置 (ブレークポイント、ステップ実行のあと、プログラムが異常終了してコアファイルが作成された、いずれかの時点で実行されていたルーチン) はメモリー上位に存在しますが、main() のような呼び出し側ルーチンはメモリー下位に位置します。
この章の内容は次のとおりです。
where コマンドを使用すると、スタックでの現在位置を検索できます。
where [-f] [-h] [-l] [-q] [-v] number_id |
JavaTM コードおよび C JNI (Java Native Interface) コードまたは C++ JNI コードが混在するアプリケーションをデバッグする場合、where コマンドの構文は次のとおりです。
where [-f] [-q] [-v] [ thread_id ] number_id |
where コマンドは、クラッシュしてコアファイルを作成したプログラムの状態を知る場合にも役立ちます。プログラムがクラッシュしてコアファイルを作成した場合、そのコアファイルを dbx に読み込むことができます (「既存のコアファイルのデバッグ」を参照)。
where コマンドの完全な構文については、「where コマンド」を参照してください。
スタックを上下に移動することを「スタックの移動」といいます。スタックを上下に移動して関数を表示すると、dbx は現在の関数とソース行を表示します。開始する位置つまり「ホーム」は、プログラムが実行を停止した位置です。このホームを起点にし、up コマンド、down コマンド、または frame コマンドを使用してスタックを上下に移動 できます。
dbx コマンドの up および down はともに、引数として、スタック内で現在のフレームから上下に移動するフレームの数を指定する値 (number) を受け付けます。number を指定しない場合、デフォルトは 1 です。-h オプションを付けると、隠されたフレームもすべてカウントされます。
現在の関数以外の関数にある局所変数を調べることができます。
呼び出しスタックを number で指定されたレベル分、上に (main に向かって) 移動するには、次のように入力します。
up [-h] [ number ] |
number を指定しない場合、デフォルトは 1 レベルになります。詳細については、「up コマンド」を参照してください。
呼び出しスタックを number で指定されたレベル分、下に (現在の停止点に向かって) 移動するには、次のように入力します。
down [-h] [ number ] |
number を指定しない場合、デフォルトは 1 レベルになります。詳細については、「down コマンド」を参照してください。
frame コマンドは、up コマンドや down コマンドと同じような働きをします。where コマンドで得た番号を指定すると、その番号によって特定されるフレームに直接移動できます。
frame frame -h frame [-h] number frame [-h] +[number] frame [-h] -[number] |
引数なしの frame コマンドは、現在のフレーム番号を出力します。number を指定すると、その番号によって示されるフレームに直接移動できます。"+" または "-" だけを指定すると、現在のフレームから 1 レベルだけ上 (+) または下 (-) に移動できます。また、正負の符号と number をともに指定すると、指定した数のレベルだけ上または下に移動できます。- h オプションを付けると、隠されたフレームもカウントされます。
pop コマンドを使用して特定のフレームに移動できます (「呼び出しスタックのポップ」参照)。
呼び出しスタックから、停止した関数を削除し、呼び出し中の関数を新たに指定関数で停止する関数にすることができます。
呼び出しスタックの上下方向への移動とは異なり、スタックのポップは、プログラムの実行を変更します。スタックから停止した関数が削除されると、プログラムは以前の状態に戻ります。ただし、大域または静的変数、外部ファイル、共有メンバー、および同様のグローバル状態への変更は対象外です。
pop コマンドは、1 個または複数のフレームを呼び出しスタックから削除します。たとえば、スタックから 5 つのフレームをポップするには、次のように入力します。
pop 5 |
指定のフレームへポップすることもできます。フレーム 5 へポップするには、次のように入力します。
pop -f 5 |
詳細については、「pop コマンド」を参照してください。
hide コマンドを使用して、現在有効なスタックフレームフィルタをリスト表示します。
正則表現に一致するすべてのスタックフレームを隠すか、または削除するには、次のように入力します。
hide [ regular_expression ] |
regular_expression は、関数名、またはロードオブジェクト名のいずれかを表し、ファイルの照合に sh または ksh の構文を使用します。
すべてのスタックフレームフィルタを削除するには、unhide を使用します。
unhide 0 |
hide コマンドは、番号とともにフィルタをリスト表示するため、このフィルタ番号を使用して unhide コマンドを使用することもできます。
unhide [ number | regular_expression ] |
プログラムフローのどこで実行が停止し、この地点までどのように実行が到達したのかが、スタックトレースに示されます。スタックトレースは、プログラムの状態を、もっとも簡潔に記述したものです。
スタックトレースを表示するには、where コマンドを使用します。
-g オプションでコンパイルされた関数の場合、引数の名前と種類が既知であるため、正確な値が表示されます。デバッグ情報を持たない関数の場合、16 進数が引数として表示されます。これらの数字に意味があるとはかぎりません。関数ポインタ 0 を介して関数が呼び出される場合、記号名の代わりに関数の値が下位 16 進数として示されます。
-g オプションを使ってコンパイルされなかった関数の中でも停止することができます。このような関数でトレースを停止すると、dbx はスタックを検索し、関数が -g オプションでコンパイルされている最初のフレームを探し、現在の適用範囲 (「プログラムスコープ」を参照) そのフレームに設定します。これは、矢印記号 (=>) によって示されます。
次の例で、main() は -g オプションでコンパイルされているため、記号名と引数の値が表示されます。main() によって呼び出されたライブラリ関数は、-g でコンパイルされていないため、関数の記号名は表示されますが、引数については $i0 から $i5 までの SPARC 入力レジスタの 16 進数の内容が示されます。
次の例で、プログラムはセグメント例外によりクラッシュしています。クラッシュの原因は、SPARC 入力レジスタ $0 において strlen() にヌルの引数が指定されたことにあると考えられます。
(dbx) run Running: Cdlib (process id 6723) CD Library Statistics: Titles: 1 Total time: 0:00:00 Average time: 0:00:00 signal SEGV (no mapping at the fault address) in strlen at 0xff2b6c5c 0xff2b6c5c: strlen+0x0080: ld [%o1], %o2 Current function is main (dbx) where [1] strlen(0x0, 0x0, 0x11795, 0x7efefeff, 0x81010100, 0xff339323), at 0xff2b6c5c [2] _doprnt(0x11799, 0x0, 0x0, 0x0, 0x0, 0xff00), at 0xff2fec18 [3] printf(0x11784, 0xff336264, 0xff336274, 0xff339b94, 0xff331f98, 0xff00), at 0xff300780 =>[4] main(argc = 1, argv = 0xffbef894), line 133 in "Cdlib.c" (dbx) |
スタックトレースの例については、「呼び出しスタックを確認する」および「呼び出しのトレース」を参照してください。