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

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

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

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

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

1.1.1 临时生效

sh 复制代码
ulimit -c unlimited

1.1.2 永久生效

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

sh 复制代码
* soft core unlimited
* hard core unlimited

说明:

  • * 表示对所有用户生效,若仅针对特定用户,可替换为用户名(如 root soft core unlimited
  • soft 为软限制(用户可临时调整)
  • hard 为硬限制(系统强制上限)

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

1.2.1 临时生效

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

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

sh 复制代码
# 停止 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,添加或修改以下参数:

sh 复制代码
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 使配置立即生效

sh 复制代码
sysctl -p

可以再通过查看

sh 复制代码
cat /proc/sys/kernel/core_pattern

1.3 需要配有gdb工具

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

sh 复制代码
gdb --version

1.4 编译时加上-g选项

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

sh 复制代码
/gcc -g test.c -o test

2 在Ubuntu虚拟机上测试

2.1 测试代码

c 复制代码
//gcc -g test.c -o test

#include <stdio.h>

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

int main()
{
	TestFun();
	return 0;
}

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

2.2 实测结果

2.2.1 编译、临时配置与运行

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

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

2.2.2 gdb调试core文件

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

3 在嵌入式Linux板子上测试

3.1 交叉编译代码

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

sh 复制代码
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,在文件末尾添加以下两行

sh 复制代码
* soft core unlimited
* hard core unlimited

3.3.2 配置sysctl.conf

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

sh 复制代码
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文件末尾添加:

bash 复制代码
ulimit -c unlimited > /dev/null 2>&1

3.3.5 将sysctl加入开机启动

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

sh 复制代码
#!/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可执行权限,并运行检查是否报错:

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

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

sh 复制代码
ln -s /etc/rc.local /etc/init.d/rc.local

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

sh 复制代码
# 新增:调用 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文件的调试

sh 复制代码
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将文件拷贝到板子中:

sh 复制代码
scp test root@192.168.5.113:/home/mytest/cpp/test

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

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

4 总结

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

相关推荐
天竺鼠不该去劝架2 小时前
传统财务管理瓶颈:财务机器人如何提升效率
大数据·数据库·人工智能
大聪明-PLUS2 小时前
数字与字节:Linux 中的内存是如何工作的?
linux·嵌入式·arm·smarc
猿小喵2 小时前
MySQL数据库binlog解析
数据库·mysql
橙汁味的风2 小时前
6关系数据理论
数据库
旖旎夜光2 小时前
Linux(6)(下)
linux·学习
牛魔王_12 小时前
SqlServer 大数据量分页查询
数据库·sqlserver·分页·查询·翻页
醉风塘2 小时前
MongoDB持久化深度解析:从数据安全到性能平衡的艺术
数据库·mongodb
典孝赢麻崩乐急2 小时前
Redis复习------跳表
数据库·redis·缓存
✿ ༺ ོIT技术༻2 小时前
Redis:Redis背景、特性、客户端及单线程模型
数据库·redis·缓存