gdb使用watch命令设置数据断点

前言

“数据断点”这个说法是沿用在Visual Studio中学到的设置断点的方法,在gdb中一般被叫做“硬件断点”,算是断点调试中一种较为高级的调试方法了,这个方法起初是在VS中学会的,属于有需求必有响应的产物。刚开始调试程序的时候只会设置普通断点,就是在要调试的程序代码所在行设置断点,然后等程序运行到断点处可以单步执行,查看内存变量,遇到多个位置修改一个变量并且要查看是谁改变了变量的时候,就要设置多个断点,当时就想如果可以设置一个断点,当变量值被改变就触发这个断点那该多好啊。

当年果然是太年轻,后来发现这个功能就是VS中的数据断点,同样作用的还有gdb工具的中硬件断点,硬件断点不仅可以处理上面提到的需求,更是查找内存写超过的强大工具,要想知道一个正常的变量如何被“不正常”地修改了,硬件断点可以说是最佳工具了。

数据变化断点

在gdb工具中设置普通断点的语法是b 变量名/函数名/文件位置,设置数据变化断点(硬件断点)语法也很简单,只需要一个watch命令即可,写法为watch 变量名,但是与普通断点不同的是,数据断点必须在程序运行时设置,在敲入r命令之前对变量设置数据断点会提示找不到符号。

编写测试程序代码

  • 首先新建测试文件watchtest.cpp然后添加下面的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #include <iostream>
    using namespace std;

    int main()
    {
    int k = 1;
    int n;

    n = 1;
    k = 2;
    cout << n << "," << k << endl;

    n = 3;
    k = 4;
    cout << n << "," << k << endl;

    return 0;
    }
  • 将C++源代码编译成可执行文件,为了调试记得加-O0 -g选项

    1
    [albert@localhost#17:08:00#/home/albert/test]$g++ watchtest.cpp -O0 -g -o watchtest

加数据断点并调试

以下为gdb添加数据变化断点(硬件断点)并调试的整个过程,(gdb)后面的内容为敲入的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
[albert@localhost#17:52:47#/home/albert/test]$gdb watchtest
GNU gdb (GDB) Red Hat Enterprise Linux (7.2-83.el6)
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/albert/test/watchtest...done.
(gdb) b watchtest.cpp : 6
Breakpoint 1 at 0x40085c: file watchtest.cpp, line 6.
(gdb) watch n
No symbol "n" in current context.
(gdb) r
Starting program: /home/albert/test/watchtest

Breakpoint 1, main () at watchtest.cpp:6
6 int k = 1;
Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.209.el6_9.2.x86_64 libstdc++-4.4.7-23.el6.x86_64
(gdb) watch n
Hardware watchpoint 2: n
(gdb) c
Continuing.
Hardware watchpoint 2: n

Old value = 0
New value = 1
main () at watchtest.cpp:10
10 k = 2;
(gdb) c
Continuing.
1,2
Hardware watchpoint 2: n

Old value = 1
New value = 3
main () at watchtest.cpp:14
14 k = 4;
(gdb) c
Continuing.
3,4

Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
0x00007ffff72c6d1d in __libc_start_main () from /lib64/libc.so.6
(gdb) q
A debugging session is active.

Inferior 1 [process 18567] will be killed.

Quit anyway? (y or n) y
[albert@localhost#17:55:04#/home/albert/test]$

总结

  • 设置数据断点需要在程序启动之后,在运行r命令之前设置断点给出信息:No symbol "n" in current context.
  • 当程序运行到监控变量的作用域之外以后,断点自动被删除,这一点观察执行q命令之前的文字可以看出
  • 添加数据变化断点(硬件断点)格式:watch 变量名
Albert Shi wechat
欢迎您扫一扫上面的微信公众号,订阅我的博客