GNU Project Debugger, GDB 一个代码调试工具,通过系统提供的 ptrace 接口实现的控制进程,然后可以在进程内部查看信息,甚至调用函数。
简介
在使用 gdb 时,需要通过 -g
参数把调试信息加到可执行文件中,否则没有函数名、变量名、代码地址,所代替的全是运行时的内存地址。
$ cc -g hello.c -o hello
$ g++ -g hello.cpp -o hello
GDB 的参数和命令很多,可以通过 gdb --help
命令查看具体的启动参数,启动之后对某些不熟悉的命令可以通过 help <CMD>
方式查看。
注意,gdb 在保证命令不冲突的前提下,提供了简写命令,例如 list
查看源码,实际上通过 l
也可以。
启动方式
不同场景下使用 GDB 的方式略有不同,这里详细介绍一些常用的使用方式。
直接加载运行
最简单的是编译好二进制后通过 GDB 加载启动,启动时可以有如下几种方式设置参数。
----- 启动时同时指定运行的参数
$ gdb --args YourExecPath YourArgs...
----- 启动gdb加载程序后,在运行时设置参数
$ gdb YourExecPath
(gdb) run YourArgs...
----- 启动后在运行前设置参数
$ gdb YourExecPath
(gdb) set args YourArgs...
(gdb) run
----- 查看设置好的运行参数
(gdb) show args
设置完参数后可以通过 show args
命令查看,在通过 r/run
正式运行前,除了设置运行参数之外还可以设置如下环境变量信息。
----- 设置查看程序运行的路径,默认使用PATH环境变量
(gdb) path <ExecPath>
(gdb) show paths
----- 设置查看环境变量,可以简写为 env ,如果 VarValue 为空则会清空
(gdb) set environment VarName=VarValue
(gdb) show environment VarName
远程调试
通过 gdbserver 允许在不同机器上运行 gdb 调试程序,允许使用网络以及串口。
----- 启动监听端口
# gdbserver :5100 <YourExec> [Args...]
----- 连接到正在运行的程序
# gdbserver :5100 --attach <pid>
----- 无需启动程序
# gdbserver :5100 --multi
然后在本地建立连接即可。
$ gdb YourExecPath
(gdb) target remote TargeIPAddr:5100
其它
还支持调试 CoreDump 文件以及 Attach 到正在运行的程序上。
----- 调试Core文件
$ gdb <program> core
----- Attach到正在运行的进程上,也可以进入gdb后执行attach命令
$ gdb <program> <PID>
另外一些启动时的常用参数为。
-symbols/-s <file>
指定文件读取符号表。-se file
从指定文件中读取符号表信息,并把他用在可执行文件中。-core/-c <file>
调试 Core 文件。-directory/-d <directory>
加入一个源文件的搜索路径,默认是PATH指定的路径。
是否查找到源文件,可以通过 list/l
命令查看。
环境变量
可以通过如下命令查看、设置、清除环境变量。
(gdb) show environment JAVA_HOME
(gdb) set environment JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk
(gdb) unset environment JAVA_HOME
信息查看
如上已经介绍了运行参数和环境变量的设置,默认显示不太方便查看,可以通过如下方式设置更好的展示。
(gdb) set print pretty on
主要是通过 info
命令查看各种信息,例如函数、全局、局部、静态变量等等,如下是一些常用的命令。
----- 查看函数信息,可以使用正则表达式
(gdb) info functions
----- 查看所有的全局和静态变量
(gdb) info variables
----- 当前栈的局部变量,包括了本函数中的静态变量
(gdb) info locals
----- 查看参数
(gdb) info args
内存查看
也就是 examine
命令,通常简写为 x
,对应的命令格式为 x/nfu <ADDR>
。
其它
----- 查看版本信息,默认启动时会打印
(gdb) show version
----- 查看版权信息
(gdb) show copying
(gdb) show warranty
----- 退出时无需确认,直接退出
(gdb) set confirm off
----- 关闭分页,会将信息全部输出
(gdb) set pagination off
(gdb) set height 0
其中时通过 -q
或者 --quiet
可以禁止打印版本信息,
断点设置
----- 设置基于条件的断点
(gdb) break main:120 if var == 10
----- 查看栈信息,使用 full 时会同时显示本地变量
(gdb) backtrace full
符号加载
GDB 调试是要依赖一些调试信息的,否则可能会出现 No symbol table is loaded
的报错,如果是调试阶段通常需要在编译时添加 -g
参数,或者通过 file YourExecPath
加载文件。
常见问题
保存日志
GDB 允许将输出打印到某个文件中,这样可以便有共享或者后续查看。
----- 开启或者关闭日志,默认保存在当前了目录中的gdb.txt文件中
(gdb) set logging on
(gdb) set logging off
----- 仅保存某个命令的输出
(gdb) backtrace > /tmp/backtrace.txt
绝对路径
默认像 CMake 会使用源码的绝对路径,但有时调试环境的源码路径与出包的路径不同,那么就可以将源码路径进行简单映射。
----- 确认二进制文件的绝对路径
$ readelf -p .debug_str YourExecPath
----- 设置替换路径
(gdb) set substitute-path /Your/Exec/Path /Your/Source/Path