Sun Studio 12:使用 dbx 调试程序

第 15 章 使用 dbx 调试 C++

本章说明了 dbx 如何处理 C++ 异常及调试 C++ 模板,其中概括介绍了完成这些任务所使用的命令,并提供了代码样例示例。

本章由以下部分组成:

有关编译 C++ 程序的信息,请参见编译调试程序

使用 dbx 调试 C++

虽然本章只重点介绍了调试 C++ 的两个特定方面,但您在调试 C++ 程序时可使用 dbx 的全部功能。可以使用的功能包括:

dbx 中的异常处理

如果出现异常,程序便停止运行。异常会发送编程异常信号,例如:被零除或数组上溢。可以设置块来捕获代码中其他位置的表达式引起的异常。

调试程序时,您可以使用 dbx 完成以下操作:

如果在程序停止于异常抛出点后执行 step 命令,则将于堆栈展开期间执行的第一个析构函数的起始处返回控制。如果通过 step 命令步出堆栈展开期间执行的析构函数,则将于下一个析构函数的起始处返回控制。当所有析构函数都执行完毕后,step 命令将前进到处理异常抛出的 catch 块。

异常处理命令

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 命令,则会发现拦截列表中包括未处理的异常和意外的异常(缺省情况下将拦截这些异常),以及 Error 类的异常(CommonError 类的异常除外)。


(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 可从拦截列表中删除一个类型。使用 -x 可从排除列表中删除一个类型。

有关更多信息,请参见unintercept 命令

whocatches typename 命令

如果在当前执行点抛出异常,whocatches 命令会报告捕获类型为 typename 的异常的位置。使用此命令可查出自栈的顶帧抛出异常时会发生什么情况。

捕获 typename 的 catch 子句的行号、函数名和帧号均会显示出来。如果捕获点所在函数与抛出异常的函数相同,则该命令返回 "type is unhandled"

有关更多信息,请参见whocatches 命令

异常处理示例

此示例通过一个包含异常的程序样例说明dbx 中如何进行异常处理。在函数 bar 中抛出类型为 int 的异常,并在后面的 catch 块中捕获该异常。


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
(process id 304)
Stopped in bar at line 13 in file “foo.cc”
   13       c c1(3);
(dbx) whocatches int
int is caught at line 24, in function main (frame number 2)
(dbx) whocatches c
dbx: no runtime type info for class c (never thrown or caught)
(dbx) cont
Exception of type int is caught at line 24, in function main (frame number 4)
stopped in _exdbg_notify_of_throw at 0xef731494
0xef731494: _exdbg_notify_of_throw          :        jmp     %o7 + 0x8
Current function is bar
   14        throw(99);
(dbx) step
stopped in c::~c at line 8 in file "foo.cc"
    8         printf("destructor for c(%d)\n", x);
(dbx) step
destructor for c(3)
stopped in c::~c at line 9 in file "foo.cc"
    9       }
(dbx) step
stopped in c::~c at line 8 in file "foo.cc"
    8        printf("destructor for c(%d)\n", x);
(dbx) step
destructor for c(5)
stopped in c::~c at line 9 in file "foo.cc"
    9       )
(dbx) step
stopped in main at line 24 in file "foo.cc"
   24           printf("caught exception %d\n", i);
(dbx) step
caught exception 99
stopped in main at line 26 in file "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
member function: `Array<int>::Array(int)
member function: `Array<double>::Array(int)
class template instance: `Array<int>
class template instance: `Array<double>
class template: `a.out`template_doc_2.cc`Array

对于函数模板:


(dbx) whereis square
function template instance: `square<int>(__type_0,__type_0*)
function template instance: `square<double>(__type_0,__type_0*)

__type_0 参数引用 0 号模板参数。__type_1 引用下一个模板参数。

有关更多信息,请参见whereis 命令

whatis name 命令

使用 whatis 命令可打印函数模板和类模板的定义以及实例化的函数和类。

对于类模板:


(dbx) whatis -t Array
template<class T> class Array
To get the full template declaration, try `whatis -t Array<int>’;

对于类模板的构造函数:


(dbx) whatis Array
More than one identifier ’Array’.
Select one of the following:
 0) Cancel
 1) Array<int>::Array(int)
 2) Array<double>::Array(int>
> 1
Array<int>::Array(int 1);

对于函数模板:


(dbx) whatis square
More than one identifier ’square’.
Select one of the following:
 0) Cancel
 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

使用 printthis 指针求值。


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

有关更多信息,请参见print 命令

list 表达式

可使用 list 命令打印指定函数实例的源码列表。


(dbx) list square(int, int*)

有关更多信息,请参见list 命令