GDB调式工具学习笔记---断点

GDB调式工具学习笔记---断点


在前文,作者学习到了GDB调试工具单步执行和跟踪函数调用的功能,但是很多时候我们会面临这么一种局面,那就是我们代码量超级大,而且我们已经可以通过经验大概确定BUG出现的范围,只是不确定具体位置,此时如果只是使用之前的技巧,从main函数开始一步一步的往下执行,作者选择回家种地,开个玩笑,因为作者种地都不会。。。咳咳,所以断点的出现就很有必要,我们只需要在我们怀疑的代码段之前打上一个断点,gdb调试工具运行到断点的时候,会暂停住等待我们的下一步指令,下面就让我们一起来学习,出来吧,就是你了——皮卡丘。。。(GDB之断点)。

2.断点

2.1 示例代码

还是熟悉的地点,还是熟悉的配方,今天老八。。。今天作者给大家表演一个手撕代码,兄弟们,奥里给。

#include <stdio.h>

int main(void)
{
        int sum = 0, i = 0;
        char input[5];

        while(1)
        {
                scanf("%s", input);
                for(i=0; input[i]!='\0'; i++)
                {
                        sum = sum * 10 + input[i] - '0';
                }
                printf("res = %d\n", sum);
        }
        return 0;
}

上述代码的功能,作者说了一堆,其实就是将字符串数字转换成整型数字,即"123"===>123。我们编译运行一下,看看输出结果。

zz@ubuntu:~/Project/gdb_study$ vim demo2.c
zz@ubuntu:~/Project/gdb_study$ zz@ubuntu:~/Project/gdb_study$ gcc -g demo2.c -o demo2
zz@ubuntu:~/Project/gdb_study$ ./demo2
123
res = 123
123
res = 123123
234
res = 123123234

结果一目了然,第一次完全符合我们的预期,但是第二次以后,结果就偏离正常轨道了,这是怎么肥四呢,大佬请闭嘴,因为作者该登场了。

2.2 常用命令

2.2.1 display和undisplay

跟踪显示某个变量的值,使用后者取消跟踪
zz@ubuntu:~/Project/gdb_study$ gdb demo2
...
(gdb) start
Temporary breakpoint 1 at 0x1169: file demo2.c, line 4.
Starting program: /home/zz/Project/gdb_study/demo2

