GDB 学习笔记
2023-08-15 20:36:00
# Tools
1. 常见调试策略
1.1 确认
- 你相信某个变量有某个确定的值
- 你相信在给定的
if-then-else语句中,else语句是被执行的部分 - 你相信当你调用某个函数的时候, 该函数会正确接收其参数
找 bug 的过程就是确认上述所有事情
1.2 二分
根据代码行数二分, 在 mid 的位置确认上述事情, 进而缩小范围
1.3 甚至无法通过编译
删除代码直到不产生编译错误, 再逐步缩小删除的代码范围, 进而确认错误的具体位置
2. 使用调试工具和一个好的文本编辑器
2.1 不要使用 print 大法作为主要调试手段
你可能在代码中间添加 print 语句从而检查变量的值
这样很不方便, 你需要重新编译所有文件, 改完 bug 还要逐一删除
调试工具不需要重新编译, 而且还可以自动追踪所有变量
而且它还可以告诉你段错误等致命错误发生的位置
2.2 工具
- 调试工具
gdb最常用的调试工具, 并不一定是最好ddd是基于 $GUI$ 界面的gdb
不过建议先使用 $TUI$ 界面的gdb
- 编辑器: 最好支持
undo,redo, 多窗口等功能 IDE: 有时, 调试器会集成在IDE中
3. 如何使用 gdb
基本策略: 设置断点, 然后往下逐步执行代码, 并随时检测变量的值
3.1 常用命令
首先确认编译的时候使用 -g 命令
1 | gcc -g file.c |
- 开始和结束调试:
- 开始调试
gdb <可执行文件> - 退出调试
q
- 开始调试
r(run), 正常运行程序后面要加的参数也要加进来r < a.in > a.outl(list)- 单个文件后面加行号表示列出某行, 回车键继续向下滚动
- 多个文件
l a.b.c:55 - 可以指定函数名从而列出函数
b(breakpoint),c(continue)b- 第一参数是位置, 表示在哪行或者哪个函数位置打断点, 同
l - 第二参数是条件, 条件断点:
b main if x > 0
- 第一参数是位置, 表示在哪行或者哪个函数位置打断点, 同
c表示断点过后继续执行disable <断点编号>表示取消断点
disp(display),p(print)disp <变量名>表示每次运行都要显示这个变量, 用undisp <编号>取消p <变量名>只打印一次,p /x <变量名>表示使用十六进制输出printf "X = %d, Y = %d\n", X, Y, 相当于C的printf去掉括号
x/nfu <地址>- n 表示多少内存单元
- f 表示输出格式(同 C 语言)
- u 表示多少个字节组成一个内存单元, 默认为 4
n(next),s(step)n向下执行一步, 但不会进入调用的函数内部s向下执行一步, 如果调用了函数就会跳转到函数第一行si,ni执行汇编代码
bt(backtrace): 查看堆栈信息, 可能会在未知问题上生效set改变程序中变量的值:set variable x = 12call func()调用程序中的函数, 通常是调试目的的函数define <宏名称>, 在接下来的行中描述宏命令, 以新一行的end结尾
更改代码之后, 重新编译, 不需要退出 gdb, 它会自动检测到二进制文件更改