GDB 调试 Coredump

news2024/11/24 17:01:10

在这里插入图片描述

在计算机系统中运行程序时,问题经常发生,而且通常很难找到根源。幸运的是,有一种叫做 coredump 的文件可以帮助我们找到问题的源头。本文将解释什么是 coredump,它是如何工作的,以及如何利用它来定位问题。

01 什么是 coredump


Core dump(核心转储)是指在程序运行过程中发生错误或异常时,操作系统将程序的内存内容保存到磁盘上的一种文件。这个文件包含了程序崩溃时的内存状态,包括变量的值、函数调用栈、寄存器状态等信息。通过分析 coredump 文件,可以了解程序崩溃的原因,以便进行调试和修复。

1.1 ulimit 命令

要生成 core dump 文件,通常需要在操作系统中设置相应的配置。在 Linux 和 Unix 系统中,可以使用 ulimit 命令设置 core dump 文件的大小限制,并使用 gcore 或 kill -SIGQUIT 命令生成 core dump 文件。

ulimit 是 Unix 和 Linux 系统中的内置命令,用于控制用户级别的系统资源限制。这些资源包括文件大小、进程数、核心文件大小、堆栈大小等等。以下是一些使用 ulimit 的基础知识。

使用 ulimit -a 可以列出所有的限制,每一行都对应一个资源类型和其对应的限制。
以下是一些比较常用的 ulimit 选项:

  • ulimit -u : 查看用户可以用的最大进程数。
  • ulimit -n : 文件描述符的最大个数,即一个进程可以同时打开的最大文件数。
  • ulimit -d : 一个进程可以使用的最大数据段大小,单位为KB。
  • ulimit -s : 最大堆栈大小,单位为KB。
  • ulimit -c : 生成coredump文件的最大大小,单位为KB。
  • ulimit -v : 进程虚拟内存的最大值,单位KB。

我们可以在命令后添加具体的数值来设置对应的资源限制,例如:

  • ulimit -n 1024 : 设置最大可以打开的文件描述符数为1024。
  • ulimit -c unlimited : 设置coredump的大小为无限。

需要注意的是,ulimit 命令设置的资源限制是以 Shell 环境为单位的,而不是全局性的。也就是说,在一个 Shell 环境中设置的资源限制,并不会影响到其他的 Shell 环境。同时,这些限制只对当前 Shell 环境以及它派生出来的子进程生效,对已经存在的其他进程没有影响。

总的来说,ulimit 命令是一个很有用的工具,它可以帮助我们控制进程对系统资源的使用,从而防止一些程序错误导致系统资源的耗尽。

1.2 coredump 实例

1. ulimit 查看资源限制

一般情况下如果 coredump 文件没有生成,很大可能是由于受到资源限制,使用 ulimit命令查看和设置资源限制

ulimit -c						 # 查看是否开启 core,0 表示关闭 
ulimit -c [filesize] # 设置 core 文件大小
ulimit -c unlimited  # 设置 core 文件大小为无限

2. 设置 core 文件路径

在 Linux 系统中,core dump 文件的路径是由 /proc/sys/kernel/core_pattern 定义的,如果这个文件不存在,或者内容为空,那么 core dump 文件就会生成在当前目录下

也可以通过修改 /proc/sys/kernel/core_pattern 指定 core 文件生成的路径和文件名

# 查看当前 core 文件路径
cat /proc/sys/kernel/core_pattern 

# 指定 core 文件路径
sudo echo "yourpath/core.%e.%p.%h.%t" > /proc/sys/kernel/core_pattern
sudo sysctl -w kernel.core_pattern=yourpath/core.%e.%p.%h.%t  # # 也可以使用 sysctl 修改 kernel.core_pattern 来指定 core 文件路径

其中 core 文件名称定义中,可以使用占位符保留一些有用信息

%p: pid
%u: uid
%g: gid
%s: signal number
%t: UNIX time of dump
%h: hostname
%e: executable filename

3. 空指针 core 示例

下面这个例子中试图通过一个 NULL 指针来访问内存,这是非法的,因为 NULL 指针并没有指向任何有效的内存位置,因而在运行时,操作系统将识别这个非法操作,并生成一个 Coredump 文件。

#include <stdio.h>

int main() {
    int *ptr = NULL;
    printf("%d", *ptr);
    return 0;
}

编译运行这段程序如下,可以看到触发了 core dumped

需要注意的是编译的时候记得加上 -g 参数保留调试信息,否则使用 GDB 调试时会找不到函数名或者变量名

$ gcc -g main.c -o main
$ ./main
[1]    277 segmentation fault (core dumped)  ./main

4. 使用 GDB 调试 core 文件

找到 core 文件,然后使用命令 gdb [exec file] [core file] 调试 core 文件

$ cd your-core-path
$ ls
core.main
$ gdb ~/main ./core.main

