Linux下调试core dump 文件的方法

本文介绍在Linux系统中如何开启core dump功能并利用gdb进行core文件调试,包括设置core文件生成条件、查看core文件及调试技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在开发和使用Linux 程序时,引擎有时会莫名
其妙的core 掉,在网上查了一下,整理了一个简
单的调试core 文件的方法。
1、什么是core dump?
Core,即core memory,而dump 就是堆放的
意思。core dump 又叫核心转储,当程序运行过
程中发生异常,程序异常退出时,由操作系统把
程序当前的内存状况存储在一个core 文件中,
叫core dump。
2、如何打开core dump支持?
有的操作系统并没有默认打开core dump 支
持,需要用ulimit -c unlimited 语句进行设置,
core 文件生成的位置一般在程序运行的当前目
录下,文件名为core. 进程号( 当然不同的系统
也许有所不同,可以查看相手册对路径和文件名
进行设置).
3、Core dump的使用方法
首先应该在用gcc 进行编译时选择-g 选项,
以便起动debug 支持,生成可执行文件时ex,./
ex 运行可执行文件,如果程序当掉,则会生成
一个core 文件,假设为core.1568,则gdb ex
core.1568 进入gdb,然后再用where 命令进行
查看即可。
先看看我用的是个什么机器:
$ uname -a
再看看默认的一些参数,注意core file size
是个0,程序出错时不会产生core 文件了。
$ ulimit -a
core file size (blocks, -c) 0
……
写个简单的程序,看看core 文件是不是会被
产生。
(代码略)
$ gcc -Wall -g foo.c
$ ./a.out
Segmentation fault
$ ls -l core.*
ls: core.*: No such file or directory
没有找到core 文件,我们改改ulimit 的设置,
让它产生。1024 是随便取的,要是core 文件大
于1024 个块,就产生不出来了。
$ ulimit -c 1024
$ ulimit -a
core file size (blocks, -c) 1024
……
$ ./a.out
Segmentation fault (core dumped)
$ ls -l core.*
-rw------- 1 uniware uniware 53248
Jun 30 17:10 core.9128
注意看上述的输出信息,多了个(core
dumped)。确实产生了一个core 文件,9128 是
该进程的PID。我们用GDB 来看看这个core。
$ gdb --core=core.9128
(输出信息略)
(gdb) bt
#0 0x08048373 in ?? ()
#1 0xbfffd8f8 in ?? ()
#2 0x0804839e in ?? ()
#3 0xb74cc6b3 in ?? ()
#4 0x00000000 in ?? ()
此时用bt 看不到backtrace,也就是调用堆栈,
原来GDB 还不知道符号信息在哪里。我们告诉
它一下:

(gdb) file ./a.out

(gdb) bt
#0 0x08048373 in sub () at foo.c:17
#1 0x08048359 in main () at foo.c:8
此时backtrace 出来了。
在程序不寻常退出时,内核会在当前工作目
录下生成一个core 文件(是一个内存映像,同时
加上调试信息)。使用gdb 来查看core 文件,可
以指示出导致程序出错的代码所在文件和行数。
其他总结
1.core文件的生成开关和大小限制
1)使用ulimit -c 命令可查看core 文件的生
成开关。若结果为0,则表示关闭了此功能,不
会生成core 文件。
2)使用ulimit -c filesize 命令,可以限制
core 文件的大小(filesize 的单位为kbyte)。若
ulimit -c unlimited,则表示core 文件的大小不
受限制。如果生成的信息超过此大小,将会被裁
剪,最终生成一个不完整的core 文件。在调试
此core 文件的时候,gdb 会提示错误。
2.core文件的名称和生成路径
core 文件生成路径:
输入可执行文件运行命令的同一路径下。
若系统生成的core 文件不带其他任何扩展名
称,则全部命名为core。新的core 文件生成将
覆盖原来的core 文件。
1)/proc/sys/kernel/core_uses_pid 可以控
制core 文件的文件名中是否添加pid 作为扩展。
文件内容为1,表示添加pid 作为扩展名,生成的
core 文件格式为core.xxxx ;为0 则表示生成的
core 文件同一命名为core。
可通过以下命令修改此文件:
echo “1″ > /proc/sys/kernel/core_uses_
pid
2)proc/sys/kernel/core_pattern 可以控制
core 文件保存位置和文件名格式。
可通过以下命令修改此文件:
e c h o “/ c o r e f i l e / c o r e -%e -%p -%t” >
core_pattern,可以将core 文件统一生成到/
corefile 目录下,产生的文件名为core- 命令
名-pid- 时间戳
3.core文件的查看
core 文件需要使用gdb 来查看。
gdb ./a.out
core-file core.xxxx
使用bt 命令即可看到程序出错的地方。
以下两种命令方式具有相同的效果,但是在
有些环境下不生效,所以推荐使用上面的命令。
1)gdb -core=core.xxxx
file ./a.out
bt
2)gdb -c core.xxxx
file ./a.out
bt
4. 开发板上使用core 文件调试
在 PC 上调试开发板上产生的core 文件,需
要使用交叉编译器自带的gdb,并且需要在gdb
中指定solib-absolute-prefix 和 solib-searchpath
两个变量以保证gdb 能够找到可执行程序
的依赖库路径。有一种建立配置文件的方法,不
需要每次启动gdb 都配置以上变量,即:在待运
行gdb 的路径下建立.gdbinit。
配置文件内容:
set solib-abso lute-prefix YOUR_CROSS_
COMPILE_PATH
s e t s o l i b - s e a r c h - p a t h Y O U R _ C R O S S _
COMPILE_PATH
set solib-search-path YOUR_DEVELOPER_
TOOLS_LIB_PATH
handle SIG32 nostop noprint pass
注意:待调试的可执行文件,在编译的时候需
要加-g,core 文件才能正常显示出错信息!有
时候core 信息很大,可以通过挂载到PC 的方式
来规避这一点.


