一. gdb简介
编写一个优秀的代码离不开程序的调试,在 Windows 下有很多的集成开发环境内置了调试工具,使用鼠标就可以轻松地为程序打上断点,只要键盘按一下 F5 就可以调试执行,但是如果是在 Linux 命令行下调试程序就没有这么方便了。gdb 是 GNU 发布的一款功能强大的程序调试工具,可以帮助程序员调试程序。
二. gdb的使用
1. 准备工作
首先你需要确保你的 Linux 系统上已经安装了 gcc 或者 g++,如果没有安装,直接使用 sudo apt-get install gcc 或者 sudo apt-get install g++ 安装即可(ubuntu 系统是 apt-get 安装,其他 Linux 系统自行搜如何安装 gcc/g++ 即可)。安装完成后可以在命令行输入 gdb -v 查看当前 gdb 版本信息,如果成功显示代表当前系统已经支持 gdb 调试了。
2. 使用gdb启动程序
假设现在我们编写了一个 gdb_test.cpp 的文件,文件内容如下所示。
1 #include <iostream>
2 #include <cstdio>
3
4 using namespace std;
5
6 int add(int a,int b)
7 {
8 int result = a + b;
9 return result;
10 }
11
12 int main()
13 {
14 cout << "这是一个gdb测试程序!" << endl;
15
16 int x = 3, y = 4;
17 int result = add(x,y);
18 printf("%d + %d = %d\n",x,y,result);
19
20 cout << "gdb测试程序退出" << endl;
21
22 return 0;
23 }
首先我们需要使用 g++ 进行编译,注意在参数中加入 -g 选项代表包含调试信息。g++ -g gdb_test.cpp -o gdb_test
使用 gdb 启动该可执行文件。gdb gdb_test
执行完上面两个步骤后,屏幕上会显示如下信息。
出现此页面后,我们就可以使用 gdb 的交互命令进行一些调试操作,例如打断点,运行程序,打印出变量值等。
3. gdb交互命令
(1) 查看程序
list :列出程序的源代码,默认每次只显示 10 行。
list 行号n :显示当前文件以第 n 行为中心的前后共 10 行代码,如:list 12,再输入 list 可以接着原来输出的内容继续显示后面 10 行代码。
list 函数名func :以函数 func 定义处那一行为中心显示前后共 10 行代码,再输入 list 可以接着原来输出的内容继续显示后面 10 行代码。
(2)设置断点
break 行号n :在当前文件第 n 行设置断点,也可以写成 b 行号。
break 文件名:行号n :在指定文件的第 n 行设置一个断点。
break 函数名func :在函数 func 的入口处设置断点。
info break :显示当前程序的断点设置情况,如下所示,Num 这一列代表断点标号,What 代表断点打在哪个文件的哪一行。
clear 行号n :清除第 n 行的断点。
delete 断点号n :删除第 n 个断点,n 就是 info break 显示信息的 Num 列对应的数字。
disable 断点号n :暂停第 n 个断点,断点设置为 disable 后 info break 时还能看到,只是 Enb 这一列被设置为 n。
enable 断点号n :开启第 n 个断点,用于那些被 disable 的断点。
delete breakpoints :删除所有断点。
(3)运行程序
设置完一些必要的断点信息后就可以开始运行程序,查看程序运行状态了。
run :运行程序。当遇到断点后进程会暂停运行,等待用户输入交互命令。
continue :继续执行到下一个断点处。
next :单步调试,逐行执行代码。
step :单步调试,逐行执行代码,与 next 的区别在于 step 如果执行到函数调用的地方会跳入函数定义内部逐行执行。
call 函数名(参数列表) :调用函数并打印结果。
quit :退出 gdb 调试。
(4)打印设置变量信息
print 表达式 :print 也可以简写为 p,表达式是程序中可测试的有效表达式,例如执行完 add 函数到 return result 之前,我们可以先 print result 打印此时 result 的结果,也可以直接打印函数调用的结果,如 print add(3,4)。
set var = value :设置变量的值。
(5)退出gdb调试
quit :在交互命令输入 quit 即可退出 gdb 调试。
三. 常见用法
1. 设置gdb跟踪调试子进程
gdb 默认调试的是主进程,但是 gdb 7.0 版本以上可以支持调试子进程,为了选择调试子进程我们需要设置 follow-fork-mode 选项,将取值修改为 child(默认是 parent)就可以调试子进程了。
查看 follow-fork-mode 的值:show follow-fork-mode
设置 follow-fork-mode 的值:set follow-fork-mode child
还有个 detach-on-fork 选项,取值可以是 on/off,默认情况下是 on(表示只调试父进程或者子进程中的一个),调试父进程还是子进程由 follow-fork-mode 决定,如果 detach-on-fork 被设置为 off,代表父子进程都可以调试,但是调试父进程的时候,子进程就会被暂停,调试子进程的时候,父进程也会被暂停。
2. 使用gdb调试带启动参数进程
一般情况下,如果我们启动程序时不需要参数,则 gdb 调试时使用 gdb gdb_test (gdb_test 是编译好的程序名)启动即可,但是如果 gdb_test 启动需要参数,例如正常情况下是 ./gdb_test -m 1 -s 200 这样启动的,那我们就需要先 gdb gdb_test 启动程序,然后 set args 添加后面的参数了。
设置程序需要的启动参数 :set args -m 1 -s 200
四. 结束语
关于 gdb 调试的其他用法还有很多,本文只是列出了一些常见的用法,更多的关于 gdb 调试的命令请大家在有需要的时候再自行百度,不需要一下子把所有的 gdb 调试用法全都背下来。