Bootstrap

基于嵌入式Linux设备状态监测系统(一)程序崩溃检测

一、引言

  • 嵌入式系统在我们的日常生活中扮演的角色越来越多。嵌入式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",新产生的会覆盖旧的文件。
  1. 设置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
  2. 设置路径及其他标签
    修改文件: 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", 
;