GDB 运行后会停止在发生异常的代码处,并且将发生异常的代码打印出来,如下图中指出了异常位于 mian.c 的第 5 行代码 *ptr 是一个空指针

在这里插入图片描述

02 coredump 是怎么发生的


2.1 程序运行错误导致 coredump

程序执行非法操作时,例如解引用空指针,除数为零,或者访问越界的内存,操作系统就会生成一个 coredump 文件并终止程序运行。以下是一些常见导致 core dump 发生的原因:

  • 空指针引用:当程序试图访问一个空指针时,操作系统会捕获这个错误并生成 core dump 文件
  • 内存越界:当程序试图访问超出其分配内存范围的位置时,可能会导致内存越界错误,从而触发 core dump
  • 栈溢出:当程序的函数调用栈超过其允许的最大深度时,可能会发生栈溢出错误,导致 core dump 发生
  • 除零错误:当程序试图除以零时,会触发除零错误,操作系统可能会生成 core dump 文件
  • 非法指令:当程序执行了无效或非法的机器指令时,操作系统通常会生成 core dump 文件
  • 内存分配错误:当程序遇到内存分配错误,如申请内存失败或释放已释放的内存时,可能会触发 core dump

这些程序执行非法操作时,操作系统会向指定进程发送特定信号(signal)终止程序运行并生成 coredump,一些常见信号有:

  • SIGSEGV (信号值 11):当一个进程由于无效的内存访问,如解引用空指针,或访问受保护的内存区域时,系统会向它发送此信号。这是生成coredump最常见的原因
  • SIGABRT (信号值 6):当进程自身检测到一个无法恢复的问题,并选择主动终止时,它会发送这个信号给自己。例如,C库函数abort()就会发送这个信号
  • SIGILL (信号值 4):当CPU检测到进程试图执行一条无效或未定义的指令时,系统会发送此信号。一个可能的原因是代码的内存被错误地当作数据修改
  • SIGFPE (信号值 8):在数学运算错误时发送,比如除以零或浮点溢出
  • SIGBUS (信号值 7):用于处理错误的内存访问,但这个信号在不同的系统和架构下含义可能会有所不同。在某些系统中,它用于处理对齐(alignment)问题
  • SIGQUIT (信号值 3):用户通过控制台(通常是按Ctrl+\)向进程发送此信号,它不仅会停止进程的运行,还会生成coredump
SignalValueActionComment
SIGSEGV11CoreInvalid memory reference
SIGABRT6CoreAbort signal from abort
SIGILL4CoreIllegal Instruction
SIGFPE8CoreFloating point exception
SIGBUS7CoreBus error (bad memory access)
SIGQUIT3CoreQuit from keyboard

2.2 coredump 文件生成原理

本节参考如有侵权,请告知:https://cloud.tencent.com/developer/article/1860631

coredump 文件的产生过程如下图所示:

Linux 内核实现中使用一个复杂的任务结构(task_struct)结构体来代表系统中的每个进程或线程,这个结构体被定义在 include/linux/sched.h 文件中,其中也包含了记录信号处理相关的属性,如用于存放待处理信号的 pending 信号队列和阻塞信号 blocked 等。

当一个信号被发送到进程时,它首先被添加到该进程的 pending 信号队列中。而内核在进程切换的上下文切换中,在运行被调用进程时会先检查这个 pending 信号队列。如果有待处理的信号,内核会在恢复进程运行前,调用信号的处理函数。这个过程大多数发生在 do_signal 函数中,这个函数在每次中断返回,系统调用返回,或者任何可能会改变进程状态的操作后执行。

如果一个信号是致命的(如 SIGSEGV, SIGABRT),并且进程并没有注册处理函数来处理它,那么内核会根据这个信号的默认行为来操作,比如可能会终止进程,或者产生 coredump 文件等。
在这里插入图片描述
通过上述分析,coredump 文件生成的过程可以总结为:程序运行产生 core 相关的信号 signal;do_signal 函数处理信号;如果默认行为是 Core 则调用 do_coredump 函数生成 core 文件。下面结合源码进一步分析该过程

1. 信号处理过程

在进程切换的上下文切换时,检查信号队列 pending 是否有待处理信号,有则调用 do_singal 函数处理,该函数中使用 get_signal_to_deliver 函数从进程的信号队列 pending 中获取一个信号,然后根据信号的类型来进行不同的操作。

get_signal_to_deliver 函数中处理 coredump 相关信号的代码实现如下,首先使用 dequeue_signal 函数获取信号,然后使用 sig_kernel_coredump 函数判断该信号是否为 coredump 相关信号,如果是则执行 core 相关动作

int get_signal_to_deliver(siginfo_t *info, struct k_sigaction *return_ka,
                          struct pt_regs *regs, void *cookie)
{
    sigset_t *mask = &current->blocked;
    int signr = 0;

