打印堆栈函数
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h> // backtrace, backtrace_symbols
void print_stack_trace(void) {
void *trace[16];
char **messages = NULL;
int i, trace_size = 0;
trace_size = backtrace(trace, 16);
messages = backtrace_symbols(trace, trace_size);
printf("[bt] Execution path:\n");
for (i = 0; i < trace_size; i++)
printf("[bt] %s\n", messages[i]);
}
void foo(void) {
print_stack_trace();
}
int main(int argc, char **argv) {
foo();
return 0;
}
注册 exit handler
《LINUX 系统编程》
系统调用 atexit() 是由 POSIX 1003.1-2001 所定义,Linux 也实现了该函数。它是用来注册一些在进程结束时要调用的函数:
#include <stdlib.h> int atexit (void (*function)(void));
atexit() 调用成功时,会注册指定的函数作为终止函数,在程序正常结束时(即进程通过调用 exit() 或从 main() 函数返回)运行。如果进程调用了 exec 函数(exec函数族,用于在当前进程中执行一个新的程序),会清空所注册的函数列表(这些函数不再存在于新进程的地址空间中)。通过信号结束的进程也不会调用这些注册的函数。
指定函数必须是无参的,且没有返回值。函数形式如下:
void my_function (void);
函数调用的顺序和注册的顺序相反。也就是说,这些函数是存储在栈中,以后进先出的方式被调用(LIFO)。注册的函数不能调用 exit(),否则会导致递归调用死循环。如果需要提前结束进程,应该调用 _exit()。
POSIX 标准要求 atexit() 至少支持注册 ATEXIT_MAX 个注册函数,而且这个值至少是32.具体的最大值可以通过 sysconf() 得到,参数是 _SC_ATEXIT_MAX:
#include <unistd.h> // sysconf #include <stdlib.h> // _SC_ATEXIT_MAX long atexit_max = sysconf (_SC_ATEXIT_MAX); printf ("atexit_max=%ld\n", atexit_max);
成功时,atexit() 返回 0。错误时,返回 -1。
进一步解析堆栈信息
利用 addr2line 工具打印代码具体行数 -e 指定执行程序 -f 打印函数名称和具体行数