watchpoint介紹
watchpoint(觀察點):
很多情況下,程序的bug是由於某個變量或地址被莫名修改而導致的,但是具體什么時候修改了該值,我們很難定位到。使用傳統的方法只能一步一步去調試跟蹤程序,傷神費力,調試效率特別低。
gdb提供了觀察點watchpoint功能,可以監控程序中變量或表達式的值,只要在運行過程中發生改變,程序就會停止執行。可以說學會watchpoint,能夠實現讓bug自動現身的效果。
觀察點適用場景:
- 由於變量值異常變化導致的bug。
- 確定了某個異常變量,但是該變量被多次使用、還會在各種循環內被操作。
- 多線程場景,線程切來切去,不知道變量具體被哪個線程修改了。
watchpoint命令
命令 | 含義 |
---|---|
watch a | 觀察變量a |
watch a*b+c | 觀察表達式a*b+c |
watch *0x123456 | 觀察地址0x123456 |
info watchpoints | 查看觀察點 |
delete num | 根據編號num刪除觀察點 |
disable num | 根據編號num禁用觀察點 |
enable num | 根據編號num啟用觀察點 |
watchpoint使用方法
測試用例test_watchpoint.c
:
1 /*================================================================
2 * Author: LiuHanxu
3 * Date: 2022-06-11
4 * Description:
5 ================================================================*/
6 #include <stdio.h>
7
8 int main()
9 {
10 int a = 1, b = 2, c = 3;
11 printf("before: a = %d, b = %d, c = %d\n", a, b, c);
12 int* ptr = &c;
13 for(int i=0; i<=100; i++)
14 {
15 if (i == 66)
16 a = 0;
17 if (i == 88)
18 b = 0;
19 if (i == 99)
20 *ptr = 123;
21 }
22 printf("after: a = %d, b = %d, c = %d\n", a, b, c);
23 return 0;
24 }
觀察變量watch a
給變量a設置觀察點,然后繼續運行,當a被修改后程序就停止運行,可以看出當循環變量i為66時,將a的值改為了0。因此,我們就很快定位到程序第16行改變了變量值,程序停到17行。
lhx@ubuntu:~/test_notes$ gdb ./test_watchpoint
Reading symbols from ./test_watchpoint...
(gdb) b main
Breakpoint 1 at 0x1169: file test_watchpoint.c, line 9.
(gdb) r
Starting program: /home/lhx/test_notes/test_watchpoint
Breakpoint 1, main () at test_watchpoint.c:9
9 {
(gdb) n
10 int a = 1, b = 2, c = 3;
(gdb) n
11 printf("before: a = %d, b = %d, c = %d\n", a, b, c);
(gdb) watch a
Hardware watchpoint 2: a
(gdb) c
Continuing.
before: a = 1, b = 2, c = 3
Hardware watchpoint 2: a
Old value = 1
New value = 0
main () at test_watchpoint.c:17
17 if (i == 88)
(gdb) i loc
i = 66
a = 0
b = 2
c = 3
ptr = 0x7fffffffe280
觀察表達式watch b+2*c
觀察表達式b+2*c
,每次當表達式的值發生變化,程序就會暫停。通過下面調試結果發現在第18行時b的值改變導致表達式變化,第20行時c的值發生改變(此處是通過指針ptr修改c的值,所以gdb會定位到第12行,能發現循環變量i的值是99)。
lhx@ubuntu:~/test_notes$ gdb ./test_watchpoint
Reading symbols from ./test_watchpoint...
(gdb) b main
Breakpoint 1 at 0x1169: file test_watchpoint.c, line 9.
(gdb) r
Starting program: /home/lhx/test_notes/test_watchpoint
Breakpoint 1, main () at test_watchpoint.c:9
9 {
(gdb) n
10 int a = 1, b = 2, c = 3;
(gdb) n
11 printf("before: a = %d, b = %d, c = %d\n", a, b, c);
(gdb) n
before: a = 1, b = 2, c = 3
12 int* ptr = &c;
(gdb) n
13 for(int i=0; i<=100; i++)
(gdb) watch b+2*c
Hardware watchpoint 2: b+2*c
(gdb) c
Continuing.
Hardware watchpoint 2: b+2*c
Old value = 8
New value = 6
main () at test_watchpoint.c:19
19 if (i == 99)
(gdb) c
Continuing.
Hardware watchpoint 2: b+2*c
Old value = 6
New value = 246
main () at test_watchpoint.c:13
13 for(int i=0; i<=100; i++)
(gdb) i loc
i = 99
a = 0
b = 0
c = 123
ptr = 0x7fffffffe280
(gdb) c
Continuing.
after: a = 0, b = 0, c = 123
......
觀察地址watch *0x7fffffffe280
觀察變量c的地址,找出哪里修改變量c的值。通過命令watch *0x7fffffffe280
觀察變量c的地址,定位到程序第12行修改了該地址,gdb顯示的下一行為13行,可以看到循環變量i為99。
lhx@ubuntu:~/test_notes$ gdb ./test_watchpoint
Reading symbols from ./test_watchpoint...
(gdb) b 13
Breakpoint 1 at 0x11bd: file test_watchpoint.c, line 13.
(gdb) r
Starting program: /home/lhx/test_notes/test_watchpoint
before: a = 1, b = 2, c = 3
Breakpoint 1, main () at test_watchpoint.c:13
13 for(int i=0; i<=100; i++)
(gdb) i loc
i = 21845
a = 1
b = 2
c = 3
ptr = 0x7fffffffe280
(gdb) watch *0x7fffffffe280
Hardware watchpoint 2: *0x7fffffffe280
(gdb) c
Continuing.
Hardware watchpoint 2: *0x7fffffffe280
Old value = 3
New value = 123
main () at test_watchpoint.c:13
13 for(int i=0; i<=100; i++)
(gdb) i loc
i = 99
a = 0
b = 0
c = 123
ptr = 0x7fffffffe280