linux c程序崩溃前执行回调函数(包括打印core堆栈信息,也可以做我们想做的其他事情)

需求
如果程序崩溃的话,我们希望留下程序崩溃在的core信息,记录了程序崩溃的原因,崩溃的函数,甚至可以定位到文件的第几行
思想
实现思想很简单即是:使用信号捕捉。

具体思想:
例如我们捕捉到段错误信号,那么就去执行回调函数执行,记录core信息,而linux c为我们提供了打印core信息的函数即是backtrace()函数,获取函数调用堆栈帧数据

具体实现:
第一部分,建立信号捕捉集合
第二部分:写回调函数

第一部分,建立信号捕捉集合

    #其中saveBackTrace为回调函数
    signal(SIGSEGV, saveBackTrace);
    signal(SIGILL, saveBackTrace);
    signal(SIGFPE, saveBackTrace);
    signal(SIGABRT, saveBackTrace);
    signal(SIGTERM, saveBackTrace);
    signal(SIGKILL, saveBackTrace);
    signal(SIGXFSZ, saveBackTrace);

    // block SIGINT to all child process:
    sigset_t bset, oset;
    sigemptyset(&bset);
    sigaddset(&bset, SIGINT);
    // equivalent to sigprocmask
    #设置信号为阻塞信号
    if (pthread_sigmask(SIG_BLOCK, &bset, &oset) != 0)
    {
        printf("set thread signal mask error!");
        return 0;
    }

第二部分:写回调函数

void saveBackTrace(int signal)
{

    #先执行其他回调函数
    if (pErrorExit != NULL)
    {
        (*pErrorExit)();
    }
    time_t tSetTime;
    time( &tSetTime);
    tm ptm;
    #以生成core的日期为文件名
    localtime_r(&tSetTime, &ptm) ;
    char fname[256] = {0};
    sprintf(fname, "core.%d-%d-%d %d:%d:%d",
        ptm.tm_year + 1900, ptm.tm_mon + 1, ptm.tm_mday,
        ptm.tm_hour, ptm.tm_min, ptm.tm_sec);

    FILE* f = fopen(fname, "a");
    if (f == NULL)
    {
        return;
    }
    int fd = fileno(f);
    fcntl(fd, F_SETLKW, file_lock(F_WRLCK, SEEK_SET));

    char buffer[4096] = {0};
    int count = readlink("/proc/self/exe", buffer, 4096);
    if(count > 0)
    {
        buffer[count] = '\n';
        buffer[count + 1] = 0;
        fwrite(buffer, 1, count + 1, f);
        fflush(f);
    }

    sprintf(buffer, "Dump Time: %d-%d-%d %d:%d:%d\n",
        ptm.tm_year + 1900, ptm.tm_mon + 1, ptm.tm_mday,
        ptm.tm_hour, ptm.tm_min, ptm.tm_sec);
    fwrite(buffer, 1, strlen(buffer), f);
    fflush(f);

    #记录捕捉到的信号
    strcpy(buffer, "Catch signal: ");
    switch (signal)
    {
    case SIGSEGV: strcat(buffer, "SIGSEGV\n");
        break;
    case SIGILL: strcat(buffer, "SIGILL\n");
        break;
    case SIGFPE: strcat(buffer, "SIGFPE\n");
        break;
    case SIGABRT: strcat(buffer, "SIGABRT\n");
        break;
    case SIGTERM: strcat(buffer, "SIGTERM\n");
        break;
    case SIGKILL: strcat(buffer, "SIGKILL\n");
        break;
    case SIGXFSZ: strcat(buffer, "SIGXFSZ\n");
        break;
    default: sprintf(buffer, "Catch signal: %d\n", signal);
        break;
    }
    fwrite(buffer, 1, strlen(buffer), f);
    fflush(f);

    #打印一些全局变量
    sprintf(buffer, "Processing cmd: %d\n", g_processingCmd);
    fwrite(buffer, 1, strlen(buffer), f);
    fflush(f);
    sprintf(buffer, "Processing uid: %lld\n", g_processingUID);
    fwrite(buffer, 1, strlen(buffer), f);
    fflush(f);

    #打印堆栈信息
    void* DumpArray[256];
    int nSize = backtrace(DumpArray, 256);
    char** symbols = backtrace_symbols(DumpArray, nSize);
    if (symbols)
    {
        if (nSize > 256)
        {
            nSize = 256;
        }
        if (nSize > 0)
        {
            for (int i = 0; i < nSize; i++)
            {
                fwrite(symbols[i], 1, strlen(symbols[i]), f);
                fwrite("\n", 1, 1, f);
                fflush(f);
            }
        }
        free(symbols);
    }
    fcntl(fd, F_SETLK, file_lock(F_UNLCK, SEEK_SET));
    fclose(f);

    exit(1);
#endif
}

猜你喜欢

转载自blog.csdn.net/weixin_37098881/article/details/81412693
今日推荐