在Linux系统中,GDB(GNU Debugger)是功能强大的调试工具,主要用于调试C、C++、Go等语言编写的程序,通过GDB,开发者可以控制程序执行、设置断点、查看变量值、分析内存状态等,从而快速定位程序中的bug,以下将详细介绍GDB的使用方法,从安装到高级功能,帮助开发者掌握这一工具。
安装GDB
在使用GDB前,需确保系统已安装,不同Linux发行版的安装命令不同:
- Ubuntu/Debian:
sudo apt update && sudo apt install gdb
- CentOS/RHEL:
sudo yum install gdb
或sudo dnf install gdb
(适用于较新版本)
安装完成后,通过gdb --version
验证是否成功,输出版本号即表示安装成功。
编译程序以支持调试
GDB调试需要程序包含调试符号(如变量名、行号信息),因此编译时需添加-g
选项,使用gcc编译C程序:
gcc -g test.c -o test # -g选项生成调试信息,-o指定输出文件
若忽略-g
,GDB将无法显示源码行号和变量名,调试功能受限。
启动GDB
启动GDB的基本语法为gdb [可执行文件]
,
gdb ./test # 调试当前目录下的test程序
启动后,GDB会进入交互式界面,提示符为(gdb)
,GDB还支持其他启动方式:
- 调试已运行的进程:
gdb -p [进程ID]
(需配合ps aux
查找进程ID) - 调试core文件:
gdb [可执行文件] [core文件]
(需先用ulimit -c unlimited
开启core文件生成)
GDB核心调试命令
GDB通过命令控制程序执行,以下是常用命令及功能说明(部分命令可缩写,如break
→b
):
命令(缩写) | 功能描述 | 示例 |
---|---|---|
run (r ) |
启动程序,运行至断点或结束 | (gdb) r |
start |
启动程序,停在main函数第一行 | (gdb) start |
next (n ) |
单步执行,不进入函数 | (gdb) n |
step (s ) |
单步执行,进入函数内部 | (gdb) s |
continue (c ) |
继续运行至下一个断点或结束 | (gdb) c |
finish |
执行至当前函数返回,显示返回值 | (gdb) finish |
break (b ) |
设置断点 | (gdb) b 10 (第10行) |
info breakpoints (i b ) |
查看所有断点信息 | (gdb) i b |
delete (d ) |
删除断点 | (gdb) d 1 (删除断点1) |
disable/enable |
禁用/启用断点 | (gdb) disable 1 |
print (p ) |
打印变量值 | (gdb) p i (打印变量i) |
ptype |
打印变量类型 | (gdb) ptype i |
display |
持续显示变量值(每次停顿时) | (gdb) display i |
undisplay |
取消持续显示 | (gdb) undisplay 1 |
examine (x ) |
查看内存内容 | (gdb) x/4xw $ebp (查看4个32位字) |
backtrace (bt ) |
查看调用堆栈 | (gdb) bt |
frame (f ) |
切换堆栈帧 | (gdb) f 2 (切换到第2帧) |
info frame (i f ) |
显示当前帧信息 | (gdb) i f |
info locals |
显示当前局部变量 | (gdb) info locals |
info args |
显示当前函数参数 | (gdb) info args |
断点管理
断点是调试的核心,GDB支持多种断点类型:
- 行号断点:在指定源码行设置断点,如
b main.c:20
(main.c第20行)。 - 函数断点:在函数入口处设置断点,如
b main
或b 'void func(int)'
(带函数签名)。 - 条件断点:仅当条件满足时触发,如
b 10 if i == 5
(第10行且i等于5时停)。 - 观察点:监控变量值变化,如
watch i
(i变化时停),rwatch
(读变化),awatch
(读/写变化)。
高级调试功能
-
多线程调试
- 查看线程:
info threads
(显示所有线程,标记当前线程) - 切换线程:
thread [线程ID]
(如thread 2
) - 设置锁调度:
set scheduler-locking on
(调试时锁定线程,避免其他线程干扰)
- 查看线程:
-
远程调试
通过target remote
调试远程设备上的程序,如target remote 192.168.1.100:1234
(连接远程GDB服务器)。 -
动态断点
使用catch
捕获事件,如catch throw
(捕获异常)、catch fork
(捕获进程创建)。 -
源码查看
list
(l
):显示当前行附近的源码,如l 1,20
(显示1-20行)set listsize 50
:设置每次显示的源码行数
调试流程示例
假设有以下C程序test.c
(存在数组越界bug):
#include <stdio.h> int main() { int arr[3] = {1, 2, 3}; int i = 0; while (i < 5) { printf("%dn", arr[i]); // 越界访问arr[3]、arr[4] i++; } return 0; }
调试步骤:
- 编译:
gcc -g test.c -o test
- 启动GDB:
gdb ./test
- 设置断点:
b main
(停在main函数入口) - 运行:
r
,执行后用n
单步执行,观察i
和arr[i]
的变化(p i
、p arr[i]
) - 当
i=3
时,arr[3]
越界,GDB会显示错误信息,定位到问题代码行。
相关问答FAQs
Q1: GDB调试时提示“No symbol table is loaded”,怎么办?
A: 该错误通常是因为编译时未加-g
选项,导致可执行文件不含调试符号,解决方法:重新编译程序时添加-g
,如gcc -g test.c -o test
,然后重新启动GDB调试。
Q2: 如何调试多线程程序中的死锁问题?
A: 可通过以下步骤定位死锁:
- 启动GDB后,用
info threads
查看所有线程状态,确认线程是否卡住。 - 对每个线程执行
bt
(backtrace
),查看调用堆栈,分析线程是否等待同一锁或资源。 - 使用
set scheduler-locking on
锁定当前线程,避免其他线程干扰,逐步分析线程间的资源竞争关系。 - 若怀疑锁未释放,可在加锁处设置观察点(如
watch mutex_var
),监控锁状态变化。
原创文章,发布者:酷番叔,转转请注明出处:https://cloud.kd.cn/ask/25556.html