Temporary breakpoint 1, main () at demo2.c:4
4       {
(gdb) i locals
sum = 1431654528
i = 21845
input = "\377\377\177\000"
(gdb) n
5               int sum = 0, i = 0;
(gdb) i locals
sum = 1431654528
i = 21845
input = "\377\377\177\000"
(gdb) display sum
1: sum = 1431654528
(gdb) n
10                      scanf("%s", input);
1: sum = 0

还是熟悉的和书上写得不一样,但是没关系,不影响我们分析,可以看到,程序开始会停留在main函数的’{'处,此时函数局部参数都刚被分配内存,但是值还未被初始化,这是不是说明,即使一个函数的局部参数在定义的时候初始化了,也还是先分配内存在赋值,而不是分配内存的时候就把数值写入了,值得思考,作者回去查一下。

2.2.2 break(b)

给程序添加断点
(gdb) l
5               int sum = 0, i = 0;
6               char input[5];
7
8               while(1)
9               {
10                      scanf("%s", input);
11                      for(i=0; input[i]!='\0'; i++)
12                      {
13                              sum = sum * 10 + input[i] - '0';
14                      }
(gdb) break 10
Breakpoint 2 at 0x555555555192: file demo2.c, line 10.

这里我们使用break 10命令将断点打在程序的第10行,等待下一步命令。

(gdb) break 10
Breakpoint 2 at 0x555555555192: file demo2.c, line 10.
(gdb) continue
Continuing.
123
res = 123

Breakpoint 2, main () at demo2.c:10
10                      scanf("%s", input);
1: sum = 123

2.2.3 continue(c)

连续运行
(gdb)
10                      scanf("%s", input);
1: sum = 0
(gdb) b 10
Breakpoint 2 at 0x555555555192: file demo2.c, line 10.
(gdb) continue
Continuing.
123
res = 123

Breakpoint 2, main () at demo2.c:10
10                      scanf("%s", input);
1: sum = 123
(gdb) continue
Continuing.
234
res = 123234

Breakpoint 2, main () at demo2.c:10
10                      scanf("%s", input);
1: sum = 123234

这里我们可以看到,运行continue命令之后,程序继续向下执行,因为处于while循环之中,所以在此来到了断点处sum的值变为了123,再次执行命令,错误就出现了,这是聪明的我们可以一下就知道了bug出现的地方,咳咳,心机之娃一直摸你肚子,是你sum变量初始化。没错,我们可以清晰的发现第一次运行的之前,sum的值为0,但是执行第二次循环的时候,sum的值为第一次的结果,并未重新赋值为0,这导致了程序的错误,那么为了验证我们的猜想,我们手动将sum设置为0,看看结果是否正确。

(gdb) set var sum=0
(gdb) continue
Continuing.
2345
res = 2345

Breakpoint 2, main () at demo2.c:10
10                      scanf("%s", input);
1: sum = 2345

果然如我们所料,一切尽在掌握中。

2.2.4 disable

暂时禁用某些断点

随着我们进行深入的调试,断点会越来越多,程序运行的时候和便秘一样,搞得我们十分难受,我们希望可以暂时停用一些断点,此时我们可以下怒用info breakpoints命令展示所有的断点,然后使用disable breakpoints 断点号命令暂时停用某些断点。

(gdb) i breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x0000555555555192 in main at demo2.c:10
        breakpoint already hit 3 times
3       breakpoint     keep y   0x00005555555551b3 in main at demo2.c:13
(gdb) disable breakpoints 2
(gdb) continue
Continuing.
123

Breakpoint 3, main () at demo2.c:13
13                              sum = sum * 10 + input[i] - '0';
1: sum = 2345
(gdb)

可以看到在10行的2号断点被我们禁用,执行continue命令后,gdb停在了位于13行的3号断点处。

2.2.6 enble

重新启用断点

人生如戏,断点和恋爱一样,当你有了备胎的时候,你以为原配没用了,你把他抛在一边不管不顾,可是突然有天你发现,对象还是原配好,怎么办,你舔着脸去和原配说:我最爱的还是你,我们和好吧。你会得到两个大嘴巴子,但是断点不会这么对你,断点还爱你。

(gdb) enable breakpoints 2
(gdb) i breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x0000555555555192 in main at demo2.c:10
        breakpoint already hit 3 times
3       breakpoint     keep y   0x00005555555551b3 in main at demo2.c:13
        breakpoint already hit 1 time
(gdb) disable breakpoints 3
(gdb) continue
Continuing.
res = 2345123

Breakpoint 2, main () at demo2.c:10
10                      scanf("%s", input);
1: sum = 2345123
(gdb)

可以看到,这里我们和2号断点重归于好,至于3号断点,我们将它暂时禁用,你问我为什么不永远删除,这我们没法回答你,你懂的。

2.2.5 delete

删除断点

当我们十分确定某个断点是没用的时候,我们要做一个渣男,无情的将它抛弃,相当的无情!!!

(gdb) delete breakpoints 3
(gdb) i breakpoints
Num     Type           Disp Enb Address            What
2       breakpoint     keep y   0x0000555555555192 in main at demo2.c:10
        breakpoint already hit 4 times
(gdb)

2.2.6 run

你删除了小三、小四,哭着说要重新做人,人生不能重来,但是程序可以,命令run可以让程序重新从头运行。

(gdb) i locals
sum = 2345123
i = 3
input = "123\000"
(gdb) run
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/zz/Project/gdb_study/demo2

Breakpoint 2, main () at demo2.c:10
10                      scanf("%s", input);
1: sum = 0
(gdb)

我们可以看到,命令运行之后,果然给你一次重来的机会,重新停在了2号断点出

2.2.7 if

你说你见惯了风雨,玩够了,现在想找个人结婚,安安稳稳,原配被你伤透了,咬牙切齿说除非太阳从西面出来,但是我们可爱的断点不会,它会跑到你面前红着脸,低着头望着脚尖说if sum != 0

(gdb) delete breakpoints 2
(gdb) i breakpoints
No breakpoints or watchpoints.
(gdb) break 10 if sum != 0
Breakpoint 4 at 0x555555555192: file demo2.c, line 10.
(gdb) continue
Continuing.
123
res = 123

Breakpoint 4, main () at demo2.c:10
10                      scanf("%s", input);
1: sum = 123

可以看到,非常简单,你的断点妹妹简直是白给,断点再一次生效,程序再一次停在了断点处,但是你非常的坏,你想挑逗下断点妹妹,你将sum的值手动设置为0,我劝你善良。

(gdb) set var sum=0
(gdb) continue
Continuing.
0
res = 0

q
res = 65

Breakpoint 4, main () at demo2.c:10
10                      scanf("%s", input);
1: sum = 65
(gdb)

程序不知道停在了哪里,但是可以肯定的是,没有陷入死循环,因为作者用top命令监控了cpu和内存的使用情况,并没有爆满,过了一段时间也没有。

2.3 小结

好了,到此该总结以下渣男都用了哪些命令

命令 函数名
break 设置断点(break 行号:在某一行设置断点;break 函数名:在某个函数开头设置断点)
break…if… 当if后面的条件成立,设置断点
continue 从当前开始连续运行
delete 删除断点
display 跟踪显示某个变量
undisable 取消跟踪某个变量
disable 暂时停用某个断点
enable 重新启用某个断点
run 从头运行程序
上一篇:变量


下一篇:javaweb遇到的问题