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

第 15 章 dbx を使用してプログラムをデバッグする

この章では、dbx による C++ の例外の処理方法と C++ テンプレートのデバッグについて説明します。これらの作業を実行するために使用するコマンドの要約とコード例も示します。

この章の内容は次のとおりです。

C++ プログラムのコンパイルの詳細については、「デバッグのためのプログラムのコンパイル」を参照してください。

C++ での dbx の使用

この章では C++ デバッグの 2 つの特殊な点を中心に説明しますが、dbx を使用すると、C++ プログラムのデバッグに次の機能を利用することができます。

dbx での例外処理

プログラムは例外が発生すると実行を停止します。例外は、ゼロによる除算や配列のオーバーフローといったプログラムの障害を知らせるものです。ブロックを設定して、コードのどこかほかの場所で起こった式による例外を捕獲できます。

プログラムのデバッグ中、dbx を使用すると次のことが可能になります。

例外処理の発生箇所で step コマンドを実行すると、スタックの開放時に実行された最初のデストラクタの先頭に制御が戻ります。step を実行して、スタックの解放時に実行されたデストラクタを終了すると、制御は次のデストラクタの先頭に移ります。こうしてすべてのデストラクタが終了したあとに step コマンドを実行すると、例外処理の原因を扱う捕獲ブロックに制御が移ります。

例外処理コマンド

exception [-d | +d] コマンド

exception コマンドでは、デバッグ時にいつでも 例外処理の型を確認できます。オプションなしで exception コマンドを実行するときに表示される型は、dbx 環境変数output_dynamic_type の設定で制御できます。

-d オプションや +d オプションを指定すると、環境変数の設定が無効になります。

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

intercept [-all] [-x] [-set] [typename] コマンド

スタックを解放する前に、特定の型の例外を阻止または捕獲できます。intercept コマンドを引数を付けずに使用すると、阻止される型がリストで示されます。-all を使用すると、すべての例外が阻止されます。阻止リストに型を追加するには typename を使用します。-x を使用すると、特定の型を除外リストに格納し、阻止から除外することができます。-set を使用すると、阻止リストと除外リストの両方をクリアし、リストを指定した型のみをスローするインターセプトまたは除外に設定できます。

たとえば、int を除くすべての型を阻止するには、次のように入力します。


(dbx) intercept -all -x int

Error 型の例外を阻止するには、次のように入力します。


(dbx) intercept Error

CommonError 例外の阻止が多すぎた場合は、次のように入力してその除外を実行することができます。


(dbx) intercept -x CommonError

intercept コマンド引数なしで入力すると、処理されていない例外および予期で きない例外を含んだ阻止リストが表示されます。これらの例外はデフォルトで阻止され、それに加えてクラス CommonError を除くクラス Error の例外が阻止されます。


(dbx) intercept
-unhandled   -unexpected   class Error -x class CommonError

Error が例外クラスのものではなく、探している例外クラスの名前が分からない 場合は、次のように入力すると、クラス Error 以外のすべての例外を阻止できます。


(dbx) intercept -all -x Error

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

unintercept [-all] [-x] [typename] コマンド

unintercept コマンドは、阻止リストまたは除外リストから例外の型を削除するために使用します。引数を付けずにこのコマンドを使用すると、阻止されている型のリストが示されます (intercept コマンドに同じ)。-all を使用すると、阻止リストからすべての型を削除することができます。typename を使用すると、阻止リストから 1 つの型を削除することができます。-x を使用すると、除外リストから 1 つの型を削除することができます。

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

whocatches typename コマンド

whocatches コマンドは、typename の例外が実行の現時点で送出された場合に、どこで捕獲されるかを報告するものです。このコマンドは、例外がスタックのトップフレームから送出された場合に何が起こるかを検出する場合に使用します。

typename を捕獲した元の送出の行番号、関数名、およびフレーム数が表示されます。捕獲ポイントがスルーを行なっている関数と同じ関数内にあると、このコマンドは、「型にはハンドルがありません」というメッセージを表示します。

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

例外処理の例

