260

我正在通过 gdb 运行应用程序,并且我想在任何时候访问/更改特定变量时设置断点。有没有这样做的好方法?我也对在 C/C++ 中监视变量以查看它是否/何时更改的其他方法感兴趣。

4

6 回答 6

307

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.
于 2008-09-12T14:35:50.667 回答
38

您要查找的内容称为watchpoint

用法

(gdb) watch foo: 观察变量的值 foo

(gdb) watch *(int*)0x12345678:观察地址指向的值,转换为你想要的任何类型

(gdb) watch a*b + c/d:观察任意复杂的表达式,在程序的母语中有效

观察点分为三种:

  • watch : 发生写入时gdb 将中断
  • rwatch:gdb 将在发生读取时中断
  • awatch : gdb 在这两种情况下都会中断

您可以选择更适合您需要的。

有关更多信息,请查看内容。

于 2015-07-03T08:53:07.877 回答
25

假设第一个答案是指类似 C 的语法(char *)(0x135700 +0xec1a04f),那么答案rwatch *0x135700+0xec1a04f是不正确的。正确的语法是rwatch *(0x135700+0xec1a04f).

那里缺少()s 给我自己尝试使用观察点带来了很大的痛苦。

于 2009-06-08T19:26:38.877 回答
9

我刚刚尝试了以下方法:

 $ 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

所以这似乎是可能的,但你似乎确实需要一些硬件支持。

于 2008-09-12T13:00:06.763 回答
2

如上所述,使用 watch 查看何时写入变量,读取时使用 rwatch,读取/写入时使用 awatch。但是,请注意,要使用此命令,您必须中断程序,并且当您中断程序时,变量必须在范围内:

使用 watch 命令。watch 命令的参数是一个被计算的表达式。这意味着您要设置观察点的变量必须在当前范围内。因此,要在非全局变量上设置观察点,您必须设置一个断点,当变量在范围内时将停止您的程序。您在程序中断后设置观察点。

于 2013-06-26T16:05:37.657 回答
0

除了asksolPaolo M已经回答/评论的内容

起初我没有读明白,为什么我们需要转换结果。虽然我读到了这个: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 因为它检测到值已更改。

于 2022-01-06T16:14:28.483 回答