在Linux下开发应用程序时,我们经常会遇到程序崩溃的问题,比如Segmentation fault
。
这样的问题是比较棘手的,因为出错时往往没有相关的报错信息打印出来。
当问题容易复现或者可以在开发环境下进行调试时,我们可以直接使用gdb来调试我们的程序。
但是当问题不易复现或者处于生产环境时,使用gdb直接调试的效率就比较低了。
在这种情况下,保存core dump
文件的重要性就体现出来了。
什么是core dump
文件
core dump
文件也叫核心存储文件,它是操作系统在程序崩溃时自动生成的文件,包含了程序在崩溃时的内存快照(如寄存器状态、调用栈等)。
我们可以使用gdb分析core dump
文件,从而分析出程序崩溃的具体原因。
下面就来看看具体方法吧。
配置和存储 core dump
文件
检查配置
在默认情况下,Linux可能不会自动生成core dump
文件,可以执行如下命令查看自己的配置:
ulimit -c
如果回显为0,则说明当前不会生成
core dump
文件。
生成core dump
文件
为了生成core dump
文件,首先要解除文件大小限制,执行如下命令:
ulimit -c unlimited
这里将文件的大小设置为了无限制,大家也可以根据自己的实际需要设置大小。
配置路径
文件/proc/sys/kernel/core_pattern
中保存了core dump
文件的默认存储路径。
大家可以使用cat
命令查看下这个文件的内容,输出的结果可能是类似于core
或/var/core/%e.%p.%t
。
其中%e
表示程序名称,%p
表示进程 ID,%t
表示时间戳。
注意,如果文件/proc/sys/kernel/core_pattern
中出现的是apport
,说明系统当前使用Apport
服务处理程序崩溃。
这个时候我们的core dump
文件不会在默认存储路径下生成。
因此,我们需要修改core_pattern
,将core dump
文件保存到自己指定的目录,例如/var/core_dumps/
:
echo "/var/dumps/core_%e.%p.%t" | sudo tee /proc/sys/kernel/core_pattern
注意给/var/dumps/设置合适的读写权限。
如果想恢复Apport服务的存储路径,可以执行如下命令:
sudo systemctl restart apport.service
调试core dump
文件
在配置完成后,我们可以编写一个简单的 C 程序segfault.c
,故意导致崩溃,从而验证core dump
文件是否正确生成:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *p = NULL;
/* 故意制造一个段错误 */
*p = 10;
return 0;
}
编译并运行上述代码:
# 使用-g添加调试信息
gcc -g segfault.c -o segfault
./segfault
程序崩溃后,我们可以检查在配置目录下是否生成了 core dump
文件。
接下来我们可以使用gdb对core dump
文件进行分析:
gdb ./segfault /var/dumps/your_core_dump_file
执行后可以得到如下信息:
...
Reading symbols from ./segfault...
[New LWP 111402]
Core was generated by `./segfault'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00005585739b113d in main () at segfault.c:8
8 *p = 10;
...
可以看到,通过使用gdb分析core dump
文件,我们直接找到了出问题的代码。
总结
通过设置 ulimit
和 core pattern
,并确保适当的目录权限,我们就可以让系统在程序崩溃时自动存储 core dump
文件,从而帮助我们调试分析问题。希望这篇文章对大家有所帮助。
最后,欢迎大家关注我的微信公众号《嵌入式 3分钟》,一起学习嵌入式!