次の例は、例外を含むサンプルプログラムを使用して、 dbx で例外処理がどのように実行されるかを示しています。型 int の例外が、関数 bar で送出されて、次の捕獲ブロックで捕獲されています。


1  #include <stdio.h>
2
3  class c {
4      int x;
5    public:
6      c(int i) { x = i; }
7      ~c() {
8                printf("destructor for c(%d)\n", x);
9           }
10  };
11
12  void bar() {
13      c c1(3);
14      throw(99);
15  }
16
17  int main() {
18      try {
19          c c2(5);
20          bar();
21          return 0;
22      }
23      catch (int i) {
24          printf("caught exception %d\n", i);
25      }
26  }

サンプルプログラムからの次のトランスクリプトは、dbx の例外処理機能を示しています。


(dbx) intercept
-unhandled -unexpected
(dbx) intercept int
<dbx> intercept
-unhandled -unexpected int
(dbx) stop in bar
(2) stop in bar()
(dbx)run
Running: a.out
(プロセス id 304)
bar で停止しました 行番号 13 ファイル "foo.cc"
   13       c c1(3);
(dbx) whocatches int
int が行番号 24 で捕獲されました、関数 main (フレーム番号 2)
(dbx) whocatches c
dbx: class c の実行時型情報がありません (送出も捕獲もされていない)
(dbx) cont
例外の型 int が行番号 24 で捕獲されました、関数 main (フレーム番号 4)
_exdbg_notify_of_throw で停止しました アドレス 0xef731494
0xef731494: _exdbg_notify_of_throw          :        jmp     %o7 + 0x8
現関数 : bar
   14        throw(99);
(dbx) step
c::~c で停止しました 行番号 8 ファイル "foo.cc"
    8         printf("destructor for c(%d)\n", x);
(dbx) step
destructor for c(3)
c::~c で停止しました 行番号 9 ファイル "foo.cc"
    9       }
(dbx) step
c::~c で停止しました 行番号 8 ファイル "foo.cc"
    8        printf("destructor for c(%d)\n", x);
(dbx) step
destructor for c(5)
c::~c で停止しました 行番号 9 ファイル "foo.cc"
    9       )
(dbx) step
main で停止しました 行番号 24 ファイル "foo.cc"
   24           printf("caught exception %d\n", i);
(dbx) step
caught exception 99
main で停止しました 行番号 26 ファイル "foo.cc"
   26   }

C++ テンプレートでのデバッグ

dbx は C++ テンプレートをサポートしています。 クラスおよび関数テンプレートを 含むプログラムを dbx に読み込み、クラスや関数に対して使用する任意の dbx コマンドをテンプレートに対して次のように呼び出すことができます。

テンプレートの例

次のコード例は、クラステンプレート Array とそのインスタンス化、および関数テンプレート square とそのインスタンス化を示しています。


 1        template<class C> void square(C num, C *result)
 2        {
 3             *result = num * num;
 4        }
 5    
 6        template<class T> class Array
 7        {
 8        public:
 9              int getlength(void)
10             {
11                    return length;
12              }
13    
14              T & operator[](int i)
15              {
16                    return array[i];
17             }
18    
19              Array(int l)
20              {
21                    length = l;
22                    array = new T[length];
23              }
24    
25              ~Array(void)
26              {
27                    delete [] array;
28              }
29    
30        private:
31              int length;
32              T *array;
33        };
34    
35        int main(void)
36        {
37              int i, j = 3;
38             square(j, &i);
39    
40             double d, e = 4.1;
41              square(e, &d);
42    
43              Array<int> iarray(5);
44              for (i = 0; i < iarray.getlength(); ++i)
45              {
46                   iarray[i] = i;
47             }
48    
49              Array<double> darray(5);
50              for (i = 0; i < darray.getlength(); ++i)
51             {
52                    darray[i] = i * 2.1;
53              }
54    
55              return 0;
56        }

この例の内容は次のとおりです。

C++ テンプレートのコマンド

次に示すコマンドは、テンプレートおよびインスタンス化されたテンプレートに使用します。クラスまたは型定義がわかったら、値の出力、ソースリストの表示、またはブレークポイントの設定を行うことができます。

