1.debug版本的文件才能调试
gcc默认编译生成的是release版本,在输入gcc编译指令时,要加-g,才会生成debug版本的可执行文件。
可以看到,code_dbug比code大,因为debug版本含有调试信息,往往比release版本的数据大。我们用readelf指令查看一下可执行文件中debug的信息 。
我们在code中查看带有debug的信息(忽略大小写),没有找到,但在code_dbug文件中找到了一系列的调试信息。
所以当我们想调试一个文件时,必须生成它的debug版本。
2. 开始调试
我们新建一个目录test_gdb,创建makefile和mycode.c。
创建可执行文件mycode。
输入gdb mycode。进入gdg调试交互环境。
输入q或quit退出交互环境。
1.list指令(缩写l):显示代码
输入list或l可以查看代码, 如果要看某行代码,比如第五行代码,可输入l 5。
同时一直按回车建,gdb会执行上一次命令的操作,就会一直展示代码知道展示完。
如果要查看某个函数,可以输入l+函数名。
2.run/r指令:运行程序
从开始连续而非单步执行程序。
3.break/b:设置断点
break(b) 行号:在某一行设置断点break
函数名:在某个函数开头设置断点
这样我们就打了三个断点,分别在19、20、24行。
我们也可以对函数打断点,
还可以对文件中某行或,某个函数打断点,
4.info break(b):查看断点信息
Num就是断点的序号。如果要删除一个断点,必须通过Num删除。
5.delete/n:删除序号为n的断点
比如,我要删除序号为2的断点,
注意:如果我们在调试中途退出调试,那么这次调试的信息包括断点信息都会被gdb自动清除,下次调试又要重新设置断点。
注意:因为是19行是空行,gdb会自动跳过空白行赚到最近的有效语句行,所以断点1和断点2地址相同。
6.逐过程调试指令:next/n
打完断点后,我们r,启动程序,会自动跳转到离main函数最近断点的最近有效行。
现在我们输入n,就是逐过程调试,不会进入内嵌函数块中。
如果我们不输入指令按回车,gdb会默认执行上一个指令。所以我们在第一次输入n后,可以一直按回车,直到显示,这样就调试到程序运行结束了(估计bug还没找到)。
现在我们在info b,会发现每个断点下都显示断点命中次数。
7.逐语句调试指令:step/s
我们删除序号1的断点,在18行添加 一个断点, 开始调试,r
如果我们想逐语句调试,想进入addToTop函数内部,输入s即可,
然后我们可以一直按回车,就会逐语句调试,注意:如果语句已经是最基本的C式语言了,逐语句无法进入C非自定义函数内部,逐语句就相当于逐过程。
这样我们就进入addToTop函数内部的for循环中。
8.查看变量的值/地址:print/p
如果我们在调试过程中要查看某个变量,只要输入p+变量名。
但这样调试下一句,就又要重新输入p i。
所以我们可以用display。
9.常显示(跟踪)变量:disolay
我们只要将要跟踪的变量用display修饰,每一次调试都会打印变量的值。
那么如何取消“常显示”呢?
10.取消对先前设置的变量的跟踪:undisplay
我们可以用指令undisplay + “常显示序号”,注意,这里是“+ 变量名”。
11.跳转所需行:until n(n是行号)
12.执行完当前函数:finish
13.执行到下一个断点:continue/c
从当前位置开始连续而非单步执行到下一个断点,直到没有断点程序执行结束。这不是跳跃性执行,两个断点间的函数语句都会按语法规则连续性执行。
14.禁用断点:disable
从1号断点直接跳到3号断点,因为2号断点被禁用了。
禁用后的断点信息中“End”选项就是n,没有禁用就是y。
15.启用禁用的断点:enbale
16.修改变量的值: set var
相当于条件断点。
17.查看各级函数调用及参数:breaktrace/bt
18.查看当前栈帧局部变量的值:info(i) locals