GDB 知识点速查

本清单提供了对 GDB 的入门简要概述,以及 GDB 常用示例,完整文档参阅 Debugging with gdb,该文档最后有 GDB index,可以快速查找命令。

入门

常用命令

[] 内为命令缩写

命令 [缩写]说明
help[h]查看命令帮助。如 help run
run[r]运行程序。可搭配参数使用
start运行程序,停在第一条执行语句。可搭配参数使用
list[l]查看程序源码
break[b]设置断点。可指定文件名、函数名和行号等参数来设置断点
watch设置监视点。当监视的变量发生更改时,程序会被中断
delete删除断点等。可用于删除断点、监视点、display
continue[c]继续执行程序。让程序继续执行,到下一个断点或程序结束
next[n]单步执行程序,跳过函数调用
step[s]单步执行程序,进入函数调用
finish结束当前函数。返回到函数调用点
kill杀死当前的调试进程
backtrace[bt]查看函数调用栈。它会打印出当前的函数调用栈
frame[fr]切换栈帧。以查看该栈帧中的局部变量和参数等
info查看程序状态信息。例如断点、寄存器、线程、局部变量等
show查看 gdb 配置信息。与 info 不同, show 查看 GDB 本身的配置信息
set设置变量值。有时指定变量类型才能设置,如 set *(int*)(&a) = 3
whatis查看变量、函数类型。例如,whatis a 可以显示变量 a 的类型
ptype查看变量、函数类型。会显示完整的结构体类型
print[p]打印变量的值。例如,print x 可以显示变量 x 的当前值
display持续打印变量的值。与 print 类似,但它会在每次停下时自动输出值
thread切换线程。例如,thread 2 切换到编号为 2 的线程
signal向进程发送信号。例如,signal 9 发送编号为 9 的信号

启动调试

启动进程,不带参数

# gdb <program>
(gdb) run

启动进程,带参数 <args>

# gdb <program>
(gdb) run <args>

启动 gdb 时传入参数,run 就不用传入了

# gdb --args <program> 1 2 3
(gdb) run

通过 set 设置参数

# gdb <program>
(gdb) set args 1 2 3
(gdb) run

显示运行时将要或已经传递给程序的参数

(gdb) show args

在启动进程前,添加环境变量

(gdb) set env DEBUG 1

在启动进程前,清除环境变量

(gdb) unset env DEBUG

通过进程号 123 连接到正在运行的进程

(gdb) attach 123

core dump 文件

默认情况下,linux 系统中程序崩溃时也不会生成 core dump 文件,需要先启用

ulimit -c unlimited
echo "/tmp/core-%e-%p-%t" > /proc/sys/kernel/core_pattern

调试 core 文件

gdb program /tmp/core-file

查看源码

命令说明
(gdb) list 30查看第 30 行为中心的上下 5 行源码
(gdb) list main查看 main 函数为中心的上下 5 行源码
(gdb) list file.c:30查看 file.c 文件中 30 行的源码
(gdb) list file.c:main查看 file.c 文件中 main 函数
(gdb) disassemble查看当前可执行文件的汇编源码
(gdb) disassemble myfun查看指定函数的汇编源码

流程控制

命令说明
(gdb) step[s]执行源码级别的单步进入操作
(gdb) stepi[si]执行指令级别的单步进入操作
(gdb) next[n]执行源码级别的单步跳过操作
(gdb) nexti[ni]执行指令级别的单步跳过操作
(gdb) continue[c]继续执行,到下一个断点或程序结束
(gdb) finish运行完当前函数,并返回到函数调用点
(gdb) return直接退出当前函数,不执行剩下代码块
(gdb) return expression可以指定返回值的内容
(gdb) until结束当前循环

断点命令

命令说明
(gdb) break main在所有名为 main 的函数处设置一个断点
(gdb) break test.c:12在文件 test.c 的第 12 行设置断点
(gdb) break test.c:func在文件 test.cfunc 函数处设置断点
(gdb) rbreak regular-expression在正则表达式匹配的函数名上设置断点
(gdb) break foo if a < 100设置条件断点,条件满足才停止
(gdb) info break列出所有断点位置、编号
(gdb) delete 2删除指定编号的断点
(gdb) clear删除刚才停止处的断点
(gdb) disable 1disable 指定编号的断点
(gdb) enable 1enable 指定编号的断点

watch 命令

命令说明
(gdb) watch var监视变量,当值变化时会输出新、旧值
(gdb) info break列出断点,也包括 watchpoint
(gdb) i watch只列出 watchpoint
(gdb) delete 1删除指定的 watchpoint

查看变量

命令说明
(gdb) info args查看传入参数信息
(gdb) info local查看当前栈帧(函数)的本地变量
(gdb) print var查看指定变量的值
(gdb) print/x var以十六进制输出变量的值
(gdb) print ptr假设 int *ptr=&a,输出变量 a 的地址
(gdb) print *ptr假设 int *ptr=&a,输出变量 a 的值
(gdb) print *ptr@5假设 int ptr[5],输出数组的值
(gdb) display varprint 作用相同,但每次停下来都自动输出变量的值
(gdb) info display列出所有设置了 display 的变量
(gdb) undisplay 1display 相反,不能指定变量名,只能是编号
(gdb) delete display 1undisplay 类似,通过编号取消显示
(gdb) whatis var查看变量类型
(gdb) ptype vartype 更详细,会给出结构体的定义

frame 栈帧

每当一个函数被调用时,一个新的栈帧 frame 就会被压入栈中,栈帧包含了该函数的局部变量、参数、返回地址和其他信息,当函数执行完毕后,这个栈帧会被弹出栈并销毁。

命令说明
(gdb) frame显示当前栈帧和源代码行
(gdb) backtrace打印出当前正在执行的所有栈帧
(gdb) backtrace 5只显示最近调用的 5 个栈帧
(gdb) frame 2切换到第 2 个栈帧,以查看信息
(gdb) up切换到上一级调用栈帧
(gdb) down切换到下一级调用栈帧

函数调用

callprint 调用的函数如果存在全局变量、静态变量的修改,在函数返回后会恢复到调用之前的值,这两个调用不会影响程序的状态

命令说明
(gdb) call func(a, b)调用指定的函数,不影响主线程变量
(gdb) print func(a, b)call 类似
(gdb) finish结束当前运行的函数

信号

linux 下使用 kill -l 查看信号编号与信号名,使用 info signal 查看信号的处理方式、描述等:

(gdb) info signal
Signal        Stop  Print   Pass to program Description

SIGHUP        Yes   Yes     Yes             Hangup
SIGINT        Yes   Yes     No              Interrupt
SIGQUIT       Yes   Yes     Yes             Quit
SIGILL        Yes   Yes     Yes             Illegal instruction
命令说明
(gdb) signal SIGKILL向进程发送信号,用信号名或编号表示
(gdb) signal 9向进程发送信号,用信号名或编号表示
(gdb) handle <signal> actions指定信号的处理方式,选择如下,可以组合
stop/nostop收到信号是否停止进程,类似断点
print/noprint收到信号是否输出消息
pass/nopass是否将信号传递给程序

线程

命令说明
(gdb) info threads列出所有线程,标识当前所在线程
(gdb) thread 2切换到编号为 2 的线程
(gdb) break file.c:23 thread all在所有线程中相应的行上设置断点
(gdb) thread apply all command让所有线程执行 gdb 命令
(gdb) thread apply ID1 ID2 command让指定线程执行 gdb 命令
(gdb) set scheduler-locking off所有线程都执行,这是默认值
(gdb) set scheduler-locking on只让当前线程执行