whereis name コマンド

whereis コマンドは、関数テンプレートまたはクラステンプレートの、インスタンス化された関数やクラスの出現すべてのリストを出力するために使用します。

クラステンプレートの場合は、次のように入力します。


(dbx) whereis Array
メンバー関数: `Array<int>::Array(int)
メンバー関数: `Array<double>::Array(int)
クラステンプレートインスタンス: `Array<int>
クラステンプレートインスタンス: `Array<double>
クラステンプレート: `a.out `template_doc_2.cc` Array

関数テンプレートの場合は、次のように入力します。


(dbx) whereis square
関数テンプレートインスタンス: `square<int>(__type_0,__type_0*)
関数テンプレートインスタンス: `square<double>(__type_0,__type_0*)

__type_0 パラメータは、0 番目のパラメータを表します。__type_1 パラメータは、次のパラメータを表します。

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

whatis name コマンド

関数テンプレートおよびクラステンプレートと、インスタンス化された関数やクラスの定義を出力するために使用します。

クラステンプレートの場合は、次のように入力します。


(dbx) whatis -t Array
template<class T> class Array
完全なテンプレート宣言を得るために次を実行してください: 'whatis -t Array<int>';

クラステンプレートの構造については次のように実行します。


(dbx) whatis Array
識別子 'Array' が複数あります
次のうち 1 つ選択してください:
 0) 取り消し
 1) Array<int>::Array(int)
 2) Array<double>::Array(int>
> 1
Array<int>::Array(int 1);

関数テンプレートの場合は、次のように入力します。


(dbx) whatis square
識別子 'square' が複数あります
次のうち 1 つ選択してください:
 0) 取り消し
 1) square<int(__type_0,__type_0*)
 2) square<double>(__type_0,__type_0*)
> 2
void square<double>(double num, double *result);

クラステンプレートのインスタンス化の場合は、次のように入力します。


(dbx) whatis -t Array<double>
class Array<double>; {
public:
    int Array<double>::getlength()
    double &Array<double>::operator [](int i);
    Array<double>::Array<double>(int l);
    Array<double>::~Array<double>();
private:
    int length;
    double *array;
};

関数テンプレートのインスタンス化の場合は、次のように入力します。


(dbx) whatis square(int, int*)
void square(int num, int *result);

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

stop inclass classname コマンド

テンプレートクラスのすべてのメンバー関数を停止するには、次のように入力します。


(dbx)stop inclass Array
(2) stop inclass Array

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


(dbx) stop inclass Array<int>
(2) stop inclass Array<int>

詳細については、stop コマンド」inclass classname [-recurse | -norecurse]を参照してください。

stop infunction name コマンド

stop infunction コマンドを利用して、指定した関数テンプレートのインスタンスにブレークポイントを設定します。


(dbx) stop infunction square
(9) stop infunction square

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

stop in function コマンド

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

クラスインスタンス化のメンバーの場合は、次のとおりです。


(dbx) stop in Array<int>::Array(int l)
(2) stop in Array<int>::Array(int)

関数インスタンス化の場合は、次のように入力します。


(dbx) stop in square(double, double*)
(6) stop in square(double, double*)

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

call function_name( parameters) コマンド

スコープ内で停止した場合に、インスタンス化された関数やクラステンプレートのメンバー関数を明示的に呼び出すには、call コマンドを使用します。dbx で正しいインスタンスを決定できない場合、選択肢となる番号が付いたインスタンスのリストが表示されます。


(dbx) call square(j,&i)

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

print コマンド

print コマンドを使用して、インスタンス化された関数またはクラステンプレートメンバー関数を評価します。


(dbx) print iarray.getlength()
iarray.getlength() = 5

printを使用して this ポインタを評価します。


(dbx) whatis this
class Array<int> *this;
(dbx) print *this
*this = {
    length = 5
    array   = 0x21608
}

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

list コマンド

list コマンドを使用して、指定のインスタンス化された関数のソースリストを出力します。


(dbx) list square(int, int*)

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