您的位置:首页 > 运维架构 > Linux

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

2018-08-04 16:51 288 查看

需求
如果程序崩溃的话,我们希望留下程序崩溃在的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)
{
nSi
4000
ze = 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
}
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