- 添加编译参数
-std=c++11 -fpermissive
- 指定编译生成的可执行文件名字
-o program_name
- 添加调试编译,将源代码信息编译到可执行文件中
-g
- 不用
-g
,看不到程序的函数名、变量名,代替的是运行时的内存地址 - 没有源代码,调试和跟踪时只能是汇编代码级别的
- 先启动 gdb,再加载被调试的可执行程序文件:
gdb
file program_name
- 也可在启动调试时载入被调试程序名字
gdb program_name
- 同时调试一个运行程序和 core 文件,core 是程序非法执行后 core dump 后产生的文件
gdb program_name core
- 指定程序运行的进程 ID
gdb program_name process_id
,主要用于服务程序 - 调试一个正在运行的程序
gdb -p process_id
,-p
可用于忽略程序名 - 退出 GDB 调试环境
q(quit)
- b + 行号
b [file:]line_num
- b + 函数名称
b [file:]func_name
- b + *函数名称,将断点设置在由编译器生成的 prolg 代码处
b *main
- b + *代码地址
b *004835c
break file:line_num if expression
当expression
满足时,程序会在文件file
的第line_num
停下来condition breakpoint_num expression
当expression
满足时,程序会在第breakpoint_num
个断点处停下来 ,可用来修改断点产生的条件
rbreak regex
对所有调用了regex
包含的函数设置断点rbreak file:regex
对某个文件中的满足regex
的函数设置断点
tbreak file:line_num
u(until)
ignore breakpoint_num N
跳过第breakpoint_num
个断点N
次,当某个地方之前多少次不会出错,之后可能出错时使用
watch expression
当expression
变化时会打印相关内容- 注意:程序必须运行起来,否则可能会提示当前上下文没有符号的错误
rwatch
设置变量被读时停止awatch
设置变量被读或被写时停止
disable (breakpoint_num)
禁用断点,不指定编号则禁用所有断点enable (breakpoint_num)
启用断点,不指定编号则启用所有断点enable delete breakpoint_num
启用断点,并在此之后删除断点
d (breakpoint_num)
删除断点,不指定编号则删除所有断点clear
删除当前行的所有断点clear func_name
删除函数名为func_name
的断点clear line_num
删除行号是line_num
的断点clear file:func_name
删除文件file
中函数名为func_name
的断点clear file:line_num
删除文件file
中行号是line_num
的断点
- 查看当前的所有断点信息
i(info) breakpoints
- 查看程序是否在运行,进程号,被暂停的原因
- 查看程序运行路径
show paths
- 设置环境变量
set env(environment) varname[=value]
- 查看环境变量
show environment [varname]
- 显示当前所在目录
pwd
- 查看函数堆栈
bt(backtrace)
- 指定运行时参数
set args 参数
- 查看设置好的参数
show args
l(list)
从第一行开始显示源码,继续输入l
列出后面的源码l+
和l-
分别列出上一次列出源码的后面或者前面部分l line_num
跟行号则列出附近的源码l start_line_num,end_line_num
列出指定行之间的源码- 不指定开始行,则列出到结束行的指定行数
- 不指定结束行,则列出从开始行的指定行数
l func_name
跟函数名列出函数附近的源码l file
列出指定文件的源码l file:func_name
列出指定文件指定函数的源码l file:line_num
列出指定文件指定行附近的源码l file:start_line_num,file:end_line_num
列出指定文件指定行范围的源码
set listsize num
设置源码一次列出行数:设置为 0 或者 unlimited 时没有限制show listsize
查看源码一次列出行数- 当依赖的源码文件位置移动时
- 使用
dir path
指定源码文件路径 - 或者使用
substitute-path
替换路径字符串- 查看源码路径使用
readelf file -p .debug_str
- 替换原路径
set substitute-path path_from path_to
- 查看设置结果
show substitute-path
- 取消设置
unset substitute-path path_from
- 查看源码路径使用
- 使用
- 显示指定变量(临时变量或全局变量)的值
p(print)
p a
p 'file':a
- 变量名相同时,可以在前面加上函数名或文件名以便区分
p var_name
打印基本类型p pointer_name
打印指针地址p *pointer_name
打印指针指向的内容p *pointer_name@N
打印指针的前 N 个元素
格式控制字符 | 含义 |
---|---|
x | 16 进制 |
d | 10 进制 |
u | 16 进制无符号整型 |
o | 8 进制 |
t | 2 进制 |
a | 16 进制 |
c | 字符格式 |
f | 浮点数格式 |
示例: p/x var_name
p/t var_name
x(examine)
用于查看内存地址中的值,语法 x/[n][f][u] addr
n
表示要显示的内存单元数,默认为 1f
表示打印格式,即上述的格式控制字符u
表示要打印的单元长度addr
表示内存地址
单元类型控制字符 | 含义 |
---|---|
b | 字节 |
h | 半字,2 字节 |
w | 字,4 字节 |
g | 8 字节 |
示例:x/4tb &var_name
以二进制方式打印变量 var_name
,打印单位是字节,显示变量的 4 个字节
display var_name
在程序停止时,会显示变量var_name
的值- 例如
display /i $pc
,每次程序中断后可以看到即将被执行的下一条汇编指令,$pc
代表当前汇编指令,/i
表示以十六进制显示
- 例如
info display
查看哪些变量设置了 displaydelete display (display_num)
删除 display,不指定编号则删除所有 displaydisable display (display_num)
禁用 display,不指定编号则禁用所有 displayundisplay N
取消先前的 display 设置,编号从 1 递增
info register
- 运行
r(run) [arglist]
,如果没有断点则执行完,否则暂停在第一个可用断点处 - 继续执行被调试程序
c(continue) (num)
,直至下一个断点或程序结束- 后面跟上数字表示执行该命令的次数
- 执行一行源程序代码:
- 如果该行有程序调用,则进入该函数
s(step into)
,单步进入- 要求进入的函数由调试信息且有源码信息
- 使用
finish
跳过函数的执行
- 一并执行该行代码中的函数调用
n(step over) (num)
,单步执行- 后面跟上数字表示执行该命令的次数
- 如果该行有程序调用,则进入该函数
- 执行一行汇编指令
si/ni
,类似于 s/n 命令
- help,提供对 GDB 各种命令的解释说明
- 指定了命令名称参数,则显示该命令的详细说明
help display
- 没有指定参数,则分类显示所有 GDB 命令
- 指定了命令名称参数,则显示该命令的详细说明
- 直接回车,表示重复上一次命令
执行 sudo gdb golang_binary_file
。比如有一个 Golang 的可执行程序 rtspserver,依赖 ffmpeg 库。调试的流程:
# 开始调试
gdb
# 进入 gdb 之后先设置 ffmpeg 库路径
set environment LD_LIBRARY_PATH=/home/kiki/Documents/ffmpeg/ffmpeg-4.1/lib
# 开始调试
file rtspserver
# 运行程序
r
# 程序崩溃,查看堆栈
where
# ... ...
man gdb
- GDB调试入门指南