1、backtrace和backtrace_symbols函数
这两个函数的主要作用是打印出函数的调用方式,即压栈的信息。
使用方法:
static void dump(void)
{
void *buffer[30] = {0};
size_t size;
char **strings = NULL;
size_t i = 0;
size = backtrace(buffer, 30);
fprintf(stdout, "Obtained %zd stack frames.nm\n", size);
strings = backtrace_symbols(buffer, size);
if (strings == NULL)
{
perror("backtrace_symbols.");
exit(EXIT_FAILURE);
}
for (i = 0; i < size; i++)
{
fprintf(stdout, "%s\n", strings[i]);
}
free(strings);
strings = NULL;
}
这两个函数是获取调用函数的栈的信息,如果遇到段错误的时候根据退栈信息大体能定位出是在哪个函数或者什么地方出的问题。
2、初始化信号量
void initSegvCatch()
{
struct sigaction act;
sigemptyset(&act.sa_mask);
act.sa_sigaction = OnSIGSEGV;
act.sa_flags = SA_SIGINFO;
if(sigaction(SIGSEGV, &act, NULL)<0 )
{
perror("sigaction:");
}
}
3、回调函数
static void dump(void)
{
void *buffer[30] = {0};
size_t size;
char **strings = NULL;
size_t i = 0;
size = backtrace(buffer, 30);
fprintf(stdout, "Obtained %zd stack frames.nm\n", size);
strings = backtrace_symbols(buffer, size);
if (strings == NULL)
{
perror("backtrace_symbols.");
exit(EXIT_FAILURE);
}
for (i = 0; i < size; i++)
{
fprintf(stdout, "%s\n", strings[i]);
}
free(strings);
strings = NULL;
}
static void OnSIGSEGV(int signum, siginfo_t *info, void *ptr)
{
printf("\n-------------------------- 进程挂掉时的MAPS文件 --------------------------\n");
/* 动态链接库的映射地址是动态的,需要将maps文件打印出来 */
char file[64], buffer[1032];
pid_t pid = getpid();
snprintf(file, sizeof(file), "/proc/%d/maps", pid);
FILE *fp = fopen(file, "r");
if (NULL != fp)
{
while(fgets(buffer, 1024, fp))
{
fputs(buffer, stdout);
}
}
else
{
printf("读取MAPS文件失败!\n");
}
debuging("-------------------------------------------------------------------------\n\n");
debuging("---------------------------进程挂掉时的堆栈信息--------------------------\n");
static int iTime = 0;
if (iTime++ >= 1)
{ /* 容错处理:如果访问 ucontext_t 结构体时产生错误会进入该分支 */
debuging("ReEnter %s is not allowed!\n", __FUNCTION__);
abort();
}
dump();
debuging("-------------------------------------------------------------------------\n\n");
abort();
}
4、说明
通过信号量