工具函数: atexit, signal
在嵌入式调试中,经常有segment_fault, 但却没有core_dump(当然ulimit是打开的),此时应该怎样调试?
第一种(常规办法), 从main 开始单步跟踪函数找到问题点
第二种(查看崩溃时的调用堆栈), 可是core_dump 没有生成,如何查看呢?
然后我们在回调函数中打印出当前的函数调用栈,就可以知道程序在哪里退出了.
1. 正常退出, 调用atexit()函数,安装exit 时的回调函数
程序的正常退出会调用exit()函数
不过exit 是c 库函数,我们最好中断到我们自己的函数中,所以,
在程序开始时,通过系统提供的atexit(),向系统注册一个回调函数,在程序调用exit()退出的时候,exit会调用这个回调函数就,
使用atexit函数。
头文件:#include <stdlib.h>,
函数原型:int atexit(void (*func)(void));
atexit可以调用多次,注册多个回调函数,在进程退出时调用.
2. 异常退出, 调用signal(), 安装信号处理器
相应某些signal 的默认处理是异常退出,处理方法是使用signal 函数, 注册自己的回调函数,避免系统默认回调,
因为系统的默认回调往往是杀死进程, 下面是常用的信号处理框架!
#include <signal.h>
void before_exit(void)
{
printf("that's all, folks!\n");
}
void crash_handler(int sig)
{
printf("crash_handler! sig is %d\n",sig);
exit(-1); //exit 会回调before_exit, 因为已经注册
}
void signal_exit_handler(int sig)
{
exit(0);
}
int main(int argc, char *argv[])
{
atexit(before_exit);
signal(SIGTERM, signal_exit_handler);
signal(SIGINT, signal_exit_handler);
// ignore SIGPIPE
signal(SIGPIPE, SIG_IGN);
signal(SIGBUS, crash_handler); // 总线错误
signal(SIGSEGV, crash_handler); // SIGSEGV,非法内存访问
signal(SIGFPE, crash_handler); // SIGFPE,数学相关的异常,如被0除,浮点溢出,等等
signal(SIGABRT, crash_handler); // SIGABRT,由调用abort函数产生,进程非正常退出
return 0;
}
3. 段错误退出,
这只是异常退出的一个特例, 该方法可以做为<segment_fault 的一种处理方法>(另一篇博客)的更完善补充
只所以单独来说,是因为它太普遍了.
signal(SIGSEGV, crash_handler); // SIGSEGV,非法内存访问
实例:
#include <stdio.h>
#include <signal.h>
void crash_handler(int sig)
{
(void) sig;
printf("crash_handler!\n");
}
int test_crash2(int *p)
{
int i;
i=*p; // 此句会引起segment fault, 该segment falut事件会激发signal,并回调crash_handler
return i;
}
int test_crash(int *p)
{
int j;
j=test_crash2(p);
return j;
}
int main()
{
signal(SIGSEGV, crash_handler); //安装segment fault 事件处理器
printf("hello\n");
int k = test_crash(0); // 传入一个非法地址
printf("k is %d\n",k);
return 0;
}