    ...
    for (;;) {
        ...
        // 1. 从进程信号队列中获取一个信号
        signr = dequeue_signal(current, mask, info); 

        ...
        // 2. 判断是否会生成 coredump 文件的信号
        if (sig_kernel_coredump(signr)) {
            // 3. 调用 do_coredump() 函数生成 coredump 文件
            do_coredump((long)signr, signr, regs);
        }
        ...
    }
    ...
}

2. 生成 coredump 文件

当 coredump 相关信号被处理时,调用内核就会调用 do_coredump 函数来生成 coredump 文件,该函数核心代码如下,首先判断 ulimit 的资源限制情况,如果可用则创建 coredump 文件,最后将当前进程的寄存器、内存管理等相关信息写入到该文件中。

int do_coredump(long signr, int exit_code, struct pt_regs *regs)
{
    char corename[CORENAME_MAX_SIZE + 1];
    struct mm_struct *mm = current->mm;
    struct linux_binfmt *binfmt;
    struct inode *inode;
    struct file *file;
    int retval = 0;
    int fsuid = current->fsuid;
    int flag = 0;
    int ispipe = 0;

    binfmt = current->binfmt; // 当前进程所使用的可执行文件格式(如ELF格式)

    ...
    // 1. 判断当前进程可生成的 coredump 文件大小是否受到资源限制
    if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
        goto fail_unlock;

    ...
    // 2. 生成 coredump 文件名
    ispipe = format_corename(corename, core_pattern, signr);

    ...
    // 3. 创建 coredump 文件
    file = filp_open(corename, O_CREAT|2|O_NOFOLLOW|O_LARGEFILE|flag, 0600);

    ...
    // 4. 把进程的内存信息写入到 coredump 文件中
    retval = binfmt->core_dump(signr, regs, file);

fail_unlock:
    ...
    return retval;
}

如果文章对你有帮助,欢迎一键三连 👍 ⭐️ 💬 。如果还能够点击关注,那真的是对我最大的鼓励 🔥 🔥 🔥 。


参考资料

一文读懂 | coredump文件是如何生成的-腾讯云开发者社区-腾讯云

core dump 路径定义以及监控

Linux下gdb调试生成core文件并调试core文件-阿里云开发者社区

Linux进程描述符task_struct结构体详解

gdb调试coredump(使用篇)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1024366.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023/9/19 -- C++/QT

作业 1> 登录框实现注册功能&#xff0c;将注册的结果放入文件中&#xff08;君子作业&#xff09; 2> 完成文本编辑器的保存工作 void Widget::on_saveBtn_clicked() {QString fileName QFileDialog::getSaveFileName(this,"另存为","./","…

R的一些奇奇怪怪的功能

1. 欧氏距离计算 df <- data.frame(x 1:10, y 1:10, row.names paste0("s", 1:10)) euro_dist <- as.matrix(dist(df))2. 集合运算 union(x, y) # 并集 intersect(x, y) # 交集 setdiff(x, y) # 只在x中存在&#xff0c;y中不存在的元素 setequal(x, y)…

Linux内核源码分析 (B.3) 深入理解 Linux 物理内存分配全链路实现

Linux内核源码分析 (B.3) 深入理解 Linux 物理内存分配全链路实现 文章目录 Linux内核源码分析 (B.3) 深入理解 Linux 物理内存分配全链路实现[toc] 前文回顾1\. 内核物理内存分配接口2.规范物理内存分配行为的掩码 gfp\_mask3\. 物理内存分配内核源码实现3.1 内存分配行为标识…

HAProxy集群与常见的Web集群软件调度器对比

HAProxy集群与常见的Web集群软件调度器对比 1、常见的Web集群调度器2、Haproxy基本介绍2.1Haproxy是什么&#xff1f;2.2Haproxy的特性2.3Haproxy常用的8种负载均衡调度算法2.3.1轮询&#xff1a;RR&#xff08;Round Robin&#xff09;2.3.2最小连接数&#xff1a;LC&#xff…

【操作系统笔记】链接阶段ELF文件

链接阶段&#xff1a;符号解析 链接阶段主要包含&#xff1a; 符号解析重定位 一般情况下&#xff0c;每个 C 文件可以看成一个程序模块&#xff0c;比如下边的main.c就是一个程序模块 #include <stdio.h>extern int shared; int sum(int *a, int n); int array[2] …

关于RISC-V安全性的全面综述

目录 摘要引言RISC-V安全综述通用平台的安全要求信任的根源与硬件安全模块OTP管理模块安全内存对称加密&#xff08;如AES&#xff09;引擎不对称加密[131]&#xff08;例如&#xff0c;公钥RSA&#xff09;引擎HASH/HAMC引擎随机数/位生成&#xff08;例如TRNG[136]&#xff0…

