如何在看不到核心转储文件的情况下排查程序崩溃问题
在Linux开发过程中,程序崩溃时生成核心转储文件(core dump)是调试的重要手段。然而,有时候我们会遇到看不到核心转储文件的情况,或者即使有了核心转储文件,也难以快速找到问题的根源。本文将详细记录一次使用核心转储文件排查问题的过程,希望能为大家提供一些参考。
一、看不到核心转储文件时的处理步骤
当程序崩溃后看到类似“段错误 (核心已转储)”的提示时,却发现没有生成核心转储文件,可以按以下步骤操作:
-
检查核心转储文件是否被生成:
- 核心转储文件通常被保存在当前工作目录或系统指定的目录下,可以使用以下命令来查看核心转储文件的生成路径:
如果输出为ulimit -c
0
,说明系统禁止生成核心转储文件。可以通过以下命令启用:ulimit -c unlimited
- 核心转储文件通常被保存在当前工作目录或系统指定的目录下,可以使用以下命令来查看核心转储文件的生成路径:
-
检查核心转储文件路径配置:
- 核心转储文件的路径由系统参数
core_pattern
决定。可以通过以下命令查看:
通常情况下,如果路径以cat /proc/sys/kernel/core_pattern
|
开头,说明核心转储文件被管道到一个处理程序,比如apport
。如果希望将核心转储文件保存在程序目录下,可以修改core_pattern
:
这将核心转储文件命名为echo "./core.%e.%p" | sudo tee /proc/sys/kernel/core_pattern
core.<程序名>.<进程ID>
并保存在当前目录。
- 核心转储文件的路径由系统参数
-
验证生成:
- 重现崩溃问题,确认核心转储文件是否正确生成,并检查文件大小和位置。
二、使用核心转储文件进行问题排查
在成功获取核心转储文件后,可以使用 gdb
等调试工具进行问题排查。以下是一个具体的案例分析:
-
加载核心转储文件:
- 使用以下命令启动
gdb
,并加载生成的核心转储文件:
例如:gdb <程序名> <核心转储文件名>
gdb server ./server.core.26400
- 使用以下命令启动
-
查看崩溃位置:
- 加载核心转储文件后,
gdb
会自动显示崩溃的位置:
上述信息表明,程序因Core was generated by `./server'. Program terminated with signal SIGSEGV, Segmentation fault. #0 0x00007f224c28cddb in _IO_new_fclose (fp=0x0) at iofclose.c:48
SIGSEGV
信号(分段错误)崩溃,崩溃发生在fclose
函数内,因为传递给fclose
的文件指针fp
为NULL
。
- 加载核心转储文件后,
-
查看调用栈:
- 使用
bt
(backtrace)命令查看调用栈,确定崩溃时的函数调用顺序:
调用栈显示,(gdb) bt #0 0x00007f224c28cddb in _IO_new_fclose (fp=0x0) at iofclose.c:48 #1 0x000055d1bfdf20bc in Log::write (this=0x55d1bfe20460 <Log::Instance()::inst>, level=1, format=0x55d1bfe14071 "log level is %d") at ../code/log/log.cpp:121 #2 0x000055d1bfdf2682 in Log::init (this=0x55d1bfe20460 <Log::Instance()::inst>, level=level@entry=1, path=path@entry=0x55d1bfe16149 "./log", suffix=suffix@entry=0x55d1bfe16144 ".log", maxQueueSize=maxQueueSize@entry=1024) at ../code/log/log.cpp:48
fclose
被Log::write
函数调用,而Log::write
又是从Log::init
中调用的。
- 使用
-
分析问题根源:
- 根据调用栈,可以推断出问题可能出现在日志系统的初始化过程中。具体地,日志系统在
Log::init
中未能正确打开日志文件,导致Log::write
中的文件指针为NULL
,最终导致fclose
崩溃。 - 进一步查看
Log::init
和Log::write
的实现,可以确认是否存在文件打开失败、未检查文件指针有效性等问题。
- 根据调用栈,可以推断出问题可能出现在日志系统的初始化过程中。具体地,日志系统在
-
修复与验证:
- 在代码中添加检查逻辑,确保在调用
fclose
之前文件指针有效。修复完成后,重新编译程序并验证问题是否解决。
- 在代码中添加检查逻辑,确保在调用
总结
通过以上步骤,即使在看不到核心转储文件的情况下,我们也能通过配置系统参数和使用调试工具找到程序崩溃的根源。在这个案例中,我们发现了日志系统未正确处理文件指针的情况,并最终通过添加检查逻辑解决了问题。这一过程不仅提升了我们对系统调试工具的熟悉程度,也增强了我解决实际问题的能力。希望这篇博客能为大家在遇到类似问题时提供一些帮助。