• 正文
  • 相关推荐
申请入驻 产业图谱

嵌入式Linux利用core-dump文件和gdb工具分析程序崩溃问题

2025/12/31
130
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

之前介绍过使用backtrace的方式定位程序崩溃问题,本篇来介绍另一种方式,通过生成core-dump文件,再通过gdb工具来定位程序崩溃问题。

1 使用core-dump分析崩溃的条件

1.1 开启core-dump文件的生成条件

解除core 文件大小的限制,有临时生效和永久生效两种方案,在本篇的例子中,在Ubuntu中使用临时生效的方式,嵌入式Linux板子中,使用永久生效的方式进行测试。

1.1.1 临时生效

ulimit -c unlimited

1.1.2 永久生效

编辑 /etc/security/limits.conf,在文件末尾添加以下两行

* soft core unlimited
* hard core unlimited

说明:

* 表示对所有用户生效,若仅针对特定用户,可替换为用户名(如 root soft core unlimited

soft 为软限制(用户可临时调整)

hard 为硬限制(系统强制上限)

1.2 自定义core文件的名称与生成目录

1.2.1 临时生效

Ubuntu 系统默认通过 apport 接管了 core 文件,不会直接生成在程序运行目录。

若要生成core文件,需要如下指令:

# 停止 apport 服务(临时生效,重启后恢复)
sudo service apport stop

# 重置 core_pattern 为默认文件格式(生成在程序运行目录)
echo "/tmp/core-%e-%p-%t" | sudo tee /proc/sys/kernel/core_pattern

说明:

/tmp/:core 文件存储路径,可按需求指定

%e:程序名称,

%p:进程 PID,

%t:崩溃时间戳

1.2.2 永久生效

编辑 /etc/sysctl.conf,添加或修改以下参数:

kernel.core_pattern = /tmp/core-%e-%p-%t
kernel.core_uses_pid = 0

说明:

/tmp/:core 文件存储路径,可按需求指定

%e:程序名称,

%p:进程 PID,

%t:崩溃时间戳

kernel.core_uses_pid = 0:关闭默认的 PID 后缀命名,使用自定义规则

执行 sysctl -p 使配置立即生效

sysctl -p

可以再通过查看

cat /proc/sys/kernel/core_pattern

1.3 需要配有gdb工具

查看版本号,确认有没有gdb工具

gdb --version

1.4 编译时加上-g选项

用于调试的代码不需要修改,只需要在编译时加上-g的选项,例如:

/gcc -g test.c -o test

2 在Ubuntu虚拟机上测试

2.1 测试代码

//gcc -g test.c -o test

#include <stdio.h>

void TestFun()
{
    printf("[%s] inn", __func__);
    
int a[2] = {123, 456};
printf("[%s] a[1]=%dn", a[0]); // 这里会崩溃,少了__func__

printf("[%s] outn", __func__);
}

int main()
{
 TestFun();
return0;
}

这里在printf格式化打印时,想打印函数名,但忘记写__func__,将会导致程序崩溃。

2.2 实测结果

2.2.1 编译、临时配置与运行

先在Ubuntu虚拟机中编译并测试:

程序运行后,生成了core文件

2.2.2 gdb调试core文件

使用Ubuntu中的gdb工具调试core,定位到了崩溃的行号:

3 在嵌入式Linux板子上测试

3.1 交叉编译代码

在Linux板子中运行,需要使用交叉编译的程序,例如我的这个板子:

export PATH=/home/xxpcb/myTest/OK3568/gcc_aarch64/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
aarch64-linux-gnu-gcc -g test.c -o test

3.2 运行

将编译好的程序放到板子中运行

板子里没有gdb工具,可以将core文件拷到Ubuntu中进行分析。

3.3 永久配置测试

在分析板子中的core文件之前,先来对板子的core文件生成进行永久配置:

3.3.1 配置limits.conf

编辑 /etc/security/limits.conf,在文件末尾添加以下两行

* soft core unlimited
* hard core unlimited

3.3.2 配置sysctl.conf

编辑 /etc/sysctl.conf,添加或修改以下参数:

kernel.core_pattern = /tmp/core-%e-%p-%t
kernel.core_uses_pid = 0

3.3.3 初步验证

重启板子,看下是否是默认开始了core。

实际是ulimit和core文件的名称和生成位置都没有生效,需要再使用其它方式继续配置。

3.3.4 将ulimit指令添加到/etc/profile

对于ulimit没生效,可以在/etc/profile文件末尾添加:

ulimit -c unlimited > /dev/null 2>&1

3.3.5 将sysctl加入开机启动

对于core文件的名称和生成位置未生效,可以在 /etc/rc.local 中配置:

#!/bin/sh -e

/sbin/sysctl -p /etc/sysctl.conf > /dev/null 2>&1

exit 0

注:

-e 表示脚本遇到错误时立即退出

sysctl -p 是系统级初始化操作,应放在开机启动脚本(rc.local/systemd)中

ulimit -c 是用户会话级配置,放在 /etc/profile 更合理(或也放 rc.local 实现全局生效)

然后给rc.local可执行权限,并运行检查是否报错:

chmod +x rc.local
/etc/rc.local
echo $?  # 输出 0 表示执行成功

最后将rc.local添加到开机启动:

ln -s /etc/rc.local /etc/init.d/rc.local

rc.local还需要通过rcS脚本在开机时调用,在rcS脚本中添加调用的逻辑:

# 新增:调用 rc.local
if [ -x /etc/rc.local ]; then
    /etc/rc.local
fi

然后重启板子

3.3.6 再次验证

这次重启板子后,默认配置就对了

运行程序,在指定位置生成了指定格式名称的core文件

3.3.7 将core文件拷回ubuntu中分析

因为是嵌入式Liunx中的程序的core文件,架构与Ubuntu不一样,需要使用交叉编译工具链的gdb进行core文件的调试

export PATH=/home/xxpcb/myTest/OK3568/gcc_aarch64/gcc-linaro-7.5.0-2019.12-x86_64_aarch64-linux-gnu/bin:$PATH
aarch64-linux-gnu-gcc -g -static test.c -o test

实测结果,定位不到具体的行号,应该是找不到相关的动态库

3.3.8 编译时静态链接,避免库依赖

一种解决方案是,在编译程序的时候,使用静态链接:

静态连接生成的可执行文件会比较大,比如使用scp将文件拷贝到板子中:

scp test root@192.168.5.113:/home/mytest/cpp/test

再次在板子中运行,再将core文件拷回Ubuntu:

最终,使用交叉编译工具链的gdb进行core文件的调试,定位到了具体的行号:

4 总结

本篇文件,介绍了嵌入式Linux中如何利用core-dump文件和gdb工具来分析程序崩溃问题,并在Ubuntu虚拟机和嵌入式Linux板子中分别进行了实际的测试,演示了定位到程序崩溃的具体代码位置和行号。

相关推荐

登录即可解锁
  • 海量技术文章
  • 设计资源下载
  • 产业链客户资源
  • 写文章/发需求
立即登录