一、引言
- 嵌入式系统在我们的日常生活中扮演的角色越来越多。嵌入式Linux是将日益流行的Linux操作系统进行裁剪修改,使之能在嵌入式计算机系统上运行的一种操作系统,它既继承了Internet上无限的开放源代码资源,又具有嵌入式操作系统的特性。其中基于Linux的嵌入式系统就占据了半壁江山。
- 对于嵌入式Linux系统,其应用软件在实际运行过程中难免会出现一系列问题,为了防止程序崩溃等异常状况导致实际使用过程中出现故障,需要进行设备软件的状态监测。
- 对于软件层面问题的排查,无非就是老生常谈的程序崩溃、程序死锁、内存泄漏等。对于一些需要一直运行的程序,人工排查问题实在过于麻烦,所以此设计就是写一个守护程序,让其后台自动检查设备中运行的进程状态,进而将出现问题的地方记录到日志,方便后续对问题的处理。
二、程序崩溃的检测
*简要思路:当Linux程序异常崩溃时,都会产生core文件,我们只需要监控生成core文件的那个目录,一有新的文件生成,就利用gdb对core文件进行调试,获取到需要的信息,并打印堆栈信息。
1、Linux程序core dump
Linux下程序如果异常终止或者崩溃,操作系统会将程序崩溃时的内存保存下来,并储存在一个文件里。这种行为就叫做core dump(中文译为:核心转储),除了内存信息,一些关键的程序运行状态也会被记录在core文件中。core dump对程序员诊断调试程序都有很大的帮助,一些难以复现的问题都可以通过调试core文件中的信息查找出来。
->打开core dump功能 :
- 可以在终端利用命令unlimit -c查看设备是否开启,若输出为0则代表没有开启,若为非零数字则代表限制生成core文件大小为该数字KB,若为unlimited,则代表无限制;
- 命令unlimit -c unlimited 可以开启,也可以将unlimited换为具体数字以控制core文件大小;
- 输入上述命令只能让设置在当前终端有效,若想永久生效,则要改
/etc/security/limits.conf
文件。
->设置core文件的路径以及命名方式
- 默认的生成路径是输出的可执行文件目录下,且默认名称为"core",新产生的会覆盖旧的文件。
- 设置core文件带pid:
修改 /proc/sys/kernel/core_uses_pid 文件内容为: 1
修改文件命令: echo “1” > /proc/sys/kernel/core_uses_pid
或者sysctl -w kernel.core_uses_pid=1 kernel.core_uses_pid = 1 - 设置路径及其他标签
修改文件: echo “/core/core_%e_%p_%t” > /proc/sys/kernel/core_pattern
或者:
sysctl -w kernel.core_pattern=/core/core_%e_%p_%t
%p - insert pid into filename 添加pid(进程id)
%u - insert current uid into filename 添加当前uid(用户id)
%g - insert current gid into filename 添加当前gid(用户组id)
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加导致产生core的命令
** 这里需要注意,设置的路径必须有写入权限,否则是无法生成core文件的。
2、生成core文件目录的监控
针对Linux下文件的变化,我们需要用到inotify.h中的函数。(Linux inotify具体内容参见此处)
- 在生成core文件的目录下创建一个监听(watch),事件掩码设为IN_CREATE(生成文件)
- 循环read事件,若读取到文件创建则调用gdb去调试core
//创建文件描述符
int file = inotify_init();
if (file == -1) {
free(buff);
LOG("inotify init failed:%s\n", strerror(errno));
return -1;
}
char *core_file = (char *)malloc(50);
if (core_file == NULL) {
free(buff);
LOG("%s malloc failed", "core_file");
return -1;
}
sprintf(core_file, "%s", CORE_PATH);//core文件路径
//添加文件变化事件watch
int wd = inotify_add_watch(file, core_file, IN_CREATE);
if (wd == -1) {
free(buff);
free(core_file);
LOG("watch failed:%s\n",