<think>我们正在分析一个内核崩溃(panic)的调用栈。用户提到涉及mrdump.ko模块(内存转储模块)以及atomic_notifier_call_chain和do_exit等函数。但用户提供的调用栈中并没有直接出现mrdump.ko和atomic_notifier_call_chain,而是出现了panic和进程退出的路径。因此,我们需要结合调用栈和内核panic的常见原因来分析。调用栈回溯:[<ffffffdd4e12a1e8>]panic+0x1b0/0x474[<ffffffdd4e1384dc>]do_exit+0xae0/0x1040[<ffffffdd4e137900>]do_group_exit+0xc4/0x1c0[<ffffffdd4e15ac68>]get_signal+0xcf8/0xfa0[<ffffffdd4e083ea8>]do_signal+0x98/0x254[<ffffffdd4e083c7c>]do_notify_resume+0xb4/0x248[<ffffffdd4e013484>]work_pending+0x8/0x384注意:这个调用栈显示的是从work_pending开始,经过一系列函数调用最终导致panic。关键点在于panic是从do_exit函数中调用的。分析:1.调用栈起始于`work_pending`,这是内核在返回用户空间之前处理待处理工作的入口点。2.然后进入`do_notify_resume`,它处理信号和进程状态恢复。3.接着调用`do_signal`,用于处理传递给进程的信号。4.在`get_signal`函数中,内核处理接收到的信号。根据调用栈,在`get_signal`中调用了`do_group_exit`(因为偏移量0xcf8处是`do_group_exit`的调用点?注意调用栈中的地址偏移,我们需要结合代码具体分析,但通常调用栈中函数名后面的偏移量表示函数内的偏移,因此可以推测在`get_signal`函数内部执行到了某个分支调用了`do_group_exit`)。5.`do_group_exit`用于处理进程组退出,然后调用`do_exit`。6.在`do_exit`函数中,发生了panic。因此,问题出在`do_exit`函数执行过程中。panic通常发生在内核检测到无法恢复的错误时,比如内核态访问非法地址、断言失败、关键数据结构损坏等。结合用户提到的mrdump.ko模块(这是一个内存转储模块,用于在发生panic时保存内存快照)和atomic_notifier_call_chain(原子通知链,用于在系统事件发生时调用注册的回调函数),我们可以推测:-在`do_exit`函数执行过程中,可能触发了某个通知链(例如进程退出通知链),而mrdump.ko可能注册了该通知链的回调函数。-在执行通知链回调时,可能由于某种原因(如回调函数访问了无效的内存地址)导致内核崩溃。另一种可能是,在`do_exit`函数中,由于进程退出时的资源清理过程中遇到严重错误(例如释放已经被释放的资源,或访问了已经释放的内存),导致内核崩溃。但需要注意的是,调用栈中并没有直接出现atomic_notifier_call_chain,因此我们只能推测它可能被包含在`do_exit`函数调用的某个子函数中。根据Linux内核代码,`do_exit`函数会调用`exit_notify`,而`exit_notify`会调用`forget_original_parent`和`exit_ptrace`等函数,其中可能会通过通知链通知其他模块。此外,`do_exit`还会调用`profile_handoff_task`(如果配置了性能分析)等,这些地方都有可能调用通知链。具体分析步骤:1.**定位panic发生点**:在调用栈中,panic函数被调用,说明在`do_exit`函数中调用了`panic`。我们需要查看内核源码中`do_exit`函数,找到在什么情况下会调用`panic`。在标准内核代码中,`do_exit`函数通常不会直接调用`panic`。但是,在一些特定情况下,比如内核调试选项(如`CONFIG_DEBUG_OBJECTS`)检测到错误时,可能会调用`panic`。或者,在`do_exit`中调用的某个函数(如资源释放函数)发生了BUG_ON或panic。2.**检查mrdump.ko的影响**:mrdump.ko模块可能会在系统panic时被调用,以保存内存转储。但在这个调用栈中,panic发生在`do_exit`中,而mrdump.ko可能是在panic之后才被调用的(因为panic函数会调用注册的panic处理程序)。因此,mrdump.ko可能是用于捕获这次panic的,而不是导致panic的原因。3.**考虑原子通知链(atomic_notifier_call_chain)**:在进程退出过程中,内核会调用`profile_handoff_task`,该函数会通过`blocking_notifier_call_chain`(或原子通知链)发送任务退出通知。如果注册到该通知链的某个回调函数(可能是mrdump.ko或其他模块)有缺陷,就可能导致内核崩溃。4.**结合调用栈偏移量分析**:在调用栈中,`do_exit`函数的偏移量是0xae0,即`do_exit+0xae0`处。我们可以通过反汇编内核或查看内核源码,定位该偏移量对应的代码位置。例如,假设`do_exit`函数的起始地址为A,那么A+0xae0处的指令就是发生panic的位置。通过这个位置,我们可以知道在`do_exit`函数中具体是哪一行代码导致了panic。5.**查看内核日志**:除了调用栈,内核在panic时通常会打印出更多的信息,比如寄存器状态、堆栈内容、错误描述(如"BUG:unabletohandlekernelNULLpointerdereference")等。这些信息对于定位问题至关重要。由于我们没有更多的日志信息,这里只能给出可能的原因方向:**可能的原因**:-进程退出过程中,某个资源(如文件描述符、内存映射、信号处理等)已经被释放,但在后续清理步骤中又被访问,导致Use-After-Free。-通知链回调函数(可能是mrdump.ko或其他模块注册的)存在缺陷,比如访问了无效指针。-内核数据结构损坏(如task_struct结构被破坏),导致在`do_exit`中访问时出错。**调试建议**:1.**获取完整的内核崩溃日志**:包括panic消息、寄存器信息、堆栈内容等。2.**定位`do_exit+0xae0`对应的代码**:通过反汇编内核,找到该地址对应的代码行,查看是什么操作导致了panic。3.**检查mrdump.ko模块**:确认其版本和兼容性,是否与当前内核匹配。尝试卸载mrdump.ko,看问题是否复现。4.**检查其他内核模块**:特别是那些注册了任务退出通知链的模块。5.**使用内核调试工具**:如KGDB、kdump等,获取崩溃时的内存转储,然后使用GDB分析。由于调用栈显示panic发生在`do_exit`函数中,而`do_exit`是进程退出的必经之路,因此问题可能由特定进程的退出触发。可以尝试:-分析崩溃时正在退出的进程(通过内核日志中打印的进程信息)-检查该进程的资源和状态是否异常如果无法获取更多日志,可以尝试复现问题,并在内核配置中打开更多调试选项(如`CONFIG_DEBUG_KMEMLEAK`、`CONFIG_DEBUG_SLAB`等)。总结:根据现有信息,问题发生在进程退出路径上(`do_exit`函数内部),具体原因需要结合崩溃点的代码和寄存器状态分析。§§相关问题§§1.如何通过反汇编Linux内核定位函数内的偏移地址?2.在Linux内核中,do_exit函数通常会在哪些情况下调用panic?3.如何调试Linux内核模块(如mrdump.ko)导致的内核崩溃?4.如何获取和分析Linux内核崩溃时的完整日志?5.原子通知链(atomic_notifier_call_chain)在Linux内核中有哪些应用场景?</think>### 分析 Linux 内核崩溃调用栈定位 panic 原因 从提供的调用栈分析,问题发生在进程退出路径中触发了内核 panic。调用栈显示完整的信号处理到进程退出的执行路径,最终在 `do_exit` 函数中引发系统级崩溃。以下是关键环节分析: ```plaintext [<ffffffdd4e12a1e8>] panic+0x1b0/0x474 [<ffffffdd4e1384dc>] do_exit+0xae0/0x1040 [<ffffffdd4e137900>] do_group_exit+0xc4/0x1c0 [<ffffffdd4e15ac68>] get_signal+0xcf8/0xfa0 [<ffffffdd4e083ea8>] do_signal+0x98/0x254 [<ffffffdd4e083c7c>] do_notify_resume+0xb4/0x248 [<ffffffdd4e013484>] work_pending+0x8/0x384 ``` #### 关键问题定位 1. **`do_exit` 函数异常 (崩溃点)** `panic` 直接由 `do_exit+0xae0` 触发,表明进程退出过程中出现不可恢复错误: - 可能原因:资源释放异常(如双释放)、内核数据结构损坏、硬件资源耗尽 - 典型场景:$$ \text{内存页释放失败} \quad \text{或} \quad \text{task\_struct 结构体损坏} $$ 2. **`mrdump.ko` 模块关联性** 内存转储模块通常在 panic 后激活,但若其回调函数通过 `atomic_notifier_call_chain` 注册: - 可能在进程退出路径中被触发(如 `profile_munmap` 通知链) - 风险点:模块未正确处理原子上下文导致死锁或内存访问冲突 3. **信号处理路径分析** `get_signal+0xcf8` 偏移指向信号强制退出的关键分支: ```c // 内核代码片段 (signal.c) if (sig_kernel_coredump(signr)) { do_coredump(&ksig->info); // 可能触发 mrdump } else if (sig_kernel_exit(signr)) { do_group_exit(exit_code); // → 最终触发 panic } ``` #### 根本原因假设 结合调用栈和模块特性,最可能的原因链: $$ \text{信号触发} \rightarrow \text{进程退出} \rightarrow \text{资源清理} \xrightarrow{\text{mrdump回调}} \text{原子操作冲突} \rightarrow \text{panic} $$ 具体可能性: 1. **原子上下文违规** `atomic_notifier_call_chain` 在中断上下文执行时,`mrdump.ko` 尝试了阻塞操作(如内存分配) 2. **内存映射冲突** 进程退出时释放用户内存空间,与 `mrdump` 的转储操作发生 VMA 访问竞争 3. **硬件资源耗尽** OOM 场景下 `do_exit` 尝试释放资源时遭遇: - 页分配失败:`alloc_pages(GFP_ATOMIC)` 返回 NULL - 锁依赖破坏:$$ \text{spin\_lock\_irqsave() 在无效地址调用} $$ #### 诊断步骤 1. **定位崩溃点代码** ```bash # 通过 vmlinux 反汇编 arm64-linux-gnu-objdump -d vmlinux | grep -A 20 "do_exit+0xae0" ``` 2. **检查 mrdump 通知链注册** ```bash # 查看 notifier 注册点 grep -rn "atomic_notifier_chain_register" /path/to/mrdump.ko ``` 3. **分析崩溃时内存状态** ```bash crash /path/to/vmlinux /path/to/vmcore crash> bt -f # 完整堆栈 crash> ps # 退出进程状态 crash> struct task_struct -x <退出进程地址> ``` 4. **复现时开启内核检测** ```bash # 启用死锁检测 echo 1 > /proc/sys/kernel/softlockup_panic # 启用内存检测 CONFIG_DEBUG_KMEMLEAK=y ``` #### 修复方向 - **mrdump 模块**:确保通知回调函数满足原子操作要求: ```c static int mrdump_callback(struct notifier_block *self, unsigned long cmd, void *v) { // 禁止阻塞操作 if (!in_atomic()) return NOTIFY_DONE; ... } ``` - **内核补丁**:在 `do_exit` 关键路径添加资源检查: ```c if (WARN_ON_ONCE(atomic_read(&mm->mm_users) < 0)) panic("mm_users underflow"); ``` > 关键证据:若 `dmesg` 出现 `"BUG: scheduling while atomic"` 或 `"Unable to handle kernel paging request"` 日志,可确认原子上下文违规问题[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值