GDB
- GDB(GNU Debugger)是一个功能强大的调试工具,广泛用于调试 C、C++ 和其他编程语言编写的程序。它是 GNU 项目的一部分,专为帮助开发者在程序执行时检测和修复错误设计。GDB 能够控制程序的执行,查看程序内部的状态,帮助定位代码中的问题,并提供详细的信息以供开发者分析。
主要功能
- 设置断点:你可以在代码的特定行、特定函数或满足条件时设置断点,程序运行时会在断点处暂停。
- 单步执行:逐行执行代码,方便查看每行代码执行后的状态。
- 查看变量和内存:可以查看当前程序的变量值、内存内容,甚至修改它们。
- 分析程序崩溃:通过分析程序崩溃时的核心转储文件,帮助开发者找到崩溃的根本原因。
- 跟踪调用堆栈:能够查看函数调用栈,帮助分析程序执行的路径。
GDB 的工作流程
GDB 的调试过程主要包括以下几个步骤
- 编译程序:要使用 GDB 调试,首先需要在编译时添加 -g 选项,这样会生成包含调试信息的可执行文件。
- 启动 GDB:通过 gdb 启动调试,并加载需要调试的程序。
- 设置断点:在程序中指定某些行或函数设置断点,方便在特定位置停止程序。
- 运行程序:在 GDB 中运行程序,程序会在断点处停止。
- 查看状态:在停止的地方可以检查变量、查看内存、打印调用栈等。
- 单步调试:通过逐行或逐步执行代码,追踪程序的运行流程。
- 继续执行:在检查完状态后,继续执行程序,直到下一个断点或程序结束。
使用步骤
- 编译程序时添加调试信息
要调试的程序需要包含调试信息。这是通过在编译时添加 -g 选项来实现的。例如,如果你有一个 C 语言源文件 main.c,你可以用以下命令编译它
gcc -g -o my_program main.c
- 启动 GDB
启动 GDB 并加载你想调试的程序
gdb ./my_program
启动后,你将进入 GDB 的调试界面,可以使用 GDB 提供的各种命令进行调试。
- GDB调试命令大全表
命令 | 说明 |
---|---|
gdb program | 启动 GDB 并调试指定的可执行文件 |
run 或 r | 开始执行程序 |
continue 或 c | 继续执行程序直到下一个断点 |
break 或 b | 在指定位置设置断点,如:break main 或 b 10 (在第10行设置断点) |
step 或 s | 单步执行代码(进入函数内部) |
next 或 n | 单步执行代码(跳过函数调用) |
finish | 执行当前函数直到返回 |
backtrace 或 bt | 显示调用栈 |
print 或 p | 打印变量的值,如:print x |
info locals | 查看当前栈帧的局部变量 |
info args | 查看当前函数的参数 |
set var | 设置变量的值,如:set var x=10 |
display | 在每次停止时自动显示变量的值,如:display x |
undisplay | 停止自动显示某个变量的值 |
list 或 l | 显示源代码,如:list 或 list 10 显示从第10行开始的代码 |
info break | 显示所有断点信息 |
delete 或 d | 删除断点,如:delete 1 删除第一个断点 |
info functions | 显示所有函数名 |
info variables | 显示所有全局变量 |
info threads | 显示当前所有线程 |
thread 或 t | 切换到指定线程,如:thread 2 |
thread apply all | 对所有线程执行命令,如:thread apply all bt 显示所有线程的调用栈 |
watch | 设置变量的观察点,当变量值变化时暂停程序执行,如:watch x |
rwatch | 设置读取观察点,程序读取某个变量时暂停,如:rwatch x |
awatch | 设置访问观察点,程序访问某个变量时暂停,如:awatch x |
info watchpoints | 显示所有观察点 |
info source | 显示当前调试的源文件信息 |
info registers | 显示当前 CPU 寄存器的值 |
frame 或 f | 切换到指定的栈帧,如:frame 2 |
x | 查看内存地址的内容,如:x/x 0xaddress 以十六进制显示指定地址的内容 |
ptype | 显示变量的类型,如:ptype x |
stepi 或 si | 逐指令执行 |
nexti 或 ni | 逐指令跳过函数调用 |
info sharedlibrary | 显示加载的共享库信息 |
clear | 清除某行或某函数的断点,如:clear 10 清除第10行的断点 |
enable | 启用断点 |
disable | 禁用断点 |
x/10i | 以指令格式显示10条从指定地址开始的内容,如:x/10i $pc |
start | 启动程序,并在 main() 函数处停止 |
info files | 显示加载的符号文件及其内存地址 |
detach | 从当前进程分离,不停止进程 |
quit 或 q | 退出 GDB 调试 |
一些高级功能
- 断点管理
- 条件断点:让断点只有在满足某个条件时才会触发。
break <line_number> if <condition>
- 断点命令:可以在断点处自动执行某些命令。
break 30 # 在源代码的第 30 行设置一个断点。程序在执行到这行代码时将暂停。
commands 1#这个命令定义了在断点 1(即刚才设置的断点)处触发时要自动执行的命令序列。
print x # 命令用于打印变量 x 的当前值
continue # 这是告诉 GDB 继续执行程序的命令,直到遇到下一个断点或程序结束。
end #这是命令序列的结束标志,表示在断点 1 处应执行的命令已经定义完毕。
- 临时断点:只触发一次后自动删除
tbreak <line_number>
tbreak 20 #只在第 20 行触发一次。
- 禁用/启用断点
disable <breakpoint_number>
enable <breakpoint_number>
- 观察点和监视点(其实就是运行到它们变化时会停下来,并报告变化)
- 观察点(Watchpoint):监控内存位置或变量的变化,每次改变时会停止程序。
watch <variable>
#watch x 会在变量 x 的值改变时停止程序。
- 读写监视:监视特定内存地址的读取或写入操作
rwatch <variable> # 监视读取
awatch <variable> # 监视读取和写入
- 堆栈调试
- 查看调用栈
backtrace # 或 bt
- 切换栈帧
frame <frame_number>
- 查看指定帧的局部变量
info locals
- 查看函数参数
info args
- 内存调试
- 查看内存内容
x/<format> <address> <format> 表示显示格式,包括显示的单位(如字节、字)、数量以及显示类型(如十六进制、十进制) 显示类型 x:以十六进制显示 d:以十进制显示 c:以字符形式显示 s:以字符串形式显示 f:以浮点数显示 数量单位 b:字节(byte) h:半字(halfword) w:字(word,通常为 4 字节) 例如:查看 0x600000 地址的 4 个字的十六进制内容 x/4xw 0x600000
- 修改内存内容
- 使用 set 命令来修改变量或内存的值。
set <variable> = <value> set x = 100 #修改变量 x 的值
2. 修改内存地址的值 如果你知道某个地址并想修改该地址处的值,可以通过 *(type *)<address> 访问内存并设置值
set *(int *)0x600000 = 42 #地址 0x600000 处的值修改为 42(以整数形式)
- 线程调试
(gdb) info threads
(gdb) thread 2 #假设我们想调试线程 2,可以使用以下命令切换到线程 2
(gdb) backtrace #可以使用 backtrace 命令查看该线程的调用栈
- 脚本化调试
- GDB允许你使用脚本来自动化调试任务,这可以减少重复操作,提高效率。
GDB 命令脚本:你可以将一系列GDB命令写入文件,然后通过source命令来加载执行。例如,将常用的断点设置或打印命令放入一个文件,然后每次启动GDB时执行它。
# example.gdb
break main
run
backtrace
使用
(gdb)source example.gdb
- 反向调试
GDB 支持反向调试,这是一个非常强大的特性,允许你回到程序的某个状态,查看之前的变量值,定位问题的根源。常用命令如下:- reverse-continue:反向继续执行,直到遇到断点。
- reverse-step:反向执行一步,进入函数。
- reverse-next:反向执行一步,跳过函数。
反向调试对于追踪难以重现的错误,特别是并发性错误或随机出现的崩溃非常有用。
- 远程调试
GDB 支持远程调试,你可以通过网络连接到远程设备进行调试(如嵌入式设备或容器中的应用)。- 嵌入式开发
- 远程调试
- 调试没有本地调试环境的系统
- GDB服务器模式:在目标设备上启动GDB的服务器模式。
gdbserver :1234 ./my_program # gdbserver:这个命令启动 gdbserver,它允许程序在远程主机上运行,并通过网络与本地主机上的 GDB 连接,GDB 可以控制和调试该程序。 # :1234:表示 gdbserver 监听的端口号,1234 是一个 TCP 端口。 # ./my_program:这是你要调试的程序的路径。
- GDB客户端连接:在本地使用GDB连接到远程设备上的GDB服务。
gdb ./my_program
target remote <remote_ip>:1234
# <remote_ip> 是运行 gdbserver 的远程主机的 IP 地址
# 1234 是 gdbserver 监听的端口。