GDB 高阶进阶用法
以下高阶用法如果有多个用法表示同一个意思,只保留缩写或者最简单的那个。
以下笔记是在阅读过 Debugging with GDB 20250527 版本后做的笔记,学习完毕可以声称精通 GDB。
启动与启动文件
启动文件可以位于以下地点:
$XDG_CONFIG_HOME/gdb/gdbinit
$HOME/.config/gdb/gdbinit
$HOME/.gdbinit
| 命令 |
解释 |
| gdb -q |
静默启动,不打印版本等信息 |
| gdb -tui |
GDB启动时即打开可视化窗口 |
| gdb -statistics |
启动和运行每条命令时打印时间和内存信息 |
内部命令
| 命令 |
解释 |
示例 |
| shell <command> |
在 gdb 内运行任意外界命令 |
|
| set logging on |
打开日志记录,默认文件为 gdb.txt |
|
| set logging file <file> |
设置日志文件名 |
|
| pipe <gdb-command> | <linux-command> |
将 GDB 的输出传入 linux 命令, 例如 grep |
|
| file <file_name> |
切换加载的文件 |
|
| help <class> |
查看某些命令的帮助 |
help status |
| i r |
打印寄存器信息 |
|
| i b |
打印断点信息 |
|
| i args |
打印当前参数信息 |
|
| start |
自动运行并停在程序入口点 (main) |
|
| starti |
自动运行并停在汇编入口点 (_start) |
|
| set args <args> |
设置当前 GDB 窗口的运行参数 |
|
| path <directory> |
设置可执行文件运行时搜索动态库的路径 |
|
ch resta <checkpoint-id> |
设置检查点 从某检查点直接恢复 (回去调试) |
|
| i ch |
显示当前所有检查点 |
|
多进程调试
| attach <process_id> |
附加进程并调试进程的程序 |
|
| infr <N> |
切换到第 N 个 inferior 进程接着调试 |
|
add-i file <other-program> <other-args> |
创建一个新的进程以多程序调试 |
|
| clone-i <N> |
在当前程序基础上 clone 进程以多路径调试 |
|
| remove-i <N> |
删除某进程 |
|
| b <loc> inferior <inferior-id> |
将断点打在某进程的对应位置(也可以加条件 if) |
|
| i i |
查看所有“被调试的程序实例”(一行一个进程) |
|
多线程调试
注意,b 的断点会打在所有线程,即所有线程都会在断点处停顿
| i th |
打印当前线程 |
| thr <N> |
切换线程 |
| taas <command> |
所有线程都执行某命令 |
| tfaas |
所有线程都返回 (finish) |
| thr a <threads | all> <command> |
所有线程都运行某命令 |
检查点与备份
ch resta <checkpoint-id> |
设置检查点 (新进程) 从某检查点直接恢复 (回去调试) |
|
| i ch |
显示当前所有检查点 |
|
| d ch <N> |
删除某检查点 |
|
断点/观察点/捕捉点
b <loc> if <cond>
|
条件断点 |
b func if a == 10 |
| tb <loc> |
临时断点 (只停一次) |
|
rb <regex> rb <file:regex> |
模糊匹配设置断点 (所有匹配的都是断点) |
|
| i b |
打印所有断点 |
|
wa <loc> wa <loc> th <thread-id> |
设置写观察点 |
|
| rw <loc> |
设置读检查点 |
|
| aw |
设置读写检查点 |
|
| i wat |
显示所有检查点 |
|
| cat <event> |
捕获某事件 |
catch exception Program_Error catch syscall open |
| clear |
删除所有断点 |
|
| d br <list> |
删除断点 |
|
| disa/ena br <breakpoint-id> |
禁用或者启用断点 |
|
| ena once <N> |
断点 N 在下一次命中后就自动禁用 |
|
| ena count <times> <N> |
断点 N 在出发一定次数后不再触发 |
|
| ena del <N> |
触发后就直接删除断点 |
|
commands <breakpoint-id> <command> end |
将命令自动化附加到某断点上,到达断点时自动执行命令 |
commands 2 if x > 100 print "x is big" end continue end |
| dp <loc> <exprs> |
动态断点,运行到指定位置只执行表达式但不停留 |
dprintf main.c:42, "val=%dn", val |
| sa bre <filename> |
把断点存到某文件去 |
|
| b <loc> th <thread-id> |
线程特定的断点 |
|
步
| fg |
等同于 continue |
|
| step/next/si/ni <count> |
步进/步入/指令步入/指令步进指定次数 |
|
| finish |
返回父级函数 |
|
| u <line-number> |
运行直到指定行号 |
|
| sk |
跳过某些内容 |
(gdb) skip function <funcname> (gdb) skip file <filename> (gdb) skip range <start-addr> <end-addr> (gdb) skip delete <N> # 删除 skip 规则 (gdb) info skip # 查看当前 skip 列表 |
反向运行
仅单线程程序支持反向运行
| rs |
反向单步 |
|
| rc |
反向继续执行到断点 |
|
| rsi |
|
|
| rn |
|
|
| rni |
|
|
| reverse-f |
|
|
记录进程行为
该命令存在兼容性问题,很可能不支持目标 CPU
| rec full |
完全记录 GDB 的行为 |
|
| rec s |
停止记录 GDB 的行为 |
|
| rec g <loc> |
前往特定 Log位置 |
可以是 begin,end,N |
| res sa |
存储记录的 Log 到文件 |
|
| res re |
恢复本地文件到 Log |
恢复的 log 必须由 save 生成 |
| i rec |
显示 recording 基本信息 |
|
栈检查
| bt <N> |
只打印前几层栈 |
|
| bt -full |
同时打印临时变量 |
|
f <function> f <N> f <view> |
选择想要的栈帧并查看 |
|
| up <N> |
跳到当前函数调用者或其他调用者 |
|
| down <N> |
跳到被调用者 |
|
| i f |
打印当前栈帧完整基本信息 |
|
| i loc |
打印当前栈帧变量信息 |
|
| frame apply <frames> <command> |
对所有或部分栈帧进行操作 |
frame apply all info args f ap a i ar f ap 2 5 print some_var f ap all -q p $sp (quiet 静默栈帧信息)
|
检查原文件
| l |
打印当前执行上下文 |
|
l <linenum> l <func>
|
指定打印上下文 |
|
| disas |
反汇编当前函数 |
|
disas <address> <address> disas <address> +<size> |
指定反汇编范围 |
|
| disas/m |
源码和汇编对照 |
|
检查数据
| l |
打印当前执行上下文 |
|
| p -pretty <something> |
优雅打印 |
有些 GDB 不支持 |
| explore <vars> |
递归得查看复杂数据结构 |
属于 tui扩展功能 |
| @ 操作符 |
人工数组构造器 |
x/4x arr@4 p arr@4 |
| :: 作用域界定符 |
|
p myfile.cpp::some_var |
| {type} addr |
将内存开始的内容当做指定 type 解读 |
p struct MyType 0xdeadbeef |
| x |
检查内存(支持如下输出格式) |
|
| disp <expr> |
程序每次停下 (无论单步还是断点) 都自动执行表达式 (支持如下输出格式) |
display i 每次都打印 i 的值 |
| i di |
显示当前 display 信息 |
|
| p *$1 |
通过历史编号快速引用之前的 print 内容 |
p *$.next 打印 ptr->next 指向的结构体 p *$ $.next 打印前一个值的 next |
| set <alias>=<foo> |
建立临时别名变量 |
set $foo = *object_ptr |
| i r |
查看寄存器信息 |
|
| x/i $ pc |
查看当前 PC 指向的指令 |
|
| i fl |
查看硬件浮点单元信息 |
|
| i ve |
查看硬件向量单元信息 |
|
du memory <filename> <start-addr> <end-addr> du value <filename> <expr> du registers <filename> |
将内存或者寄存器等信息打印到文件 |
|
app 用法如上 restore 用法如上 |
从文件恢复内存或寄存器等信息 |
|
| gcore |
手动保存进程快照 |
|
find[/s或/n] start_addr, +len, <vars> find[/s或/n] start_addr, end_addr, <vars>
|
查找指定内存中的内容(支持 b 字节 h 半字 w 字 g 双字) |
|
| 输出格式: |
|
|
| 格式 |
含义 |
| x |
十六进制(Hexadecimal) |
| d |
十进制(Decimal) |
| u |
无符号十进制(Unsigned decimal) |
| o |
八进制(Octal) |
| t |
二进制(Binary,“t”代表“two”) |
| a |
地址(以符号+偏移形式显示)如:0x54320 <_initialize_vx+396> |
| c |
字符(Character constant,与整数同时显示) |
| f |
浮点数格式(Floating point) |
| s |
字符串(尝试将值解释为字符串) |
| z |
十六进制,带前导 0(zero-padded hexadecimal) |
| r |
原始(raw)格式,禁用 Python pretty-printer,显示底层结构 |
| i |
解析为指令进行打印 |
find /sb 0x600000, 0x601000, 0x68, 0x65, 0x6c, 0x6c, 0x6f
find /n3 0x600000, 0x700000, 0x0 # 找出前三个 NULL 字节的位置
宏
| i macro <MACRO> |
显示程序 MACRO 的信息 |
前提是 -g3 编译
追溯点
tracepoint 的用法和 breakpoint 一模一样
但是实际应该用不到,暂时略过
| 特性 |
breakpoint |
tracepoint |
| 是否中断程序 |
✅ 会中断程序 |
❌ 不中断 |
| 是否实时查看值 |
✅ 可以立即查看 |
❌ 稍后查看(trace buffer) |
| 使用场景 |
本地调试 |
远程/嵌入式/高性能调试 |
| 是否依赖目标支持 |
❌ GDB 自身支持 |
✅ 需要 target 支持 trace |
| 命令 |
功能描述 |
说明 |
|
|
| trace <location> |
设置追踪点(tracepoint) |
在不停止程序的前提下记录位置数据,适用于远程或嵌入式调试 |
|
|
| collect <expr> |
指定采集哪些变量或表达式 |
可收集变量、寄存器(如 $regs、$locals)、结构体字段等 |
|
|
| tstart |
开始 trace 会话 |
启动采样机制,程序运行时会在 tracepoints 自动记录 |
|
|
| tstop |
停止 trace 会话 |
停止采样并允许分析采集到的快照 |
|
|
| tfind <n> |
查找第 n 个 trace 快照 |
若不加参数则查找下一个,可用 start、end、none 等特殊参数 |
|
|
| tdump |
打印当前 trace 快照采集到的数据 |
必须先用 tfind 定位快照 |
|
|
| i tracepoints |
查看所有 tracepoint |
列出编号、位置、状态等信息 |
|
|
| i collected |
查看当前采样点收集了哪些内容 |
仅列出采样项的名称,不包含具体值 |
|
|
| actions [num] |
为某个 tracepoint 编号指定采集行为 |
可交互式输入 collect、while-stepping 等命令,以 end 结尾 |
|
|
| while-stepping <count> |
步进若干次并采集 |
在触发 tracepoint 后单步执行并继续采集 |
|
|
| passcount <n> |
设置某 tracepoint 命中 n 次后停止 |
自动终止 trace 会话,适用于限制记录量 |
|
|
| tvariable $name = <expr> |
创建并赋值 trace 状态变量 |
可用于内部计数或条件判断,未指定值时默认为 0 |
|
|
| info tvariables |
查看所有 trace 状态变量 |
包括初始值及当前值(若 trace 正在运行) |
|
|
| delete tvariable [$name ...] |
删除指定 trace 状态变量 |
不带参数将全部清除 |
|
|
| target tfile <filename> |
加载文件作为 trace 数据源 |
可用 tdump 查看内容,但不能运行新的 trace 会话 |
|
|
| target ctf <dirname> |
加载 CTF 格式 trace 数据目录 |
用于共享或兼容其他 tracing 工具(如 LTTng)的分析数据 |
|
|
符号表检查
| 命令 |
功能说明 |
示例 |
| i address <sym> |
显示符号 <sym> 的地址 |
i address myVar |
| i symbol <addr> |
根据地址 <addr> 查找符号 |
i symbol 0x400123 |
| demangle <mangled-name> |
将重整(mangled)名称还原 |
demangle _Z3fooIiEvv |
| whatis [/<fmt>] <sym> |
显示符号 <sym> 的类型 |
whatis /x ptr |
| ptype <type> |
打印类型 <type> 的完整定义 |
ptype struct Person |
| i types [<regex>] |
列出匹配 <regex> 的所有类型 |
i types "My.*" |
| i scope <sym> |
显示符号 <sym> 的作用域信息 |
i scope foo |
| i source <file> |
显示源文件 <file> 的路径 |
i source main.c |
| i sources |
列出所有加载的源文件 |
i sources |
| i functions [<regex>] |
列出匹配 <regex> 的函数名 |
i functions "mˆain$" |
| i variables [<regex>] |
列出匹配 <regex> 的变量名 |
\texttt{i variables "\^g\_.\*"} |
| i modules [<regex>] |
列出所有 Fortran 模块 |
i modules "Mˆath$" |
| i main |
显示程序的入口函数名 |
i main |
| i classes [<regex>] |
列出匹配 <regex> 的 Objective-C 类 |
i classes "My.*" |
| maint i symtabs [<regex>] |
列出符号表文件(.o/.so)信息 |
maint info symtabs ".*.o$" |
| maint i psymtabs [<regex>] |
列出已加载的进程符号表信息 |
maint info psymtabs "mˆodule" |
| maint i line [<regex>] |
列出行号—地址映射表 |
maint info line-table "mˆain" |
代替执行 (重点)
本部分提供了你“改变程序行为”的能力,不再只是观察和打印!
因为不用改代码就知道验证修复是否有效!
set var <var>=<val> set {<type>}<address> = <val> |
修改变量值或者地址值 |
set {int}0x83040 = 4 |
| j <loc> |
直接跳到指定位置执行, 忽略部分内容如 Bug 代码(同函数内) |
|
| sig <signal> |
向程序发送一个信号并继续运行 |
sig 0 表示继续运行 sig SIGINT 表示模拟 Ctrl+C 中断 |
| ret <expr> |
强制返回父级函数,并可以指定返回值 |
|
| call <expr> |
①调用程序中的函数 ②修改状态,如副作用函数 ③动态计算表达式 |
call printf("x = %dn", x)
|
| compi code -raw -- <src> |
单行“原始”模式编译(无自动包装作用域) |
\texttt{compile code -raw -- int \_gdb\_expr_() { return 42; }} |
| compi code |
进入多行编辑模式,直至输入 end 结束 |
compile code> int y = x+1;> end |
| compi file <file> |
从指定文件编译并执行 |
compile file /home/me/snippet.c |
| compi file -raw <file> |
原始模式下从文件编译 |
compile file -raw /home/me/snippet.c |
| compi print [opts] -- <expr> |
编译并执行 <expr>,结果按类型自动输出 |
compile print -- sin(3.14) |
| compi print /f [opts] -- <expr> |
编译并执行 <expr>,并以浮点格式输出 |
compile print /f -- cos(0.5) |
| compi print [opts] -- |
进入多行编辑模式输入表达式,直至 end |
compile print> x = x+1;> end |
| compi print /f [opts] -- |
多行模式下编译并以浮点格式输出 |
compile print /f> double z = sqrt(2);> end |
文件
file <file>
|
选择输入的文件 |
|
| i dll |
查看动态库 |
|
调试目标
set arch <arch> set processor <processor> |
设置架构或处理器型号 |
|
| tar <target> |
设置调试目标 |
可以是 core,ctf,exec,... |
远程调试
暂时略过,无法实操
自定义命令
| def <command> |
自定义命令 |
可以写在. gdbinit |
| echo |
输出文本,支持 C 风格转义字符(如 \n),默认不自动换行 |
\texttt{echo Hello\ world!\n} |
| output |
输出表达式值(不带换行、不加入历史记录,不显示 $n =) |
output x + 5 |
| output/ |
使用指定格式输出表达式值(格式同 p/) |
output/x my_var |
| printf , <exprs…> |
类似 C 语言 printf,使用模板格式化多个值输出 |
\texttt{printf “foo = 0x\%x,\ bar = 0x\%x\n”, foo, bar} |
| pi |
直接进入 python 交互时命令行 |
|
| py <expr> |
用法和 shell 一样,后面跟 python 内容 |
|
| 语法 |
功能说明 |
| if |
判断表达式是否为真(非 0) |
| else |
可选,表达式为假时执行 |
| while |
当 为真时循环执行 |
| loop_break |
跳出当前 while 循环 |
| loop_continue |
跳过本轮剩余命令,进入下一轮循环 |
| end |
必须出现在每个块结构的结尾 |
TUI 命令
断点标记(图形提示)
| 符号 |
含义 |
| B |
断点已命中过 |
| b |
断点未命中过 |
| H |
硬件断点命中过 |
| h |
硬件断点未命中过 |
| + |
断点是启用状态 |
| - |
断点是禁用状态 |
| 按键绑定 |
|
| 按键 |
作用 |
Control + x a |
退出 TUI 模式 |
Control + x 1 |
TUI 使用单窗口布局 |
Control + x 2 |
TUI 使用双窗口布局 |
Control + x o |
切换活跃窗口 |
Control + x s |
单键模式 (下面讲解) |
| Control + l |
刷新当前页面 |
| 单键模式按钮 |
|
| 键位 |
等价命令 |
说明 |
| c |
continue |
继续程序运行 |
| C |
reverse-continue |
反向继续运行 |
| d |
down |
堆栈向下(进入调用者) |
| f |
finish |
运行直到当前函数返回 |
| F |
reverse-finish |
反向运行直到函数返回 |
| n |
next |
单步执行(不进入函数) |
| N |
reverse-next |
反向单步执行(不进入函数) |
| o |
nexti |
单步执行一条机器指令 |
| O |
reverse-nexti |
反向执行一条机器指令 |
| q |
— |
退出单键模式 |
| r |
run |
重新启动程序 |
| s |
step |
单步执行(进入函数) |
| S |
reverse-step |
反向单步进入 |
| i |
stepi |
单步执行一条指令(进入) |
| I |
reverse-stepi |
反向执行一条指令(进入) |
| u |
up |
堆栈向上(进入被调用者) |
| v |
info locals |
查看局部变量 |
| w |
where |
显示当前调用栈 |
| 命令 |
|
|
tu en tu dis |
打开关闭 TUI |
|
| i win |
当前窗口信息 |
|
| la <mode> |
TUI 以某种形式展示 |
next,prev,src,asm,split,regs |
| foc <mode> |
聚焦哪个子 TUI 窗口 |
|
| ref |
刷新窗口 |
|
| tu reg group |
切换寄存器组 |
next,prev,general,float,system,vector,all |
win <name> ±<num>
|
调整窗口大小 |
|
命令行快捷键
| Control + b |
向左移动一个字符 (back) |
|
| Control + f |
向右移动一个字符 (forward) |
|
| Control + d |
删除光标下的字符 |
|
| Control + a |
移动到行首 |
|
| Control + e |
移动到行尾 |
|
| Control + l |
清屏 |
|
| ! |
开始一次历史替换 |
|
| !! |
执行上一条命令 |
|
| !n |
引用编号为 n 的命令 |
|
| !-n |
引用向上第 n 条命令 |
|
| !string |
引用最近一条以 string 开头的命令 |
|
| !?string? |
引用最近一条包含 string 的命令 |
|