对于我当前的嵌入式应用程序,我尝试将 GDB 观察点放在固定的内存地址。
作为示例,我的应用程序更新以下地址:0x10793ad0。为了确定代码的哪一部分破坏了值,我尝试了
watch 0x10793ad0
即使 GDB 在此之后不会打印任何错误,但它也无法在执行过程中中断,即使我验证了该值在执行开始和结束之间进行了修改。
问题:
在地址上设置观察点的正确方法是watch *0x10793ad0。请参阅gdb 文档
-l/-location
示例
在这个答案中,我想进一步强调 Nathan Kidd 在评论中提到的
-l/-location
选项。
如果您不使用此选项,则执行以下操作:
watch mylocalvar
一旦
mylocalvar
超出范围,GDB 就会中断,并自动删除该内存观察点。
因此,当您知道某个值只有一个实例通过引用传递时(通常是类似于
-l
的 this
),
struct
会非常有用。考虑:
main.c
typedef struct {
int i;
} MyThing;
void MyThing_init(MyThing *s, int i) {
i += 1;
s->i = i;
i += 2;
i += 3;
}
int MyThing_get_i(MyThing *s) {
return s->i;
}
int main(void) {
MyThing s;
MyThing_init(&s, 1);
MyThing_init(&s, 2);
MyThing_init(&s, 3);
MyThing_init(&s, 4);
return MyThing_get_i(&s);
}
编译和调试:
gcc -ggdb3 -O0 -o main.out main.c
gdb -nh -ex 'tb MyThing_init' -ex r main.out
此页位于:
6 i += 1;
现在如果我们这样做:
watch s->i
它显示在:
(gdb) i b
Num Type Disp Enb Address What
2 hw watchpoint keep y s->i
然后第一个
c
在根据需要修改变量后停止:
(gdb) c
Continuing.
Hardware watchpoint 2: s->i
Old value = 0
New value = 2
MyThing_init (s=0x7fffffffccb4, i=2) at main.c:8
8 i += 2;
但是当
c
返回时第二个
MyThing_init
停止并向我们解释它删除了观察点:(gdb) c
Continuing.
Watchpoint 2 deleted because the program has left the block in
which its expression is valid.
main () at main.c:19
19 MyThing_init(&s, 2);
我们可以通过以下方式确认:
(gdb) i b
No breakpoints or watchpoints.
因此再次使用
c
运行程序将一直运行直到退出。
但是如果我们改用-l
:
watch -l s->i
在
i b
下显示为:
(gdb) i b
Num Type Disp Enb Address What
2 hw watchpoint keep y -location s->i
那么观察点不会被删除,并且我们每次调用都会中断:
(gdb) c
Continuing.
Hardware watchpoint 2: -location s->i
Old value = 2
New value = 3
MyThing_init (s=0x7fffffffccb4, i=3) at main.c:8
8 i += 2;
(gdb) c
Continuing.
Hardware watchpoint 2: -location s->i
Old value = 3
New value = 4
MyThing_init (s=0x7fffffffccb4, i=4) at main.c:8
8 i += 2;
(gdb) c
Continuing.
Hardware watchpoint 2: -location s->i
Old value = 4
New value = 5
MyThing_init (s=0x7fffffffccb4, i=5) at main.c:8
8 i += 2;
(gdb) c
Continuing.
Hardware watchpoint 2: -location s->i
Old value = 5
New value = 32767
0x00007ffff7c44fd6 in __run_exit_handlers (status=5, listp=0x7ffff7dfe860 <__exit_funcs>, run_list_atexit=run_list_atexit@entry=true, run_dtors=run_dtors@entry=true) at ./stdlib/exit.c:43
43 ./stdlib/exit.c: No such file or directory.
此技术与Mozilla rr 反向调试
结合使用时特别强大,因为通常会发生的情况是您处于失败点,例如:
b MyThing_get_i
并且您注意到某事物的错误值,例如
s->i
,然后您想知道设置该错误值的最后一件事是什么。一旦进入
rr
,您可以立即回答:watch -l s->i
rc
在 Ubuntu 23.10、GCC 13.2.0 上测试。 GDB 14.