700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > linux c 程序异常退出时打印堆栈调用信息

linux c 程序异常退出时打印堆栈调用信息

时间:2021-04-24 23:52:41

相关推荐

linux c 程序异常退出时打印堆栈调用信息

先来了解三个函数

#include <execinfo.h>

int backtrace(void **buffer, intsize);

char **backtrace_symbols(void *const *buffer, intsize);

void backtrace_symbols_fd(void *const *buffer, intsize, intfd);

int backtrace(void **buffer,int size)该函数用与获取当前线程的调用堆栈,获取的信息将会被存放在buffer中,它是一个指针数组。参数 size 用来指定buffer中可以保存多少个void* 元素。函数返回值是实际获取的指针个数,最大不超过size大小在buffer中的指针实际是从堆栈中获取的返回地址,每一个堆栈框架有一个返回地址。注意某些编译器的优化选项对获取正确的调用堆栈有干扰,另外内联函数没有堆栈框架;删除框架指针也会使无法正确解析堆栈内容char ** backtrace_symbols (void *const *buffer, int size)backtrace_symbols将从backtrace函数获取的信息转化为一个字符串数组. 参数buffer应该是从backtrace函数获取的数组指针,size是该数组中的元素个数(backtrace的返回值),函数返回值是一个指向字符串数组的指针,它的大小同buffer相同.每个字符串包含了一个相对于buffer中对应元素的可打印信息.它包括函数名,函数的偏移地址,和实际的返回地址现在,只有使用ELF二进制格式的程序和苦衷才能获取函数名称和偏移地址.在其他系统,只有16进制的返回地址能被获取.另外,你可能需要传递相应的标志给链接器,以能支持函数名功能(比如,在使用GNU ld的系统中,你需要传递(-rdynamic))backtrace_symbols生成的字符串都是malloc出来的,但是不要最后一个一个的free,因为backtrace_symbols是根据backtrace给出的call stack层数,一次性的malloc出来一块内存来存放结果字符串的,所以,像上面代码一样,只需要在最后,free backtrace_symbols的返回指针就OK了。这一点backtrace的manual中也是特别提到的。注意:如果不能为字符串获取足够的空间函数的返回值将会为NULLvoid backtrace_symbols_fd (void *const *buffer, int size, int fd)backtrace_symbols_fd与backtrace_symbols 函数具有相同的功能,不同的是它不会给调用者返回字符串数组,而是将结果写入文件描述符为fd的文件中,每个函数对应一行.它不需要调用malloc函数,因此适用于有可能调用该函数会失败的情况。

程序测试:

#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <fcntl.h>#include <string.h>#include <signal.h>#include <execinfo.h>void out_stack(char *sig);void signal_exit(int dunno) { char* signal_str = "";char dunno_str[10] = {0};sprintf(dunno_str, "%d", dunno);switch (dunno) {case 1:signal_str = "SIGHUP(1)";break;case 2:signal_str = "SIGINT(2:CTRL_C)"; //CTRL_Cbreak;case 3:signal_str = "SIGQUIT(3)";break;case 6:{signal_str = "SIGABRT(6)";out_stack(signal_str);}break;case 9:signal_str = "SIGKILL(9)";break;case 15:signal_str = "SIGTERM(15 KILL)"; //kill break;case 11:{signal_str = "SIGSEGV(11)"; //SIGSEGV out_stack(signal_str);}break;default:signal_str = "OTHER";break;}exit(0);}static void output_addrline(char addr[]){char cmd[256];char line[256];char addrline[32]={0,};char *str1, *str2;FILE* file;str1 = strchr(addr,'[');str2 = strchr(addr, ']');if(str1 == NULL || str2 == NULL){return;}memcpy(addrline, str1 + 1, str2 -str1);snprintf(cmd, sizeof(cmd), "addr2line -e /proc/%d/exe %s ", getpid(), addrline);file = popen(cmd, "r");if(NULL != fgets(line, 256, file)) {printf("%s\n", line);}pclose(file);}void out_stack(char *sig){void *array[32];size_t size;char **strings;int i;printf("%s\n", sig);size = backtrace (array, 32);strings = backtrace_symbols (array, size);if (NULL == strings){printf("backtrace_symbols\n");return ;}for (i = 0; i < size; i++){printf("%s",strings[i]);output_addrline(strings[i]);}free(strings);}void test3(int n){char *str;printf("in test3 [%d]\n", n);strcpy(str, "123");}void test2(int n){printf("in test2 [%d]\n", n);test3(3);}void test1(int n){printf("in test1 [%d]\n", n);test2(2);}int main(){signal(SIGHUP, signal_exit); signal(SIGINT, signal_exit);signal(SIGQUIT, signal_exit);signal(SIGABRT, signal_exit);signal(SIGKILL, signal_exit);signal(SIGTERM, signal_exit);signal(SIGSEGV, signal_exit);test1(1);}

注意编译的时候要加-g 和 -rdynamic选项

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。