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.out
l
(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 = 12
call func()
调用程序中的函数, 通常是调试目的的函数define <宏名称>
, 在接下来的行中描述宏命令, 以新一行的end
结尾
更改代码之后, 重新编译, 不需要退出 gdb
, 它会自动检测到二进制文件更改