GDB watch令:监控变量值的变化
要知道,GDB 调试器支持在程序中打 3 种断点,分别为普通断点、观察断点和捕捉断点。其中 break 令打的就是普通断点,而 watch 令打的为观察断点,关于捕捉断点,后续章节会做详细讲解。
使用 GDB 调试程序的过程中,借助观察断点可以监控程序中某个变量或者表达式的值,只要发生改变,程序就会停止执行。相比普通断点,观察断点不需要我们预测变量(表达式)值发生改变的具置。
对于监控 C、C++ 程序中某变量或表达式的值是否发生改变,watch 令的语法非常简单,如下所示:所谓表达式,就是包含多个变量的式子,比如 a+b 就是一个表达式,其中 a、b 为变量。
(gdb) watch cond
其中,conde 指的就是要监控的变量或表达式。和 watch 令功能相似的,还有 rwatch 和 awatch 令。其中:
rwatch 令:只要程序现读取目标变量(表达式)的值的操作,程序就会停止运行;
awatch 令:只要程序现读取目标变量(表达式)的值或者改变值的操作,程序就会停止运行。
强调一下,watch 令的功能是:只有当被监控变量(表达式)的值发生改变,程序才会停止运行。
举个例子:
(gdb) l <--列出要调试的程序源码
1 #include<stdio.h>
2 int main(int argc,char* argv[])
3 {
4 int num = 1;
5 while(num<=100)
6 {
7 num *= 2;
8 }
9 printf("%d",num);
10 return 0;
(gdb)
11 }
(gdb) b 4 <-- 使用 break 令打断点
Breakpoint 1 at 0x115c: file main.c, line 4.
(gdb) r <-- 执行程序
Starting program: /home/ubuntu64/demo/main.exe
Breakpoint 1, main (argc=1, argv=0x7fffffffe088) at main.c:4
4 int num = 1;
(gdb) watch num <-- 监控程序中 num 变量的值
Hardware watchpoint 2: num
(gdb) c <-- 继续执行,当 num 值发生改变时,程序才停止执行
Continuing.
Hardware watchpoint 2: num
Old value = 0
New value = 2
main (argc=1, argv=0x7fffffffe088) at main.c:5
5 while(num<=100)
(gdb) c <-- num 值发生了改变,继续执行程序
Continuing.
Hardware watchpoint 2: num
Old value = 2
New value = 4
main (argc=1, argv=0x7fffffffe088) at main.c:5
5 while(num<=100)
(gdb)
可以看到在程序运行过程中,通过借助 watch 令监控 num 的值,后续只要 num 的值发生改变,程序都会停止。感兴趣的读者,可自行尝试使用 awatch 和 rwatch 令,这里不再给出具体的示例。有关代码中蓝色部分的含义,本文后续会做详细解释。
如果我们想查看当前建立的观察点的数量,借助如下指令即可:
(gdb) info watchpoints
值得一提的是,对于使用 watch(rwatch、awatch)令监控 C、C++ 程序中变量或者表达式的值,有以下几点需要注意:
当监控的变量(表达式)为局部变量(表达式)时,一旦局部变量(表达式)失效,则监控操作也随即失效;
如果监控的是一个指针变量(例如 *p),则 watch *p 和 watch p 是有区别的,前者监控的是 p 所指数据的变化情况,而后者监控的是 p 指针本身有没有改变指向;
这 3 个监控令还可以用于监控数组中元素值的变化情况,例如对于 a[10] 这个数组,watch a 表示只要 a 数组中存储的数据发生改变,程序就会停止执行。
如果读者只想学习如何使用 watch 令,则读者这里即可。反之,如果想了解 watch 令底层是如何实现的,可以继续往下阅读。
watch令的实现原理
watch 令实现监控机制的方式有 2 种,一种是为目标变量(表达式)设置硬件观察点,另一种是为目标变量(表达式)设置软件观察点。所谓软件观点(software watchpoint),即用 watch 令监控目标变量(表达式)后,GDB 调试器会以单步执行的方式运行程序,并且每行代码执行完毕后,都会检测该目标变量(表达式)的值是否发生改变,如果改变则程序执行停止。
可想而知,这种“实时”的判别方式,一定程度上会影响程序的执行效率。但从另一个角度看,调试程序的目的并非是为了获得运行结果,而是查找导致程序异常或 Bug 的代码,因此即便软件观察点会影响执行效率,一定程度上也是可以接受的。
所谓硬件观察点(Hardware watchpoint),和前者的不同是,它在实现监控机制的同时不影响程序的执行效率。简单的理解,系统会为 GDB 调试器提供少量的寄存器(例如 32 位的 Intel x86 处理器提供有 4 个调试寄存器),每个寄存器都可以作为一个观察点协助 GDB 完成监控任务。
需要注意的是,基于寄存器个数的限制,如果调试环境中设立的硬件观察点太多,则有些可能会失去作用,这种情况下,GDB 调试器会发出如下警告:
Hardware watchpoint num: Could not insert watchpoint
解决方案也很简单,就是删除或者禁用一部分硬件观察点。除此之外,受到寄存器数量的限制,可能会出现:无法使用硬件观察点监控数据类型占用字节数较多的变量(表达式)。比如说,某些操作系统中,GDB 调试器最多只能监控 4 个字节长度的数据,这意味着 C、C++ 中 double 类型的数据是无法使用硬件观察点监测的。这种情况下,可以考虑将其换成占用字符串少的 float 类型。
目前,大多数 PowerPC 或者基于 x86 的操作系统,都支持采用硬件观点。并且 GDB 调试器在建立观察断点时,会优先尝试建立硬件观察点,只有当前环境不支持硬件观察点时,才会建立软件观察点。借助如下指令,即可强制 GDB 调试器只建立软件观察点:
set can-use-hw-watchpoints 0
注意,在执行此令之前建立的硬件观察点,不会受此令的影响。
注意,awatch 和 rwatch 令只能设置硬件观察点,如果系统不支持或者借助如上令禁用,则 GDB 调试器会打印如下信息:
Expression cannot be implemented with read/access watchpoint.
- 随机文章
- 国足 马尔代夫 直播(国足客场与马尔代夫一决胜负,比赛实况直播!)
- 长沙 直飞 马尔代夫(长沙往返马尔代夫直飞,畅游印度洋蓝湛海!)
- 马尔代夫微拉瓦鲁(马尔代夫发现微型岛屿米拉瓦鲁)
- 中国国徽马尔代夫(中马友谊深,中国国徽在马尔代夫展示)
- 马尔代夫海洋风(马尔代夫海域的浪漫海洋纷呈景色)
- 龙华大朗马尔代夫(马尔代夫旅游胜地龙华大朗体验指南)
- 马尔代夫首都房价(马尔代夫首都房价攀升,涨幅超预期)
- 塞班 马尔代夫 长滩(三地海岛游比较,塞班、马尔代夫、长滩,你更喜欢哪一个?)
- 中国德阳马尔代夫(中国德阳市建立马尔代夫友好城市关系)
- 即墨马尔代夫分带(即墨建设中国第一家马尔代夫主题公园)
- 马尔代夫出动军舰(马尔代夫派遣军舰应对局势升级)
- 裙子 马尔代夫(重温度假时光 与马代沙滩回荡裙角轻摆)
- 联通 马尔代夫 资费(联通推出马尔代夫特惠套餐,畅享低价高速网络)
- 印度马尔代夫女足(印度女足在马尔代夫获胜,赢得友谊赛)
- 如何搜索马尔代夫(如何用关键词搜索马尔代夫旅游信息?)
- 壁纸桌面马尔代夫(探索马尔代夫:美丽海岛桌面壁纸推荐)
- 小毕 马尔代夫(小毕的马尔代夫之旅)
- 南京 飞 马尔代夫(南京直飞马尔代夫的旅行攻略)
- 中国 马尔代夫 男足(男足亚洲杯预选赛:中国客场1-0小胜马尔代夫)
- 去马尔代夫旅行团(探寻马尔代夫:迎接天堂般的海滩之旅)
- 武汉马尔代夫花园(武汉马尔代夫花园:仿若身处海岛天堂)
- 印尼 马尔代夫(印尼和马尔代夫:南洋度假胜地)
- 辽宁 马尔代夫(辽宁游客赴马尔代夫漫步白沙滩 成旅游新热点)
- 潭头 马尔代夫(重返蓝色梦境:潭头探秘马尔代夫)
- 海浪席卷马尔代夫(马尔代夫受到强烈海浪袭击,局势紧急)
- 印度进攻马尔代夫(印度袭击马尔代夫,制造地区紧张情势)
- 自由潜泳马尔代夫(自由潜水探秘马尔代夫的壮丽海底世界)
- 中国 马尔代夫 进球集锦(中国 vs 马尔代夫:精彩进球集锦回顾)
- 惠安 马尔代夫(惠安旅行社推出马尔代夫度假套票)
- 谢晖头球马尔代夫(谢晖头球绝杀马尔代夫,国足三连胜。)
