一.用途:
主要用于程序异常退出时寻找错误原因
二.功能:
回溯堆栈,简单的说就是可以列出当前函数调用关系
三.原理:
1. 通过对当前堆栈的分析,找到其上层函数在栈中的帧地址,再分析上层函数的堆栈,再找再上层的帧地址……一直找到最顶层为止,帧地址指的是一块:在栈上存放局部变量,上层返回地址,及寄存器值的空间。
2. 由于不同处理器堆栈方式不同,此功能的具体实现是编译器的内建函数__buildin_frame_address及 __buildin_return_address中,它涉及工具glibc和gcc, 如果编译器不支持此函数,也可自己实现此函数,举例中有arm上的实现
四.方法:
在程序中加入backtrace及相关函数调用
五.举例:
1. 一般backtrace的实现
i. 程序
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <execinfo.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <string.h>
- #include <unistd.h>
- #define PRINT_DEBUG
- static void print_reason(int sig, siginfo_t * info, void *secret)
- {
- void *array[10];
- size_t size;
- #ifdef PRINT_DEBUG
- char **strings;
- size_t i;
- size = backtrace(array, 10);
- strings = backtrace_symbols(array, size);
- printf("Obtained %zd stack frames.\n", size);
- for (i = 0; i < size; i++)
- printf("%s\n", strings);
- free(strings);
- #else
- int fd = open("err.log", O_CREAT | O_WRONLY);
- size = backtrace(array, 10);
- backtrace_symbols_fd(array, size, fd);
- close(fd);
- #endif
- exit(0);
- }
- void die()
- {
- char *test1;
- char *test2;
- char *test3;
- char *test4 = NULL;
- strcpy(test4, "ab");
- }
- void test1()
- {
- die();
- }
- int main(int argc, char **argv)
- {
- struct sigaction myAction;
- myAction.sa_sigaction = print_reason;
- sigemptyset(&myAction.sa_mask);
- myAction.sa_flags = SA_RESTART | SA_SIGINFO;
- sigaction(SIGSEGV, &myAction, NULL);
- sigaction(SIGUSR1, &myAction, NULL);
- sigaction(SIGFPE, &myAction, NULL);
- sigaction(SIGILL, &myAction, NULL);
- sigaction(SIGBUS, &myAction, NULL);
- sigaction(SIGABRT, &myAction, NULL);
- sigaction(SIGSYS, &myAction, NULL);
- test1();
- }
ii. 编译参数
gcc main.c -o test -g -rdynamic