检查程序数据
此部分说明如何检查、测试并修改程序数据。
处理信号
dbx 调试程序可在将信号发送到程序之前捕获或忽略这些信号。 每次程序将要接收信号时,就会通知 dbx 程序。 如果信号将被忽略,那么将它传递给程序;否则,dbx 程序将停止该程序并通知您已捕获到一个信号。 如果 SIGTRAP 信号来自调试进程外的进程,那么 dbx 程序不能忽略此信号。 在多线程程序中,可通过 pthread_kill 子例程将信号发送到特殊线程。 在缺省情况下,dbx 程序将停止,并通知您已捕获到一个信号。 如果使用 ignore 子命令请求将信号传递给程序上,那么 dbx 程序将忽略该信号,并将它传递给线程上。 使用 catch 和 ignore 子命令来更改缺省处理。
在以下示例中,程序使用 SIGGRANT 和 SIGREQUEST 处理资源的分配。 为了使 dbx 程序在每次接收到这些信号之一时继续,请输入:
(dbx) ignore GRANT
(dbx) ignore SIGREQUEST
(dbx) ignore
CONT CLD ALARM KILL GRANT REQUEST如果设置了 $sigblock 变量,那么 dbx 调试程序可阻塞到程序的信号。 在缺省情况下,通过 dbx 程序接收的信号被发送到源程序或 dbx ObjectFile 参数指定的对象文件。 如果使用 set 子命令设置了 $sigblock 变量,那么 dbx 程序接收到的信号不会传递到源程序。 如果想要将信号发送到程序,那么使用 cont 子命令,并将信号作为操作数提供。
可使用此功能中断运行在 dbx 调试程序下的程序的执行。 可在继续执行前照常检查程序状态。 如果未设置 $sigblock 变量,那么中断执行将导致 SIGINT 信号被发送到程序。 继续时,这将使执行转移到信号处理程序(如果存在)。
以下示例程序演示了设置了 $sigblockdbx 变量时,使用 dbx 调试程序的执行是如何更改的:
#include <signal.h>
#include <stdio.h>
void inthand( ) {
printf("\nSIGINT received\n");
exit(0);
} main( )
{
signal(SIGINT, inthand);
while (1) {
printf(".");
fflush(stdout);
sleep(1);
}
}以下带有 dbx 程序的样本会话将上面的程序作为源文件使用。 首次运行程序时,未设置 $sigblock 变量。 在重新运行期间,设置了 $sigblock 变量。 注释被置于尖括号之间,并被置于右侧:
dbx version 3.1.
Type 'help' for help.
reading symbolic information ...
(dbx) run
.........^C <User pressed Ctrl-C here!>
interrupt in sleep at 0xd00180bc
0xd00180bc (sleep+0x40) 80410014 1 r2,0x14(r1)
(dbx) cont SIGINT received execution completed
(dbx) set $sigblock
(dbx) rerun
[ looper ]
..............^C <User pressed Ctrl-C here!>
interrupt in sleep at 0xd00180bc
0xd00180bc (sleep+0x40) 80410014 1 r2,0x14(r1)
(dbx) cont
....^C <Program did not receive signal, execution continued> interrupt in sleep at 0xd00180bc
0xd00180bc (sleep+0x40) 80410014 1 r2,0x14(r1)
(dbx) cont 2 <End program with a signal 2> SIGINT received execution completed
(dbx)调用过程
可以从 dbx 程序调用程序过程以测试不同参数。 还可调用格式化数据的诊断例程以辅助调试。 使用 call 子命令或 print 子命令来调用过程。
显示堆栈跟踪
要列出程序停止之前的过程调用,请使用 where 命令。
在以下示例中,可执行对象文件 hello由两个源文件和三个过程组成,包括标准过程main. 程序在过程中的断点处停止sub2.
(dbx) run
[1] stopped in sub2 at line 4 in file "hellosub.c"
(dbx) where
sub2(s = "hello", n = 52), line 4 in "hellosub.c"
sub(s = "hello", a = -1, k = delete), line 31 in "hello.c"
main(), line 19 in "hello.c"堆栈跟踪以逆序显示调用。 从底部开始,发生以下事件:
- 已调用 shellmain.
- main次数sub在第 19 行的过程中包含值s = "hello",a = -1和k = delete.
- sub次数sub2具有值的第 31 行中的过程s = "hello"和n = 52.
- 程序已停止sub2过程位于第 4 行。
where 0 1显示。(dbx)run
[1] stopped in sub2 at line 4 in file "hellosub.c"
(dbx) where 0 1
sub2(s = "hello", n = 52), line 4 in "hellosub.c"
sub(s = "hello", a = -1, k = delete), line 31 in "hello.c"注意: 设置调试程序变量 $noargs 以关闭传递给过程的参数的显示。 设置调试程序变量 $stack_details 显示为每个活动的功能或过程设置的帧编号和寄存器。
还可以通过 up, down来显示堆栈的部分。 和 frame 子命令。
显示和修改变量
要显示表达式,请使用 print 子命令。 要打印变量的名称和值,请使用 dump 子命令。 如果给定过程为句点,那么显示所有活动变量。 如果指定了 PATTERN 参数,那么不会仅显示指定的符号,而会显示与 PATTERN 匹配的所有符号。 要修改变量的值,请使用 assign 子命令。
在以下示例中, C 程序具有自动整数变量x值为 7 ,并且s和n中的参数sub2过程:
(dbx) print x, n
7 52
(dbx) assign x = 3*x
(dbx) print x
21
(dbx) dump
sub2(s = "hello", n = 52)
x = 21显示与线程相关的信息
要显示有关用户线程,互斥对象,条件和属性对象的信息,请使用 线程, 互斥对象, condition和 attribute 子命令。 还可以在这些对象上使用 print 子命令。 在以下示例中,正在运行的线程是线程 1。 用户将当前线程设置为线程 2 ,列出线程,在线程 1 上打印信息,最后在多个与线程相关的对象上打印信息。
(dbx) thread current 2
(dbx) thread
thread state-k wchan state-u k-tid mode held scope function
*$t1 run running 12755 u no pro main
>$t2 run running 12501 k no sys thread_1 (dbx) print $t1
(thread_id = 0x1, state = run, state_u = 0x0, tid = 0x31d3, mode = 0x1, held = 0x0, priority = 0x3c,
policy = other, scount = 0x1, cursig = 0x5, attributes = 0x200050f8) (dbx) print $a1,$c1,$m2
(attr_id = 0x1, type = 0x1, state = 0x1, stacksize = 0x0, detachedstate = 0x0, process_shared = 0x0,
contentionscope = 0x0, priority = 0x0, sched = 0x0, inherit = 0x0, protocol = 0x0, prio_ceiling = 0x0)
(cv_id = 0x1, lock = 0x0, semaphore_queue = 0x200032a0, attributes = 0x20003628)
(mutex_id = 0x2, islock = 0x0, owner = (nil), flags = 0x1, attributes = 0x200035c8)限定名称的作用域
首先使用当前函数的静态作用域的名称解析。 如果在第一个作用域中未定义名称,那么使用动态作用域。 如果静态和动态搜索未生成结果,那么将选择任意符号并显示消息using QualifiedName打印。 可通过使用块名称(如 Module.Variable)限定标识来覆盖名称解析过程。 将源文件作为由不带后缀的文件名命名的模块处理。 例如, x 变量,在subhello.c 文件中的过程,具有标准名称 hello.sub.x。 程序本身具有名称的句点。
当存在多个同名符号时, 哪些 和 其中 子命令有助于确定找到哪个符号。
在表达式中使用运算符和修饰符
dbx 程序可以显示各种各样的表达式。 使用 C 语法的公共子集以及一些 FORTRAN 扩展来指定表达式。
- *(星号)或 ^(插入标记)
- 表示正在取消引用间接寻址或者指针。
- [ ](方括号)或 ( )(圆括号)
- 表示数组表达式的下标。
- . (期间)
- 通过指针和结构来使用该字段引用运算符。 这使得 C 运算符-> (箭头) 是不必要的,尽管是允许的。
- &(& 符号)
- 获得变量的地址。
- .. (两个句点)
- 在指定数组子部分时将上下界分开。 例如:n[1..4]。
以下类型的操作在表达式中有效:
- 代数运算
- =、-、*、/(浮点运算除法)、div(整数运算除法)、mod 以及 exp(乘方)
- 按位运算
- -, 我, 比特, 西或, ~, <<, >>
- 逻辑
- 或, 和, 不, 二., &&
- 比较运算
- <, >, <=, >=, <> 或 !=, = 或 ==
- 其他
- sizeof
在 stop 和 trace 子命令中,允许逻辑表达式和比较表达式作为条件。
表达式类型的检查
dbx 调试程序检查表达式类型。 可使用重命名或数据类型转换运算符覆盖表达式类型。 类型重命名的格式有 3 种:
- Typename (表达式)
- 表达式 \ Typename
- (Typename) 表达式
注: 对结构,并集或类进行强制类型转换时,强制类型转换是左对齐的。 然而,从类转换为基本类时,要遵照 C++ 语法规则。
例如,要重命名 x 变量,而在该处 x 为一个整数且值为 97,请输入:
(dbx) print char (x), x \ char, (char) x, x,
'a' 'a' 'a' 97以下示例显示如何使用类型重命名的 (Typename) Expression 格式:
print (float) i print ((struct qq *) void_pointer)->first_element以下限制适用于 dbx 调试程序的 C 式类型转换:
- 不支持 Fortran 类型(integer*1、integer*2、integer*4、logical*1、logical*2、logical*4 等)作为强制类型转型运算符。
- 如果活动变量的名称与库类型或用户定义的类型中的某一个相同时,不能将该类型作为强制类型转型运算符使用以进行 C 式类型转换。
whatis 子命令打印标识的声明,然后可以使用块名称限定该标识。
使用 $$TagName 构造显示枚举、结构或联合标记的声明。
assign 子命令表达式的类型必须与您指定的变量类型匹配。 如果类型不匹配,那么将显示错误消息。 使用类型重命名更改表达式类型。 通过设置特殊的 dbx 调试程序 $unsafeassign 变量禁用类型检查。
将变量转换成小写和大写
在缺省情况下,dbx 程序基于当前语言转换符号。 如果当前语言为 C、C++ 或未定义,那么不转换符号。 如果当前语言为 Fortran,那么将符号转换为小写。 如果程序位于代码节中,而并未使用 debug 标记编译此代码,那么当前语言未定义。 可以使用 case 子命令来覆盖缺省处理。
使用不带参数的 case 子命令显示当前例子方式。
Fortran 编译器会将所有程序符号转换为小写;C 编译器不会这样做。 但是,有些 Fortran 编译器可能不会始终都生成小写符号。 例如,在名为 mod2 模块中提供了一个名为 proc1 的过程,XLF Fortran 编译器将生成大小写混合的 __mod2_MOD_proc1 符号。 在这样的情况下,必须将 dbx 程序中的大小写更改为大小写混合。
使用特殊调试程序变量来更改显示输出
使用 集 子命令来设置以下特殊 德布克斯 调试程序变量,以从 打印 子命令获取不同的结果:
- $hexints
- 以十六进制显示整型表达式。
- $hexchars
- 以十六进制显示字符表达式。
- $hexstrings
- 显示字符串地址,而不是字符串本身。
- $octints
- 以八进制显示整型表达式。
- $expandunions
- 显示联合内的字段。
- $pretty
- 以 pretty 格式显示复杂的 C 和 C++ 类型。
- $print_dynamic
- 显示 C++ 对象的动态类型。
- $show_vft
- 显示 C++ 对象时显示虚函数表。
设置和复位调试程序变量以获取期望结果。 例如:
(dbx) whatis x; whatis i; whatis s
int x;
char i;
char *s;
(dbx) print x, i, s
375 'c' "hello"
(dbx) set $hexstrings; set $hexints; set $hexchars
(dbx) print x, i, s
0x177 0x63 0x3fffe460
(dbx) unset $hexchars; set $octints
(dbx) print x, i
0567 'c'
(dbx) whatis p
struct info p;
(dbx) whatis struct info
struct info {
int x;
double position[3];
unsigned char c;
struct vector force;
};
(dbx) whatis struct vector
struct vector {
int a;
int b;
int c;
};
(dbx) print p
(x = 4, position = (1.3262493258532527e-315, 0.0, 0.0),
c = '\0', force = (a = 0, b = 9, c = 1))(dbx) set $pretty="on"
(dbx) print p
{
x = 4
position[0] = 1.3262493258532527e-315
position[1] = 0.0
position[2] = 0.0
c = '\0'
force = {
a = 0
b = 9
c = 1
}
}
(dbx) set $pretty="verbose"
(dbx) print p
x = 4
position[0] = 1.3262493258532527e-315
position[1] = 0.0
position[2] = 0.0
c = '\0'
force.a = 0
force.b = 9
force.c = 1未设置 show_vft 且使用 print 子命令显示对象时,不会显示虚函数表 (VFT)。 如果设置了 show_vft,那么将显示 VFT。 例如:
(dbx) p *d
B1:(int_in_b1 = 91)
B2:(int_in_b2 = 92)
(int_in_d = 93)
(dbx) p *b2
(int_in_b2 = 20)
(dbx)set $show_vft
(dbx) p *d
B1:(B1::f1(), int_in_b1 = 91)
B2:(D::f2(), int_in_b2 = 92)
(int_in_d = 93)
(dbx) p *b2
(B2::f2(), int_in_b2 = 20)
(dbx) 未设置 print_dynamic 时,对象会按照静态类型(这在源代码中定义)的模板进行显示。 否则,它将按照动态类型(对对象进行任何强制类型转换之前对象的类型)的模板进行显示。 例如:
(dbx) r
[1] stopped in main at line 57
57 A *obj1 = new A();
(dbx) n
stopped in main at line 58
58 A *obj2 = new B();
(dbx) n
stopped in main at line 59
59 cout<<" a = "<<obj2->a<<" b = "<<obj2->b<<endl;
(dbx) p *obj2
(a = 1, b = 2)
(dbx)set $print_dynamic
(dbx) print *obj2
A:(a = 1, b = 2)
(c = 3, d = 4)
(dbx)