GDB 使用watch设置观察点

通过GDB设置断点,我们可以让程序暂停运行,然后通过打印变量或内存的值,来判断当前的程序是否有错误。如果程序中的变量很多,我们依次打印,就比较浪费体力,而且程序中的很多变量可能从始至终并没变化,每次都打印它们比较麻烦,做很多无用功。

一个更高效的方法是设置观察变量,让GDB自动去检测这些变量的变化:若这些变量没有异常,程序正常运行;若这些变量有变化,则程序暂停运行,保留现场,我们可以基于这个现场进一步调试。

使用watch设置观察点

我们可以通过GDB设置观察点,通过watch命令设置一个要监控的对象:

(gdb) watch expression

其中的expression可以是一个变量,也可以是一个表达式。当这个被检测的变量或表达式的值发生变化时,就会被GDB检测到,GDB会暂停程序的运行,保留现场,让程序员做进一步的调试。

#include <stdio.h>

int main(void)
{
    int a[10] = {0};
    int i = 0;
    for(i = 0; i < 10; i++)
        a[i] = i;
    return 0;
}

在上面的程序中,我们使用一个for循环来对数组a[10]进行赋值。如果我们想检测数组元素a[5],此时就可以使用watch命令来完成。

root@ubuntu:/home/gdb# gdb a.out 
(gdb) l
1    #include <stdio.h>
2    
3    int main(void)
4    {
5        int a[10] = {0};
6        int i = 0;
7        for(i = 0; i < 10; i++)
8            a[i] = i;
9        return 0;
10    }
(gdb) b 7
Breakpoint 1 at 0x1193: file main.c, line 7.
(gdb) r
Starting program: /home/gdb/a.out 
Breakpoint 1, main () at main.c:7
7        for(i = 0; i < 10; i++)
(gdb) watch a[5]
Hardware watchpoint 2: a[5]
(gdb) c
Continuing.

Hardware watchpoint 2: a[5]

Old value = 0
New value = 5
main () at main.c:7
7        for(i = 0; i < 10; i++)
(gdb) 
Continuing.
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
__libc_start_main (main=0x555555555149 <main>, argc=1, argv=0x7fffffffe0c8, 
    init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, 
    stack_end=0x7fffffffe0b8) at ../csu/libc-start.c:342
342    ../csu/libc-start.c: No such file or directory.
(gdb) 
Continuing.
[Inferior 1 (process 3201) exited normally]
(gdb) q
root@ubuntu:/home/gdb#

设置观察断点,需要在GDB环境下进行。要先启动程序,找个合适的地方让程序暂停运行,然后就可以使用watch命令来设置观察对象了。观察断点设置好之后,再使用continue命令恢复程序的运行,当我们要观察的对象a[5]的值发生变化时,程序就会暂停运行,并将a[5]数组元素的前后值变化打印出来。

通过watch设置的观察点对象或表达式遵循作用域规则。当程序运行的范围,超出要监控的变量的作用域时,如上面程序中的a[5]数组元素,当main函数退出时,因为a[10]是在main函数内定义的,是一个局部变量,所以a[10]也就跟着销毁了,此时设置的观察点也会随之删除。

《Linux三剑客》视频教程,从零开始快速掌握Linux开发常用的工具:Git、Makefile、vim、autotools、debug,免费赠送C语言视频教程,C语言项目实战:学生成绩管理系统。详情请点击淘宝链接:Linux三剑客