我正在通过 gdb 运行应用程序,并且我想在任何时候访问/更改特定变量时设置断点。有没有这样做的好方法?我也对在 C/C++ 中监视变量以查看它是否/何时更改的其他方法感兴趣。
6 回答
watch只在写时中断,rwatch让你在读时中断,awatch让你在读/写时中断。
您可以在内存位置设置读取观察点:
gdb$ rwatch *0xfeedface
Hardware read watchpoint 2: *0xfeedface
但一个限制适用于 rwatch 和 awatch 命令;您不能在表达式中使用 gdb 变量:
gdb$ rwatch $ebx+0xec1a04f
Expression cannot be implemented with read/access watchpoint.
所以你必须自己扩展它们:
gdb$ print $ebx
$13 = 0x135700
gdb$ rwatch *0x135700+0xec1a04f
Hardware read watchpoint 3: *0x135700 + 0xec1a04f
gdb$ c
Hardware read watchpoint 3: *0x135700 + 0xec1a04f
Value = 0xec34daf
0x9527d6e7 in objc_msgSend ()
编辑:哦,顺便说一句。您需要硬件或软件支持。软件显然要慢得多。要了解您的操作系统是否支持硬件观察点,您可以查看can-use-hw-watchpoints环境设置。
gdb$ show can-use-hw-watchpoints
Debugger's willingness to use watchpoint hardware is 1.
您要查找的内容称为watchpoint。
用法
(gdb) watch foo
: 观察变量的值 foo
(gdb) watch *(int*)0x12345678
:观察地址指向的值,转换为你想要的任何类型
(gdb) watch a*b + c/d
:观察任意复杂的表达式,在程序的母语中有效
观察点分为三种:
- watch : 发生写入时gdb 将中断
- rwatch:gdb 将在发生读取时中断
- awatch : gdb 在这两种情况下都会中断
您可以选择更适合您需要的。
有关更多信息,请查看此内容。
假设第一个答案是指类似 C 的语法(char *)(0x135700 +0xec1a04f)
,那么答案rwatch *0x135700+0xec1a04f
是不正确的。正确的语法是rwatch *(0x135700+0xec1a04f)
.
那里缺少()
s 给我自己尝试使用观察点带来了很大的痛苦。
我刚刚尝试了以下方法:
$ cat gdbtest.c
int abc = 43;
int main()
{
abc = 10;
}
$ gcc -g -o gdbtest gdbtest.c
$ gdb gdbtest
...
(gdb) watch abc
Hardware watchpoint 1: abc
(gdb) r
Starting program: /home/mweerden/gdbtest
...
Old value = 43
New value = 10
main () at gdbtest.c:6
6 }
(gdb) quit
所以这似乎是可能的,但你似乎确实需要一些硬件支持。
如上所述,使用 watch 查看何时写入变量,读取时使用 rwatch,读取/写入时使用 awatch。但是,请注意,要使用此命令,您必须中断程序,并且当您中断程序时,变量必须在范围内:
使用 watch 命令。watch 命令的参数是一个被计算的表达式。这意味着您要设置观察点的变量必须在当前范围内。因此,要在非全局变量上设置观察点,您必须设置一个断点,当变量在范围内时将停止您的程序。您在程序中断后设置观察点。
起初我没有读明白,为什么我们需要转换结果。虽然我读到了这个:https ://sourceware.org/gdb/onlinedocs/gdb/Set-Watchpoints.html ,但它对我来说并不直观......
所以我做了一个实验让结果更清楚: 代码:(假设 int main() 在第 3 行; int i=0 在第 5 行,其他代码.. 来自第 10 行)
int main()
{
int i = 0;
int j;
i = 3840 // binary 1100 0000 0000 to take into account endianness
other code..
}
然后我第一次尝试使用可执行文件启动 gdb,我在变量的位置设置断点而不进行强制转换,以下是显示的结果
Thread 1 "testing2" h
Breakpoint 2 at 0x10040109b: file testing2.c, line 10.
(gdb) s
7 i = 3840;
(gdb) p i
$1 = 0
(gdb) p &i
$2 = (int *) 0xffffcbfc
(gdb) watch *0xffffcbfc
Hardware watchpoint 3: *0xffffcbfc
(gdb) s
[New Thread 13168.0xa74]
Thread 1 "testing2" hit Breakpoint 2, main () at testing2.c:10
10 b = a;
(gdb) p i
$3 = 3840
(gdb) p *0xffffcbfc
$4 = 3840
(gdb) p/t *0xffffcbfc
$5 = 111100000000
正如我们所见,我设置的第 10 行出现断点。gdb 没有中断,因为尽管变量 i 经历了更改,但被监视的位置没有改变(由于字节序,因为它继续保持全 0)
在我的第二次尝试中,我对变量的地址进行了强制转换以监视所有 sizeof(int) 字节。这次:
(gdb) p &i
$6 = (int *) 0xffffcbfc
(gdb) p i
$7 = 0
(gdb) watch *(int *) 0xffffcbfc
Hardware watchpoint 6: *(int *) 0xffffcbfc
(gdb) b 10
Breakpoint 7 at 0x10040109b: file testing2.c, line 10.
(gdb) i b
Num Type Disp Enb Address What
6 hw watchpoint keep y *(int *) 0xffffcbfc
7 breakpoint keep y 0x000000010040109b in main at testing2.c:10
(gdb) n
[New Thread 21508.0x3c30]
Thread 1 "testing2" hit Hardware watchpoint 6: *(int *) 0xffffcbfc
Old value = 0
New value = 3840
Thread 1 "testing2" hit Breakpoint 7, main () at testing2.c:10
10 b = a;
gdb break 因为它检测到值已更改。