1. 编译时加选项-g,生成具有调试信息的程序
gcc -g test.c -o test
2. 启动GDB
(1)启动GDB:
gdb test
(2)设置运行时参数:(主函数中可接收运行时参数)
set args // 设置运行时参数,如set args 10 20 30
show args // 查看设置的运行时参数
(3)启动程序
run // 执行程序,若有断点,则停在第一个断点处;简写为r
start // 程序向下执行一行
continue // 执行到第一个断点处
3. 显示源码
list 或 l // 显示当前行后面的源代码(默认总共显示10行)
list- // 显示当前行前面的源代码(默认总共显示10行)
list n // 显示第n行前后的源代码
list func // 显示func函数的源代码
set listsize n // 设置一次显示n行
show listsize // 查看一次显示行数
4. 断点操作
(1)简单断点:使用b或break命令
b n // 在第n行设置断点
b func // 在func函数入口处设置断点
info b // 显示所有断点,可简写为 i b
(2)多文件断点,假设程序有add.cpp和test.cpp两个文件
b add.cpp:n // 在add.cpp源文件第n行设置断点
b add.cpp:func // 在add.cpp源文件func函数入口处设置断点
b Animal::func // 在Animal类的func函数入口处设置断点
b Animal::doSth(int, double) // 有函数重载时,必须指定函数形参的情况
b MyNamespace::Animal::func // 在NyNamespace的Animal类的func函数入口处设置断点
(3)条件断点:为断点设置条件
b test.c:8 if Value == 5
// test.c第8行,Value为5时就停止
// 若为循环,不能停在for语句,要停在循环体中
(4)维护断点
delete 10-12 // 删除编号为10、11、12的断点,delete可以简写为d
disable n //禁用编号为n的断点
enable n //启用编号为n的断点
5. 调试程序
run // 执行程序,若有断点,则停在第一个断点处,简写为r
next // 单步跟踪。函数调用当做一条语句直接执行,简写为n
step // 单步跟踪。函数调用则进入函数体内,简写为s
finish // 退出进入的函数
until // 在循环体内单步跟踪时,执行完循环体并退出,简写为c
continue // 继续执行程序,停在下一个断点处
quit // 退出gdb,简写为q
6. 查看数据
查看运行时变量、字符串、表达式等的值:
print a // 查看a的值,print可简写为p
7. 自动查看
自己设置需要查看的值,程序停住或单步跟踪时,会自动显示需要查看的值:
display i // 设置自动显示i的值
info display // 查看所有被设置为display的变量
undisplay n // 不显示编号为n的display设置
delete display n // 删除编号为n的display设置
disable display n // 禁用编号为n的display设置
enable display n // 启用编号为n的display设置
8. 查看修改变量的类型、值
ptype i // 查看变量i的类型
p i // 查看变量i的值
set var i = 100 // 设置变量i的值为100
9. GDB调试多进程
有如下的多进程程序,需要使用GDB分别调试父子进程:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<stdlib.h>
int main(int argc, const char* argv[]) {
pid_t pid = -1;
int status = 0;
int ret = -1;
pid = fork();
if (-1 == pid) {
perror("fork");
return 1;
}
if (pid > 0) {
// 父进程
printf("父进程说太强了");
printf("父进程笑尿了");
printf("父进程哈哈哈哈哈");
} else {
// 子进程
printf("子进程说太强了");
printf("子进程笑尿了");
printf("子进程哈哈哈哈哈");
exit(0);
}
ret = wait(&status); // 父进程等待回收子进程资源
if(-1 == ret) {
perror("wait");
return 1;
}
return 0;
}
GDB调试默认跟踪父进程,如下:
如何跟踪子进程呢?
在fork函数调用之前设置跟踪子进程:
set follow-fork-mode child
然后就会跟踪子进程,如下: