一、GDB简介
GDB(GNU symbolic debugger)是GNU的一款代码调试工具,它可以实现查看代码内部结构、打印变量值、设置断点、单步调试等功能。
注意:若使用gdb调试代码,则在编译阶段需要添加-g选项。gdb只能调试生成的可执行程序,而不能调试.c源代码文件
二、GDB使用方法
1、GDB常用命令
这些都是在GDB命令行下进行输入的
set args xxxxx ---设置main函数的入参
当有特殊字符时,可以使用"xxx"来写
break 文件名:行号 或 函数 --- 在指定的地方设置断点
break 文件名:行号 或 函数 if xxxx --- 条件断点,当xxxx时断点生效
i break --- 显示当前断点
del xxxx --- 删除xxxx号断点
run --- 开始运行程序 缩略语-->r
next --- 单步调试,不进入函数内部 缩略语-->n
step --- 单步调试,进入函数内部 缩略语-->s
list --- 显示当前代码,默认是10行
set listsize xxxx --- 设置显示的代码行数为xxxx
print xxxx --- 打印xxxx变量的值 缩略语-->p
info locals --- 显示当前所有变量
continue --- 继续运行程序 缩略语-->c
set var xxxx=val --- 设置程序中xxxx变量为val
backtrace --- 查看当前调用栈关系。会显示栈关系的层号 缩略语-->bt
frame xxxx --- 调到调用栈关系的第xxxx层 缩略语-->f xxxx
disassemble --- 查看反汇编
handle SIGPIPE nostop noprint --- 当有信号时不停止运行不打印
调试多进程程序时:
set follow_fork_mode parent --- 调试父进程
set follow_fork_mode child --- 调试子进程
set detach-on-fork [on.off] --- on只阻塞当前进程
info inferiors --- 查看正在调试的进程
inferior id --- 切换到进程ID进行调试
调试多线程程序时:
info threads --- 查看线程
threads 线程ID --- 切换线程
set scheduler—locking [on.off] --- on是运行当前线程
thread apply [id.all] --- id指定线程运行dgb
2、GDB调试步骤
1)编译
在编译阶段,一定要加上可选项-g(表示开启调试),否则无法使用GDB调试代码,这个地方一定要-g在前。
gcc test.c -g -o test
-o选项有如下含义:当有优化时,断点调试中下一步可能会跳行
-O0:无优化(默认)
-O1:1级优化。使用该选项能减少目标文件大小及执行时间并且不会让编译时间明显增加。在编译较大型的程序时常用。
-O2:2级优化。包含1级优化功能并进一步优化生成的目标代码(例如使用更优化的指令调度等),不过会让编译时间增加。
//2级优化是在编译时间与优化长度上取得了一个平衡点。
-O3:3级优化。包含2级优化功能并进一步优化生成的目标代码(例如使用特殊的处理器等),不过会让编译时间大幅度增加。
2)开始调试
gdb test --- 调试还没有运行的程序
gdb -p 进程ID --- 调试正在运行的进程ID,当开始调试的时候,运行的程序会断点。如果需要应先关闭看门狗等功能。
按上面的GDB命令开始调试
3)程序运行出现段错误
1.第一步要生成core文件
ulimit -c --- 查看可以生成core文件的大小
ulimit -c unlimited --- 将core文件大小指定为不限制,默认一般是0代表不生成
sudo vi /etc/sysctl.conf
kernel.core_pattern=core --- 在文件末尾添加上core文件的存储路径,保存退出。这个core文件名可以携带其他参数,可以百度一下要开什么。
reboot --- 重启后可以查看core文件大小,如果是0就在指定一下大小就可以了。
2. ./test --- 执行程序,出现段错误后,在本目录出现一个core文件
2. gdb test core --- 调试出现段错误的代码
4)有些不生成core怎么办
我的是ubuntu20.04,在步骤3做完后不会生成core,20.04的一个服务会自动生成异常报告,会占用core文件生成。需要如下步骤
1.cat /proc/sys/kernel/core_pattern --- 看和你改的路径是否一致,一般不生成是因为不一致。
2.sudo systemctl disable apport.service --- 关闭服务
3.sudo vi /etc/default/apport --- 将文件中的enable改成0
这样重启在进行步骤3就应该可以了。
3、GDB进阶工具
我是搞嵌入式的,一般会遇到在板子上进行调试的情况,这个时候GDB可能不直观,所有我推荐使用gdbserver。
在板子上
sudo gdbserver --attach localhost:端口 进程ID
gdbserver --- gdb服务器。 嵌入式环境下,需要交叉编译,一般放入/usr/bin目录。
--attach --- 表示调试正在运行的程序。
localhost:端口 --- 表示gdbserver开放的接入ip和端口。这里也可以使用串口,改为形如/dev/ttyb,具体取决于linux /dev目录下串口名称。
进程ID 正在运行程序的pid。
在电脑上
xxx_gdb target remote localhost:端口
xxx_gdb --- 交叉编译工具链的gdb
target remote --- gdb连接远程命令
localhost:端口 --- 远程ip、端口,也可以为串口。
这样就可以调试了
像qt creator等软件自带远程,这个就可以像调试本地工程一样脱离命令行了。
听说还有一个工具叫cgdb,不过我没用过。
另外打印也是很重要的
听人推荐了一个
1.zlog是一个高可靠性、高性能、线程安全、灵活、概念清晰的纯C日志函数库