CoreDump原理和调试指南

CoreDump 原理和调试指南

从原理、配置到调试指南的完整手册。


一、CoreDump 逻辑链

CoreDump 的完整处理流程如下:

步骤 阶段 说明
1 触发 程序在用户态干了非法事(如空指针访问)
2 捕获 CPU 异常,强制切到内核态(此时还在该进程的上下文里)
3 裁决 内核决定发 SIGSEGV,在进程的 pending 位图上做标记
4 返回 内核准备切回用户态
5 劫持 内核检查到位图标记,修改用户态栈和 PC 指针
6 执行 程序回到用户态,被迫执行你写的信号处理函数(或直接默认自杀)
7 遗言 如果是默认自杀,内核在该进程上下文中执行 do_coredump,把内存写成 core 文件
8 终局 进程彻底消亡(do_exit),文件留在磁盘供 GDB 调试

二、触发 CoreDump 的主要信号

编号 信号名称 解释
11 SIGSEGV 非法内存引用(段错误)
6 SIGABRT 程序主动调用 abort()
4 SIGILL 非法指令
7 SIGBUS 总线错误
8 SIGFPE 算术运算异常

主动触发 CoreDump

# 方式一:使用 gcore 工具
gcore <PID>

# 方式二:发送信号
kill -3 <PID>

三、编译选项设置

为了后续 GDB 调试 coredump 文件,需要使用 -g 编译选项来生成带调试信息的可执行文件,同时建议加上 -O0 关闭优化,避免调试时变量被优化掉或行号错乱。

gcc -g -O0 -o myapp myapp.c

生产环境部署

为了避免带调试信息的可执行文件暴露源码信息,使用 strip 命令剥离调试符号,生成一个不带符号的版本部署到生产环境,同时保留带符号的原始文件用于事后调试。

# 剥离调试符号
strip -s myapp -o myapp-stripped

四、CoreDump 相关配置

4.1 开启 CoreDump 功能

方法一:永久配置

vi /etc/security/limits.conf
# 在文件末尾添加:
* soft core unlimited
* hard core unlimited

方法二:临时配置

ulimit -c unlimited    # 只对当前 shell 生效

验证配置是否生效

# 查看当前 shell 是否生效
ulimit -c

# 查看应用进程是否生效
cat /proc/PID/limits

⚠️ 注意:开启 coredump 功能后,需要重新登录用户、重新启动应用进程。如果应用进程是由另外一个父应用进程 fork 启动的,需要重启其父应用进程。


4.2 配置存储路径与命名

格式说明

占位符 含义
%e 进程名(executable name)
%p 进程 ID(PID)
%t 时间戳
%h 主机名

自定义存储路径与命名

vi /etc/sysctl.conf
# 文件末尾添加:
kernel.core_pattern=/corefiles/core_%e_%p

# 让配置生效
sysctl -p /etc/sysctl.conf

# 查看配置结果
cat /proc/sys/kernel/core_pattern

临时修改(重启后失效)

sysctl -w kernel.core_pattern="/corefiles/core_%e_%p"

⚠️ 注意:

  • 运行应用程序的用户必须对 core 文件的存储目录拥有写入权限
  • 确保 core 文件存储目录所在的磁盘分区有足够的剩余空间

五、GDB 打开 CoreDump 文件

5.1 使用带符号的版本

gdb myapp-full-debug core.12345

5.2 使用 Stripped 版本 + 符号文件

# 1. 启动 GDB,加载主程序和 coredump
gdb myapp-stripped core.12345

# 2. 加载主程序符号文件
symbol-file myapp.symbol

# 3. 查看动态库加载地址
info sharedlibrary

# 输出示例:
# From        To          Syms Read   Shared Object Library
# 0x00007f8a2a4a0000  0x00007f8a2a5c3a5f  Yes  /lib/x86_64-linux-gnu/libc.so.6
# 0x00007f8a2a2a0000  0x00007f8a2a3a1a5f  Yes  /usr/lib/libmylib.so
# 0x00007f8a2a0a0000  0x00007f8a2a1a1a5f  Yes  /lib/ld-linux-x86-64.so.2

# 4. 加载动态库的符号文件(需要指定基地址)
add-symbol-file libmylib.symbol 0x00007f8a2a2a0000

# 5. 查看当前加载的符号信息
info files          # 显示所有已加载的符号文件
info sharedlibrary  # 查看动态库加载状态

六、CoreDump 定位常用命令

6.1 常用命令

命令 说明
bt 打印调用栈
f <栈帧编号> 切换到指定栈帧
p <变量> 打印指定变量的值
info locals 或 info l 打印当前栈帧的所有局部变量
info args 打印当前栈帧函数的所有参数
info frame 打印当前栈帧的详细信息

6.2 多线程分析

命令 说明
info threads 或 info t 列出所有线程
thread <线程编号> 或 t <线程编号> 切换到指定线程
thread apply all bt 打印所有线程的调用栈

6.3 内存检查

x 命令语法

x/<n/f/u> <addr>
参数 说明
n 正整数,表示显示内存单元个数
f 显示格式:x=十六进制,s=字符串,i=指令地址
u 单元大小:b=单字节,h=双字节,w=四字节,g=八字节

示例

x/10i 0x555555555140    # 从某地址开始看 10 条指令
x/16xg 0x555555555140    # 以十六进制显示 16 个单元,一单元8个字节

其他内存命令

命令 说明
info proc mappings 显示进程的虚拟内存地址空间映射表

6.4 查看寄存器

命令 说明
info registers 或 info reg 显示所有寄存器

关键寄存器

X86寄存器 ARM寄存器 说明
rsp sp 堆栈指针寄存器,指向当前堆栈帧的顶部
rbp fp/x29 栈帧基址指针寄存器,指向当前函数的栈帧的基址
rip pc 正在执行的指令地址

6.5 反汇编

命令 说明
disassemble 反汇编当前函数
disassemble <函数名> 反汇编指定函数
disassemble /m <函数名> 源码和汇编对照阅读
disassemble <start>, <end> 反汇编指定地址区间
disassemble <start>, +<len> 从该地址开始反汇编指定长度

6.6 其他实用命令

命令 说明
set print pretty on 启用结构化缩进显示
set print object on 按照对象的实际派生类型来打印
set print elements 0 完整打印容器中所有元素

6.7 辅助定位工具

命令 说明
addr2line -e <程序> -f -C <地址> 将符号表地址转换为源代码文件名和行号
strings <core文件> | grep -i <关键词> 从 core 文件中提取可打印字符串,搜索特定关键词
nm <程序> 列出目标文件中的符号表
file <文件> 识别文件类型
stat <文件> 显示文件的详细元数据
readelf -h <core文件> 显示 ELF 文件头信息
posted @ 2026-09-29 09:45  CJXUNOO  阅读(5)  评论(0)    收藏  举报