目录
5.1 场景:某嵌入式设备程序偶发崩溃,coredump显示SIGSEGV信号
6. 通过 -fsanitize=address 检测内存问题的
7. 使用 addr2line 解析 0x7f1c8d8d6a56 地址的完整方法
GDB 工具是最常见的调试工具,也是平常工作中使用频率最高最广为人知的嵌入式Linux产品软件调试工具。要想使用该工具进行代码调试,首先需要在编译程序时需添加-g
选项保留调试信息。这是前提,否则无法进行后续操作。话不多说,直接进入正题。
一. GDB基础调试
1. 启动与断点操作
假如你有一个程序,首先须在编译工具makefile等通过交叉编译工具链编译成一个可执行文件,例如program,编译成功后按照如下操作可以进行gdb工具的基本操作。
-
加载程序:
gdb program
- 设置断点:
gdb program #进入gdb后 (gdb) break main # 在main函数处设断点 break file.c:20 # 在指定文件行号设断点 break func if var=5 # 条件断点
-
执行控制命令
-
run
:启动程序 -
next
(逐行跳过函数) /step
(进入函数) -
continue
:继续执行至下一断点
-
信息查看
-
print var
:查看变量值。 -
backtrace
(bt
):显示调用栈。 -
info locals
:查看当前函数局部变量。
2. 使用GDB 分析coredump文件
2.1 怎样生成coredump 文件
- 目标板解除coredump文件大小限制
ulimit -c unlimited # 允许生成任意大小的coredump文件 若需永久生效,需修改/etc/security/limits.conf配置文件。
- 设置coredump文件存储路径与命名规则
echo "/data/coredump/core-%e-%t-%p" > /proc/sys/kernel/core_pattern 支持的格式参数: %e:可执行文件名 %t:崩溃时间戳 %p:进程PID
2.2 怎样分析coredump 文件
- 加载coredump文件
程序崩溃后会生成coredump 在开发板使用交叉编译环境对应的GDB工具加载coredump文件: arm-linux-gnueabihf-gdb <可执行文件路径> <coredump文件路径> 例如: 以上面设置的路径为例,则在目标板执行如下命令: arm-linux-gnueabihf-gdb program /data/coredump/coredump文件
- 查看崩溃调用栈
加载coredump后,通过执行bt,可以定位分析崩溃位置。例如: (gdb) bt full # 显示完整调用栈及局部变量 (gdb) f <栈帧编号> # 切换到具体栈帧上下文
f + 栈帧编号
的作用
f 0
(frame 0
的缩写)表示切换到编号为0的栈帧,即直接定位到程序崩溃时执行的函数上下 文,此时可查看:
-
当前函数的局部变量(
info locals
) -
函数参数(
info args
) -
寄存器状态(
info registers
)
- 当前活动栈帧编号
通过(gdb) bt #0 0x080489a0 in process_data () at src/main.c:38 // 当前崩溃位置 #1 0x08048b2c in data_processing_thread (arg=0x0) at src/thread.c:56 #2 0xf7e3d4c0 in start_thread () from /lib/libpthread.so.0
bt
命令查看调用栈时,栈帧编号从0开始递增:
#0
:程序崩溃时正在执行的函数(最内层调用)#1
:调用#0
函数的父函数- 依此类推,直到
main
函数(最高编号)
- 线程分析
info threads
:显示所有线程状态thread <ID>
:切换至指定线程上下文break file.c:30 thread all
:在所有线程设置断点
-
关键信息检查
- 指针变量分析:
(gdb) print *ptr # 检查空指针或非法内存访问
- 内存越界检测:
(gdb) x/10x &array # 查看数组内存分布是否异常
- 指针变量分析:
2.3 为何选择编号0?
-
崩溃现场定位
当程序触发
SIGSEGV
等信号时,栈帧0是导致崩溃的直接位置。例如:(gdb) bt #0 0x080489a0 in process_data () at src/main.c:38 // 崩溃点 #1 0x08048b2c in data_processing_thread (arg=0x0) at src/thread.c:56
此时切换到
f 0
可精确观察process_data()
函数内部的变量和代码状态,而非其调用者data_processing_thread
。 <