滴滴 OrangeFS 数据湖存储关键技术揭秘!

2015年&#xff0c;滴滴为解决小文件和图片的存储&#xff0c;成立 GIFT 小对象存储项目。伴随着业务不断成长&#xff0c;我们面临的挑战也越来越多&#xff0c;经历多次非结构化存储架构演进&#xff0c;具体如下图所示&#xff1a; 随着公司不断发展&#xff0c;滴滴的业务有…

基于Java+SpringBoot+Vue的即可运动健身器材网站设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…

Spring Boot常见面试题

Spring Boot简介 Spring Boot 是由 Pivotal 团队提供&#xff0c;用来简化 Spring 应用创建、开发、部署的框架。它提供了丰富的Spring模块化支持&#xff0c;可以帮助开发者更轻松快捷地构建出企业级应用。Spring Boot通过自动配置功能&#xff0c;降低了复杂性&#xff0c;同…

ClickHouse进阶(十九):clickhouse管理与运维-权限管理

进入正文前&#xff0c;感谢宝子们订阅专题、点赞、评论、收藏&#xff01;关注IT贫道&#xff0c;获取高质量博客内容&#xff01; &#x1f3e1;个人主页&#xff1a;IT贫道_大数据OLAP体系技术栈,Apache Doris,Kerberos安全认证-CSDN博客 &#x1f4cc;订阅&#xff1a;拥抱…

MySQL数据库——索引(1)-概述以及B-Tree结构

目录 索引概述 介绍 优缺点 索引结构&#xff08;1&#xff09; 介绍 二叉树 B-Tree 索引这一个章节将分为以下几个部分来学习&#xff1a; 索引概述索引结构索引分类索引语法SQL性能分析索引使用索引设计原则 索引概述 介绍 索引&#xff08;index&#xff09;是帮助M…

基于SSM的星空游戏购买下载平台

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

RocketMq(四)消息分类

一、普通消息 1、同步发送消息&#xff1a;指的是Producer发出⼀条消息后&#xff0c;会在收到MQ返回的ACK之后才发下⼀条消息。该方式的消息可靠性最高&#xff0c;但消息发送效率低。 二、顺序消息 三、延时消息

JAVAAndroid实现MQTT上位机软件功能-订阅主题与发布主题

一、前言 本文我们将介绍Android或JAVA程序作为MQTT客户端连接MQTT服务器并订阅主题报文并发布主题报文&#xff0c;由于我的Android使用的也是JAVA语言&#xff0c;因此下面我们将使用IDEA完成JAVA程序&#xff0c;以实现订阅主题和发布主题的功能&#xff0c;该程序也可在后期…

MQ - 08 基础篇_消费者客户端SDK设计(下)

文章目录 导图Pre概述消费分组协调者消费分区分配策略轮询粘性自定义消费确认确认后删除数据确认后保存消费进度数据消费失败处理从服务端拉取数据失败本地业务数据处理失败提交位点信息失败总结导图 Pre

Linux系统编程(会话和进程)

文章目录 前言一、会话的概念二、会话和终端的区别三、终端进程组标识四、创建会话总结 前言 本篇文章我们来讲解会话和进程的概念&#xff0c;会话大家可能比较少见&#xff0c;他的英文名称叫session。 一、会话的概念 在Linux中&#xff0c;会话&#xff08;Session&…

9月15日上课内容 Zookeeper集群 + Kafka集群

Zookeeper 本章结构 Zookeeper 概述 Zookeeper 定义 *&#xff08;了解&#xff09; Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目。 Zookeeper 工作机制 *****&#xff08;非常重要&#xff0c;需要掌握&#xff09; Zookeeper从设计模式…

diffusers中DDPMScheduler/AutoencoderKL/UNet2DConditionModel/CLIPTextModel代码详解

扩散模型的训练时比较简单的 上图可见&#xff0c;unet是epsθ是unet。noise和预测出来的noise做个mse loss。 训练的常规过程&#xff1a; latents vae.encode(batch["pixel_values"].to(weight_dtype)).latent_dist_sample() latents latents*vae.config.scali…

QT连接Sqlite

使用QTCreator&#xff1b; 根据资料&#xff0c;Qt自带SQLite数据库&#xff0c;不需要再单独安装&#xff0c;默认情况下&#xff0c;使用SQLite版本3&#xff0c;驱动程序为***QSQLITE***&#xff1b; 首先创建项目&#xff1b;在 Build system 中应选中qmake&#xff0c;…

前端自定义导出PPT

1、背景 前端导出PPT&#xff0c;刚接触这个需求&#xff0c;还是比较懵逼&#xff0c;然后就在网上查找资料&#xff0c;最终确认是可行的&#xff1b;这个需求也是合理的&#xff0c;我们做了一个可视化数据报表&#xff0c;报表导出成PPT&#xff0c;将在线报表转成文档类型…