GDB Quick Start
什么是 GDB
GDB 是 GNU 项目下的一个调试器,它允许在程序运行的时候检查程序内部到底发生了什么。
GDB 可以做到以下事情:
- 开始程序,设置观测参数。
- 在特殊情况下暂停程序执行。
- 当程序停止执行的时候,检查程序状态。
- 修改程序,在修复某个 bug 后可以继续进行测试,寻找其他的 bug。
GDB 是一个跨平台的调试器,UNIX,Windows,MAC OS X 上均可使用。
GDB 支持以下语言:
- Ada
- Assembly
- C
- C++
- D
- Fortran
- Go
- Objective-C
- OpenCL
- Modula-2
- Pascal
- Rust
快速使用
编写一份 test.c 代码
#include <stdio.h>
int main()
{
int arr[4] = {1, 2, 3, 4};
for(int i = 0 ; i < 4 ; i ++)
printf("%d\n", arr[i]);
return 0;
}
现在要使用 gdb 调试这份代码:
gcc -g test.c # 编译时加 -g 表示编译时带调试信息
gdb ./a.out # gdb启动执行程序
在做完上面两步之后,进入 gdb 模式,终端输出如下内容
GNU gdb (Ubuntu 12.1-0ubuntu1~22.04) 12.1
Copyright (C) 2022 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<https://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from a.out...
(No debugging symbols found in a.out)
(gdb)
这表示已经进入了 gdb 模式,并正在对 a.out 进行调试。
在进入 gdb 之后,要实现调试的目的,还需要知道下面这些命令(或者可以 man gdb
来查找命令):
run 命令
r # (或 run) 执行程序
可以看到,输入 run
命令,程序被执行,输出了 1, 2, 3, 4 。
quit 命令
quit # 退出 gdb 模式
可以看到,输入 quit
命令,退出了 gdb 模式,回到终端。
break 命令
b # (或 break) 后跟函数名或者行数,设置断点
break 命令用于添加断点,程序在运行到断点时会自动暂停执行。
b 7 # 在第 7 行添加断点
b main # 在 main 函数处添加断点
main 函数在第四行,此时程序在第四行处设置了断点。
可以看到,程序在执行到第四行的时候暂停了并提示运行到 main() at test.c:4
。
next 命令
n # (或 next) 在 gdb 暂停程序后,命令程序单步执行
刚才在第 4 行暂停执行了,输入 next
命令让程序继续执行。
可以看到,每次输入 next
命令,程序执行一步。
continue 命令
c # (或 continue) 在 gdb 暂停程序后,命令程序继续执行
暂停执行后,输入 continue
命令让程序继续运行,直至再次遇到断点。
可以看到,程序遇到主函数的断点之后,输入 continue
命令,程序继续执行,遇到第七行的断点之后又被暂停。
list 命令
打断点的时候通常需要看一下源代码,使用 list 命令来在终端里打印源代码
list # 显示当前位置向下 10 行代码
list - # 显示当前位置向上 10 行代码
由于比较简单,不再展示。
step 命令
如果程序执行到调用某个函数,step
命令将跟踪观察被调函数,否则和 next
的作用一样。
修改一下源代码:
//test1.c
#include <stdio.h>
void hello()
{
printf("Hello, ZTer~");
}
int main()
{
int arr[4] = {1, 2, 3, 4};
int i = 0;
for(i = 0 ; i < 4 ; i ++)
{
printf("%d\n", arr[i]);
}
hello();
return 0;
}
在 15 行添加断点,输入 step
命令。
可以看到,程序跟踪进入了 hello()
函数。
print 命令
使用 print
后跟变量名以显示变量当前的值,也可以显示变量的地址。
- 在执行赋值操作之前,查询 arr[0] 的值,得到无效值 -7351 。
- 使用
next
命令,赋值操作执行,再次查询,得到 1 。 - 查询 arr[0] 和 arr[1] 的地址,相差 4 字节(一个 int)。
watchpoint 命令
watchpoint 是一个观察点,可以对一个对象或者一个内存设置观察点。当这个对象或者这块内存里的变量有变化时,自动生成提示。
info b # 查看断点情况
shell # 在 gdb 模式下使用终端命令
set logging on # 开启/关闭(off)日志模式,该模式会记录 gdb 的输出