我的程序使用
char heap[]
数组作为堆的表示,它可能包含不同大小的值。对于这个问题,最值得注意的是, (uint16_t*) &heap[0]
和 (uint16_t*) &heap[2]
处的值是两个 16 位值。
我希望在第二个值上设置一个观察点,并在达到某个值时中断。在这种情况下,第二个值是一个正在倒计时的计数器,我希望在它达到例如零时中断(但出于当前的测试目的,我使用
9998
)。
这就是我的 C 程序的样子(将其放入
test.c
并使用 gcc -g -o mainh test.c
进行编译)
#include <stdint.h>
#include <stdlib.h>
#define HEAP_SIZE 65536
char heap[HEAP_SIZE];
void proc0();
void proc1();
void proc0()
{ }
void proc1()
{ }
void main()
{
*(uint16_t *) &heap[0] = (uint16_t) 4;
proc0();
exit(0);
}
我的框架生成一个GDB文件来安装一些断点并修改这两个值,GDB毫无问题地接受它们。我遇到的问题是首先安装的观察点永远不会被执行。 (将以下命令放入
commandsh.txt
)
watch *(uint16_t*) &heap[2]
cond 1 *(uint16_t*) &heap[2] == 9998
commands
set *(uint16_t*) &heap[0] = 50
p *(uint16_t*) &heap[0]
continue
end
break proc0
commands
set *(uint16_t*) &heap[2] = (*(uint16_t*) &heap[2]) - 1
c
end
run
q
断点安装在
main
、exit
和proc0
,但只有proc0
与我遇到的问题相关,所以其余的都被省略了。 proc0
断点正确触发并将 (uint16_t *) &heap[2]
处的值从初始 9998
减少到 9999
。但是,观察点及其条件永远不会触发,使第一个值保持不变 4
,而我希望它是 50
。 (通过从 bash 运行 gdb -q -x commandsh.txt mainh
来执行命令)
运行 GDB 时的输出显示观察点永远不会中断,并且不会打印指示的堆地址处的值:
Reading symbols from mainh...
Hardware watchpoint 1: *(uint16_t*) &heap[2]
Breakpoint 2 at 0x1151: file test.c, line 8.
This GDB supports auto-downloading debuginfo from the following URLs:
https://debuginfod.ubuntu.com
Enable debuginfod for this session? (y or [n]) [answered N; input not from terminal]
Debuginfod has been disabled.
To make this setting permanent, add 'set debuginfod enabled off' to .gdbinit.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Breakpoint 2, proc0 () at test.c:8
8 { }
[Inferior 1 (process 146113) exited normally]
我怀疑问题与我的语法有关,并尝试将观察点更改为
watch {uint16_t} &heap[2]
cond 1 {uint16_t} &heap[2] == 9998
commands
set {uint16_t} &heap[0] = 50
continue
end
但这并没有改变什么。我做错了什么?
问题在于,当正在调试的程序更改值时,观察点会起作用。
当它不是程序时,它们不工作,但 GDB 本身正在执行更改(正如这里所发生的那样)。
还有其他类似的“错过观察点”的情况,例如内核写入内存:
int fd = open("/dev/zero", ...);
char buf[1] = 'a'; // set a watchpoint on location of buf[0]
read(fd, buf, 1); // buf[0] is now changed, but watchpoint doesn't "fire".