gdb.md
GDB 调试
0. pre work
在一些文章中看到需要在编译的时候加入-g的参数才能进行调试
加入gdb参数的编译指令如下
1 | gcc -g -o hello hello.c |
0.1 check file
我们可以使用readelf对elf文件进行查看,使用grep我们可以抓取到我们想要的信息
1 | linux readelf -S hello|grep plt |
编译产生可执行文件后对其进行调试
按道理说到这里我们已经可以看出这个程序是否是可以调试的,但是原文的作者还教会了我们另外一种方式
file hello|grep strip
在得到的信息中如果显示not stripped说明调试相关的信息没有被抹除,还保存在文件中,否则不能进行调试
1 Start debug
首先让我们写一个helloworld
1 |
|
按照上文所说启动调试之后就可以start了
1.1 Run
run的基本用法和我们平时执行是差不多的,在提供了arg的情况下可以直接使用run + args的形式进行运行
1 | (gdb) run |
也可以提前设置好arg的参数
1 | (gdb) set args SSR |
1.2 调试core文件
当我们在机器中执行ulimit -c
可以查看系统是否对core文件的产生进行限制
如果结果为0,那么当程序结束的时候也不会有core文件产生。
此时我们需要进行如下的设置
对core的调试waiting
2 断点调试
2.1 查看已经存在的断点
1 | (gdb) info breakpoints |
2.2 设置断点
2.2.1 在第i行设置一个断点
1 | b 9 |
2.2.2 为一个函数设置一个断点
b [function name] 实现了在函数执行处设置断点
1 | (gdb)b add |
2.2.3 根据条件设置断点
1 | (gdb) b 10 if x==11 |
2.2.4 根据规则设置断点
1 | rbreak printNum* |
这样就可以在所有符合规则的地方设置断点
其他断点的设置方式参考 link
2.3 清除断点
禁用或启用断点
如果加入了编号,就说明是对某一个断点进行操作,如果不仅爱如数字,就说明是对所有的断点进行的操作
1 | (gdb)disable bnum |
断点的清除
clear + linenum/function name/filename: function name
1 | (gdb) clear add |
3.变量查看
普通变量的查看
准备好之前的调试工具后,在相应的位置设置断点,然后在该位置程序会停下
此时p varname
可以显示变量的值
1 | Breakpoint 4, main (argc=1, argv=0x7fffffffde58) at hello.c:10 |
指针/数组的查看
如果你直接p pointname, 得到的将是地址
1 | (gdb) p p1 |
想要打印数组的名字,必须使用p *pointname
(只打印第一个数字)
如果想要限定输出的数字,则需要p *pointname@num
(将会打印数组中的前num个元素
)
其中值得注意的一点是我们的数组名和指针其实是不同的,在gdb的打印中打印一个数组名输出的是整个数组,而打印指针输出的是地址,数组名是一种直接的访问,是真实的地址,但是对于我们的指针而言,得到的将是一个地址,运行这个地址我们可以得到真实内存所在的地方。
设置我们自己的变量
在调试的过程中,我们可以通过set指令去设置一个变量
1 | (gdb) set $index = 1 |
进行函数的调试
1 |
|
使用上面的代码作为例子
在对函数进行调试的时候,我们需要在函数中设置断点,然后在调用处使用step
指令进入该函数的主体中。
If we use the stepi
,it will go in the machine code
调试中的跳转
command | role |
---|---|
continue | go to the next breakpoint |
until | go to the specific line |
监控变量的变化
1 | (gdb) wathc varname |
每次变量有变化的时候程序都会停止执行